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