xref: /onnv-gate/usr/src/cmd/cmd-inet/sbin/ifparse/ifparse.c (revision 5978:f182d580ff05)
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