cmd-inet/usr.sbin: remove -Wno-implicit-function-declaration
[unleashed.git] / usr / src / cmd / cmd-inet / usr.sbin / soconfig.c
blob7fac0f2a63e507528e340f6b8e479c670d2dd5d2
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
26 #include <ctype.h>
27 #include <dirent.h>
28 #include <errno.h>
29 #include <locale.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/socket.h>
34 #include <sys/socketvar.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
38 #define MAXLINELEN 4096
40 int _sockconfig(int, void *, void *, void *, void *);
43 * Usage:
44 * soconfig -d <dir>
45 * Reads input from files in dir.
47 * soconfig -f <file>
48 * Reads input from file. The file is structured as
49 * <fam> <type> <protocol> <path|module>
50 * <fam> <type> <protocol>
51 * with the first line registering and the second line
52 * deregistering.
54 * soconfig <fam> <type> <protocol> <path|module>
55 * registers
57 * soconfig <fam> <type> <protocol>
58 * deregisters
60 * soconfig -l
61 * print the in-kernel socket configuration table
63 * Filter Operations (Consolidation Private):
65 * soconfig -F <name> <modname> {auto [top | bottom | before:filter |
66 * after:filter] | prog} <fam>:<type>:<proto>,...
67 * configure filter
69 * soconfig -F <name>
70 * unconfigures filter
73 static int parse_files_in_dir(const char *dir);
75 static int parse_file(char *filename);
77 static int split_line(char *line, char *argvec[], int maxargvec);
79 static int parse_params(char *famstr, char *typestr, char *protostr,
80 char *path, const char *file, int line);
82 static int parse_int(char *str);
84 static void usage(void);
86 static int parse_filter_params(int argc, char **argv);
88 static int print_socktable();
90 int
91 main(argc, argv)
92 int argc;
93 char *argv[];
95 int ret;
97 argc--; argv++;
99 (void) setlocale(LC_ALL, "");
100 #if !defined(TEXT_DOMAIN)
101 #define TEXT_DOMAIN "SYS_TEST"
102 #endif
103 (void) textdomain(TEXT_DOMAIN);
105 if (argc == 1 && strcmp(argv[0], "-l") == 0) {
106 ret = print_socktable();
107 exit(ret);
110 if (argc >= 2 && strcmp(argv[0], "-F") == 0) {
111 argc--; argv++;
112 ret = parse_filter_params(argc, argv);
113 exit(ret);
115 if (argc == 2 && strcmp(argv[0], "-d") == 0) {
116 ret = parse_files_in_dir(argv[1]);
117 exit(ret);
119 if (argc == 2 && strcmp(argv[0], "-f") == 0) {
120 ret = parse_file(argv[1]);
121 exit(ret);
123 if (argc == 3) {
124 ret = parse_params(argv[0], argv[1], argv[2], NULL, NULL, -1);
125 exit(ret);
127 if (argc == 4) {
128 ret = parse_params(argv[0], argv[1], argv[2], argv[3],
129 NULL, -1);
130 exit(ret);
132 usage();
133 exit(1);
134 /* NOTREACHED */
137 static void
138 usage(void)
140 fprintf(stderr, gettext(
141 "Usage: soconfig -d <dir>\n"
142 "\tsoconfig -f <file>\n"
143 "\tsoconfig <fam> <type> <protocol> <path|module>\n"
144 "\tsoconfig <fam> <type> <protocol>\n"
145 "\tsoconfig -l\n"));
149 * Parse all files in the given directory.
151 static int
152 parse_files_in_dir(const char *dirname)
154 DIR *dp;
155 struct dirent *dirp;
156 struct stat stats;
157 char buf[MAXPATHLEN];
159 if ((dp = opendir(dirname)) == NULL) {
160 fprintf(stderr, gettext("failed to open directory '%s': %s\n"),
161 dirname, strerror(errno));
162 return (1);
165 while ((dirp = readdir(dp)) != NULL) {
166 if (dirp->d_name[0] == '.')
167 continue;
169 if (snprintf(buf, sizeof (buf), "%s/%s", dirname,
170 dirp->d_name) >= sizeof (buf)) {
171 fprintf(stderr,
172 gettext("path name is too long: %s/%s\n"),
173 dirname, dirp->d_name);
174 continue;
176 if (stat(buf, &stats) == -1) {
177 fprintf(stderr,
178 gettext("failed to stat '%s': %s\n"), buf,
179 strerror(errno));
180 continue;
182 if (!S_ISREG(stats.st_mode))
183 continue;
185 (void) parse_file(buf);
188 closedir(dp);
190 return (0);
194 * Open the specified file and parse each line. Skip comments (everything
195 * after a '#'). Return 1 if at least one error was encountered; otherwise 0.
197 static int
198 parse_file(char *filename)
200 char line[MAXLINELEN];
201 char pline[MAXLINELEN];
202 int argcount;
203 char *argvec[20];
204 FILE *fp;
205 int linecount = 0;
206 int numerror = 0;
208 fp = fopen(filename, "r");
209 if (fp == NULL) {
210 perror("soconfig: open");
211 fprintf(stderr, "\n");
212 usage();
213 return (1);
216 while (fgets(line, sizeof (line) - 1, fp) != NULL) {
217 linecount++;
218 strcpy(pline, line);
219 argcount = split_line(pline, argvec,
220 sizeof (argvec) / sizeof (argvec[0]));
221 #ifdef DEBUG
223 int i;
225 printf("scanned %d args\n", argcount);
226 for (i = 0; i < argcount; i++)
227 printf("arg[%d]: %s\n", i, argvec[i]);
229 #endif /* DEBUG */
230 switch (argcount) {
231 case 0:
232 /* Empty line - or comment only line */
233 break;
234 case 3:
235 numerror += parse_params(argvec[0], argvec[1],
236 argvec[2], NULL, filename, linecount);
237 break;
238 case 4:
239 numerror += parse_params(argvec[0], argvec[1],
240 argvec[2], argvec[3], filename, linecount);
241 break;
242 default:
243 numerror++;
244 fprintf(stderr,
245 gettext("Malformed line: <%s>\n"), line);
246 fprintf(stderr,
247 gettext("\ton line %d in %s\n"), linecount,
248 filename);
249 break;
252 (void) fclose(fp);
254 if (numerror > 0)
255 return (1);
256 else
257 return (0);
261 * Parse a line splitting it off at whitspace characters.
262 * Modifies the content of the string by inserting NULLs.
264 static int
265 split_line(char *line, char *argvec[], int maxargvec)
267 int i = 0;
268 char *cp;
270 /* Truncate at the beginning of a comment */
271 cp = strchr(line, '#');
272 if (cp != NULL)
273 *cp = '\0';
275 /* CONSTCOND */
276 while (1) {
277 /* Skip any whitespace */
278 while (isspace(*line) && *line != '\0')
279 line++;
281 if (i >= maxargvec)
282 return (i);
284 argvec[i] = line;
285 if (*line == '\0')
286 return (i);
287 i++;
288 /* Skip until next whitespace */
289 while (!isspace(*line) && *line != '\0')
290 line++;
291 if (*line != '\0') {
292 /* Break off argument */
293 *line++ = '\0';
296 /* NOTREACHED */
300 * Parse the set of parameters and issues the sockconfig syscall.
301 * If line is not -1 it is assumed to be the line number in the file.
303 static int
304 parse_params(char *famstr, char *typestr, char *protostr, char *path,
305 const char *file, int line)
307 int cmd, fam, type, protocol;
309 fam = parse_int(famstr);
310 if (fam == -1) {
311 fprintf(stderr, gettext("Bad family number: %s\n"), famstr);
312 if (line != -1)
313 fprintf(stderr,
314 gettext("\ton line %d in %s\n"), line, file);
315 else {
316 fprintf(stderr, "\n");
317 usage();
319 return (1);
322 type = parse_int(typestr);
323 if (type == -1) {
324 fprintf(stderr,
325 gettext("Bad socket type number: %s\n"), typestr);
326 if (line != -1)
327 fprintf(stderr,
328 gettext("\ton line %d in %s\n"), line, file);
329 else {
330 fprintf(stderr, "\n");
331 usage();
333 return (1);
336 protocol = parse_int(protostr);
337 if (protocol == -1) {
338 fprintf(stderr,
339 gettext("Bad protocol number: %s\n"), protostr);
340 if (line != -1)
341 fprintf(stderr,
342 gettext("\ton line %d in %s\n"), line, file);
343 else {
344 fprintf(stderr, "\n");
345 usage();
347 return (1);
351 if (path != NULL) {
352 struct stat stats;
354 if (strncmp(path, "/dev", strlen("/dev")) == 0 &&
355 stat(path, &stats) == -1) {
356 perror(path);
357 if (line != -1)
358 fprintf(stderr,
359 gettext("\ton line %d in %s\n"), line,
360 file);
361 else {
362 fprintf(stderr, "\n");
363 usage();
365 return (1);
368 cmd = SOCKCONFIG_ADD_SOCK;
369 } else {
370 cmd = SOCKCONFIG_REMOVE_SOCK;
373 #ifdef DEBUG
374 printf("not calling sockconfig(%d, %d, %d, %d, %s)\n",
375 cmd, fam, type, protocol, path == NULL ? "(null)" : path);
376 #else
377 if (_sockconfig(cmd, (void *)fam, (void *)type, (void *)protocol, (void *)path) == -1) {
378 char *s;
380 switch (errno) {
381 case EEXIST:
382 s = gettext("Mapping exists");
383 break;
384 default:
385 s = strerror(errno);
386 break;
389 fprintf(stderr,
390 gettext("warning: socket configuration failed "
391 "for family %d type %d protocol %d: %s\n"),
392 fam, type, protocol, s);
393 if (line != -1) {
394 fprintf(stderr,
395 gettext("\ton line %d in %s\n"), line, file);
397 return (1);
399 #endif
400 return (0);
403 static int
404 parse_int(char *str)
406 char *end;
407 int res;
409 res = strtol(str, &end, 0);
410 if (end == str)
411 return (-1);
412 return (res);
416 * Add and remove socket filters.
418 static int
419 parse_filter_params(int argc, char **argv)
421 struct sockconfig_filter_props filprop;
422 sof_socktuple_t *socktuples;
423 size_t tupcnt, nalloc;
424 char *hintarg, *socktup, *tupstr;
425 int i;
427 if (argc == 1) {
428 if (_sockconfig(SOCKCONFIG_REMOVE_FILTER, argv[0], NULL,
429 NULL, NULL) < 0) {
430 switch (errno) {
431 case ENXIO:
432 fprintf(stderr,
433 gettext("socket filter is not configured "
434 "'%s'\n"), argv[0]);
435 break;
436 default:
437 perror("sockconfig");
438 break;
440 return (1);
442 return (0);
445 if (argc < 4 || argc > 5)
446 return (1);
449 if (strlen(argv[1]) >= MODMAXNAMELEN) {
450 fprintf(stderr,
451 gettext("invalid module name '%s': name too long\n"),
452 argv[1]);
453 return (1);
455 filprop.sfp_modname = argv[1];
457 /* Check the attach semantics */
458 if (strcmp(argv[2], "auto") == 0) {
459 filprop.sfp_autoattach = B_TRUE;
460 if (argc == 5) {
461 /* placement hint */
462 if (strcmp(argv[3], "top") == 0) {
463 filprop.sfp_hint = SOF_HINT_TOP;
464 } else if (strcmp(argv[3], "bottom") == 0) {
465 filprop.sfp_hint = SOF_HINT_BOTTOM;
466 } else {
467 if (strncmp(argv[3], "before", 6) == 0) {
468 filprop.sfp_hint = SOF_HINT_BEFORE;
469 } else if (strncmp(argv[3], "after", 5) == 0) {
470 filprop.sfp_hint = SOF_HINT_AFTER;
471 } else {
472 fprintf(stderr,
473 gettext("invalid placement hint "
474 "'%s'\n"), argv[3]);
475 return (1);
478 hintarg = strchr(argv[3], ':');
479 if (hintarg == NULL ||
480 (strlen(++hintarg) == 0) ||
481 (strlen(hintarg) >= FILNAME_MAX)) {
482 fprintf(stderr,
483 gettext("invalid placement hint "
484 "argument '%s': name too long\n"),
485 argv[3]);
486 return (1);
489 filprop.sfp_hintarg = hintarg;
491 } else {
492 filprop.sfp_hint = SOF_HINT_NONE;
494 } else if (strcmp(argv[2], "prog") == 0) {
495 filprop.sfp_autoattach = B_FALSE;
496 filprop.sfp_hint = SOF_HINT_NONE;
497 /* cannot specify placement hint for programmatic filter */
498 if (argc == 5) {
499 fprintf(stderr,
500 gettext("placement hint specified for programmatic "
501 "filter\n"));
502 return (1);
504 } else {
505 fprintf(stderr, gettext("invalid attach semantic '%s'\n"),
506 argv[2]);
507 return (1);
510 /* parse the socket tuples */
511 nalloc = 4;
512 socktuples = calloc(nalloc, sizeof (sof_socktuple_t));
513 if (socktuples == NULL) {
514 perror("calloc");
515 return (1);
518 tupcnt = 0;
519 tupstr = argv[(argc == 4) ? 3 : 4];
520 while ((socktup = strsep(&tupstr, ",")) != NULL) {
521 int val;
522 char *valstr;
524 if (tupcnt == nalloc) {
525 sof_socktuple_t *new;
527 nalloc *= 2;
528 new = reallocarray(socktuples, nalloc,
529 sizeof (sof_socktuple_t));
530 if (new == NULL) {
531 perror("realloc");
532 free(socktuples);
533 return (1);
535 socktuples = new;
537 i = 0;
538 while ((valstr = strsep(&socktup, ":")) != NULL && i < 3) {
539 val = parse_int(valstr);
540 if (val == -1) {
541 fprintf(stderr, gettext("bad socket tuple\n"));
542 free(socktuples);
543 return (1);
545 switch (i) {
546 case 0: socktuples[tupcnt].sofst_family = val; break;
547 case 1: socktuples[tupcnt].sofst_type = val; break;
548 case 2: socktuples[tupcnt].sofst_protocol = val; break;
550 i++;
552 if (i != 3) {
553 fprintf(stderr, gettext("bad socket tuple\n"));
554 free(socktuples);
555 return (1);
557 tupcnt++;
559 if (tupcnt == 0) {
560 fprintf(stderr, gettext("no socket tuples specified\n"));
561 free(socktuples);
562 return (1);
564 filprop.sfp_socktuple_cnt = tupcnt;
565 filprop.sfp_socktuple = socktuples;
567 if (_sockconfig(SOCKCONFIG_ADD_FILTER, argv[0], &filprop, NULL, NULL) < 0) {
568 switch (errno) {
569 case EINVAL:
570 fprintf(stderr,
571 gettext("invalid socket filter configuration\n"));
572 break;
573 case EEXIST:
574 fprintf(stderr,
575 gettext("socket filter is already configured "
576 "'%s'\n"), argv[0]);
577 break;
578 case ENOSPC:
579 fprintf(stderr, gettext("unable to satisfy placement "
580 "constraint\n"));
581 break;
582 default:
583 perror("sockconfig");
584 break;
586 free(socktuples);
587 return (1);
589 free(socktuples);
590 return (0);
594 * Print the in-kernel socket configuration table
597 static int
598 print_socktable()
600 sockconfig_socktable_t sc_table;
601 int i;
603 (void) memset(&sc_table, 0, sizeof (sockconfig_socktable_t));
605 /* get number of entries */
606 if (_sockconfig(SOCKCONFIG_GET_SOCKTABLE, &sc_table, NULL, NULL, NULL) == -1) {
607 fprintf(stderr,
608 gettext("cannot get in-kernel socket table: %s\n"),
609 strerror(errno));
610 return (-1);
612 if (sc_table.num_of_entries == 0)
613 return (0);
615 sc_table.st_entries = calloc(sc_table.num_of_entries,
616 sizeof (sockconfig_socktable_entry_t));
617 if (sc_table.st_entries == NULL) {
618 fprintf(stderr, gettext("out of memory\n"));
619 return (-1);
622 /* get socket table entries */
623 if (_sockconfig(SOCKCONFIG_GET_SOCKTABLE, &sc_table, NULL, NULL, NULL) == -1) {
624 fprintf(stderr,
625 gettext("cannot get in-kernel socket table: %s\n"),
626 strerror(errno));
627 return (-1);
630 printf("%6s %4s %5s %15s %15s %6s %6s\n",
631 "FAMILY", "TYPE", "PROTO", "STRDEV", "SOCKMOD",
632 "REFS", "FLAGS");
633 for (i = 0; i < sc_table.num_of_entries; i++) {
634 printf("%6u %4u %5u %15s %15s %6u %#6x\n",
635 sc_table.st_entries[i].se_family,
636 sc_table.st_entries[i].se_type,
637 sc_table.st_entries[i].se_protocol,
638 (strcmp(sc_table.st_entries[i].se_modname,
639 "socktpi") == 0) ?
640 sc_table.st_entries[i].se_strdev : "-",
641 sc_table.st_entries[i].se_modname,
642 sc_table.st_entries[i].se_refcnt,
643 sc_table.st_entries[i].se_flags);
645 free(sc_table.st_entries);
646 return (0);