17c478bd9Sstevel@tonic-gate /*
2e11c3f44Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
37c478bd9Sstevel@tonic-gate * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate */
57c478bd9Sstevel@tonic-gate /*
67c478bd9Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California.
77c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement
87c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution.
97c478bd9Sstevel@tonic-gate */
107c478bd9Sstevel@tonic-gate
117c478bd9Sstevel@tonic-gate /*
127c478bd9Sstevel@tonic-gate * Ifparse splits up an ifconfig command line, and was written for use
13f7d61273Smeem * with the networking boot scripts; see $SRC/cmd/svc/shell/net_include.sh
147c478bd9Sstevel@tonic-gate *
157c478bd9Sstevel@tonic-gate * Ifparse can extract selected parts of the ifconfig command line,
167c478bd9Sstevel@tonic-gate * such as failover address configuration ("ifparse -f"), or everything
177c478bd9Sstevel@tonic-gate * except failover address configuration ("ifparse -s"). By default,
187c478bd9Sstevel@tonic-gate * all parts of the command line are extracted (equivalent to ("ifparse -fs").
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * Examples:
217c478bd9Sstevel@tonic-gate *
227c478bd9Sstevel@tonic-gate * The command:
237c478bd9Sstevel@tonic-gate *
247c478bd9Sstevel@tonic-gate * ifparse inet 1.2.3.4 up group two addif 1.2.3.5 up addif 1.2.3.6 up
257c478bd9Sstevel@tonic-gate *
267c478bd9Sstevel@tonic-gate * Produces the following on standard output:
277c478bd9Sstevel@tonic-gate *
287c478bd9Sstevel@tonic-gate * set 1.2.3.4 up
297c478bd9Sstevel@tonic-gate * group two
307c478bd9Sstevel@tonic-gate * addif 1.2.3.5 up
317c478bd9Sstevel@tonic-gate * addif 1.2.3.6 up
327c478bd9Sstevel@tonic-gate *
337c478bd9Sstevel@tonic-gate * The optional "set" and "destination" keywords are added to make the
347c478bd9Sstevel@tonic-gate * output easier to process by a script or another command.
357c478bd9Sstevel@tonic-gate *
367c478bd9Sstevel@tonic-gate * The command:
377c478bd9Sstevel@tonic-gate *
387c478bd9Sstevel@tonic-gate * ifparse -f inet 1.2.3.4 -failover up group two addif 1.2.3.5 up
397c478bd9Sstevel@tonic-gate *
407c478bd9Sstevel@tonic-gate * Produces:
417c478bd9Sstevel@tonic-gate *
427c478bd9Sstevel@tonic-gate * addif 1.2.3.5 up
437c478bd9Sstevel@tonic-gate *
447c478bd9Sstevel@tonic-gate * Only failover address configuration has been requested. Address
457c478bd9Sstevel@tonic-gate * 1.2.3.4 is a non-failover address, and so isn't output.
467c478bd9Sstevel@tonic-gate *
477c478bd9Sstevel@tonic-gate * The "failover" and "-failover" commands can occur several times for
487c478bd9Sstevel@tonic-gate * a given logical interface. Only the last one counts. For example:
497c478bd9Sstevel@tonic-gate *
507c478bd9Sstevel@tonic-gate * ifparse -f inet 1.2.3.4 -failover failover -failover failover up
517c478bd9Sstevel@tonic-gate *
527c478bd9Sstevel@tonic-gate * Produces:
537c478bd9Sstevel@tonic-gate *
547c478bd9Sstevel@tonic-gate * set 1.2.3.4 -failover failover -failover failover up
557c478bd9Sstevel@tonic-gate *
567c478bd9Sstevel@tonic-gate * No attempt is made to clean up such "pathological" command lines, by
577c478bd9Sstevel@tonic-gate * removing redundant "failover" and "-failover" commands.
587c478bd9Sstevel@tonic-gate */
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate #include <sys/types.h>
617c478bd9Sstevel@tonic-gate #include <stdlib.h>
627c478bd9Sstevel@tonic-gate #include <stdio.h>
637c478bd9Sstevel@tonic-gate #include <string.h>
647c478bd9Sstevel@tonic-gate #include <assert.h>
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate * Parser flags:
687c478bd9Sstevel@tonic-gate *
697c478bd9Sstevel@tonic-gate * PARSEFIXED
707c478bd9Sstevel@tonic-gate * Command should only appear if non-failover commands
717c478bd9Sstevel@tonic-gate * are requested.
727c478bd9Sstevel@tonic-gate * PARSEMOVABLE
737c478bd9Sstevel@tonic-gate * Command should only appear if failover commands are
747c478bd9Sstevel@tonic-gate * requested.
757c478bd9Sstevel@tonic-gate * PARSENOW
767c478bd9Sstevel@tonic-gate * Don't buffer the command, dump it to output immediately.
777c478bd9Sstevel@tonic-gate * PARSEADD
787c478bd9Sstevel@tonic-gate * Indicates processing has moved on to additional
797c478bd9Sstevel@tonic-gate * logical interfaces.
807c478bd9Sstevel@tonic-gate * Dump the buffer to output and clear buffer contents.
817c478bd9Sstevel@tonic-gate * PARSESET
827c478bd9Sstevel@tonic-gate * The "set" and "destination" keywords are optional.
837c478bd9Sstevel@tonic-gate * This flag indicates that the next address not prefixed
847c478bd9Sstevel@tonic-gate * with a keyword will be a destination address.
857c478bd9Sstevel@tonic-gate * PARSELOG0
867c478bd9Sstevel@tonic-gate * Command not valid on additional logical interfaces.
877c478bd9Sstevel@tonic-gate */
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate #define PARSEFIXED 0x01
907c478bd9Sstevel@tonic-gate #define PARSEMOVABLE 0x02
917c478bd9Sstevel@tonic-gate #define PARSENOW 0x04
927c478bd9Sstevel@tonic-gate #define PARSEADD 0x08
937c478bd9Sstevel@tonic-gate #define PARSESET 0x10
947c478bd9Sstevel@tonic-gate #define PARSELOG0 0x20
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate typedef enum { AF_UNSPEC, AF_INET, AF_INET6, AF_ANY } ac_t;
977c478bd9Sstevel@tonic-gate
98f7d61273Smeem #define NEXTARG (-1) /* command takes an argument */
99f7d61273Smeem #define OPTARG (-2) /* command takes an optional argument */
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate #define END_OF_TABLE (-1)
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate /* Parsemode, the type of commands requested by the user. */
1047c478bd9Sstevel@tonic-gate int parsemode = 0;
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate /* Parsetype, the type of the command currently in the buffer. */
1077c478bd9Sstevel@tonic-gate int parsetype = PARSEFIXED | PARSEMOVABLE;
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate /* Parsebuf, pointer to the buffer. */
1107c478bd9Sstevel@tonic-gate char *parsebuf = NULL;
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate /* Parsebuflen, the size of the buffer area. */
1137c478bd9Sstevel@tonic-gate unsigned parsebuflen = 0;
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate /* Parsedumplen, the amount of the buffer currently in use. */
1167c478bd9Sstevel@tonic-gate unsigned parsedumplen = 0;
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate * Setaddr, used to decide whether an address without a keyword
1207c478bd9Sstevel@tonic-gate * prefix is a source or destination address.
1217c478bd9Sstevel@tonic-gate */
1227c478bd9Sstevel@tonic-gate boolean_t setaddr = _B_FALSE;
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate * Some ifconfig commands are only valid on the first logical interface.
1267c478bd9Sstevel@tonic-gate * As soon as an "addif" command is seen, "addint" is set.
1277c478bd9Sstevel@tonic-gate */
1287c478bd9Sstevel@tonic-gate boolean_t addint = _B_FALSE;
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate * The parser table is based on that in ifconfig. A command may or
132f7d61273Smeem * may not have an argument, as indicated by whether NEXTARG/OPTARG is
133f7d61273Smeem * in the second column. Some commands can only be used with certain
134f7d61273Smeem * address families, as indicated in the third column. The fourth column
1357c478bd9Sstevel@tonic-gate * contains flags that control parser action.
1367c478bd9Sstevel@tonic-gate *
1377c478bd9Sstevel@tonic-gate * Ifparse buffers logical interface configuration commands such as "set",
1387c478bd9Sstevel@tonic-gate * "netmask" and "broadcast". This buffering continues until an "addif"
1397c478bd9Sstevel@tonic-gate * command is seen, at which point the buffer is emptied, and the process
1407c478bd9Sstevel@tonic-gate * starts again.
1417c478bd9Sstevel@tonic-gate *
1427c478bd9Sstevel@tonic-gate * Some commands do not relate to logical interface configuration and are
1437c478bd9Sstevel@tonic-gate * dumped to output as soon as they are seen, such as "group" and "standby".
1447c478bd9Sstevel@tonic-gate *
1457c478bd9Sstevel@tonic-gate */
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate struct cmd {
1487c478bd9Sstevel@tonic-gate char *c_name;
1497c478bd9Sstevel@tonic-gate int c_parameter; /* NEXTARG means next argv */
1507c478bd9Sstevel@tonic-gate int c_af; /* address family restrictions */
1517c478bd9Sstevel@tonic-gate int c_parseflags; /* parsing flags */
1527c478bd9Sstevel@tonic-gate } cmds[] = {
1537c478bd9Sstevel@tonic-gate { "up", 0, AF_ANY, 0 },
1547c478bd9Sstevel@tonic-gate { "down", 0, AF_ANY, 0 },
1557c478bd9Sstevel@tonic-gate { "trailers", 0, AF_ANY, PARSENOW },
1567c478bd9Sstevel@tonic-gate { "-trailers", 0, AF_ANY, PARSENOW },
1577c478bd9Sstevel@tonic-gate { "arp", 0, AF_INET, PARSENOW },
1587c478bd9Sstevel@tonic-gate { "-arp", 0, AF_INET, PARSENOW },
1597c478bd9Sstevel@tonic-gate { "private", 0, AF_ANY, 0 },
1607c478bd9Sstevel@tonic-gate { "-private", 0, AF_ANY, 0 },
1617c478bd9Sstevel@tonic-gate { "router", 0, AF_ANY, PARSELOG0 },
1627c478bd9Sstevel@tonic-gate { "-router", 0, AF_ANY, PARSELOG0 },
1637c478bd9Sstevel@tonic-gate { "xmit", 0, AF_ANY, 0 },
1647c478bd9Sstevel@tonic-gate { "-xmit", 0, AF_ANY, 0 },
1657c478bd9Sstevel@tonic-gate { "-nud", 0, AF_INET6, PARSENOW },
1667c478bd9Sstevel@tonic-gate { "nud", 0, AF_INET6, PARSENOW },
1677c478bd9Sstevel@tonic-gate { "anycast", 0, AF_ANY, 0 },
1687c478bd9Sstevel@tonic-gate { "-anycast", 0, AF_ANY, 0 },
1697c478bd9Sstevel@tonic-gate { "local", 0, AF_ANY, 0 },
1707c478bd9Sstevel@tonic-gate { "-local", 0, AF_ANY, 0 },
1717c478bd9Sstevel@tonic-gate { "deprecated", 0, AF_ANY, 0 },
1727c478bd9Sstevel@tonic-gate { "-deprecated", 0, AF_ANY, 0 },
1737c478bd9Sstevel@tonic-gate { "preferred", 0, AF_INET6, 0 },
1747c478bd9Sstevel@tonic-gate { "-preferred", 0, AF_INET6, 0 },
1757c478bd9Sstevel@tonic-gate { "debug", 0, AF_ANY, PARSENOW },
1767c478bd9Sstevel@tonic-gate { "verbose", 0, AF_ANY, PARSENOW },
1777c478bd9Sstevel@tonic-gate { "netmask", NEXTARG, AF_INET, 0 },
1787c478bd9Sstevel@tonic-gate { "metric", NEXTARG, AF_ANY, 0 },
1797c478bd9Sstevel@tonic-gate { "mtu", NEXTARG, AF_ANY, 0 },
1807c478bd9Sstevel@tonic-gate { "index", NEXTARG, AF_ANY, PARSELOG0 },
1817c478bd9Sstevel@tonic-gate { "broadcast", NEXTARG, AF_INET, 0 },
1827c478bd9Sstevel@tonic-gate { "auto-revarp", 0, AF_INET, PARSEFIXED},
1837c478bd9Sstevel@tonic-gate { "plumb", 0, AF_ANY, PARSENOW },
1847c478bd9Sstevel@tonic-gate { "unplumb", 0, AF_ANY, PARSENOW },
185e11c3f44Smeem { "ipmp", 0, AF_ANY, PARSELOG0 },
1867c478bd9Sstevel@tonic-gate { "subnet", NEXTARG, AF_ANY, 0 },
1877c478bd9Sstevel@tonic-gate { "token", NEXTARG, AF_INET6, PARSELOG0 },
1887c478bd9Sstevel@tonic-gate { "tsrc", NEXTARG, AF_ANY, PARSELOG0 },
1897c478bd9Sstevel@tonic-gate { "tdst", NEXTARG, AF_ANY, PARSELOG0 },
1907c478bd9Sstevel@tonic-gate { "encr_auth_algs", NEXTARG, AF_ANY, PARSELOG0 },
1917c478bd9Sstevel@tonic-gate { "encr_algs", NEXTARG, AF_ANY, PARSELOG0 },
1927c478bd9Sstevel@tonic-gate { "auth_algs", NEXTARG, AF_ANY, PARSELOG0 },
1937c478bd9Sstevel@tonic-gate { "addif", NEXTARG, AF_ANY, PARSEADD },
1947c478bd9Sstevel@tonic-gate { "removeif", NEXTARG, AF_ANY, PARSELOG0 },
1957c478bd9Sstevel@tonic-gate { "modlist", 0, AF_ANY, PARSENOW },
1967c478bd9Sstevel@tonic-gate { "modinsert", NEXTARG, AF_ANY, PARSENOW },
1977c478bd9Sstevel@tonic-gate { "modremove", NEXTARG, AF_ANY, PARSENOW },
1987c478bd9Sstevel@tonic-gate { "failover", 0, AF_ANY, PARSEMOVABLE },
1997c478bd9Sstevel@tonic-gate { "-failover", 0, AF_ANY, PARSEFIXED },
2007c478bd9Sstevel@tonic-gate { "standby", 0, AF_ANY, PARSENOW },
2017c478bd9Sstevel@tonic-gate { "-standby", 0, AF_ANY, PARSENOW },
2027c478bd9Sstevel@tonic-gate { "failed", 0, AF_ANY, PARSENOW },
2037c478bd9Sstevel@tonic-gate { "-failed", 0, AF_ANY, PARSENOW },
2047c478bd9Sstevel@tonic-gate { "group", NEXTARG, AF_ANY, PARSELOG0 },
2057c478bd9Sstevel@tonic-gate { "configinfo", 0, AF_ANY, PARSENOW },
2067c478bd9Sstevel@tonic-gate { "encaplimit", NEXTARG, AF_ANY, PARSELOG0 },
2077c478bd9Sstevel@tonic-gate { "-encaplimit", 0, AF_ANY, PARSELOG0 },
2087c478bd9Sstevel@tonic-gate { "thoplimit", NEXTARG, AF_ANY, PARSELOG0 },
2097c478bd9Sstevel@tonic-gate { "set", NEXTARG, AF_ANY, PARSESET },
2107c478bd9Sstevel@tonic-gate { "destination", NEXTARG, AF_ANY, 0 },
211f7d61273Smeem { "zone", NEXTARG, AF_ANY, 0 },
212f7d61273Smeem { "-zone", 0, AF_ANY, 0 },
213f7d61273Smeem { "all-zones", 0, AF_ANY, 0 },
214f7d61273Smeem { "ether", OPTARG, AF_ANY, PARSENOW },
215f7d61273Smeem { "usesrc", NEXTARG, AF_ANY, PARSENOW },
2167c478bd9Sstevel@tonic-gate { 0 /* ether addr */, 0, AF_UNSPEC, PARSELOG0 },
2177c478bd9Sstevel@tonic-gate { 0 /* set */, 0, AF_ANY, PARSESET },
2187c478bd9Sstevel@tonic-gate { 0 /* destination */, 0, AF_ANY, 0 },
2197c478bd9Sstevel@tonic-gate { 0, END_OF_TABLE, END_OF_TABLE, END_OF_TABLE},
2207c478bd9Sstevel@tonic-gate };
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate /* Known address families */
2247c478bd9Sstevel@tonic-gate struct afswtch {
2257c478bd9Sstevel@tonic-gate char *af_name;
2267c478bd9Sstevel@tonic-gate short af_af;
2277c478bd9Sstevel@tonic-gate } afs[] = {
2287c478bd9Sstevel@tonic-gate { "inet", AF_INET },
2297c478bd9Sstevel@tonic-gate { "ether", AF_UNSPEC },
2307c478bd9Sstevel@tonic-gate { "inet6", AF_INET6 },
2317c478bd9Sstevel@tonic-gate { 0, 0 }
2327c478bd9Sstevel@tonic-gate };
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate * Append "item" to the buffer. If there isn't enough room in the buffer,
2367c478bd9Sstevel@tonic-gate * expand it.
2377c478bd9Sstevel@tonic-gate */
2387c478bd9Sstevel@tonic-gate static void
parse_append_buf(char * item)2397c478bd9Sstevel@tonic-gate parse_append_buf(char *item)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate unsigned itemlen;
2427c478bd9Sstevel@tonic-gate unsigned newdumplen;
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate if (item == NULL)
2457c478bd9Sstevel@tonic-gate return;
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate itemlen = strlen(item);
2487c478bd9Sstevel@tonic-gate newdumplen = parsedumplen + itemlen;
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate /* Expand dump buffer as needed */
2517c478bd9Sstevel@tonic-gate if (parsebuflen < newdumplen) {
2527c478bd9Sstevel@tonic-gate if ((parsebuf = realloc(parsebuf, newdumplen)) == NULL) {
2537c478bd9Sstevel@tonic-gate perror("ifparse");
2547c478bd9Sstevel@tonic-gate exit(1);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate parsebuflen = newdumplen;
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate (void) memcpy(parsebuf + parsedumplen, item, itemlen);
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate parsedumplen = newdumplen;
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate /*
2647c478bd9Sstevel@tonic-gate * Dump the buffer to output.
2657c478bd9Sstevel@tonic-gate */
2667c478bd9Sstevel@tonic-gate static void
parse_dump_buf(void)2677c478bd9Sstevel@tonic-gate parse_dump_buf(void)
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate /*
2707c478bd9Sstevel@tonic-gate * When parsing, a set or addif command, we may be some way into
2717c478bd9Sstevel@tonic-gate * the command before we definitely know it is movable or fixed.
2727c478bd9Sstevel@tonic-gate * If we get to the end of the command, and haven't seen a
2737c478bd9Sstevel@tonic-gate * "failover" or "-failover" flag, the command is movable.
2747c478bd9Sstevel@tonic-gate */
275f7d61273Smeem if (!((parsemode == PARSEFIXED) && (parsetype & PARSEMOVABLE) != 0) &&
276f7d61273Smeem (parsemode & parsetype) != 0 && parsedumplen != 0) {
2777c478bd9Sstevel@tonic-gate unsigned i;
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate if (parsebuf[parsedumplen] == ' ')
2807c478bd9Sstevel@tonic-gate parsedumplen--;
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate for (i = 0; i < parsedumplen; i++)
2837c478bd9Sstevel@tonic-gate (void) putchar(parsebuf[i]);
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate (void) putchar('\n');
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate /* The buffer is kept in case there is more parsing to do */
2887c478bd9Sstevel@tonic-gate parsedumplen = 0;
2897c478bd9Sstevel@tonic-gate parsetype = PARSEFIXED | PARSEMOVABLE;
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate * Process a command. The command will either be put in the buffer,
2947c478bd9Sstevel@tonic-gate * or dumped directly to output. The current contents of the buffer
2957c478bd9Sstevel@tonic-gate * may be dumped to output.
2967c478bd9Sstevel@tonic-gate *
2977c478bd9Sstevel@tonic-gate * The buffer holds commands relating to a particular logical interface.
2987c478bd9Sstevel@tonic-gate * For example, "set", "destination", "failover", "broadcast", all relate
2997c478bd9Sstevel@tonic-gate * to a particular interface. Such commands have to be buffered until
3007c478bd9Sstevel@tonic-gate * all the "failover" and "-failover" commands for that interface have
3017c478bd9Sstevel@tonic-gate * been seen, only then will we know whether the command is movable
3027c478bd9Sstevel@tonic-gate * or not. When the "addif" command is seen, we know we are about to
3037c478bd9Sstevel@tonic-gate * start processing a new logical interface, we've seen all the
3047c478bd9Sstevel@tonic-gate * "failover" and "-failover" commands for the previous interface, and
3057c478bd9Sstevel@tonic-gate * can decide whether the buffer contents are movable or not.
3067c478bd9Sstevel@tonic-gate *
3077c478bd9Sstevel@tonic-gate */
3087c478bd9Sstevel@tonic-gate static void
parsedump(char * cmd,int param,int flags,char * arg)3097c478bd9Sstevel@tonic-gate parsedump(char *cmd, int param, int flags, char *arg)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate char *cmdname; /* Command name */
3127c478bd9Sstevel@tonic-gate char *cmdarg; /* Argument to command, if it takes one, or NULL */
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate /*
3157c478bd9Sstevel@tonic-gate * Is command only valid on logical interface 0?
3167c478bd9Sstevel@tonic-gate * If processing commands on an additional logical interface, ignore
3177c478bd9Sstevel@tonic-gate * the command.
3187c478bd9Sstevel@tonic-gate * If processing commands on logical interface 0, don't buffer the
3197c478bd9Sstevel@tonic-gate * command, dump it straight to output.
3207c478bd9Sstevel@tonic-gate */
3217c478bd9Sstevel@tonic-gate if ((flags & PARSELOG0) != 0) {
3227c478bd9Sstevel@tonic-gate if (addint)
3237c478bd9Sstevel@tonic-gate return;
3247c478bd9Sstevel@tonic-gate flags |= PARSENOW;
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate /*
3287c478bd9Sstevel@tonic-gate * If processing the "addif" command, a destination address may
3297c478bd9Sstevel@tonic-gate * follow without the "destination" prefix. Add PARSESET to the
3307c478bd9Sstevel@tonic-gate * flags so that such an anonymous address is processed correctly.
3317c478bd9Sstevel@tonic-gate */
3327c478bd9Sstevel@tonic-gate if ((flags & PARSEADD) != 0) {
3337c478bd9Sstevel@tonic-gate flags |= PARSESET;
3347c478bd9Sstevel@tonic-gate addint = _B_TRUE;
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate * Commands that must be dumped straight to output are always fixed
3397c478bd9Sstevel@tonic-gate * (non-movable) commands.
3407c478bd9Sstevel@tonic-gate *
3417c478bd9Sstevel@tonic-gate */
3427c478bd9Sstevel@tonic-gate if ((flags & PARSENOW) != 0)
3437c478bd9Sstevel@tonic-gate flags |= PARSEFIXED;
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate * Source and destination addresses do not have to be prefixed
3477c478bd9Sstevel@tonic-gate * with the keywords "set" or "destination". Ifparse always
3487c478bd9Sstevel@tonic-gate * inserts the optional keyword.
3497c478bd9Sstevel@tonic-gate */
3507c478bd9Sstevel@tonic-gate if (cmd == NULL) {
3517c478bd9Sstevel@tonic-gate cmdarg = arg;
3527c478bd9Sstevel@tonic-gate if ((flags & PARSESET) != 0)
3537c478bd9Sstevel@tonic-gate cmdname = "set";
3547c478bd9Sstevel@tonic-gate else if (setaddr) {
3557c478bd9Sstevel@tonic-gate cmdname = "destination";
3567c478bd9Sstevel@tonic-gate setaddr = _B_FALSE;
3577c478bd9Sstevel@tonic-gate } else
3587c478bd9Sstevel@tonic-gate cmdname = "";
3597c478bd9Sstevel@tonic-gate } else {
360f7d61273Smeem cmdarg = (param == 0) ? NULL : arg;
3617c478bd9Sstevel@tonic-gate cmdname = cmd;
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate /*
3657c478bd9Sstevel@tonic-gate * The next address without a prefix will be a destination
3667c478bd9Sstevel@tonic-gate * address.
3677c478bd9Sstevel@tonic-gate */
3687c478bd9Sstevel@tonic-gate if ((flags & PARSESET) != 0)
3697c478bd9Sstevel@tonic-gate setaddr = _B_TRUE;
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate * Dump the command straight to output?
3737c478bd9Sstevel@tonic-gate * Only dump the command if the parse mode specified on
3747c478bd9Sstevel@tonic-gate * the command line matches the type of the command.
3757c478bd9Sstevel@tonic-gate */
3767c478bd9Sstevel@tonic-gate if ((flags & PARSENOW) != 0) {
3777c478bd9Sstevel@tonic-gate if ((parsemode & flags) != 0) {
3787c478bd9Sstevel@tonic-gate (void) fputs(cmdname, stdout);
3797c478bd9Sstevel@tonic-gate if (cmdarg != NULL) {
3807c478bd9Sstevel@tonic-gate (void) fputc(' ', stdout);
3817c478bd9Sstevel@tonic-gate (void) fputs(cmdarg, stdout);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate (void) fputc('\n', stdout);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate return;
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate * Only the commands relating to a particular logical interface
3907c478bd9Sstevel@tonic-gate * are buffered. When an "addif" command is seen, processing is
3917c478bd9Sstevel@tonic-gate * about to start on a new logical interface, so dump the
3927c478bd9Sstevel@tonic-gate * buffer to output.
3937c478bd9Sstevel@tonic-gate */
3947c478bd9Sstevel@tonic-gate if ((flags & PARSEADD) != 0)
3957c478bd9Sstevel@tonic-gate parse_dump_buf();
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate * If the command flags indicate the command is fixed or
3997c478bd9Sstevel@tonic-gate * movable, update the type of the interface in the buffer
4007c478bd9Sstevel@tonic-gate * accordingly. For example, "-failover" has the "PARSEFIXED"
4017c478bd9Sstevel@tonic-gate * flag, and the contents of the buffer are not movable if
4027c478bd9Sstevel@tonic-gate * "-failover" is seen.
4037c478bd9Sstevel@tonic-gate */
4047c478bd9Sstevel@tonic-gate if ((flags & PARSEFIXED) != 0)
4057c478bd9Sstevel@tonic-gate parsetype &= ~PARSEMOVABLE;
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate if ((flags & PARSEMOVABLE) != 0)
4087c478bd9Sstevel@tonic-gate parsetype &= ~PARSEFIXED;
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate parsetype |= flags & (PARSEFIXED | PARSEMOVABLE);
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate parse_append_buf(cmdname);
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate if (cmdarg != NULL) {
4157c478bd9Sstevel@tonic-gate parse_append_buf(" ");
4167c478bd9Sstevel@tonic-gate parse_append_buf(cmdarg);
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate parse_append_buf(" ");
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate /*
4237c478bd9Sstevel@tonic-gate * Parse the part of the command line following the address family
4247c478bd9Sstevel@tonic-gate * specification, if any.
4257c478bd9Sstevel@tonic-gate *
4267c478bd9Sstevel@tonic-gate * This function is a modified version of the function "ifconfig" in
4277c478bd9Sstevel@tonic-gate * ifconfig.c.
4287c478bd9Sstevel@tonic-gate */
4297c478bd9Sstevel@tonic-gate static int
ifparse(int argc,char * argv[],struct afswtch * afp)4307c478bd9Sstevel@tonic-gate ifparse(int argc, char *argv[], struct afswtch *afp)
4317c478bd9Sstevel@tonic-gate {
432f7d61273Smeem int af = afp->af_af;
4337c478bd9Sstevel@tonic-gate
434f7d61273Smeem if (argc == 0)
4357c478bd9Sstevel@tonic-gate return (0);
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) {
438*95c74518SToomas Soome if ((parsemode & PARSEFIXED) != 0) {
439f7d61273Smeem while (argc) {
440f7d61273Smeem (void) fputs(*argv++, stdout);
441f7d61273Smeem if (--argc != 0)
442f7d61273Smeem (void) fputc(' ', stdout);
443f7d61273Smeem else
444f7d61273Smeem (void) fputc('\n', stdout);
4457c478bd9Sstevel@tonic-gate }
4467c478bd9Sstevel@tonic-gate }
447f7d61273Smeem return (0);
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate while (argc > 0) {
4517c478bd9Sstevel@tonic-gate struct cmd *p;
4527c478bd9Sstevel@tonic-gate boolean_t found_cmd;
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate found_cmd = _B_FALSE;
4557c478bd9Sstevel@tonic-gate for (p = cmds; ; p++) {
4567c478bd9Sstevel@tonic-gate assert(p->c_parseflags != END_OF_TABLE);
4577c478bd9Sstevel@tonic-gate if (p->c_name) {
4587c478bd9Sstevel@tonic-gate if (strcmp(*argv, p->c_name) == 0) {
4597c478bd9Sstevel@tonic-gate /*
4607c478bd9Sstevel@tonic-gate * indicate that the command was
4617c478bd9Sstevel@tonic-gate * found and check to see if
4627c478bd9Sstevel@tonic-gate * the address family is valid
4637c478bd9Sstevel@tonic-gate */
4647c478bd9Sstevel@tonic-gate found_cmd = _B_TRUE;
4657c478bd9Sstevel@tonic-gate if (p->c_af == AF_ANY ||
4667c478bd9Sstevel@tonic-gate af == p->c_af)
4677c478bd9Sstevel@tonic-gate break;
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate } else {
4707c478bd9Sstevel@tonic-gate if (p->c_af == AF_ANY ||
4717c478bd9Sstevel@tonic-gate af == p->c_af)
4727c478bd9Sstevel@tonic-gate break;
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate assert(p->c_parseflags != END_OF_TABLE);
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate * If we found the keyword, but the address family
4787c478bd9Sstevel@tonic-gate * did not match spit out an error
4797c478bd9Sstevel@tonic-gate */
4807c478bd9Sstevel@tonic-gate if (found_cmd && p->c_name == 0) {
4817c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ifparse: Operation %s not"
4827c478bd9Sstevel@tonic-gate " supported for %s\n", *argv, afp->af_name);
4837c478bd9Sstevel@tonic-gate return (1);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate * else (no keyword found), we assume it's an address
4877c478bd9Sstevel@tonic-gate * of some sort
4887c478bd9Sstevel@tonic-gate */
4897c478bd9Sstevel@tonic-gate if (p->c_name == 0 && setaddr) {
4907c478bd9Sstevel@tonic-gate p++; /* got src, do dst */
4917c478bd9Sstevel@tonic-gate assert(p->c_parseflags != END_OF_TABLE);
4927c478bd9Sstevel@tonic-gate }
493f7d61273Smeem
494f7d61273Smeem if (p->c_parameter == NEXTARG || p->c_parameter == OPTARG) {
4957c478bd9Sstevel@tonic-gate argc--, argv++;
496f7d61273Smeem if (argc == 0 && p->c_parameter == NEXTARG) {
4977c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
4987c478bd9Sstevel@tonic-gate "ifparse: no argument for %s\n",
4997c478bd9Sstevel@tonic-gate p->c_name);
5007c478bd9Sstevel@tonic-gate return (1);
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate }
503f7d61273Smeem
5047c478bd9Sstevel@tonic-gate /*
5057c478bd9Sstevel@tonic-gate * Dump the command if:
5067c478bd9Sstevel@tonic-gate *
5077c478bd9Sstevel@tonic-gate * there's no address family
5087c478bd9Sstevel@tonic-gate * restriction
5097c478bd9Sstevel@tonic-gate * OR
5107c478bd9Sstevel@tonic-gate * there is a restriction AND
5117c478bd9Sstevel@tonic-gate * the address families match
5127c478bd9Sstevel@tonic-gate */
5137c478bd9Sstevel@tonic-gate if ((p->c_af == AF_ANY) || (af == p->c_af))
514f7d61273Smeem parsedump(p->c_name, p->c_parameter, p->c_parseflags,
515f7d61273Smeem *argv);
5167c478bd9Sstevel@tonic-gate argc--, argv++;
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate parse_dump_buf();
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate return (0);
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate /*
5247c478bd9Sstevel@tonic-gate * Print command usage on standard error.
5257c478bd9Sstevel@tonic-gate */
5267c478bd9Sstevel@tonic-gate static void
usage(void)5277c478bd9Sstevel@tonic-gate usage(void)
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
530f7d61273Smeem "usage: ifparse [ -fs ] <addr_family> <commands>\n");
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])5347c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate int c;
5377c478bd9Sstevel@tonic-gate struct afswtch *afp;
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "fs")) != -1) {
5407c478bd9Sstevel@tonic-gate switch ((char)c) {
5417c478bd9Sstevel@tonic-gate case 'f':
5427c478bd9Sstevel@tonic-gate parsemode |= PARSEMOVABLE;
5437c478bd9Sstevel@tonic-gate break;
5447c478bd9Sstevel@tonic-gate case 's':
5457c478bd9Sstevel@tonic-gate parsemode |= PARSEFIXED;
5467c478bd9Sstevel@tonic-gate break;
5477c478bd9Sstevel@tonic-gate case '?':
5487c478bd9Sstevel@tonic-gate usage();
5497c478bd9Sstevel@tonic-gate exit(1);
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate if (parsemode == 0)
5547c478bd9Sstevel@tonic-gate parsemode = PARSEFIXED | PARSEMOVABLE;
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate argc -= optind;
5577c478bd9Sstevel@tonic-gate argv += optind;
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate afp = afs;
5607c478bd9Sstevel@tonic-gate if (argc > 0) {
5617c478bd9Sstevel@tonic-gate struct afswtch *aftp;
5627c478bd9Sstevel@tonic-gate for (aftp = afs; aftp->af_name; aftp++) {
5637c478bd9Sstevel@tonic-gate if (strcmp(aftp->af_name, *argv) == 0) {
5647c478bd9Sstevel@tonic-gate argc--; argv++;
5657c478bd9Sstevel@tonic-gate afp = aftp;
5667c478bd9Sstevel@tonic-gate break;
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate return (ifparse(argc, argv, afp));
5727c478bd9Sstevel@tonic-gate }
573