dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / sbin / ifparse / ifparse.c
blob848fad1687957305b6b89de8b4ba88232a92f70e
1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5 /*
6 * Copyright (c) 1983 Regents of the University of California.
7 * All rights reserved. The Berkeley software License Agreement
8 * specifies the terms and conditions for redistribution.
9 */
11 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
15 * Ifparse splits up an ifconfig command line, and was written for use
16 * with the networking boot scripts; see $SRC/cmd/svc/shell/net_include.sh
18 * Ifparse can extract selected parts of the ifconfig command line,
19 * such as failover address configuration ("ifparse -f"), or everything
20 * except failover address configuration ("ifparse -s"). By default,
21 * all parts of the command line are extracted (equivalent to ("ifparse -fs").
23 * Examples:
25 * The command:
27 * ifparse inet 1.2.3.4 up group two addif 1.2.3.5 up addif 1.2.3.6 up
29 * Produces the following on standard output:
31 * set 1.2.3.4 up
32 * group two
33 * addif 1.2.3.5 up
34 * addif 1.2.3.6 up
36 * The optional "set" and "destination" keywords are added to make the
37 * output easier to process by a script or another command.
39 * The command:
41 * ifparse -f inet 1.2.3.4 -failover up group two addif 1.2.3.5 up
43 * Produces:
45 * addif 1.2.3.5 up
47 * Only failover address configuration has been requested. Address
48 * 1.2.3.4 is a non-failover address, and so isn't output.
50 * The "failover" and "-failover" commands can occur several times for
51 * a given logical interface. Only the last one counts. For example:
53 * ifparse -f inet 1.2.3.4 -failover failover -failover failover up
55 * Produces:
57 * set 1.2.3.4 -failover failover -failover failover up
59 * No attempt is made to clean up such "pathological" command lines, by
60 * removing redundant "failover" and "-failover" commands.
63 #include <sys/types.h>
64 #include <stdlib.h>
65 #include <stdio.h>
66 #include <string.h>
67 #include <assert.h>
68 #include <unistd.h>
71 * Parser flags:
73 * PARSEFIXED
74 * Command should only appear if non-failover commands
75 * are requested.
76 * PARSEMOVABLE
77 * Command should only appear if failover commands are
78 * requested.
79 * PARSENOW
80 * Don't buffer the command, dump it to output immediately.
81 * PARSEADD
82 * Indicates processing has moved on to additional
83 * logical interfaces.
84 * Dump the buffer to output and clear buffer contents.
85 * PARSESET
86 * The "set" and "destination" keywords are optional.
87 * This flag indicates that the next address not prefixed
88 * with a keyword will be a destination address.
89 * PARSELOG0
90 * Command not valid on additional logical interfaces.
93 #define PARSEFIXED 0x01
94 #define PARSEMOVABLE 0x02
95 #define PARSENOW 0x04
96 #define PARSEADD 0x08
97 #define PARSESET 0x10
98 #define PARSELOG0 0x20
100 typedef enum { AF_UNSPEC, AF_INET, AF_INET6, AF_ANY } ac_t;
102 #define NEXTARG (-1) /* command takes an argument */
103 #define OPTARG (-2) /* command takes an optional argument */
105 #define END_OF_TABLE (-1)
107 /* Parsemode, the type of commands requested by the user. */
108 int parsemode = 0;
110 /* Parsetype, the type of the command currently in the buffer. */
111 int parsetype = PARSEFIXED | PARSEMOVABLE;
113 /* Parsebuf, pointer to the buffer. */
114 char *parsebuf = NULL;
116 /* Parsebuflen, the size of the buffer area. */
117 unsigned parsebuflen = 0;
119 /* Parsedumplen, the amount of the buffer currently in use. */
120 unsigned parsedumplen = 0;
123 * Setaddr, used to decide whether an address without a keyword
124 * prefix is a source or destination address.
126 boolean_t setaddr = _B_FALSE;
129 * Some ifconfig commands are only valid on the first logical interface.
130 * As soon as an "addif" command is seen, "addint" is set.
132 boolean_t addint = _B_FALSE;
135 * The parser table is based on that in ifconfig. A command may or
136 * may not have an argument, as indicated by whether NEXTARG/OPTARG is
137 * in the second column. Some commands can only be used with certain
138 * address families, as indicated in the third column. The fourth column
139 * contains flags that control parser action.
141 * Ifparse buffers logical interface configuration commands such as "set",
142 * "netmask" and "broadcast". This buffering continues until an "addif"
143 * command is seen, at which point the buffer is emptied, and the process
144 * starts again.
146 * Some commands do not relate to logical interface configuration and are
147 * dumped to output as soon as they are seen, such as "group" and "standby".
151 struct cmd {
152 char *c_name;
153 int c_parameter; /* NEXTARG means next argv */
154 int c_af; /* address family restrictions */
155 int c_parseflags; /* parsing flags */
156 } cmds[] = {
157 { "up", 0, AF_ANY, 0 },
158 { "down", 0, AF_ANY, 0 },
159 { "trailers", 0, AF_ANY, PARSENOW },
160 { "-trailers", 0, AF_ANY, PARSENOW },
161 { "arp", 0, AF_INET, PARSENOW },
162 { "-arp", 0, AF_INET, PARSENOW },
163 { "private", 0, AF_ANY, 0 },
164 { "-private", 0, AF_ANY, 0 },
165 { "router", 0, AF_ANY, PARSELOG0 },
166 { "-router", 0, AF_ANY, PARSELOG0 },
167 { "xmit", 0, AF_ANY, 0 },
168 { "-xmit", 0, AF_ANY, 0 },
169 { "-nud", 0, AF_INET6, PARSENOW },
170 { "nud", 0, AF_INET6, PARSENOW },
171 { "anycast", 0, AF_ANY, 0 },
172 { "-anycast", 0, AF_ANY, 0 },
173 { "local", 0, AF_ANY, 0 },
174 { "-local", 0, AF_ANY, 0 },
175 { "deprecated", 0, AF_ANY, 0 },
176 { "-deprecated", 0, AF_ANY, 0 },
177 { "preferred", 0, AF_INET6, 0 },
178 { "-preferred", 0, AF_INET6, 0 },
179 { "debug", 0, AF_ANY, PARSENOW },
180 { "verbose", 0, AF_ANY, PARSENOW },
181 { "netmask", NEXTARG, AF_INET, 0 },
182 { "metric", NEXTARG, AF_ANY, 0 },
183 { "mtu", NEXTARG, AF_ANY, 0 },
184 { "index", NEXTARG, AF_ANY, PARSELOG0 },
185 { "broadcast", NEXTARG, AF_INET, 0 },
186 { "auto-revarp", 0, AF_INET, PARSEFIXED},
187 { "plumb", 0, AF_ANY, PARSENOW },
188 { "unplumb", 0, AF_ANY, PARSENOW },
189 { "ipmp", 0, AF_ANY, PARSELOG0 },
190 { "subnet", NEXTARG, AF_ANY, 0 },
191 { "token", NEXTARG, AF_INET6, PARSELOG0 },
192 { "tsrc", NEXTARG, AF_ANY, PARSELOG0 },
193 { "tdst", NEXTARG, AF_ANY, PARSELOG0 },
194 { "encr_auth_algs", NEXTARG, AF_ANY, PARSELOG0 },
195 { "encr_algs", NEXTARG, AF_ANY, PARSELOG0 },
196 { "auth_algs", NEXTARG, AF_ANY, PARSELOG0 },
197 { "addif", NEXTARG, AF_ANY, PARSEADD },
198 { "removeif", NEXTARG, AF_ANY, PARSELOG0 },
199 { "modlist", 0, AF_ANY, PARSENOW },
200 { "modinsert", NEXTARG, AF_ANY, PARSENOW },
201 { "modremove", NEXTARG, AF_ANY, PARSENOW },
202 { "failover", 0, AF_ANY, PARSEMOVABLE },
203 { "-failover", 0, AF_ANY, PARSEFIXED },
204 { "standby", 0, AF_ANY, PARSENOW },
205 { "-standby", 0, AF_ANY, PARSENOW },
206 { "failed", 0, AF_ANY, PARSENOW },
207 { "-failed", 0, AF_ANY, PARSENOW },
208 { "group", NEXTARG, AF_ANY, PARSELOG0 },
209 { "configinfo", 0, AF_ANY, PARSENOW },
210 { "encaplimit", NEXTARG, AF_ANY, PARSELOG0 },
211 { "-encaplimit", 0, AF_ANY, PARSELOG0 },
212 { "thoplimit", NEXTARG, AF_ANY, PARSELOG0 },
213 { "set", NEXTARG, AF_ANY, PARSESET },
214 { "destination", NEXTARG, AF_ANY, 0 },
215 { "zone", NEXTARG, AF_ANY, 0 },
216 { "-zone", 0, AF_ANY, 0 },
217 { "ether", OPTARG, AF_ANY, PARSENOW },
218 { "usesrc", NEXTARG, AF_ANY, PARSENOW },
219 { 0 /* ether addr */, 0, AF_UNSPEC, PARSELOG0 },
220 { 0 /* set */, 0, AF_ANY, PARSESET },
221 { 0 /* destination */, 0, AF_ANY, 0 },
222 { 0, END_OF_TABLE, END_OF_TABLE, END_OF_TABLE},
226 /* Known address families */
227 struct afswtch {
228 char *af_name;
229 short af_af;
230 } afs[] = {
231 { "inet", AF_INET },
232 { "ether", AF_UNSPEC },
233 { "inet6", AF_INET6 },
234 { 0, 0 }
238 * Append "item" to the buffer. If there isn't enough room in the buffer,
239 * expand it.
241 static void
242 parse_append_buf(char *item)
244 unsigned itemlen;
245 unsigned newdumplen;
247 if (item == NULL)
248 return;
250 itemlen = strlen(item);
251 newdumplen = parsedumplen + itemlen;
253 /* Expand dump buffer as needed */
254 if (parsebuflen < newdumplen) {
255 if ((parsebuf = realloc(parsebuf, newdumplen)) == NULL) {
256 perror("ifparse");
257 exit(1);
259 parsebuflen = newdumplen;
261 (void) memcpy(parsebuf + parsedumplen, item, itemlen);
263 parsedumplen = newdumplen;
267 * Dump the buffer to output.
269 static void
270 parse_dump_buf(void)
273 * When parsing, a set or addif command, we may be some way into
274 * the command before we definitely know it is movable or fixed.
275 * If we get to the end of the command, and haven't seen a
276 * "failover" or "-failover" flag, the command is movable.
278 if (!((parsemode == PARSEFIXED) && (parsetype & PARSEMOVABLE) != 0) &&
279 (parsemode & parsetype) != 0 && parsedumplen != 0) {
280 unsigned i;
282 if (parsebuf[parsedumplen] == ' ')
283 parsedumplen--;
285 for (i = 0; i < parsedumplen; i++)
286 (void) putchar(parsebuf[i]);
288 (void) putchar('\n');
290 /* The buffer is kept in case there is more parsing to do */
291 parsedumplen = 0;
292 parsetype = PARSEFIXED | PARSEMOVABLE;
296 * Process a command. The command will either be put in the buffer,
297 * or dumped directly to output. The current contents of the buffer
298 * may be dumped to output.
300 * The buffer holds commands relating to a particular logical interface.
301 * For example, "set", "destination", "failover", "broadcast", all relate
302 * to a particular interface. Such commands have to be buffered until
303 * all the "failover" and "-failover" commands for that interface have
304 * been seen, only then will we know whether the command is movable
305 * or not. When the "addif" command is seen, we know we are about to
306 * start processing a new logical interface, we've seen all the
307 * "failover" and "-failover" commands for the previous interface, and
308 * can decide whether the buffer contents are movable or not.
311 static void
312 parsedump(char *cmd, int param, int flags, char *arg)
314 char *cmdname; /* Command name */
315 char *cmdarg; /* Argument to command, if it takes one, or NULL */
318 * Is command only valid on logical interface 0?
319 * If processing commands on an additional logical interface, ignore
320 * the command.
321 * If processing commands on logical interface 0, don't buffer the
322 * command, dump it straight to output.
324 if ((flags & PARSELOG0) != 0) {
325 if (addint)
326 return;
327 flags |= PARSENOW;
331 * If processing the "addif" command, a destination address may
332 * follow without the "destination" prefix. Add PARSESET to the
333 * flags so that such an anonymous address is processed correctly.
335 if ((flags & PARSEADD) != 0) {
336 flags |= PARSESET;
337 addint = _B_TRUE;
341 * Commands that must be dumped straight to output are always fixed
342 * (non-movable) commands.
345 if ((flags & PARSENOW) != 0)
346 flags |= PARSEFIXED;
349 * Source and destination addresses do not have to be prefixed
350 * with the keywords "set" or "destination". Ifparse always
351 * inserts the optional keyword.
353 if (cmd == NULL) {
354 cmdarg = arg;
355 if ((flags & PARSESET) != 0)
356 cmdname = "set";
357 else if (setaddr) {
358 cmdname = "destination";
359 setaddr = _B_FALSE;
360 } else
361 cmdname = "";
362 } else {
363 cmdarg = (param == 0) ? NULL : arg;
364 cmdname = cmd;
368 * The next address without a prefix will be a destination
369 * address.
371 if ((flags & PARSESET) != 0)
372 setaddr = _B_TRUE;
375 * Dump the command straight to output?
376 * Only dump the command if the parse mode specified on
377 * the command line matches the type of the command.
379 if ((flags & PARSENOW) != 0) {
380 if ((parsemode & flags) != 0) {
381 (void) fputs(cmdname, stdout);
382 if (cmdarg != NULL) {
383 (void) fputc(' ', stdout);
384 (void) fputs(cmdarg, stdout);
386 (void) fputc('\n', stdout);
388 return;
392 * Only the commands relating to a particular logical interface
393 * are buffered. When an "addif" command is seen, processing is
394 * about to start on a new logical interface, so dump the
395 * buffer to output.
397 if ((flags & PARSEADD) != 0)
398 parse_dump_buf();
401 * If the command flags indicate the command is fixed or
402 * movable, update the type of the interface in the buffer
403 * accordingly. For example, "-failover" has the "PARSEFIXED"
404 * flag, and the contents of the buffer are not movable if
405 * "-failover" is seen.
407 if ((flags & PARSEFIXED) != 0)
408 parsetype &= ~PARSEMOVABLE;
410 if ((flags & PARSEMOVABLE) != 0)
411 parsetype &= ~PARSEFIXED;
413 parsetype |= flags & (PARSEFIXED | PARSEMOVABLE);
415 parse_append_buf(cmdname);
417 if (cmdarg != NULL) {
418 parse_append_buf(" ");
419 parse_append_buf(cmdarg);
422 parse_append_buf(" ");
426 * Parse the part of the command line following the address family
427 * specification, if any.
429 * This function is a modified version of the function "ifconfig" in
430 * ifconfig.c.
432 static int
433 ifparse(int argc, char *argv[], struct afswtch *afp)
435 int af = afp->af_af;
437 if (argc == 0)
438 return (0);
440 if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) {
441 if ((parsemode & PARSEFIXED) != 0) {
442 while (argc) {
443 (void) fputs(*argv++, stdout);
444 if (--argc != 0)
445 (void) fputc(' ', stdout);
446 else
447 (void) fputc('\n', stdout);
450 return (0);
453 while (argc > 0) {
454 struct cmd *p;
455 boolean_t found_cmd;
457 found_cmd = _B_FALSE;
458 for (p = cmds; ; p++) {
459 assert(p->c_parseflags != END_OF_TABLE);
460 if (p->c_name) {
461 if (strcmp(*argv, p->c_name) == 0) {
463 * indicate that the command was
464 * found and check to see if
465 * the address family is valid
467 found_cmd = _B_TRUE;
468 if (p->c_af == AF_ANY ||
469 af == p->c_af)
470 break;
472 } else {
473 if (p->c_af == AF_ANY ||
474 af == p->c_af)
475 break;
478 assert(p->c_parseflags != END_OF_TABLE);
480 * If we found the keyword, but the address family
481 * did not match spit out an error
483 if (found_cmd && p->c_name == 0) {
484 (void) fprintf(stderr, "ifparse: Operation %s not"
485 " supported for %s\n", *argv, afp->af_name);
486 return (1);
489 * else (no keyword found), we assume it's an address
490 * of some sort
492 if (p->c_name == 0 && setaddr) {
493 p++; /* got src, do dst */
494 assert(p->c_parseflags != END_OF_TABLE);
497 if (p->c_parameter == NEXTARG || p->c_parameter == OPTARG) {
498 argc--, argv++;
499 if (argc == 0 && p->c_parameter == NEXTARG) {
500 (void) fprintf(stderr,
501 "ifparse: no argument for %s\n",
502 p->c_name);
503 return (1);
508 * Dump the command if:
510 * there's no address family
511 * restriction
512 * OR
513 * there is a restriction AND
514 * the address families match
516 if ((p->c_af == AF_ANY) || (af == p->c_af))
517 parsedump(p->c_name, p->c_parameter, p->c_parseflags,
518 *argv);
519 argc--, argv++;
521 parse_dump_buf();
523 return (0);
527 * Print command usage on standard error.
529 static void
530 usage(void)
532 (void) fprintf(stderr,
533 "usage: ifparse [ -fs ] <addr_family> <commands>\n");
537 main(int argc, char *argv[])
539 int c;
540 struct afswtch *afp;
542 while ((c = getopt(argc, argv, "fs")) != -1) {
543 switch ((char)c) {
544 case 'f':
545 parsemode |= PARSEMOVABLE;
546 break;
547 case 's':
548 parsemode |= PARSEFIXED;
549 break;
550 case '?':
551 usage();
552 exit(1);
556 if (parsemode == 0)
557 parsemode = PARSEFIXED | PARSEMOVABLE;
559 argc -= optind;
560 argv += optind;
562 afp = afs;
563 if (argc > 0) {
564 struct afswtch *aftp;
565 for (aftp = afs; aftp->af_name; aftp++) {
566 if (strcmp(aftp->af_name, *argv) == 0) {
567 argc--; argv++;
568 afp = aftp;
569 break;
574 return (ifparse(argc, argv, afp));