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