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