ifconfig: split argument parsing

Simplify main() by factoring out argument parsing code.

Reviewed by:	kp
MFC after:	2 weeks
Differential Revision: https://reviews.freebsd.org/D40179
This commit is contained in:
Alexander V. Chernikov 2023-05-20 11:14:39 +00:00
parent 50be18cc77
commit 197bff385e

View file

@ -407,14 +407,144 @@ list_interfaces(struct ifconfig_args *args)
#endif
}
int
main(int argc, char *argv[])
static char *
args_peek(struct ifconfig_args *args)
{
int c;
const struct afswtch *afp = NULL;
int ifindex;
char options[1024], *envformat;
if (args->argc > 0)
return (args->argv[0]);
return (NULL);
}
static char *
args_pop(struct ifconfig_args *args)
{
if (args->argc == 0)
return (NULL);
char *arg = args->argv[0];
args->argc--;
args->argv++;
return (arg);
}
static void
args_parse(struct ifconfig_args *args, int argc, char *argv[])
{
char options[1024];
struct option *p;
int c;
/* Parse leading line options */
strlcpy(options, "G:adf:klmnuv", sizeof(options));
for (p = opts; p != NULL; p = p->next)
strlcat(options, p->opt, sizeof(options));
while ((c = getopt(argc, argv, options)) != -1) {
switch (c) {
case 'a': /* scan all interfaces */
args->all = true;
break;
case 'd': /* restrict scan to "down" interfaces */
args->downonly = true;
break;
case 'f':
if (optarg == NULL)
usage();
setformat(optarg);
break;
case 'G':
if (optarg == NULL || args->all == 0)
usage();
args->nogroup = optarg;
break;
case 'k':
args->printkeys = true;
break;
case 'l': /* scan interface names only */
args->namesonly++;
break;
case 'm': /* show media choices in status */
args->supmedia = true;
break;
case 'n': /* suppress module loading */
args->noload = true;
break;
case 'u': /* restrict scan to "up" interfaces */
args->uponly = true;
break;
case 'v':
args->verbose++;
break;
case 'g':
if (args->all) {
if (optarg == NULL)
usage();
args->matchgroup = optarg;
break;
}
/* FALLTHROUGH */
default:
for (p = opts; p != NULL; p = p->next)
if (p->opt[0] == c) {
p->cb(optarg);
break;
}
if (p == NULL)
usage();
break;
}
}
argc -= optind;
argv += optind;
/* -l cannot be used with -a or -m */
if (args->namesonly && (args->all || args->supmedia))
usage();
/* nonsense.. */
if (args->uponly && args->downonly)
usage();
/* no arguments is equivalent to '-a' */
if (!args->namesonly && argc < 1)
args->all = 1;
/* -a and -l allow an address family arg to limit the output */
if (args->all || args->namesonly) {
if (argc > 1)
usage();
if (argc == 1) {
const struct afswtch *afp = af_getbyname(*argv);
if (afp == NULL) {
warnx("Address family '%s' unknown.", *argv);
usage();
}
if (afp->af_name != NULL)
argc--, argv++;
/* leave with afp non-zero */
args->afp = afp;
}
} else {
/* not listing, need an argument */
if (argc < 1)
usage();
}
args->argc = argc;
args->argv = argv;
/* Sync global variables */
printkeys = args->printkeys;
verbose = args->verbose;
}
int
main(int ac, char *av[])
{
char *envformat;
size_t iflen;
int flags;
@ -434,125 +564,29 @@ main(int argc, char *argv[])
*/
atexit(printifnamemaybe);
/* Parse leading line options */
strlcpy(options, "G:adf:klmnuv", sizeof(options));
for (p = opts; p != NULL; p = p->next)
strlcat(options, p->opt, sizeof(options));
while ((c = getopt(argc, argv, options)) != -1) {
switch (c) {
case 'a': /* scan all interfaces */
args.all = true;
break;
case 'd': /* restrict scan to "down" interfaces */
args.downonly = true;
break;
case 'f':
if (optarg == NULL)
usage();
setformat(optarg);
break;
case 'G':
if (optarg == NULL || args.all == 0)
usage();
args.nogroup = optarg;
break;
case 'k':
args.printkeys = true;
break;
case 'l': /* scan interface names only */
args.namesonly++;
break;
case 'm': /* show media choices in status */
args.supmedia = true;
break;
case 'n': /* suppress module loading */
args.noload = true;
break;
case 'u': /* restrict scan to "up" interfaces */
args.uponly = true;
break;
case 'v':
args.verbose++;
break;
case 'g':
if (args.all) {
if (optarg == NULL)
usage();
args.matchgroup = optarg;
break;
}
/* FALLTHROUGH */
default:
for (p = opts; p != NULL; p = p->next)
if (p->opt[0] == c) {
p->cb(optarg);
break;
}
if (p == NULL)
usage();
break;
}
}
argc -= optind;
argv += optind;
args_parse(&args, ac, av);
/* Sync global variables */
printkeys = args.printkeys;
verbose = args.verbose;
/* -l cannot be used with -a or -m */
if (args.namesonly && (args.all || args.supmedia))
usage();
/* nonsense.. */
if (args.uponly && args.downonly)
usage();
/* no arguments is equivalent to '-a' */
if (!args.namesonly && argc < 1)
args.all = 1;
/* -a and -l allow an address family arg to limit the output */
if (args.all || args.namesonly) {
if (argc > 1)
usage();
ifindex = 0;
if (argc == 1) {
afp = af_getbyname(*argv);
if (afp == NULL) {
warnx("Address family '%s' unknown.", *argv);
usage();
}
if (afp->af_name != NULL)
argc--, argv++;
/* leave with afp non-zero */
}
} else {
if (!args.all && !args.namesonly) {
/* not listing, need an argument */
if (argc < 1)
usage();
args.ifname = *argv;
argc--, argv++;
args.ifname = args_pop(&args);
/* check and maybe load support for this interface */
ifmaybeload(&args, args.ifname);
ifindex = if_nametoindex(args.ifname);
if (ifindex == 0) {
char *arg = args_peek(&args);
if (if_nametoindex(args.ifname) == 0) {
/*
* NOTE: We must special-case the `create' command
* right here as we would otherwise fail when trying
* to find the interface.
*/
if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
strcmp(argv[0], "plumb") == 0)) {
if (arg != NULL && (strcmp(arg, "create") == 0 ||
strcmp(arg, "plumb") == 0)) {
iflen = strlcpy(name, args.ifname, sizeof(name));
if (iflen >= sizeof(name))
errx(1, "%s: cloning name too long",
args.ifname);
ifconfig(argc, argv, 1, NULL);
ifconfig(args.argc, args.argv, 1, NULL);
exit(exit_code);
}
#ifdef JAIL
@ -561,12 +595,12 @@ main(int argc, char *argv[])
* right here as we would otherwise fail when trying
* to find the interface as it lives in another vnet.
*/
if (argc > 0 && (strcmp(argv[0], "-vnet") == 0)) {
if (arg != NULL && (strcmp(arg, "-vnet") == 0)) {
iflen = strlcpy(name, args.ifname, sizeof(name));
if (iflen >= sizeof(name))
errx(1, "%s: interface name too long",
args.ifname);
ifconfig(argc, argv, 0, NULL);
ifconfig(args.argc, args.argv, 0, NULL);
exit(exit_code);
}
#endif
@ -576,21 +610,21 @@ main(int argc, char *argv[])
* Do not allow use `create` command as hostname if
* address family is not specified.
*/
if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
strcmp(argv[0], "plumb") == 0)) {
if (argc == 1)
if (arg != NULL && (strcmp(arg, "create") == 0 ||
strcmp(arg, "plumb") == 0)) {
if (args.argc == 1)
errx(1, "interface %s already exists",
args.ifname);
argc--, argv++;
args_pop(&args);
}
}
}
/* Check for address family */
if (argc > 0) {
afp = af_getbyname(*argv);
if (afp != NULL)
argc--, argv++;
if (args.argc > 0) {
args.afp = af_getbyname(args_peek(&args));
if (args.afp != NULL)
args_pop(&args);
}
/*
@ -598,7 +632,7 @@ main(int argc, char *argv[])
* which doesn't require building, sorting, and searching the entire
* system address list
*/
if ((argc > 0) && (args.ifname != NULL)) {
if ((args.argc > 0) && (args.ifname != NULL)) {
iflen = strlcpy(name, args.ifname, sizeof(name));
if (iflen >= sizeof(name)) {
warnx("%s: interface name too long, skipping", args.ifname);
@ -607,15 +641,12 @@ main(int argc, char *argv[])
if (!(((flags & IFF_CANTCONFIG) != 0) ||
(args.downonly && (flags & IFF_UP) != 0) ||
(args.uponly && (flags & IFF_UP) == 0)))
ifconfig(argc, argv, 0, afp);
ifconfig(args.argc, args.argv, 0, args.afp);
}
goto done;
}
args.afp = afp;
args.allfamilies = afp == NULL;
args.argc = argc;
args.argv = argv;
args.allfamilies = args.afp == NULL;
list_interfaces(&args);