10Sstevel@tonic-gate /* 2*5978Smeem * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate /* 60Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 70Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 80Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 90Sstevel@tonic-gate */ 100Sstevel@tonic-gate 110Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 120Sstevel@tonic-gate 130Sstevel@tonic-gate /* 140Sstevel@tonic-gate * Ifparse splits up an ifconfig command line, and was written for use 15*5978Smeem * with the networking boot scripts; see $SRC/cmd/svc/shell/net_include.sh 160Sstevel@tonic-gate * 170Sstevel@tonic-gate * Ifparse can extract selected parts of the ifconfig command line, 180Sstevel@tonic-gate * such as failover address configuration ("ifparse -f"), or everything 190Sstevel@tonic-gate * except failover address configuration ("ifparse -s"). By default, 200Sstevel@tonic-gate * all parts of the command line are extracted (equivalent to ("ifparse -fs"). 210Sstevel@tonic-gate * 220Sstevel@tonic-gate * Examples: 230Sstevel@tonic-gate * 240Sstevel@tonic-gate * The command: 250Sstevel@tonic-gate * 260Sstevel@tonic-gate * ifparse inet 1.2.3.4 up group two addif 1.2.3.5 up addif 1.2.3.6 up 270Sstevel@tonic-gate * 280Sstevel@tonic-gate * Produces the following on standard output: 290Sstevel@tonic-gate * 300Sstevel@tonic-gate * set 1.2.3.4 up 310Sstevel@tonic-gate * group two 320Sstevel@tonic-gate * addif 1.2.3.5 up 330Sstevel@tonic-gate * addif 1.2.3.6 up 340Sstevel@tonic-gate * 350Sstevel@tonic-gate * The optional "set" and "destination" keywords are added to make the 360Sstevel@tonic-gate * output easier to process by a script or another command. 370Sstevel@tonic-gate * 380Sstevel@tonic-gate * The command: 390Sstevel@tonic-gate * 400Sstevel@tonic-gate * ifparse -f inet 1.2.3.4 -failover up group two addif 1.2.3.5 up 410Sstevel@tonic-gate * 420Sstevel@tonic-gate * Produces: 430Sstevel@tonic-gate * 440Sstevel@tonic-gate * addif 1.2.3.5 up 450Sstevel@tonic-gate * 460Sstevel@tonic-gate * Only failover address configuration has been requested. Address 470Sstevel@tonic-gate * 1.2.3.4 is a non-failover address, and so isn't output. 480Sstevel@tonic-gate * 490Sstevel@tonic-gate * The "failover" and "-failover" commands can occur several times for 500Sstevel@tonic-gate * a given logical interface. Only the last one counts. For example: 510Sstevel@tonic-gate * 520Sstevel@tonic-gate * ifparse -f inet 1.2.3.4 -failover failover -failover failover up 530Sstevel@tonic-gate * 540Sstevel@tonic-gate * Produces: 550Sstevel@tonic-gate * 560Sstevel@tonic-gate * set 1.2.3.4 -failover failover -failover failover up 570Sstevel@tonic-gate * 580Sstevel@tonic-gate * No attempt is made to clean up such "pathological" command lines, by 590Sstevel@tonic-gate * removing redundant "failover" and "-failover" commands. 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate 620Sstevel@tonic-gate #include <sys/types.h> 630Sstevel@tonic-gate #include <stdlib.h> 640Sstevel@tonic-gate #include <stdio.h> 650Sstevel@tonic-gate #include <string.h> 660Sstevel@tonic-gate #include <assert.h> 670Sstevel@tonic-gate 680Sstevel@tonic-gate /* 690Sstevel@tonic-gate * Parser flags: 700Sstevel@tonic-gate * 710Sstevel@tonic-gate * PARSEFIXED 720Sstevel@tonic-gate * Command should only appear if non-failover commands 730Sstevel@tonic-gate * are requested. 740Sstevel@tonic-gate * PARSEMOVABLE 750Sstevel@tonic-gate * Command should only appear if failover commands are 760Sstevel@tonic-gate * requested. 770Sstevel@tonic-gate * PARSENOW 780Sstevel@tonic-gate * Don't buffer the command, dump it to output immediately. 790Sstevel@tonic-gate * PARSEADD 800Sstevel@tonic-gate * Indicates processing has moved on to additional 810Sstevel@tonic-gate * logical interfaces. 820Sstevel@tonic-gate * Dump the buffer to output and clear buffer contents. 830Sstevel@tonic-gate * PARSESET 840Sstevel@tonic-gate * The "set" and "destination" keywords are optional. 850Sstevel@tonic-gate * This flag indicates that the next address not prefixed 860Sstevel@tonic-gate * with a keyword will be a destination address. 870Sstevel@tonic-gate * PARSELOG0 880Sstevel@tonic-gate * Command not valid on additional logical interfaces. 890Sstevel@tonic-gate */ 900Sstevel@tonic-gate 910Sstevel@tonic-gate #define PARSEFIXED 0x01 920Sstevel@tonic-gate #define PARSEMOVABLE 0x02 930Sstevel@tonic-gate #define PARSENOW 0x04 940Sstevel@tonic-gate #define PARSEADD 0x08 950Sstevel@tonic-gate #define PARSESET 0x10 960Sstevel@tonic-gate #define PARSELOG0 0x20 970Sstevel@tonic-gate 980Sstevel@tonic-gate typedef enum { AF_UNSPEC, AF_INET, AF_INET6, AF_ANY } ac_t; 990Sstevel@tonic-gate 100*5978Smeem #define NEXTARG (-1) /* command takes an argument */ 101*5978Smeem #define OPTARG (-2) /* command takes an optional argument */ 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate #define END_OF_TABLE (-1) 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate /* Parsemode, the type of commands requested by the user. */ 1060Sstevel@tonic-gate int parsemode = 0; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate /* Parsetype, the type of the command currently in the buffer. */ 1090Sstevel@tonic-gate int parsetype = PARSEFIXED | PARSEMOVABLE; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate /* Parsebuf, pointer to the buffer. */ 1120Sstevel@tonic-gate char *parsebuf = NULL; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /* Parsebuflen, the size of the buffer area. */ 1150Sstevel@tonic-gate unsigned parsebuflen = 0; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate /* Parsedumplen, the amount of the buffer currently in use. */ 1180Sstevel@tonic-gate unsigned parsedumplen = 0; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate /* 1210Sstevel@tonic-gate * Setaddr, used to decide whether an address without a keyword 1220Sstevel@tonic-gate * prefix is a source or destination address. 1230Sstevel@tonic-gate */ 1240Sstevel@tonic-gate boolean_t setaddr = _B_FALSE; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate /* 1270Sstevel@tonic-gate * Some ifconfig commands are only valid on the first logical interface. 1280Sstevel@tonic-gate * As soon as an "addif" command is seen, "addint" is set. 1290Sstevel@tonic-gate */ 1300Sstevel@tonic-gate boolean_t addint = _B_FALSE; 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate /* 1330Sstevel@tonic-gate * The parser table is based on that in ifconfig. A command may or 134*5978Smeem * may not have an argument, as indicated by whether NEXTARG/OPTARG is 135*5978Smeem * in the second column. Some commands can only be used with certain 136*5978Smeem * address families, as indicated in the third column. The fourth column 1370Sstevel@tonic-gate * contains flags that control parser action. 1380Sstevel@tonic-gate * 1390Sstevel@tonic-gate * Ifparse buffers logical interface configuration commands such as "set", 1400Sstevel@tonic-gate * "netmask" and "broadcast". This buffering continues until an "addif" 1410Sstevel@tonic-gate * command is seen, at which point the buffer is emptied, and the process 1420Sstevel@tonic-gate * starts again. 1430Sstevel@tonic-gate * 1440Sstevel@tonic-gate * Some commands do not relate to logical interface configuration and are 1450Sstevel@tonic-gate * dumped to output as soon as they are seen, such as "group" and "standby". 1460Sstevel@tonic-gate * 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate struct cmd { 1500Sstevel@tonic-gate char *c_name; 1510Sstevel@tonic-gate int c_parameter; /* NEXTARG means next argv */ 1520Sstevel@tonic-gate int c_af; /* address family restrictions */ 1530Sstevel@tonic-gate int c_parseflags; /* parsing flags */ 1540Sstevel@tonic-gate } cmds[] = { 1550Sstevel@tonic-gate { "up", 0, AF_ANY, 0 }, 1560Sstevel@tonic-gate { "down", 0, AF_ANY, 0 }, 1570Sstevel@tonic-gate { "trailers", 0, AF_ANY, PARSENOW }, 1580Sstevel@tonic-gate { "-trailers", 0, AF_ANY, PARSENOW }, 1590Sstevel@tonic-gate { "arp", 0, AF_INET, PARSENOW }, 1600Sstevel@tonic-gate { "-arp", 0, AF_INET, PARSENOW }, 1610Sstevel@tonic-gate { "private", 0, AF_ANY, 0 }, 1620Sstevel@tonic-gate { "-private", 0, AF_ANY, 0 }, 1630Sstevel@tonic-gate { "router", 0, AF_ANY, PARSELOG0 }, 1640Sstevel@tonic-gate { "-router", 0, AF_ANY, PARSELOG0 }, 1650Sstevel@tonic-gate { "xmit", 0, AF_ANY, 0 }, 1660Sstevel@tonic-gate { "-xmit", 0, AF_ANY, 0 }, 1670Sstevel@tonic-gate { "-nud", 0, AF_INET6, PARSENOW }, 1680Sstevel@tonic-gate { "nud", 0, AF_INET6, PARSENOW }, 1690Sstevel@tonic-gate { "anycast", 0, AF_ANY, 0 }, 1700Sstevel@tonic-gate { "-anycast", 0, AF_ANY, 0 }, 1710Sstevel@tonic-gate { "local", 0, AF_ANY, 0 }, 1720Sstevel@tonic-gate { "-local", 0, AF_ANY, 0 }, 1730Sstevel@tonic-gate { "deprecated", 0, AF_ANY, 0 }, 1740Sstevel@tonic-gate { "-deprecated", 0, AF_ANY, 0 }, 1750Sstevel@tonic-gate { "preferred", 0, AF_INET6, 0 }, 1760Sstevel@tonic-gate { "-preferred", 0, AF_INET6, 0 }, 1770Sstevel@tonic-gate { "debug", 0, AF_ANY, PARSENOW }, 1780Sstevel@tonic-gate { "verbose", 0, AF_ANY, PARSENOW }, 1790Sstevel@tonic-gate { "netmask", NEXTARG, AF_INET, 0 }, 1800Sstevel@tonic-gate { "metric", NEXTARG, AF_ANY, 0 }, 1810Sstevel@tonic-gate { "mtu", NEXTARG, AF_ANY, 0 }, 1820Sstevel@tonic-gate { "index", NEXTARG, AF_ANY, PARSELOG0 }, 1830Sstevel@tonic-gate { "broadcast", NEXTARG, AF_INET, 0 }, 1840Sstevel@tonic-gate { "auto-revarp", 0, AF_INET, PARSEFIXED}, 1850Sstevel@tonic-gate { "plumb", 0, AF_ANY, PARSENOW }, 1860Sstevel@tonic-gate { "unplumb", 0, AF_ANY, PARSENOW }, 1870Sstevel@tonic-gate { "subnet", NEXTARG, AF_ANY, 0 }, 1880Sstevel@tonic-gate { "token", NEXTARG, AF_INET6, PARSELOG0 }, 1890Sstevel@tonic-gate { "tsrc", NEXTARG, AF_ANY, PARSELOG0 }, 1900Sstevel@tonic-gate { "tdst", NEXTARG, AF_ANY, PARSELOG0 }, 1910Sstevel@tonic-gate { "encr_auth_algs", NEXTARG, AF_ANY, PARSELOG0 }, 1920Sstevel@tonic-gate { "encr_algs", NEXTARG, AF_ANY, PARSELOG0 }, 1930Sstevel@tonic-gate { "auth_algs", NEXTARG, AF_ANY, PARSELOG0 }, 1940Sstevel@tonic-gate { "addif", NEXTARG, AF_ANY, PARSEADD }, 1950Sstevel@tonic-gate { "removeif", NEXTARG, AF_ANY, PARSELOG0 }, 1960Sstevel@tonic-gate { "modlist", 0, AF_ANY, PARSENOW }, 1970Sstevel@tonic-gate { "modinsert", NEXTARG, AF_ANY, PARSENOW }, 1980Sstevel@tonic-gate { "modremove", NEXTARG, AF_ANY, PARSENOW }, 1990Sstevel@tonic-gate { "failover", 0, AF_ANY, PARSEMOVABLE }, 2000Sstevel@tonic-gate { "-failover", 0, AF_ANY, PARSEFIXED }, 2010Sstevel@tonic-gate { "standby", 0, AF_ANY, PARSENOW }, 2020Sstevel@tonic-gate { "-standby", 0, AF_ANY, PARSENOW }, 2030Sstevel@tonic-gate { "failed", 0, AF_ANY, PARSENOW }, 2040Sstevel@tonic-gate { "-failed", 0, AF_ANY, PARSENOW }, 2050Sstevel@tonic-gate { "group", NEXTARG, AF_ANY, PARSELOG0 }, 2060Sstevel@tonic-gate { "configinfo", 0, AF_ANY, PARSENOW }, 2070Sstevel@tonic-gate { "encaplimit", NEXTARG, AF_ANY, PARSELOG0 }, 2080Sstevel@tonic-gate { "-encaplimit", 0, AF_ANY, PARSELOG0 }, 2090Sstevel@tonic-gate { "thoplimit", NEXTARG, AF_ANY, PARSELOG0 }, 2100Sstevel@tonic-gate { "set", NEXTARG, AF_ANY, PARSESET }, 2110Sstevel@tonic-gate { "destination", NEXTARG, AF_ANY, 0 }, 212*5978Smeem { "zone", NEXTARG, AF_ANY, 0 }, 213*5978Smeem { "-zone", 0, AF_ANY, 0 }, 214*5978Smeem { "all-zones", 0, AF_ANY, 0 }, 215*5978Smeem { "ether", OPTARG, AF_ANY, PARSENOW }, 216*5978Smeem { "usesrc", NEXTARG, AF_ANY, PARSENOW }, 2170Sstevel@tonic-gate { 0 /* ether addr */, 0, AF_UNSPEC, PARSELOG0 }, 2180Sstevel@tonic-gate { 0 /* set */, 0, AF_ANY, PARSESET }, 2190Sstevel@tonic-gate { 0 /* destination */, 0, AF_ANY, 0 }, 2200Sstevel@tonic-gate { 0, END_OF_TABLE, END_OF_TABLE, END_OF_TABLE}, 2210Sstevel@tonic-gate }; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* Known address families */ 2250Sstevel@tonic-gate struct afswtch { 2260Sstevel@tonic-gate char *af_name; 2270Sstevel@tonic-gate short af_af; 2280Sstevel@tonic-gate } afs[] = { 2290Sstevel@tonic-gate { "inet", AF_INET }, 2300Sstevel@tonic-gate { "ether", AF_UNSPEC }, 2310Sstevel@tonic-gate { "inet6", AF_INET6 }, 2320Sstevel@tonic-gate { 0, 0 } 2330Sstevel@tonic-gate }; 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate /* 2360Sstevel@tonic-gate * Append "item" to the buffer. If there isn't enough room in the buffer, 2370Sstevel@tonic-gate * expand it. 2380Sstevel@tonic-gate */ 2390Sstevel@tonic-gate static void 2400Sstevel@tonic-gate parse_append_buf(char *item) 2410Sstevel@tonic-gate { 2420Sstevel@tonic-gate unsigned itemlen; 2430Sstevel@tonic-gate unsigned newdumplen; 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate if (item == NULL) 2460Sstevel@tonic-gate return; 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate itemlen = strlen(item); 2490Sstevel@tonic-gate newdumplen = parsedumplen + itemlen; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate /* Expand dump buffer as needed */ 2520Sstevel@tonic-gate if (parsebuflen < newdumplen) { 2530Sstevel@tonic-gate if ((parsebuf = realloc(parsebuf, newdumplen)) == NULL) { 2540Sstevel@tonic-gate perror("ifparse"); 2550Sstevel@tonic-gate exit(1); 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate parsebuflen = newdumplen; 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate (void) memcpy(parsebuf + parsedumplen, item, itemlen); 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate parsedumplen = newdumplen; 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate /* 2650Sstevel@tonic-gate * Dump the buffer to output. 2660Sstevel@tonic-gate */ 2670Sstevel@tonic-gate static void 2680Sstevel@tonic-gate parse_dump_buf(void) 2690Sstevel@tonic-gate { 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * When parsing, a set or addif command, we may be some way into 2720Sstevel@tonic-gate * the command before we definitely know it is movable or fixed. 2730Sstevel@tonic-gate * If we get to the end of the command, and haven't seen a 2740Sstevel@tonic-gate * "failover" or "-failover" flag, the command is movable. 2750Sstevel@tonic-gate */ 276*5978Smeem if (!((parsemode == PARSEFIXED) && (parsetype & PARSEMOVABLE) != 0) && 277*5978Smeem (parsemode & parsetype) != 0 && parsedumplen != 0) { 2780Sstevel@tonic-gate unsigned i; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate if (parsebuf[parsedumplen] == ' ') 2810Sstevel@tonic-gate parsedumplen--; 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate for (i = 0; i < parsedumplen; i++) 2840Sstevel@tonic-gate (void) putchar(parsebuf[i]); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate (void) putchar('\n'); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate /* The buffer is kept in case there is more parsing to do */ 2890Sstevel@tonic-gate parsedumplen = 0; 2900Sstevel@tonic-gate parsetype = PARSEFIXED | PARSEMOVABLE; 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate /* 2940Sstevel@tonic-gate * Process a command. The command will either be put in the buffer, 2950Sstevel@tonic-gate * or dumped directly to output. The current contents of the buffer 2960Sstevel@tonic-gate * may be dumped to output. 2970Sstevel@tonic-gate * 2980Sstevel@tonic-gate * The buffer holds commands relating to a particular logical interface. 2990Sstevel@tonic-gate * For example, "set", "destination", "failover", "broadcast", all relate 3000Sstevel@tonic-gate * to a particular interface. Such commands have to be buffered until 3010Sstevel@tonic-gate * all the "failover" and "-failover" commands for that interface have 3020Sstevel@tonic-gate * been seen, only then will we know whether the command is movable 3030Sstevel@tonic-gate * or not. When the "addif" command is seen, we know we are about to 3040Sstevel@tonic-gate * start processing a new logical interface, we've seen all the 3050Sstevel@tonic-gate * "failover" and "-failover" commands for the previous interface, and 3060Sstevel@tonic-gate * can decide whether the buffer contents are movable or not. 3070Sstevel@tonic-gate * 3080Sstevel@tonic-gate */ 3090Sstevel@tonic-gate static void 3100Sstevel@tonic-gate parsedump(char *cmd, int param, int flags, char *arg) 3110Sstevel@tonic-gate { 3120Sstevel@tonic-gate char *cmdname; /* Command name */ 3130Sstevel@tonic-gate char *cmdarg; /* Argument to command, if it takes one, or NULL */ 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate /* 3160Sstevel@tonic-gate * Is command only valid on logical interface 0? 3170Sstevel@tonic-gate * If processing commands on an additional logical interface, ignore 3180Sstevel@tonic-gate * the command. 3190Sstevel@tonic-gate * If processing commands on logical interface 0, don't buffer the 3200Sstevel@tonic-gate * command, dump it straight to output. 3210Sstevel@tonic-gate */ 3220Sstevel@tonic-gate if ((flags & PARSELOG0) != 0) { 3230Sstevel@tonic-gate if (addint) 3240Sstevel@tonic-gate return; 3250Sstevel@tonic-gate flags |= PARSENOW; 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* 3290Sstevel@tonic-gate * If processing the "addif" command, a destination address may 3300Sstevel@tonic-gate * follow without the "destination" prefix. Add PARSESET to the 3310Sstevel@tonic-gate * flags so that such an anonymous address is processed correctly. 3320Sstevel@tonic-gate */ 3330Sstevel@tonic-gate if ((flags & PARSEADD) != 0) { 3340Sstevel@tonic-gate flags |= PARSESET; 3350Sstevel@tonic-gate addint = _B_TRUE; 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * Commands that must be dumped straight to output are always fixed 3400Sstevel@tonic-gate * (non-movable) commands. 3410Sstevel@tonic-gate * 3420Sstevel@tonic-gate */ 3430Sstevel@tonic-gate if ((flags & PARSENOW) != 0) 3440Sstevel@tonic-gate flags |= PARSEFIXED; 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate /* 3470Sstevel@tonic-gate * Source and destination addresses do not have to be prefixed 3480Sstevel@tonic-gate * with the keywords "set" or "destination". Ifparse always 3490Sstevel@tonic-gate * inserts the optional keyword. 3500Sstevel@tonic-gate */ 3510Sstevel@tonic-gate if (cmd == NULL) { 3520Sstevel@tonic-gate cmdarg = arg; 3530Sstevel@tonic-gate if ((flags & PARSESET) != 0) 3540Sstevel@tonic-gate cmdname = "set"; 3550Sstevel@tonic-gate else if (setaddr) { 3560Sstevel@tonic-gate cmdname = "destination"; 3570Sstevel@tonic-gate setaddr = _B_FALSE; 3580Sstevel@tonic-gate } else 3590Sstevel@tonic-gate cmdname = ""; 3600Sstevel@tonic-gate } else { 361*5978Smeem cmdarg = (param == 0) ? NULL : arg; 3620Sstevel@tonic-gate cmdname = cmd; 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate /* 3660Sstevel@tonic-gate * The next address without a prefix will be a destination 3670Sstevel@tonic-gate * address. 3680Sstevel@tonic-gate */ 3690Sstevel@tonic-gate if ((flags & PARSESET) != 0) 3700Sstevel@tonic-gate setaddr = _B_TRUE; 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate /* 3730Sstevel@tonic-gate * Dump the command straight to output? 3740Sstevel@tonic-gate * Only dump the command if the parse mode specified on 3750Sstevel@tonic-gate * the command line matches the type of the command. 3760Sstevel@tonic-gate */ 3770Sstevel@tonic-gate if ((flags & PARSENOW) != 0) { 3780Sstevel@tonic-gate if ((parsemode & flags) != 0) { 3790Sstevel@tonic-gate (void) fputs(cmdname, stdout); 3800Sstevel@tonic-gate if (cmdarg != NULL) { 3810Sstevel@tonic-gate (void) fputc(' ', stdout); 3820Sstevel@tonic-gate (void) fputs(cmdarg, stdout); 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate (void) fputc('\n', stdout); 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate return; 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate /* 3900Sstevel@tonic-gate * Only the commands relating to a particular logical interface 3910Sstevel@tonic-gate * are buffered. When an "addif" command is seen, processing is 3920Sstevel@tonic-gate * about to start on a new logical interface, so dump the 3930Sstevel@tonic-gate * buffer to output. 3940Sstevel@tonic-gate */ 3950Sstevel@tonic-gate if ((flags & PARSEADD) != 0) 3960Sstevel@tonic-gate parse_dump_buf(); 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate /* 3990Sstevel@tonic-gate * If the command flags indicate the command is fixed or 4000Sstevel@tonic-gate * movable, update the type of the interface in the buffer 4010Sstevel@tonic-gate * accordingly. For example, "-failover" has the "PARSEFIXED" 4020Sstevel@tonic-gate * flag, and the contents of the buffer are not movable if 4030Sstevel@tonic-gate * "-failover" is seen. 4040Sstevel@tonic-gate */ 4050Sstevel@tonic-gate if ((flags & PARSEFIXED) != 0) 4060Sstevel@tonic-gate parsetype &= ~PARSEMOVABLE; 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate if ((flags & PARSEMOVABLE) != 0) 4090Sstevel@tonic-gate parsetype &= ~PARSEFIXED; 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate parsetype |= flags & (PARSEFIXED | PARSEMOVABLE); 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate parse_append_buf(cmdname); 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate if (cmdarg != NULL) { 4160Sstevel@tonic-gate parse_append_buf(" "); 4170Sstevel@tonic-gate parse_append_buf(cmdarg); 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate parse_append_buf(" "); 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate /* 4240Sstevel@tonic-gate * Parse the part of the command line following the address family 4250Sstevel@tonic-gate * specification, if any. 4260Sstevel@tonic-gate * 4270Sstevel@tonic-gate * This function is a modified version of the function "ifconfig" in 4280Sstevel@tonic-gate * ifconfig.c. 4290Sstevel@tonic-gate */ 4300Sstevel@tonic-gate static int 4310Sstevel@tonic-gate ifparse(int argc, char *argv[], struct afswtch *afp) 4320Sstevel@tonic-gate { 433*5978Smeem int af = afp->af_af; 4340Sstevel@tonic-gate 435*5978Smeem if (argc == 0) 4360Sstevel@tonic-gate return (0); 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) { 439*5978Smeem if ((parsemode & PARSEFIXED) != NULL) { 440*5978Smeem while (argc) { 441*5978Smeem (void) fputs(*argv++, stdout); 442*5978Smeem if (--argc != 0) 443*5978Smeem (void) fputc(' ', stdout); 444*5978Smeem else 445*5978Smeem (void) fputc('\n', stdout); 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate } 448*5978Smeem return (0); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate while (argc > 0) { 4520Sstevel@tonic-gate struct cmd *p; 4530Sstevel@tonic-gate boolean_t found_cmd; 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate found_cmd = _B_FALSE; 4560Sstevel@tonic-gate for (p = cmds; ; p++) { 4570Sstevel@tonic-gate assert(p->c_parseflags != END_OF_TABLE); 4580Sstevel@tonic-gate if (p->c_name) { 4590Sstevel@tonic-gate if (strcmp(*argv, p->c_name) == 0) { 4600Sstevel@tonic-gate /* 4610Sstevel@tonic-gate * indicate that the command was 4620Sstevel@tonic-gate * found and check to see if 4630Sstevel@tonic-gate * the address family is valid 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate found_cmd = _B_TRUE; 4660Sstevel@tonic-gate if (p->c_af == AF_ANY || 4670Sstevel@tonic-gate af == p->c_af) 4680Sstevel@tonic-gate break; 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate } else { 4710Sstevel@tonic-gate if (p->c_af == AF_ANY || 4720Sstevel@tonic-gate af == p->c_af) 4730Sstevel@tonic-gate break; 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate assert(p->c_parseflags != END_OF_TABLE); 4770Sstevel@tonic-gate /* 4780Sstevel@tonic-gate * If we found the keyword, but the address family 4790Sstevel@tonic-gate * did not match spit out an error 4800Sstevel@tonic-gate */ 4810Sstevel@tonic-gate if (found_cmd && p->c_name == 0) { 4820Sstevel@tonic-gate (void) fprintf(stderr, "ifparse: Operation %s not" 4830Sstevel@tonic-gate " supported for %s\n", *argv, afp->af_name); 4840Sstevel@tonic-gate return (1); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * else (no keyword found), we assume it's an address 4880Sstevel@tonic-gate * of some sort 4890Sstevel@tonic-gate */ 4900Sstevel@tonic-gate if (p->c_name == 0 && setaddr) { 4910Sstevel@tonic-gate p++; /* got src, do dst */ 4920Sstevel@tonic-gate assert(p->c_parseflags != END_OF_TABLE); 4930Sstevel@tonic-gate } 494*5978Smeem 495*5978Smeem if (p->c_parameter == NEXTARG || p->c_parameter == OPTARG) { 4960Sstevel@tonic-gate argc--, argv++; 497*5978Smeem if (argc == 0 && p->c_parameter == NEXTARG) { 4980Sstevel@tonic-gate (void) fprintf(stderr, 4990Sstevel@tonic-gate "ifparse: no argument for %s\n", 5000Sstevel@tonic-gate p->c_name); 5010Sstevel@tonic-gate return (1); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate } 504*5978Smeem 5050Sstevel@tonic-gate /* 5060Sstevel@tonic-gate * Dump the command if: 5070Sstevel@tonic-gate * 5080Sstevel@tonic-gate * there's no address family 5090Sstevel@tonic-gate * restriction 5100Sstevel@tonic-gate * OR 5110Sstevel@tonic-gate * there is a restriction AND 5120Sstevel@tonic-gate * the address families match 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate if ((p->c_af == AF_ANY) || (af == p->c_af)) 515*5978Smeem parsedump(p->c_name, p->c_parameter, p->c_parseflags, 516*5978Smeem *argv); 5170Sstevel@tonic-gate argc--, argv++; 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate parse_dump_buf(); 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate return (0); 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate /* 5250Sstevel@tonic-gate * Print command usage on standard error. 5260Sstevel@tonic-gate */ 5270Sstevel@tonic-gate static void 5280Sstevel@tonic-gate usage(void) 5290Sstevel@tonic-gate { 5300Sstevel@tonic-gate (void) fprintf(stderr, 531*5978Smeem "usage: ifparse [ -fs ] <addr_family> <commands>\n"); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate int 5350Sstevel@tonic-gate main(int argc, char *argv[]) 5360Sstevel@tonic-gate { 5370Sstevel@tonic-gate int c; 5380Sstevel@tonic-gate struct afswtch *afp; 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate while ((c = getopt(argc, argv, "fs")) != -1) { 5410Sstevel@tonic-gate switch ((char)c) { 5420Sstevel@tonic-gate case 'f': 5430Sstevel@tonic-gate parsemode |= PARSEMOVABLE; 5440Sstevel@tonic-gate break; 5450Sstevel@tonic-gate case 's': 5460Sstevel@tonic-gate parsemode |= PARSEFIXED; 5470Sstevel@tonic-gate break; 5480Sstevel@tonic-gate case '?': 5490Sstevel@tonic-gate usage(); 5500Sstevel@tonic-gate exit(1); 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate if (parsemode == 0) 5550Sstevel@tonic-gate parsemode = PARSEFIXED | PARSEMOVABLE; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate argc -= optind; 5580Sstevel@tonic-gate argv += optind; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate afp = afs; 5610Sstevel@tonic-gate if (argc > 0) { 5620Sstevel@tonic-gate struct afswtch *aftp; 5630Sstevel@tonic-gate for (aftp = afs; aftp->af_name; aftp++) { 5640Sstevel@tonic-gate if (strcmp(aftp->af_name, *argv) == 0) { 5650Sstevel@tonic-gate argc--; argv++; 5660Sstevel@tonic-gate afp = aftp; 5670Sstevel@tonic-gate break; 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate return (ifparse(argc, argv, afp)); 5730Sstevel@tonic-gate } 574