# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Makefile for "ifparse" # # Copyright 2000-2003 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # PROG = ifparse ROOTFS_PROG = $(PROG) OBJS= ifparse.o SRCS= $(OBJS:%.o=%.c) include ../../../Makefile.cmd include ../../Makefile.cmd-inet CPPFLAGS += -I$(CMDINETCOMMONDIR) LINTFLAGS += -m # these #defines are required to use UNIX 98 interfaces $(OBJS) : CPPFLAGS +=-D_POSIX_C_SOURCE LINTFLAGS += -D_POSIX_C_SOURCE -I$(CMDINETCOMMONDIR) .KEEP_STATE: all: $(ROOTFS_PROG) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) install: all $(ROOTSBINPROG) clean: $(RM) $(OBJS) lint: lint_SRCS include ../../../Makefile.targ Copyright (c) 1983 Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by the University of California, Berkeley and its contributors. 4. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PORTIONS OF IFPARSE COMMAND FUNCTIONALITY /* * 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 #include #include #include #include /* * 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. */ #define PARSEFIXED 0x01 #define PARSEMOVABLE 0x02 #define PARSENOW 0x04 #define PARSEADD 0x08 #define PARSESET 0x10 #define PARSELOG0 0x20 typedef enum { AF_UNSPEC, AF_INET, AF_INET6, AF_ANY } ac_t; #define NEXTARG (-1) /* command takes an argument */ #define OPTARG (-2) /* command takes an optional argument */ #define END_OF_TABLE (-1) /* Parsemode, the type of commands requested by the user. */ int parsemode = 0; /* Parsetype, the type of the command currently in the buffer. */ int parsetype = PARSEFIXED | PARSEMOVABLE; /* Parsebuf, pointer to the buffer. */ char *parsebuf = NULL; /* 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. */ boolean_t setaddr = _B_FALSE; /* * Some ifconfig commands are only valid on the first logical interface. * As soon as an "addif" command is seen, "addint" is set. */ boolean_t addint = _B_FALSE; /* * The parser table is based on that in ifconfig. A command may or * may not have an argument, as indicated by whether NEXTARG/OPTARG is * 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; int c_parameter; /* NEXTARG means next argv */ int c_af; /* address family restrictions */ int c_parseflags; /* parsing flags */ } cmds[] = { { "up", 0, AF_ANY, 0 }, { "down", 0, AF_ANY, 0 }, { "trailers", 0, AF_ANY, PARSENOW }, { "-trailers", 0, AF_ANY, PARSENOW }, { "arp", 0, AF_INET, PARSENOW }, { "-arp", 0, AF_INET, PARSENOW }, { "private", 0, AF_ANY, 0 }, { "-private", 0, AF_ANY, 0 }, { "router", 0, AF_ANY, PARSELOG0 }, { "-router", 0, AF_ANY, PARSELOG0 }, { "xmit", 0, AF_ANY, 0 }, { "-xmit", 0, AF_ANY, 0 }, { "-nud", 0, AF_INET6, PARSENOW }, { "nud", 0, AF_INET6, PARSENOW }, { "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 }, { "debug", 0, AF_ANY, PARSENOW }, { "verbose", 0, AF_ANY, PARSENOW }, { "netmask", NEXTARG, AF_INET, 0 }, { "metric", NEXTARG, AF_ANY, 0 }, { "mtu", NEXTARG, AF_ANY, 0 }, { "index", NEXTARG, AF_ANY, PARSELOG0 }, { "broadcast", NEXTARG, AF_INET, 0 }, { "auto-revarp", 0, AF_INET, PARSEFIXED}, { "plumb", 0, AF_ANY, PARSENOW }, { "unplumb", 0, AF_ANY, PARSENOW }, { "ipmp", 0, AF_ANY, PARSELOG0 }, { "subnet", NEXTARG, AF_ANY, 0 }, { "token", NEXTARG, AF_INET6, PARSELOG0 }, { "tsrc", NEXTARG, AF_ANY, PARSELOG0 }, { "tdst", NEXTARG, AF_ANY, PARSELOG0 }, { "encr_auth_algs", NEXTARG, AF_ANY, PARSELOG0 }, { "encr_algs", NEXTARG, AF_ANY, PARSELOG0 }, { "auth_algs", NEXTARG, AF_ANY, PARSELOG0 }, { "addif", NEXTARG, AF_ANY, PARSEADD }, { "removeif", NEXTARG, AF_ANY, PARSELOG0 }, { "modlist", 0, AF_ANY, PARSENOW }, { "modinsert", NEXTARG, AF_ANY, PARSENOW }, { "modremove", NEXTARG, AF_ANY, PARSENOW }, { "failover", 0, AF_ANY, PARSEMOVABLE }, { "-failover", 0, AF_ANY, PARSEFIXED }, { "standby", 0, AF_ANY, PARSENOW }, { "-standby", 0, AF_ANY, PARSENOW }, { "failed", 0, AF_ANY, PARSENOW }, { "-failed", 0, AF_ANY, PARSENOW }, { "group", NEXTARG, AF_ANY, PARSELOG0 }, { "configinfo", 0, AF_ANY, PARSENOW }, { "encaplimit", NEXTARG, AF_ANY, PARSELOG0 }, { "-encaplimit", 0, AF_ANY, PARSELOG0 }, { "thoplimit", NEXTARG, AF_ANY, PARSELOG0 }, { "set", NEXTARG, AF_ANY, PARSESET }, { "destination", NEXTARG, AF_ANY, 0 }, { "zone", NEXTARG, AF_ANY, 0 }, { "-zone", 0, AF_ANY, 0 }, { "all-zones", 0, AF_ANY, 0 }, { "ether", OPTARG, AF_ANY, PARSENOW }, { "usesrc", NEXTARG, AF_ANY, PARSENOW }, { 0 /* ether addr */, 0, AF_UNSPEC, PARSELOG0 }, { 0 /* set */, 0, AF_ANY, PARSESET }, { 0 /* destination */, 0, AF_ANY, 0 }, { 0, END_OF_TABLE, END_OF_TABLE, END_OF_TABLE}, }; /* 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 parse_append_buf(char *item) { unsigned itemlen; unsigned newdumplen; if (item == NULL) return; itemlen = strlen(item); newdumplen = parsedumplen + itemlen; /* Expand dump buffer as needed */ if (parsebuflen < newdumplen) { if ((parsebuf = realloc(parsebuf, newdumplen)) == NULL) { perror("ifparse"); exit(1); } parsebuflen = newdumplen; } (void) memcpy(parsebuf + parsedumplen, item, itemlen); parsedumplen = newdumplen; } /* * 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. */ if (!((parsemode == PARSEFIXED) && (parsetype & PARSEMOVABLE) != 0) && (parsemode & parsetype) != 0 && parsedumplen != 0) { unsigned i; if (parsebuf[parsedumplen] == ' ') parsedumplen--; for (i = 0; i < parsedumplen; i++) (void) putchar(parsebuf[i]); (void) putchar('\n'); } /* The buffer is kept in case there is more parsing to do */ parsedumplen = 0; parsetype = PARSEFIXED | PARSEMOVABLE; } /* * 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 parsedump(char *cmd, int param, int flags, char *arg) { char *cmdname; /* Command name */ char *cmdarg; /* Argument to command, if it takes one, or NULL */ /* * 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 ((flags & PARSELOG0) != 0) { if (addint) return; flags |= PARSENOW; } /* * 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. */ if ((flags & PARSEADD) != 0) { flags |= PARSESET; addint = _B_TRUE; } /* * Commands that must be dumped straight to output are always fixed * (non-movable) commands. * */ if ((flags & PARSENOW) != 0) flags |= PARSEFIXED; /* * Source and destination addresses do not have to be prefixed * with the keywords "set" or "destination". Ifparse always * inserts the optional keyword. */ if (cmd == NULL) { cmdarg = arg; if ((flags & PARSESET) != 0) cmdname = "set"; else if (setaddr) { cmdname = "destination"; setaddr = _B_FALSE; } else cmdname = ""; } else { cmdarg = (param == 0) ? NULL : arg; cmdname = cmd; } /* * The next address without a prefix will be a destination * address. */ if ((flags & PARSESET) != 0) setaddr = _B_TRUE; /* * 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. */ if ((flags & PARSENOW) != 0) { if ((parsemode & flags) != 0) { (void) fputs(cmdname, stdout); if (cmdarg != NULL) { (void) fputc(' ', stdout); (void) fputs(cmdarg, stdout); } (void) fputc('\n', stdout); } 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 ((flags & PARSEADD) != 0) parse_dump_buf(); /* * 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; parsetype |= flags & (PARSEFIXED | PARSEMOVABLE); parse_append_buf(cmdname); if (cmdarg != NULL) { parse_append_buf(" "); parse_append_buf(cmdarg); } 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 ifparse(int argc, char *argv[], struct afswtch *afp) { int af = afp->af_af; if (argc == 0) return (0); if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) { if ((parsemode & PARSEFIXED) != 0) { while (argc) { (void) fputs(*argv++, stdout); if (--argc != 0) (void) fputc(' ', stdout); else (void) fputc('\n', stdout); } } return (0); } while (argc > 0) { struct cmd *p; boolean_t found_cmd; found_cmd = _B_FALSE; for (p = cmds; ; p++) { assert(p->c_parseflags != END_OF_TABLE); if (p->c_name) { if (strcmp(*argv, p->c_name) == 0) { /* * indicate that the command was * found and check to see if * the address family is valid */ found_cmd = _B_TRUE; if (p->c_af == AF_ANY || af == p->c_af) break; } } else { if (p->c_af == AF_ANY || af == p->c_af) break; } } assert(p->c_parseflags != END_OF_TABLE); /* * If we found the keyword, but the address family * did not match spit out an error */ if (found_cmd && p->c_name == 0) { (void) fprintf(stderr, "ifparse: Operation %s not" " supported for %s\n", *argv, afp->af_name); return (1); } /* * else (no keyword found), we assume it's an address * of some sort */ if (p->c_name == 0 && setaddr) { p++; /* got src, do dst */ assert(p->c_parseflags != END_OF_TABLE); } if (p->c_parameter == NEXTARG || p->c_parameter == OPTARG) { argc--, argv++; if (argc == 0 && p->c_parameter == NEXTARG) { (void) fprintf(stderr, "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 */ if ((p->c_af == AF_ANY) || (af == p->c_af)) parsedump(p->c_name, p->c_parameter, p->c_parseflags, *argv); argc--, argv++; } parse_dump_buf(); return (0); } /* * Print command usage on standard error. */ static void usage(void) { (void) fprintf(stderr, "usage: ifparse [ -fs ] \n"); } int main(int argc, char *argv[]) { int c; struct afswtch *afp; while ((c = getopt(argc, argv, "fs")) != -1) { switch ((char)c) { case 'f': parsemode |= PARSEMOVABLE; break; case 's': parsemode |= PARSEFIXED; break; case '?': usage(); exit(1); } } if (parsemode == 0) parsemode = PARSEFIXED | PARSEMOVABLE; argc -= optind; argv += optind; afp = afs; if (argc > 0) { struct afswtch *aftp; for (aftp = afs; aftp->af_name; aftp++) { if (strcmp(aftp->af_name, *argv) == 0) { argc--; argv++; afp = aftp; break; } } } return (ifparse(argc, argv, afp)); }