2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
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.
12 * Ifparse splits up an ifconfig command line, and was written for use
13 * with the networking boot scripts; see $SRC/cmd/svc/shell/net_include.sh
15 * Ifparse can extract selected parts of the ifconfig command line,
16 * such as failover address configuration ("ifparse -f"), or everything
17 * except failover address configuration ("ifparse -s"). By default,
18 * all parts of the command line are extracted (equivalent to ("ifparse -fs").
24 * ifparse inet 1.2.3.4 up group two addif 1.2.3.5 up addif 1.2.3.6 up
26 * Produces the following on standard output:
33 * The optional "set" and "destination" keywords are added to make the
34 * output easier to process by a script or another command.
38 * ifparse -f inet 1.2.3.4 -failover up group two addif 1.2.3.5 up
44 * Only failover address configuration has been requested. Address
45 * 1.2.3.4 is a non-failover address, and so isn't output.
47 * The "failover" and "-failover" commands can occur several times for
48 * a given logical interface. Only the last one counts. For example:
50 * ifparse -f inet 1.2.3.4 -failover failover -failover failover up
54 * set 1.2.3.4 -failover failover -failover failover up
56 * No attempt is made to clean up such "pathological" command lines, by
57 * removing redundant "failover" and "-failover" commands.
60 #include <sys/types.h>
70 * Command should only appear if non-failover commands
73 * Command should only appear if failover commands are
76 * Don't buffer the command, dump it to output immediately.
78 * Indicates processing has moved on to additional
80 * Dump the buffer to output and clear buffer contents.
82 * The "set" and "destination" keywords are optional.
83 * This flag indicates that the next address not prefixed
84 * with a keyword will be a destination address.
86 * Command not valid on additional logical interfaces.
89 #define PARSEFIXED 0x01
90 #define PARSEMOVABLE 0x02
94 #define PARSELOG0 0x20
96 typedef enum { AF_UNSPEC
, AF_INET
, AF_INET6
, AF_ANY
} ac_t
;
98 #define NEXTARG (-1) /* command takes an argument */
99 #define OPTARG (-2) /* command takes an optional argument */
101 #define END_OF_TABLE (-1)
103 /* Parsemode, the type of commands requested by the user. */
106 /* Parsetype, the type of the command currently in the buffer. */
107 int parsetype
= PARSEFIXED
| PARSEMOVABLE
;
109 /* Parsebuf, pointer to the buffer. */
110 char *parsebuf
= NULL
;
112 /* Parsebuflen, the size of the buffer area. */
113 unsigned parsebuflen
= 0;
115 /* Parsedumplen, the amount of the buffer currently in use. */
116 unsigned parsedumplen
= 0;
119 * Setaddr, used to decide whether an address without a keyword
120 * prefix is a source or destination address.
122 boolean_t setaddr
= _B_FALSE
;
125 * Some ifconfig commands are only valid on the first logical interface.
126 * As soon as an "addif" command is seen, "addint" is set.
128 boolean_t addint
= _B_FALSE
;
131 * The parser table is based on that in ifconfig. A command may or
132 * may not have an argument, as indicated by whether NEXTARG/OPTARG is
133 * in the second column. Some commands can only be used with certain
134 * address families, as indicated in the third column. The fourth column
135 * contains flags that control parser action.
137 * Ifparse buffers logical interface configuration commands such as "set",
138 * "netmask" and "broadcast". This buffering continues until an "addif"
139 * command is seen, at which point the buffer is emptied, and the process
142 * Some commands do not relate to logical interface configuration and are
143 * dumped to output as soon as they are seen, such as "group" and "standby".
149 int c_parameter
; /* NEXTARG means next argv */
150 int c_af
; /* address family restrictions */
151 int c_parseflags
; /* parsing flags */
153 { "up", 0, AF_ANY
, 0 },
154 { "down", 0, AF_ANY
, 0 },
155 { "trailers", 0, AF_ANY
, PARSENOW
},
156 { "-trailers", 0, AF_ANY
, PARSENOW
},
157 { "arp", 0, AF_INET
, PARSENOW
},
158 { "-arp", 0, AF_INET
, PARSENOW
},
159 { "private", 0, AF_ANY
, 0 },
160 { "-private", 0, AF_ANY
, 0 },
161 { "router", 0, AF_ANY
, PARSELOG0
},
162 { "-router", 0, AF_ANY
, PARSELOG0
},
163 { "xmit", 0, AF_ANY
, 0 },
164 { "-xmit", 0, AF_ANY
, 0 },
165 { "-nud", 0, AF_INET6
, PARSENOW
},
166 { "nud", 0, AF_INET6
, PARSENOW
},
167 { "anycast", 0, AF_ANY
, 0 },
168 { "-anycast", 0, AF_ANY
, 0 },
169 { "local", 0, AF_ANY
, 0 },
170 { "-local", 0, AF_ANY
, 0 },
171 { "deprecated", 0, AF_ANY
, 0 },
172 { "-deprecated", 0, AF_ANY
, 0 },
173 { "preferred", 0, AF_INET6
, 0 },
174 { "-preferred", 0, AF_INET6
, 0 },
175 { "debug", 0, AF_ANY
, PARSENOW
},
176 { "verbose", 0, AF_ANY
, PARSENOW
},
177 { "netmask", NEXTARG
, AF_INET
, 0 },
178 { "metric", NEXTARG
, AF_ANY
, 0 },
179 { "mtu", NEXTARG
, AF_ANY
, 0 },
180 { "index", NEXTARG
, AF_ANY
, PARSELOG0
},
181 { "broadcast", NEXTARG
, AF_INET
, 0 },
182 { "auto-revarp", 0, AF_INET
, PARSEFIXED
},
183 { "plumb", 0, AF_ANY
, PARSENOW
},
184 { "unplumb", 0, AF_ANY
, PARSENOW
},
185 { "ipmp", 0, AF_ANY
, PARSELOG0
},
186 { "subnet", NEXTARG
, AF_ANY
, 0 },
187 { "token", NEXTARG
, AF_INET6
, PARSELOG0
},
188 { "tsrc", NEXTARG
, AF_ANY
, PARSELOG0
},
189 { "tdst", NEXTARG
, AF_ANY
, PARSELOG0
},
190 { "encr_auth_algs", NEXTARG
, AF_ANY
, PARSELOG0
},
191 { "encr_algs", NEXTARG
, AF_ANY
, PARSELOG0
},
192 { "auth_algs", NEXTARG
, AF_ANY
, PARSELOG0
},
193 { "addif", NEXTARG
, AF_ANY
, PARSEADD
},
194 { "removeif", NEXTARG
, AF_ANY
, PARSELOG0
},
195 { "modlist", 0, AF_ANY
, PARSENOW
},
196 { "modinsert", NEXTARG
, AF_ANY
, PARSENOW
},
197 { "modremove", NEXTARG
, AF_ANY
, PARSENOW
},
198 { "failover", 0, AF_ANY
, PARSEMOVABLE
},
199 { "-failover", 0, AF_ANY
, PARSEFIXED
},
200 { "standby", 0, AF_ANY
, PARSENOW
},
201 { "-standby", 0, AF_ANY
, PARSENOW
},
202 { "failed", 0, AF_ANY
, PARSENOW
},
203 { "-failed", 0, AF_ANY
, PARSENOW
},
204 { "group", NEXTARG
, AF_ANY
, PARSELOG0
},
205 { "configinfo", 0, AF_ANY
, PARSENOW
},
206 { "encaplimit", NEXTARG
, AF_ANY
, PARSELOG0
},
207 { "-encaplimit", 0, AF_ANY
, PARSELOG0
},
208 { "thoplimit", NEXTARG
, AF_ANY
, PARSELOG0
},
209 { "set", NEXTARG
, AF_ANY
, PARSESET
},
210 { "destination", NEXTARG
, AF_ANY
, 0 },
211 { "zone", NEXTARG
, AF_ANY
, 0 },
212 { "-zone", 0, AF_ANY
, 0 },
213 { "all-zones", 0, AF_ANY
, 0 },
214 { "ether", OPTARG
, AF_ANY
, PARSENOW
},
215 { "usesrc", NEXTARG
, AF_ANY
, PARSENOW
},
216 { 0 /* ether addr */, 0, AF_UNSPEC
, PARSELOG0
},
217 { 0 /* set */, 0, AF_ANY
, PARSESET
},
218 { 0 /* destination */, 0, AF_ANY
, 0 },
219 { 0, END_OF_TABLE
, END_OF_TABLE
, END_OF_TABLE
},
223 /* Known address families */
229 { "ether", AF_UNSPEC
},
230 { "inet6", AF_INET6
},
235 * Append "item" to the buffer. If there isn't enough room in the buffer,
239 parse_append_buf(char *item
)
247 itemlen
= strlen(item
);
248 newdumplen
= parsedumplen
+ itemlen
;
250 /* Expand dump buffer as needed */
251 if (parsebuflen
< newdumplen
) {
252 if ((parsebuf
= realloc(parsebuf
, newdumplen
)) == NULL
) {
256 parsebuflen
= newdumplen
;
258 (void) memcpy(parsebuf
+ parsedumplen
, item
, itemlen
);
260 parsedumplen
= newdumplen
;
264 * Dump the buffer to output.
270 * When parsing, a set or addif command, we may be some way into
271 * the command before we definitely know it is movable or fixed.
272 * If we get to the end of the command, and haven't seen a
273 * "failover" or "-failover" flag, the command is movable.
275 if (!((parsemode
== PARSEFIXED
) && (parsetype
& PARSEMOVABLE
) != 0) &&
276 (parsemode
& parsetype
) != 0 && parsedumplen
!= 0) {
279 if (parsebuf
[parsedumplen
] == ' ')
282 for (i
= 0; i
< parsedumplen
; i
++)
283 (void) putchar(parsebuf
[i
]);
285 (void) putchar('\n');
287 /* The buffer is kept in case there is more parsing to do */
289 parsetype
= PARSEFIXED
| PARSEMOVABLE
;
293 * Process a command. The command will either be put in the buffer,
294 * or dumped directly to output. The current contents of the buffer
295 * may be dumped to output.
297 * The buffer holds commands relating to a particular logical interface.
298 * For example, "set", "destination", "failover", "broadcast", all relate
299 * to a particular interface. Such commands have to be buffered until
300 * all the "failover" and "-failover" commands for that interface have
301 * been seen, only then will we know whether the command is movable
302 * or not. When the "addif" command is seen, we know we are about to
303 * start processing a new logical interface, we've seen all the
304 * "failover" and "-failover" commands for the previous interface, and
305 * can decide whether the buffer contents are movable or not.
309 parsedump(char *cmd
, int param
, int flags
, char *arg
)
311 char *cmdname
; /* Command name */
312 char *cmdarg
; /* Argument to command, if it takes one, or NULL */
315 * Is command only valid on logical interface 0?
316 * If processing commands on an additional logical interface, ignore
318 * If processing commands on logical interface 0, don't buffer the
319 * command, dump it straight to output.
321 if ((flags
& PARSELOG0
) != 0) {
328 * If processing the "addif" command, a destination address may
329 * follow without the "destination" prefix. Add PARSESET to the
330 * flags so that such an anonymous address is processed correctly.
332 if ((flags
& PARSEADD
) != 0) {
338 * Commands that must be dumped straight to output are always fixed
339 * (non-movable) commands.
342 if ((flags
& PARSENOW
) != 0)
346 * Source and destination addresses do not have to be prefixed
347 * with the keywords "set" or "destination". Ifparse always
348 * inserts the optional keyword.
352 if ((flags
& PARSESET
) != 0)
355 cmdname
= "destination";
360 cmdarg
= (param
== 0) ? NULL
: arg
;
365 * The next address without a prefix will be a destination
368 if ((flags
& PARSESET
) != 0)
372 * Dump the command straight to output?
373 * Only dump the command if the parse mode specified on
374 * the command line matches the type of the command.
376 if ((flags
& PARSENOW
) != 0) {
377 if ((parsemode
& flags
) != 0) {
378 (void) fputs(cmdname
, stdout
);
379 if (cmdarg
!= NULL
) {
380 (void) fputc(' ', stdout
);
381 (void) fputs(cmdarg
, stdout
);
383 (void) fputc('\n', stdout
);
389 * Only the commands relating to a particular logical interface
390 * are buffered. When an "addif" command is seen, processing is
391 * about to start on a new logical interface, so dump the
394 if ((flags
& PARSEADD
) != 0)
398 * If the command flags indicate the command is fixed or
399 * movable, update the type of the interface in the buffer
400 * accordingly. For example, "-failover" has the "PARSEFIXED"
401 * flag, and the contents of the buffer are not movable if
402 * "-failover" is seen.
404 if ((flags
& PARSEFIXED
) != 0)
405 parsetype
&= ~PARSEMOVABLE
;
407 if ((flags
& PARSEMOVABLE
) != 0)
408 parsetype
&= ~PARSEFIXED
;
410 parsetype
|= flags
& (PARSEFIXED
| PARSEMOVABLE
);
412 parse_append_buf(cmdname
);
414 if (cmdarg
!= NULL
) {
415 parse_append_buf(" ");
416 parse_append_buf(cmdarg
);
419 parse_append_buf(" ");
423 * Parse the part of the command line following the address family
424 * specification, if any.
426 * This function is a modified version of the function "ifconfig" in
430 ifparse(int argc
, char *argv
[], struct afswtch
*afp
)
437 if (strcmp(*argv
, "auto-dhcp") == 0 || strcmp(*argv
, "dhcp") == 0) {
438 if ((parsemode
& PARSEFIXED
) != NULL
) {
440 (void) fputs(*argv
++, stdout
);
442 (void) fputc(' ', stdout
);
444 (void) fputc('\n', stdout
);
454 found_cmd
= _B_FALSE
;
455 for (p
= cmds
; ; p
++) {
456 assert(p
->c_parseflags
!= END_OF_TABLE
);
458 if (strcmp(*argv
, p
->c_name
) == 0) {
460 * indicate that the command was
461 * found and check to see if
462 * the address family is valid
465 if (p
->c_af
== AF_ANY
||
470 if (p
->c_af
== AF_ANY
||
475 assert(p
->c_parseflags
!= END_OF_TABLE
);
477 * If we found the keyword, but the address family
478 * did not match spit out an error
480 if (found_cmd
&& p
->c_name
== 0) {
481 (void) fprintf(stderr
, "ifparse: Operation %s not"
482 " supported for %s\n", *argv
, afp
->af_name
);
486 * else (no keyword found), we assume it's an address
489 if (p
->c_name
== 0 && setaddr
) {
490 p
++; /* got src, do dst */
491 assert(p
->c_parseflags
!= END_OF_TABLE
);
494 if (p
->c_parameter
== NEXTARG
|| p
->c_parameter
== OPTARG
) {
496 if (argc
== 0 && p
->c_parameter
== NEXTARG
) {
497 (void) fprintf(stderr
,
498 "ifparse: no argument for %s\n",
505 * Dump the command if:
507 * there's no address family
510 * there is a restriction AND
511 * the address families match
513 if ((p
->c_af
== AF_ANY
) || (af
== p
->c_af
))
514 parsedump(p
->c_name
, p
->c_parameter
, p
->c_parseflags
,
524 * Print command usage on standard error.
529 (void) fprintf(stderr
,
530 "usage: ifparse [ -fs ] <addr_family> <commands>\n");
534 main(int argc
, char *argv
[])
539 while ((c
= getopt(argc
, argv
, "fs")) != -1) {
542 parsemode
|= PARSEMOVABLE
;
545 parsemode
|= PARSEFIXED
;
554 parsemode
= PARSEFIXED
| PARSEMOVABLE
;
561 struct afswtch
*aftp
;
562 for (aftp
= afs
; aftp
->af_name
; aftp
++) {
563 if (strcmp(aftp
->af_name
, *argv
) == 0) {
571 return (ifparse(argc
, argv
, afp
));