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