/* options.c -- process the command line options Copyright (C) 2001, 2002 Free Software Foundation, Inc. Written by Marcus Brinkmann. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #if STDC_HEADERS # include #else # ifndef HAVE_STRCHR # define strchr index # define strrchr rindex # endif #endif #if HAVE_STRING_H # include #else # include #endif #include #include #include "ifconfig.h" /* Be verbose about actions. */ int verbose; /* Array of all interfaces on the command line. */ struct ifconfig *ifs; /* Size of IFS. */ int nifs; static struct ifconfig ifconfig_initializer = { NULL, /* name */ 0, /* valid */ }; struct format formats[] = { /* This is the default output format if no system_default_format is specified. */ { "default", "${format}{gnu}", }, /* This is the standard GNU output. */ { "gnu", "${first?}{}{${\\n}}${format}{gnu-one-entry}" }, { "gnu-one-entry", "${format}{check-existance}" \ "${name} (${index}):${\\n}" \ "${addr?}{ inet address ${tab}{16}${addr}${\\n}}" \ "${netmask?}{ netmask ${tab}{16}${netmask}${\\n}}" \ "${brdaddr?}{ broadcast ${tab}{16}${brdaddr}${\\n}}" \ "${dstaddr?}{ peer address ${tab}{16}${dstaddr}${\\n}}" \ "${flags?}{ flags ${tab}{16}${flags}${\\n}}" \ "${mtu?}{ mtu ${tab}{16}${mtu}${\\n}}" \ "${metric?}{ metric ${tab}{16}${metric}${\\n}}" \ "${exists?}{hwtype?}{${hwtype?}{ link encap ${tab}{16}${hwtype}${\\n}}}" \ "${exists?}{hwaddr?}{${hwaddr?}{ hardware addr ${tab}{16}${hwaddr}${\\n}}}" \ "${exists?}{txqlen?}{${txqlen?}{ tx queue len ${tab}{16}${txqlen}${\\n}}}" }, /* Resembles the output of ifconfig 1.39 (1999-03-19) in net-tools 1.52. */ { "net-tools", "${format}{check-existance}" \ "${name}${exists?}{hwtype?}{${hwtype?}{${tab}{10}Link encap:${hwtype}}" \ "${hwaddr?}{ HWaddr ${hwaddr}}}${\\n}" \ "${addr?}{${tab}{10}inet addr:${addr}" \ "${brdaddr?}{ Bcast:${brdaddr}}" \ "${netmask?}{ Mask:${netmask}}" \ "${newline}}" \ "${tab}{10}${flags}" \ "${mtu?}{ MTU:${mtu}}" \ "${metric?}{ Metric:${metric}}" \ "${newline}" \ "${exists?}{txqlen?}{${txqlen?}{${tab}{10}txqueuelen:${txqlen}}${\\n}}" \ "${newline}" }, /* Resembles the output of ifconfig shipped with unix systems like Solaris 2.7 or HPUX 10.20. */ { "unix", "${format}{check-existance}" \ "${name}: flags=${flags}{number}<${flags}{string}{,}>" \ "${mtu?}{ mtu ${mtu}}${\\n}" \ "${addr?}{${\\t}inet ${addr}" \ " netmask ${netmask}{0}{%02x}${netmask}{1}{%02x}" \ "${netmask}{2}{%02x}${netmask}{3}{%02x}" \ "${brdaddr?}{ broadcast ${brdaddr}}${\\n}}" \ "${exists?}{hwtype?}{${hwtype?}{${\\t}${hwtype}" \ "}${exists?}{hwaddr?}{${hwaddr?}{ ${hwaddr}}}${\\n}}" }, /* Resembles the output of ifconfig shipped with OSF 4.0g. */ { "osf", "${format}{check-existance}" \ "${name}: flags=${flags}{number}{%x}<${flags}{string}{,}>${\\n}" \ "${addr?}{${\\t}inet ${addr}" \ " netmask ${netmask}{0}{%02x}${netmask}{1}{%02x}" \ "${netmask}{2}{%02x}${netmask}{3}{%02x}" \ "${brdaddr?}{ broadcast ${brdaddr}}" \ "${mtu?}{ ipmtu ${mtu}}${\\n}}" }, /* If interface does not exist, print error message and exit. */ { "check-existance", "${index?}{}" \ "{${error}{${progname}: error: interface `${name}' does not exist${\\n}}" \ "${exit}{1}}" }, { 0, 0 } }; /* Default format. */ const char *default_format; /* The "+" is necessary to avoid parsing of system specific pseudo options like `-promisc'. */ static const char *short_options = "+i:a:m:d:p:b:M:vV" ; static struct option long_options[] = { #ifdef SYSTEM_LONG_OPTIONS SYSTEM_LONG_OPTIONS #endif {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, '&'}, {"interface", required_argument, 0, 'i'}, {"address", required_argument, 0, 'a'}, {"netmask", required_argument, 0, 'm'}, {"dstaddr", required_argument, 0, 'd'}, {"peer", required_argument, 0, 'p'}, {"brdaddr", required_argument, 0, 'b'}, {"broadcast", required_argument, 0, 'B'}, {"mtu", required_argument, 0, 'M'}, {"metric", required_argument, 0, '3'}, {"format", optional_argument, 0, '4'}, {0, 0, 0, 0} }; void usage (int err) { if (err != EXIT_SUCCESS) { fprintf (stderr, "Usage: %s [OPTION]...%s\n", __progname, system_help ? " [SYSTEM OPTION]..." : ""); fprintf (stderr, "Try `%s --help' for more information.\n", __progname); } else { fprintf (stdout, "Usage: %s [OPTION]...%s\n", __progname, system_help ? " [SYSTEM OPTION]..." : ""); puts ("Configure network interfaces.\n\n\ Options are:\n\ -i, --interface NAME Configure network interface NAME\n\ -a, --address ADDR Set interface address to ADDR\n\ -m, --netmask MASK Set netmask to MASK\n\ -d, --dstaddr DSTADDR,\n\ -p, --peer DSTADDR Set destination (peer) address to DSTADDR\n\ -b, --broadcast BRDADDR,\n\ --brdaddr BRDADDR Set broadcast address to BRDADDR\n\ -M, --mtu N Set mtu of interface to N\n\ --metric N Set metric of interface to N\n\ --format=FORMAT Select output format (or set back to default)"); if (system_help_options) puts (system_help_options); puts("\ -v, --verbose Output information when configuring interface.\n\ --help Display this help and exit\n\ -V, --version Output version information and exit"); if (system_help) { puts ("\nSystem options are:"); puts (system_help); puts ("\ The system options provide an alternative, backward compatible command line\n\ interface. It is discouraged and should not be used."); } fprintf (stdout, "\nSubmit bug reports to %s.\n", PACKAGE_BUGREPORT); } exit (err); } struct ifconfig * parse_opt_new_ifs (char *name) { struct ifconfig *ifp; ifs = realloc (ifs, ++nifs * sizeof (struct ifconfig)); if (!ifs) { fprintf (stderr, "%s: can't get memory for interface " "configuration: %s\n", __progname, strerror (errno)); exit (EXIT_FAILURE); } ifp = &ifs[nifs - 1]; *ifp = ifconfig_initializer; ifp->name = name; return ifp; } #define PARSE_OPT_SET_ADDR(field, fname, fvalid) \ void \ parse_opt_set_##field (struct ifconfig *ifp, char *addr) \ { \ if (!ifp) \ { \ fprintf (stderr, "%s: no interface specified for " #fname \ " `%s'\n", __progname, addr); \ usage (EXIT_FAILURE); \ } \ if (ifp->valid & IF_VALID_##fvalid) \ { \ fprintf (stderr, "%s: only one " #fname \ " allowed for interface `%s'\n", \ __progname, ifp->name); \ usage (EXIT_FAILURE); \ } \ ifp->field = addr; \ ifp->valid |= IF_VALID_##fvalid; \ } PARSE_OPT_SET_ADDR(address, address, ADDR) PARSE_OPT_SET_ADDR(netmask, netmask, NETMASK) PARSE_OPT_SET_ADDR(dstaddr, destination/peer address, DSTADDR) PARSE_OPT_SET_ADDR(brdaddr, broadcast address, BRDADDR) #define PARSE_OPT_SET_INT(field, fname, fvalid) \ void \ parse_opt_set_##field (struct ifconfig *ifp, char *arg) \ { \ char *end; \ if (!ifp) \ { \ fprintf (stderr, "%s: no interface specified for " #fname \ " `%s'\n", __progname, arg); \ usage (EXIT_FAILURE); \ } \ if (ifp->valid & IF_VALID_##fvalid) \ { \ fprintf (stderr, "%s: only one " #fname \ " allowed for interface `%s'\n", \ __progname, ifp->name); \ usage (EXIT_FAILURE); \ } \ ifp->field = strtol (arg, &end, 0); \ if (*arg == '\0' || *end != '\0') \ { \ fprintf (stderr, "%s: mtu value `%s' for interface `%s' " \ "is not a number.\n", \ __progname, optarg, ifp->name); \ exit (EXIT_FAILURE); \ } \ ifp->valid |= IF_VALID_##fvalid; \ } PARSE_OPT_SET_INT(mtu, mtu value, MTU) PARSE_OPT_SET_INT(metric, metric value, METRIC) void parse_opt_set_af (struct ifconfig *ifp, char *af) { if (!ifp) { fprintf (stderr, "%s: no interface specified for address" " family `%s'\n", __progname, af); usage (EXIT_FAILURE); } if (! strcasecmp (af, "inet")) ifp->af = AF_INET; else { fprintf (stderr, "%s: unknown address family `%s' for interface `%s'" " is not a number.\n", __progname, optarg, ifp->name); exit (EXIT_FAILURE); } ifp->valid |= IF_VALID_AF; } void parse_opt_set_default_format (const char *new_format) { struct format *frm = formats; const char *format = new_format; if (! format) format = system_default_format ? system_default_format : "default"; while (frm->name) { if (! strcmp (format ? format : "default", frm->name)) break; frm++; } /* If we didn't find the format, set the user specified one. */ if (frm->name) default_format = frm->templ; else if (format) default_format = format; else default_format = "default"; } /* Must be reentrant! */ void parse_opt_finalize (struct ifconfig *ifp) { if (ifp && ! ifp->valid) { ifp->valid = IF_VALID_FORMAT; ifp->format = default_format; } } void parse_opt (int argc, char *argv[]) { int option; struct ifconfig *ifp = ifs; #ifndef HAVE___PROGNAME __progname = argv[0]; #endif parse_opt_set_default_format (NULL); while ((option = getopt_long (argc, argv, short_options, long_options, 0)) != EOF) { /* XXX: Allow new ifs be created by system_parse_opt. Provide helper function for that (esp necessary for system specific parsing of remaining args. */ if (system_parse_opt (&ifp, option, optarg)) continue; switch(option) { case 'i': /* Interface name. */ parse_opt_finalize (ifp); ifp = parse_opt_new_ifs (optarg); break; case 'a': /* Interface address. */ parse_opt_set_address (ifp, optarg); break; case 'm': /* Interface netmask. */ parse_opt_set_netmask (ifp, optarg); break; case 'd': /* Interface dstaddr. */ case 'p': parse_opt_set_dstaddr (ifp, optarg); break; case 'b': /* Interface broadcast address. */ case 'B': parse_opt_set_brdaddr (ifp, optarg); break; case 'M': /* Interface MTU. */ parse_opt_set_mtu (ifp, optarg); break; case '3': /* Interface metric. */ parse_opt_set_metric (ifp, optarg); break; case '4': /* Output format. */ parse_opt_set_default_format (optarg); break; case 'v': /* Verbose. */ verbose = 1; break; case '&': /* Help. */ usage (EXIT_SUCCESS); /* Not reached. */ case 'V': /* Version. */ printf ("ifconfig (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); exit (EXIT_SUCCESS); case '?': default: usage (EXIT_FAILURE); /* Not reached. */ } } parse_opt_finalize (ifp); if (optind < argc) { if (! system_parse_opt_rest (&ifp, argc - optind, &argv[optind])) usage (EXIT_FAILURE); parse_opt_finalize (ifp); } if (!ifs) { /* No interfaces specified. Get a list of all interfaces. */ struct if_nameindex *ifnx, *ifnxp; ifnx = ifnxp = if_nameindex(); while (ifnxp->if_index != 0 || ifnxp->if_name != NULL) { struct ifconfig *ifp; ifs = realloc (ifs, ++nifs * sizeof (struct ifconfig)); if (!ifs) { fprintf (stderr, "%s: can't get memory for interface " "configuration: %s\n", __progname, strerror (errno)); exit (EXIT_FAILURE); } ifp = &ifs[nifs - 1]; *ifp = ifconfig_initializer; ifp->name = ifnxp->if_name; ifp->valid = IF_VALID_FORMAT; ifp->format = default_format; ifnxp++; } /* XXX: We never do if_freenameindex (ifnx), because we are keeping the names for later instead using strdup (if->if_name) here. */ } }