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