xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/soconfig.c (revision d656abb5804319b33c85955a73ee450ef7ff9739)
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