Home | History | Annotate | Download | only in usr.sbin
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <stdio.h>
     27 #include <sys/stat.h>
     28 #include <stdlib.h>
     29 #include <unistd.h>
     30 #include <string.h>
     31 #include <ctype.h>
     32 #include <locale.h>
     33 
     34 #define	MAXLINELEN	4096
     35 
     36 /*
     37  * Usage:
     38  *	sonconfig -f <file>
     39  *		Reads input from file. The file is structured as
     40  *			 <fam> <type> <protocol> <path|module>
     41  *			 <fam> <type> <protocol>
     42  *		with the first line registering and the second line
     43  *		deregistering.
     44  *
     45  *	soconfig <fam> <type> <protocol> <path|module>
     46  *		registers
     47  *
     48  *	soconfig <fam> <type> <protocol>
     49  *		deregisters
     50  */
     51 
     52 static int	parse_file(char *filename);
     53 
     54 static int	split_line(char *line, char *argvec[], int maxargvec);
     55 
     56 static int	parse_params(char *famstr, char *typestr, char *protostr,
     57 				char *path, int line);
     58 
     59 static int	parse_int(char *str);
     60 
     61 static void	usage(void);
     62 
     63 int
     64 main(argc, argv)
     65 	int argc;
     66 	char *argv[];
     67 {
     68 	int ret;
     69 
     70 	argc--; argv++;
     71 
     72 	(void) setlocale(LC_ALL, "");
     73 #if !defined(TEXT_DOMAIN)
     74 #define	TEXT_DOMAIN "SYS_TEST"
     75 #endif
     76 	(void) textdomain(TEXT_DOMAIN);
     77 
     78 	if (argc == 2 && strcmp(argv[0], "-f") == 0) {
     79 		ret = parse_file(argv[1]);
     80 		exit(ret);
     81 	}
     82 	if (argc == 3) {
     83 		ret = parse_params(argv[0], argv[1], argv[2], NULL, -1);
     84 		exit(ret);
     85 	}
     86 	if (argc == 4) {
     87 		ret = parse_params(argv[0], argv[1], argv[2], argv[3], -1);
     88 		exit(ret);
     89 	}
     90 	usage();
     91 	exit(1);
     92 	/* NOTREACHED */
     93 }
     94 
     95 static void
     96 usage(void)
     97 {
     98 	fprintf(stderr, gettext(
     99 	    "Usage:	soconfig -f <file>\n"
    100 	    "\tsoconfig <fam> <type> <protocol> <path|module>\n"
    101 	    "\tsoconfig <fam> <type> <protocol>\n"));
    102 }
    103 
    104 /*
    105  * Open the specified file and parse each line. Skip comments (everything
    106  * after a '#'). Return 1 if at least one error was encountered; otherwise 0.
    107  */
    108 static int
    109 parse_file(char *filename)
    110 {
    111 	char line[MAXLINELEN];
    112 	char pline[MAXLINELEN];
    113 	int argcount;
    114 	char *argvec[20];
    115 	FILE *fp;
    116 	int linecount = 0;
    117 	int numerror = 0;
    118 
    119 	fp = fopen(filename, "r");
    120 	if (fp == NULL) {
    121 		perror("soconfig: open");
    122 		fprintf(stderr, "\n");
    123 		usage();
    124 		return (1);
    125 	}
    126 
    127 	while (fgets(line, sizeof (line) - 1, fp) != NULL) {
    128 		linecount++;
    129 		strcpy(pline, line);
    130 		argcount = split_line(pline, argvec,
    131 		    sizeof (argvec) / sizeof (argvec[0]));
    132 #ifdef DEBUG
    133 		{
    134 			int i;
    135 
    136 			printf("scanned %d args\n", argcount);
    137 			for (i = 0; i < argcount; i++)
    138 				printf("arg[%d]: %s\n", i, argvec[i]);
    139 		}
    140 #endif /* DEBUG */
    141 		switch (argcount) {
    142 		case 0:
    143 			/* Empty line - or comment only line */
    144 			break;
    145 		case 3:
    146 			numerror += parse_params(argvec[0], argvec[1],
    147 			    argvec[2], NULL, linecount);
    148 			break;
    149 		case 4:
    150 			numerror += parse_params(argvec[0], argvec[1],
    151 			    argvec[2], argvec[3], linecount);
    152 			break;
    153 		default:
    154 			numerror++;
    155 			fprintf(stderr,
    156 			    gettext("Malformed line: <%s>\n"), line);
    157 			fprintf(stderr,
    158 			    gettext("\ton line %d\n"), linecount);
    159 			break;
    160 		}
    161 	}
    162 	(void) fclose(fp);
    163 
    164 	if (numerror > 0)
    165 		return (1);
    166 	else
    167 		return (0);
    168 }
    169 
    170 /*
    171  * Parse a line splitting it off at whitspace characters.
    172  * Modifies the content of the string by inserting NULLs.
    173  */
    174 static int
    175 split_line(char *line, char *argvec[], int maxargvec)
    176 {
    177 	int i = 0;
    178 	char *cp;
    179 
    180 	/* Truncate at the beginning of a comment */
    181 	cp = strchr(line, '#');
    182 	if (cp != NULL)
    183 		*cp = NULL;
    184 
    185 	/* CONSTCOND */
    186 	while (1) {
    187 		/* Skip any whitespace */
    188 		while (isspace(*line) && *line != NULL)
    189 			line++;
    190 
    191 		if (i >= maxargvec)
    192 			return (i);
    193 
    194 		argvec[i] = line;
    195 		if (*line == NULL)
    196 			return (i);
    197 		i++;
    198 		/* Skip until next whitespace */
    199 		while (!isspace(*line) && *line != NULL)
    200 			line++;
    201 		if (*line != NULL) {
    202 			/* Break off argument */
    203 			*line++ = NULL;
    204 		}
    205 	}
    206 	/* NOTREACHED */
    207 }
    208 
    209 /*
    210  * Parse the set of parameters and issues the sockconfig syscall.
    211  * If line is not -1 it is assumed to be the line number in the file.
    212  */
    213 static int
    214 parse_params(char *famstr, char *typestr, char *protostr, char *path, int line)
    215 {
    216 	int fam, type, protocol;
    217 
    218 	fam = parse_int(famstr);
    219 	if (fam == -1) {
    220 		fprintf(stderr, gettext("Bad family number: %s\n"), famstr);
    221 		if (line != -1)
    222 			fprintf(stderr,
    223 			    gettext("\ton line %d\n"), line);
    224 		else {
    225 			fprintf(stderr, "\n");
    226 			usage();
    227 		}
    228 		return (1);
    229 	}
    230 
    231 	type = parse_int(typestr);
    232 	if (type == -1) {
    233 		fprintf(stderr,
    234 		    gettext("Bad socket type number: %s\n"), typestr);
    235 		if (line != -1)
    236 			fprintf(stderr,
    237 			    gettext("\ton line %d\n"), line);
    238 		else {
    239 			fprintf(stderr, "\n");
    240 			usage();
    241 		}
    242 		return (1);
    243 	}
    244 
    245 	protocol = parse_int(protostr);
    246 	if (protocol == -1) {
    247 		fprintf(stderr,
    248 		    gettext("Bad protocol number: %s\n"), protostr);
    249 		if (line != -1)
    250 			fprintf(stderr,
    251 			    gettext("\ton line %d\n"), line);
    252 		else {
    253 			fprintf(stderr, "\n");
    254 			usage();
    255 		}
    256 		return (1);
    257 	}
    258 
    259 
    260 	if (path != NULL) {
    261 		struct stat stats;
    262 
    263 		if (strncmp(path, "/dev", strlen("/dev")) == 0 &&
    264 		    stat(path, &stats) == -1) {
    265 			perror(path);
    266 			if (line != -1)
    267 				fprintf(stderr,
    268 				    gettext("\ton line %d\n"), line);
    269 			else {
    270 				fprintf(stderr, "\n");
    271 				usage();
    272 			}
    273 			return (1);
    274 		}
    275 	}
    276 
    277 #ifdef DEBUG
    278 	printf("not calling sockconfig(%d, %d, %d, %s)\n",
    279 	    fam, type, protocol, path == NULL ? "(null)" : path);
    280 #else
    281 	if (_sockconfig(fam, type, protocol, path) == -1) {
    282 		perror("sockconfig");
    283 		return (1);
    284 	}
    285 #endif
    286 	return (0);
    287 }
    288 
    289 static int
    290 parse_int(char *str)
    291 {
    292 	char *end;
    293 	int res;
    294 
    295 	res = strtol(str, &end, 0);
    296 	if (end == str)
    297 		return (-1);
    298 	return (res);
    299 }
    300