/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
/*
* Ifparse splits up an ifconfig command line, and was written for use
* with the networking boot scripts; see $SRC/cmd/svc/shell/net_include.sh
*
* Ifparse can extract selected parts of the ifconfig command line,
* such as failover address configuration ("ifparse -f"), or everything
* except failover address configuration ("ifparse -s"). By default,
* all parts of the command line are extracted (equivalent to ("ifparse -fs").
*
* Examples:
*
* The command:
*
* ifparse inet 1.2.3.4 up group two addif 1.2.3.5 up addif 1.2.3.6 up
*
* Produces the following on standard output:
*
* set 1.2.3.4 up
* group two
* addif 1.2.3.5 up
* addif 1.2.3.6 up
*
* The optional "set" and "destination" keywords are added to make the
* output easier to process by a script or another command.
*
* The command:
*
* ifparse -f inet 1.2.3.4 -failover up group two addif 1.2.3.5 up
*
* Produces:
*
* addif 1.2.3.5 up
*
* Only failover address configuration has been requested. Address
* 1.2.3.4 is a non-failover address, and so isn't output.
*
* The "failover" and "-failover" commands can occur several times for
* a given logical interface. Only the last one counts. For example:
*
* ifparse -f inet 1.2.3.4 -failover failover -failover failover up
*
* Produces:
*
* set 1.2.3.4 -failover failover -failover failover up
*
* No attempt is made to clean up such "pathological" command lines, by
* removing redundant "failover" and "-failover" commands.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
/*
* Parser flags:
*
* PARSEFIXED
* Command should only appear if non-failover commands
* are requested.
* PARSEMOVABLE
* Command should only appear if failover commands are
* requested.
* PARSENOW
* Don't buffer the command, dump it to output immediately.
* PARSEADD
* Indicates processing has moved on to additional
* logical interfaces.
* Dump the buffer to output and clear buffer contents.
* PARSESET
* The "set" and "destination" keywords are optional.
* This flag indicates that the next address not prefixed
* with a keyword will be a destination address.
* PARSELOG0
* Command not valid on additional logical interfaces.
*/
/* Parsemode, the type of commands requested by the user. */
int parsemode = 0;
/* Parsetype, the type of the command currently in the buffer. */
/* Parsebuf, pointer to the buffer. */
/* Parsebuflen, the size of the buffer area. */
unsigned parsebuflen = 0;
/* Parsedumplen, the amount of the buffer currently in use. */
unsigned parsedumplen = 0;
/*
* Setaddr, used to decide whether an address without a keyword
* prefix is a source or destination address.
*/
/*
* Some ifconfig commands are only valid on the first logical interface.
* As soon as an "addif" command is seen, "addint" is set.
*/
/*
* The parser table is based on that in ifconfig. A command may or
* in the second column. Some commands can only be used with certain
* address families, as indicated in the third column. The fourth column
* contains flags that control parser action.
*
* Ifparse buffers logical interface configuration commands such as "set",
* "netmask" and "broadcast". This buffering continues until an "addif"
* command is seen, at which point the buffer is emptied, and the process
* starts again.
*
* Some commands do not relate to logical interface configuration and are
* dumped to output as soon as they are seen, such as "group" and "standby".
*
*/
struct cmd {
char *c_name;
} cmds[] = {
{ "up", 0, AF_ANY, 0 },
{ "down", 0, AF_ANY, 0 },
{ "private", 0, AF_ANY, 0 },
{ "-private", 0, AF_ANY, 0 },
{ "xmit", 0, AF_ANY, 0 },
{ "-xmit", 0, AF_ANY, 0 },
{ "anycast", 0, AF_ANY, 0 },
{ "-anycast", 0, AF_ANY, 0 },
{ "local", 0, AF_ANY, 0 },
{ "-local", 0, AF_ANY, 0 },
{ "deprecated", 0, AF_ANY, 0 },
{ "-deprecated", 0, AF_ANY, 0 },
{ "preferred", 0, AF_INET6, 0 },
{ "-preferred", 0, AF_INET6, 0 },
{ "-zone", 0, AF_ANY, 0 },
{ "all-zones", 0, AF_ANY, 0 },
{ 0 /* destination */, 0, AF_ANY, 0 },
};
/* Known address families */
struct afswtch {
char *af_name;
short af_af;
} afs[] = {
{ "inet", AF_INET },
{ "ether", AF_UNSPEC },
{ "inet6", AF_INET6 },
{ 0, 0 }
};
/*
* Append "item" to the buffer. If there isn't enough room in the buffer,
* expand it.
*/
static void
{
unsigned itemlen;
unsigned newdumplen;
return;
/* Expand dump buffer as needed */
if (parsebuflen < newdumplen) {
perror("ifparse");
exit(1);
}
}
}
/*
* Dump the buffer to output.
*/
static void
parse_dump_buf(void)
{
/*
* When parsing, a set or addif command, we may be some way into
* the command before we definitely know it is movable or fixed.
* If we get to the end of the command, and haven't seen a
* "failover" or "-failover" flag, the command is movable.
*/
unsigned i;
parsedumplen--;
for (i = 0; i < parsedumplen; i++)
(void) putchar('\n');
}
/* The buffer is kept in case there is more parsing to do */
parsedumplen = 0;
}
/*
* Process a command. The command will either be put in the buffer,
* or dumped directly to output. The current contents of the buffer
* may be dumped to output.
*
* The buffer holds commands relating to a particular logical interface.
* For example, "set", "destination", "failover", "broadcast", all relate
* to a particular interface. Such commands have to be buffered until
* all the "failover" and "-failover" commands for that interface have
* been seen, only then will we know whether the command is movable
* or not. When the "addif" command is seen, we know we are about to
* start processing a new logical interface, we've seen all the
* "failover" and "-failover" commands for the previous interface, and
* can decide whether the buffer contents are movable or not.
*
*/
static void
{
/*
* Is command only valid on logical interface 0?
* If processing commands on an additional logical interface, ignore
* the command.
* If processing commands on logical interface 0, don't buffer the
* command, dump it straight to output.
*/
if (addint)
return;
}
/*
* If processing the "addif" command, a destination address may
* follow without the "destination" prefix. Add PARSESET to the
* flags so that such an anonymous address is processed correctly.
*/
}
/*
* Commands that must be dumped straight to output are always fixed
* (non-movable) commands.
*
*/
flags |= PARSEFIXED;
/*
* Source and destination addresses do not have to be prefixed
* with the keywords "set" or "destination". Ifparse always
* inserts the optional keyword.
*/
cmdname = "set";
else if (setaddr) {
cmdname = "destination";
} else
cmdname = "";
} else {
}
/*
* The next address without a prefix will be a destination
* address.
*/
/*
* Dump the command straight to output?
* Only dump the command if the parse mode specified on
* the command line matches the type of the command.
*/
}
}
return;
}
/*
* Only the commands relating to a particular logical interface
* are buffered. When an "addif" command is seen, processing is
* about to start on a new logical interface, so dump the
* buffer to output.
*/
/*
* If the command flags indicate the command is fixed or
* movable, update the type of the interface in the buffer
* accordingly. For example, "-failover" has the "PARSEFIXED"
* flag, and the contents of the buffer are not movable if
* "-failover" is seen.
*/
if ((flags & PARSEFIXED) != 0)
parsetype &= ~PARSEMOVABLE;
if ((flags & PARSEMOVABLE) != 0)
parsetype &= ~PARSEFIXED;
parse_append_buf(" ");
}
parse_append_buf(" ");
}
/*
* Parse the part of the command line following the address family
* specification, if any.
*
* This function is a modified version of the function "ifconfig" in
* ifconfig.c.
*/
static int
{
if (argc == 0)
return (0);
while (argc) {
if (--argc != 0)
else
}
}
return (0);
}
while (argc > 0) {
struct cmd *p;
for (p = cmds; ; p++) {
if (p->c_name) {
/*
* indicate that the command was
* found and check to see if
* the address family is valid
*/
break;
}
} else {
break;
}
}
/*
* If we found the keyword, but the address family
* did not match spit out an error
*/
return (1);
}
/*
* else (no keyword found), we assume it's an address
* of some sort
*/
p++; /* got src, do dst */
}
"ifparse: no argument for %s\n",
p->c_name);
return (1);
}
}
/*
* Dump the command if:
*
* there's no address family
* restriction
* OR
* there is a restriction AND
* the address families match
*/
*argv);
}
return (0);
}
/*
* Print command usage on standard error.
*/
static void
usage(void)
{
"usage: ifparse [ -fs ] <addr_family> <commands>\n");
}
int
{
int c;
switch ((char)c) {
case 'f':
break;
case 's':
parsemode |= PARSEFIXED;
break;
case '?':
usage();
exit(1);
}
}
if (parsemode == 0)
if (argc > 0) {
break;
}
}
}
}