From b481db6c20c848888b6c671bd7dc00d936b340d5 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 11 Aug 2020 22:07:32 -0600 Subject: [PATCH 1/9] multicall: add support for unified option handling --- cmd/multicall.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++- cmd/multicall.h | 23 ++++++++ 2 files changed, 164 insertions(+), 2 deletions(-) diff --git a/cmd/multicall.c b/cmd/multicall.c index c6ae3d4..65bd9e9 100644 --- a/cmd/multicall.c +++ b/cmd/multicall.c @@ -13,10 +13,12 @@ * from the use of this software. */ +#define _GNU_SOURCE #include #include #include #include +#include #include "cmd/multicall.h" char *argv0; @@ -33,7 +35,67 @@ struct if_applet *applet_table[] = { &ifupdown_applet, }; -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) +static void +generic_usage(const struct if_applet *applet, int result) +{ + fprintf(stderr, "%s", applet->name); + if (applet->desc != NULL) + fprintf(stderr, " - %s", applet->desc); + + fprintf(stderr, "\n"); + + size_t iter; + for (iter = 0; applet->groups[iter] != NULL; iter++) + { + const struct if_option_group *group = applet->groups[iter]; + + fprintf(stderr, "\n%s:\n", group->desc); + + size_t group_iter; + for (group_iter = 0; group_iter < group->group_size; group_iter++) + { + const struct if_option *opt = &group->group[group_iter]; + + fprintf(stderr, " "); + + if (opt->short_opt) + fprintf(stderr, "-%c", opt->short_opt); + else + fprintf(stderr, " "); + + if (opt->long_opt) + fprintf(stderr, "%c --%-30s", opt->short_opt ? ',' : ' ', + opt->long_opt); + else + fprintf(stderr, "%34s", ""); + + fprintf(stderr, "%s\n", opt->desc); + } + } + + exit(result); +} + +static void +generic_usage_request(int short_opt, const struct if_option *option, const char *opt_arg, const struct if_applet *applet) +{ + (void) short_opt; + (void) option; + (void) opt_arg; + + generic_usage(applet, EXIT_SUCCESS); +} + +static struct if_option global_options[] = { + {'h', "help", "displays program help", false, generic_usage_request}, + {'V', "version", "displays program version", false, (void *) lif_common_version}, +}; + +struct if_option_group global_option_group = { + .desc = "Global options", + .group_size = ARRAY_SIZE(global_options), + .group = global_options +}; int applet_cmp(const void *a, const void *b) @@ -46,11 +108,83 @@ applet_cmp(const void *a, const void *b) void multicall_usage(int status) __attribute__((noreturn)); +static const struct if_option * +lookup_option(const struct if_applet *applet, int opt) +{ + size_t iter; + for (iter = 0; applet->groups[iter] != NULL; iter++) + { + const struct if_option_group *group = applet->groups[iter]; + size_t group_iter; + + for (group_iter = 0; group_iter < group->group_size; group_iter++) + { + const struct if_option *option = &group->group[group_iter]; + + if (option->short_opt == opt) + return option; + } + } + + return NULL; +} + +static void +process_options(const struct if_applet *applet, int argc, char *argv[]) +{ + char short_opts[256] = {}, *p = short_opts; + struct option long_opts[256] = {}; + + size_t iter, long_opt_iter = 0; + for (iter = 0; applet->groups[iter] != NULL; iter++) + { + const struct if_option_group *group = applet->groups[iter]; + size_t group_iter; + + for (group_iter = 0; group_iter < group->group_size; group_iter++) + { + const struct if_option *opt = &group->group[group_iter]; + + if (opt->short_opt) + { + *p++ = opt->short_opt; + if (opt->require_argument) + *p++ = ':'; + } + + if (opt->long_opt) + { + /* XXX: handle long-opts without short-opts */ + long_opts[long_opt_iter] = (struct option) { + .name = opt->long_opt, + .has_arg = opt->require_argument ? required_argument : no_argument, + .val = opt->short_opt + }; + + long_opt_iter++; + } + } + } + + for (;;) + { + int c = getopt_long(argc, argv, short_opts, long_opts, NULL); + if (c == -1) + break; + + const struct if_option *opt = lookup_option(applet, c); + if (opt == NULL) + break; + + opt->handle(c, opt, optarg, applet); + } +} + int main(int argc, char *argv[]) { argv0 = basename(argv[0]); - struct if_applet **app; + const struct if_applet **app; app = bsearch(argv0, applet_table, ARRAY_SIZE(applet_table), sizeof(*applet_table), @@ -62,6 +196,8 @@ main(int argc, char *argv[]) multicall_usage(EXIT_FAILURE); } + process_options(*app, argc, argv); + return (*app)->main(argc, argv); } @@ -74,6 +210,8 @@ multicall_main(int argc, char *argv[]) return main(argc - 1, argv + 1); } +struct if_applet ifupdown_applet; + void multicall_usage(int status) { @@ -97,4 +235,5 @@ struct if_applet ifupdown_applet = { .name = "ifupdown", .main = multicall_main, .usage = multicall_usage, + .groups = { &global_option_group, NULL } }; diff --git a/cmd/multicall.h b/cmd/multicall.h index 6fb26a4..d0f09c9 100644 --- a/cmd/multicall.h +++ b/cmd/multicall.h @@ -13,17 +13,40 @@ * from the use of this software. */ +#include + #ifndef IFUPDOWN_CMD_MULTICALL_H__GUARD #define IFUPDOWN_CMD_MULTICALL_H__GUARD #include "libifupdown/libifupdown.h" +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) + +struct if_applet; + +struct if_option { + char short_opt; + const char *long_opt; + const char *desc; + bool require_argument; + void (*const handle)(int short_opt, const struct if_option *opt, const char *opt_arg, const struct if_applet *applet); +}; + +struct if_option_group { + const char *desc; + size_t group_size; + const struct if_option *group; +}; + struct if_applet { const char *name; + const char *desc; int (*const main)(int argc, char *argv[]); void (*const usage)(int status); + const struct if_option_group *groups[4]; }; extern char *argv0; +extern struct if_option_group global_option_group; #endif From b817bdb999a7d3ffa837f047a671fc2af9d7c1f1 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 11 Aug 2020 22:12:37 -0600 Subject: [PATCH 2/9] multicall: move match_options to a common include --- cmd/ifquery.c | 9 --------- cmd/ifupdown.c | 6 ------ cmd/multicall.h | 9 +++++++++ 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/cmd/ifquery.c b/cmd/ifquery.c index 2778dea..f84fb28 100644 --- a/cmd/ifquery.c +++ b/cmd/ifquery.c @@ -186,15 +186,6 @@ ifquery_usage(int status) exit(status); } -struct match_options { - bool is_auto; - char *exclude_pattern; - char *include_pattern; - bool pretty_print; - bool dot; - char *property; -}; - void list_interfaces(struct lif_dict *collection, struct match_options *opts) { diff --git a/cmd/ifupdown.c b/cmd/ifupdown.c index 9a9aada..1c42a3f 100644 --- a/cmd/ifupdown.c +++ b/cmd/ifupdown.c @@ -24,12 +24,6 @@ #include "libifupdown/libifupdown.h" #include "cmd/multicall.h" -struct match_options { - bool is_auto; - char *exclude_pattern; - char *include_pattern; -}; - static bool up; static struct lif_execute_opts exec_opts = { .executor_path = EXECUTOR_PATH, diff --git a/cmd/multicall.h b/cmd/multicall.h index d0f09c9..48deb26 100644 --- a/cmd/multicall.h +++ b/cmd/multicall.h @@ -49,4 +49,13 @@ struct if_applet { extern char *argv0; extern struct if_option_group global_option_group; +struct match_options { + bool is_auto; + char *exclude_pattern; + char *include_pattern; + bool pretty_print; + bool dot; + char *property; +}; + #endif From 2be5add47bc1fc2ebe39fdf508bbe0066266b956 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 11 Aug 2020 22:15:52 -0600 Subject: [PATCH 3/9] multicall: split option handling routines out to multicall-options.c --- Makefile | 4 +- cmd/multicall-options.c | 156 ++++++++++++++++++++++++++++++++++++++++ cmd/multicall.c | 134 ---------------------------------- cmd/multicall.h | 3 + 4 files changed, 162 insertions(+), 135 deletions(-) create mode 100644 cmd/multicall-options.c diff --git a/Makefile b/Makefile index 6ce44b3..f2ad017 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,9 @@ LIBIFUPDOWN_SRC = \ LIBIFUPDOWN_OBJ = ${LIBIFUPDOWN_SRC:.c=.o} LIBIFUPDOWN_LIB = libifupdown.a -MULTICALL_SRC = cmd/multicall.c +MULTICALL_SRC = \ + cmd/multicall.c \ + cmd/multicall-options.c MULTICALL_OBJ = ${MULTICALL_SRC:.c=.o} MULTICALL = ifupdown diff --git a/cmd/multicall-options.c b/cmd/multicall-options.c new file mode 100644 index 0000000..415d24a --- /dev/null +++ b/cmd/multicall-options.c @@ -0,0 +1,156 @@ +/* + * cmd/multicall-options.c + * Purpose: multi-call binary frontend -- option handling + * + * Copyright (c) 2020 Ariadne Conill + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "cmd/multicall.h" + +static void +generic_usage(const struct if_applet *applet, int result) +{ + fprintf(stderr, "%s", applet->name); + if (applet->desc != NULL) + fprintf(stderr, " - %s", applet->desc); + + fprintf(stderr, "\n"); + + size_t iter; + for (iter = 0; applet->groups[iter] != NULL; iter++) + { + const struct if_option_group *group = applet->groups[iter]; + + fprintf(stderr, "\n%s:\n", group->desc); + + size_t group_iter; + for (group_iter = 0; group_iter < group->group_size; group_iter++) + { + const struct if_option *opt = &group->group[group_iter]; + + fprintf(stderr, " "); + + if (opt->short_opt) + fprintf(stderr, "-%c", opt->short_opt); + else + fprintf(stderr, " "); + + if (opt->long_opt) + fprintf(stderr, "%c --%-30s", opt->short_opt ? ',' : ' ', + opt->long_opt); + else + fprintf(stderr, "%34s", ""); + + fprintf(stderr, "%s\n", opt->desc); + } + } + + exit(result); +} + +static void +generic_usage_request(int short_opt, const struct if_option *option, const char *opt_arg, const struct if_applet *applet) +{ + (void) short_opt; + (void) option; + (void) opt_arg; + + generic_usage(applet, EXIT_SUCCESS); +} + +static struct if_option global_options[] = { + {'h', "help", "displays program help", false, generic_usage_request}, + {'V', "version", "displays program version", false, (void *) lif_common_version}, +}; + +struct if_option_group global_option_group = { + .desc = "Global options", + .group_size = ARRAY_SIZE(global_options), + .group = global_options +}; + +const struct if_option * +lookup_option(const struct if_applet *applet, int opt) +{ + size_t iter; + for (iter = 0; applet->groups[iter] != NULL; iter++) + { + const struct if_option_group *group = applet->groups[iter]; + size_t group_iter; + + for (group_iter = 0; group_iter < group->group_size; group_iter++) + { + const struct if_option *option = &group->group[group_iter]; + + if (option->short_opt == opt) + return option; + } + } + + return NULL; +} + +void +process_options(const struct if_applet *applet, int argc, char *argv[]) +{ + char short_opts[256] = {}, *p = short_opts; + struct option long_opts[256] = {}; + + size_t iter, long_opt_iter = 0; + for (iter = 0; applet->groups[iter] != NULL; iter++) + { + const struct if_option_group *group = applet->groups[iter]; + size_t group_iter; + + for (group_iter = 0; group_iter < group->group_size; group_iter++) + { + const struct if_option *opt = &group->group[group_iter]; + + if (opt->short_opt) + { + *p++ = opt->short_opt; + if (opt->require_argument) + *p++ = ':'; + } + + if (opt->long_opt) + { + /* XXX: handle long-opts without short-opts */ + long_opts[long_opt_iter] = (struct option) { + .name = opt->long_opt, + .has_arg = opt->require_argument ? required_argument : no_argument, + .val = opt->short_opt + }; + + long_opt_iter++; + } + } + } + + for (;;) + { + int c = getopt_long(argc, argv, short_opts, long_opts, NULL); + if (c == -1) + break; + + const struct if_option *opt = lookup_option(applet, c); + if (opt == NULL) + break; + + opt->handle(c, opt, optarg, applet); + } +} diff --git a/cmd/multicall.c b/cmd/multicall.c index 65bd9e9..6121776 100644 --- a/cmd/multicall.c +++ b/cmd/multicall.c @@ -35,68 +35,6 @@ struct if_applet *applet_table[] = { &ifupdown_applet, }; -static void -generic_usage(const struct if_applet *applet, int result) -{ - fprintf(stderr, "%s", applet->name); - if (applet->desc != NULL) - fprintf(stderr, " - %s", applet->desc); - - fprintf(stderr, "\n"); - - size_t iter; - for (iter = 0; applet->groups[iter] != NULL; iter++) - { - const struct if_option_group *group = applet->groups[iter]; - - fprintf(stderr, "\n%s:\n", group->desc); - - size_t group_iter; - for (group_iter = 0; group_iter < group->group_size; group_iter++) - { - const struct if_option *opt = &group->group[group_iter]; - - fprintf(stderr, " "); - - if (opt->short_opt) - fprintf(stderr, "-%c", opt->short_opt); - else - fprintf(stderr, " "); - - if (opt->long_opt) - fprintf(stderr, "%c --%-30s", opt->short_opt ? ',' : ' ', - opt->long_opt); - else - fprintf(stderr, "%34s", ""); - - fprintf(stderr, "%s\n", opt->desc); - } - } - - exit(result); -} - -static void -generic_usage_request(int short_opt, const struct if_option *option, const char *opt_arg, const struct if_applet *applet) -{ - (void) short_opt; - (void) option; - (void) opt_arg; - - generic_usage(applet, EXIT_SUCCESS); -} - -static struct if_option global_options[] = { - {'h', "help", "displays program help", false, generic_usage_request}, - {'V', "version", "displays program version", false, (void *) lif_common_version}, -}; - -struct if_option_group global_option_group = { - .desc = "Global options", - .group_size = ARRAY_SIZE(global_options), - .group = global_options -}; - int applet_cmp(const void *a, const void *b) { @@ -108,78 +46,6 @@ applet_cmp(const void *a, const void *b) void multicall_usage(int status) __attribute__((noreturn)); -static const struct if_option * -lookup_option(const struct if_applet *applet, int opt) -{ - size_t iter; - for (iter = 0; applet->groups[iter] != NULL; iter++) - { - const struct if_option_group *group = applet->groups[iter]; - size_t group_iter; - - for (group_iter = 0; group_iter < group->group_size; group_iter++) - { - const struct if_option *option = &group->group[group_iter]; - - if (option->short_opt == opt) - return option; - } - } - - return NULL; -} - -static void -process_options(const struct if_applet *applet, int argc, char *argv[]) -{ - char short_opts[256] = {}, *p = short_opts; - struct option long_opts[256] = {}; - - size_t iter, long_opt_iter = 0; - for (iter = 0; applet->groups[iter] != NULL; iter++) - { - const struct if_option_group *group = applet->groups[iter]; - size_t group_iter; - - for (group_iter = 0; group_iter < group->group_size; group_iter++) - { - const struct if_option *opt = &group->group[group_iter]; - - if (opt->short_opt) - { - *p++ = opt->short_opt; - if (opt->require_argument) - *p++ = ':'; - } - - if (opt->long_opt) - { - /* XXX: handle long-opts without short-opts */ - long_opts[long_opt_iter] = (struct option) { - .name = opt->long_opt, - .has_arg = opt->require_argument ? required_argument : no_argument, - .val = opt->short_opt - }; - - long_opt_iter++; - } - } - } - - for (;;) - { - int c = getopt_long(argc, argv, short_opts, long_opts, NULL); - if (c == -1) - break; - - const struct if_option *opt = lookup_option(applet, c); - if (opt == NULL) - break; - - opt->handle(c, opt, optarg, applet); - } -} - int main(int argc, char *argv[]) { diff --git a/cmd/multicall.h b/cmd/multicall.h index 48deb26..97056a2 100644 --- a/cmd/multicall.h +++ b/cmd/multicall.h @@ -58,4 +58,7 @@ struct match_options { char *property; }; +extern void process_options(const struct if_applet *applet, int argc, char *argv[]); +extern const struct if_option *lookup_option(const struct if_applet *applet, int opt); + #endif From f871002ecca2ca77d5781d44f6c2b82cc8c8af62 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 11 Aug 2020 22:37:10 -0600 Subject: [PATCH 4/9] multicall: add self_applet --- cmd/multicall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/multicall.c b/cmd/multicall.c index 6121776..9c8a891 100644 --- a/cmd/multicall.c +++ b/cmd/multicall.c @@ -27,6 +27,7 @@ extern struct if_applet ifquery_applet; extern struct if_applet ifup_applet; extern struct if_applet ifdown_applet; struct if_applet ifupdown_applet; +const struct if_applet *self_applet = NULL; struct if_applet *applet_table[] = { &ifdown_applet, @@ -62,6 +63,7 @@ main(int argc, char *argv[]) multicall_usage(EXIT_FAILURE); } + self_applet = *app; process_options(*app, argc, argv); return (*app)->main(argc, argv); From 52509c508cc4a96ed13c83e5ac1b121145da951f Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 11 Aug 2020 22:37:36 -0600 Subject: [PATCH 5/9] multicall: migrate match options to shared collection --- Makefile | 3 ++- cmd/ifquery.c | 28 +++------------------------- cmd/ifupdown.c | 1 - cmd/multicall-options.c | 6 +++--- cmd/multicall.h | 12 +++++++++--- 5 files changed, 17 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index f2ad017..a0615be 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,8 @@ LIBIFUPDOWN_LIB = libifupdown.a MULTICALL_SRC = \ cmd/multicall.c \ - cmd/multicall-options.c + cmd/multicall-options.c \ + cmd/multicall-match-options.c MULTICALL_OBJ = ${MULTICALL_SRC:.c=.o} MULTICALL = ifupdown diff --git a/cmd/ifquery.c b/cmd/ifquery.c index f84fb28..b1df261 100644 --- a/cmd/ifquery.c +++ b/cmd/ifquery.c @@ -174,9 +174,6 @@ ifquery_usage(int status) fprintf(stderr, " -V, --version show this program's version\n"); fprintf(stderr, " -i, --interfaces FILE use FILE for interface definitions\n"); fprintf(stderr, " -L, --list list matching interfaces\n"); - fprintf(stderr, " -a, --auto only match against interfaces hinted as 'auto'\n"); - fprintf(stderr, " -I, --include PATTERN only match against interfaces matching PATTERN\n"); - fprintf(stderr, " -X, --exclude PATTERN never match against interfaces matching PATTERN\n"); fprintf(stderr, " -P, --pretty-print pretty print the interfaces instead of just listing\n"); fprintf(stderr, " -S, --state-file FILE use FILE for state\n"); fprintf(stderr, " -s, --state show configured state\n"); @@ -253,13 +250,8 @@ ifquery_main(int argc, char *argv[]) struct lif_dict state = {}; struct lif_dict collection = {}; struct option long_options[] = { - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, {"interfaces", required_argument, 0, 'i'}, {"list", no_argument, 0, 'L'}, - {"auto", no_argument, 0, 'a'}, - {"include", required_argument, 0, 'I'}, - {"exclude", required_argument, 0, 'X'}, {"pretty-print", no_argument, 0, 'P'}, {"state-file", required_argument, 0, 'S'}, {"state", no_argument, 0, 's'}, @@ -268,7 +260,6 @@ ifquery_main(int argc, char *argv[]) {"executor-path", required_argument, 0, 'E'}, {NULL, 0, 0, 0} }; - struct match_options match_opts = {}; bool listing = false, listing_stat = false; char *state_file = STATE_FILE; @@ -279,27 +270,12 @@ ifquery_main(int argc, char *argv[]) break; switch (c) { - case 'h': - ifquery_usage(EXIT_SUCCESS); - break; - case 'V': - lif_common_version(); - break; case 'i': exec_opts.interfaces_file = optarg; break; case 'L': listing = true; break; - case 'a': - match_opts.is_auto = true; - break; - case 'I': - match_opts.include_pattern = optarg; - break; - case 'X': - match_opts.exclude_pattern = optarg; - break; case 'P': match_opts.pretty_print = true; break; @@ -381,6 +357,8 @@ ifquery_main(int argc, char *argv[]) struct if_applet ifquery_applet = { .name = "ifquery", + .desc = "query interface configuration", .main = ifquery_main, - .usage = ifquery_usage + .usage = ifquery_usage, + .groups = { &global_option_group, &match_option_group, NULL }, }; diff --git a/cmd/ifupdown.c b/cmd/ifupdown.c index 1c42a3f..75d9c61 100644 --- a/cmd/ifupdown.c +++ b/cmd/ifupdown.c @@ -204,7 +204,6 @@ ifupdown_main(int argc, char *argv[]) {"no-lock", no_argument, 0, 'L'}, {NULL, 0, 0, 0} }; - struct match_options match_opts = {}; for (;;) { diff --git a/cmd/multicall-options.c b/cmd/multicall-options.c index 415d24a..30e7db4 100644 --- a/cmd/multicall-options.c +++ b/cmd/multicall-options.c @@ -51,7 +51,7 @@ generic_usage(const struct if_applet *applet, int result) if (opt->long_opt) fprintf(stderr, "%c --%-30s", opt->short_opt ? ',' : ' ', - opt->long_opt); + opt->long_opt_desc ? opt->long_opt_desc : opt->long_opt); else fprintf(stderr, "%34s", ""); @@ -73,8 +73,8 @@ generic_usage_request(int short_opt, const struct if_option *option, const char } static struct if_option global_options[] = { - {'h', "help", "displays program help", false, generic_usage_request}, - {'V', "version", "displays program version", false, (void *) lif_common_version}, + {'h', "help", NULL, "this help", false, generic_usage_request}, + {'V', "version", NULL, "show this program's version", false, (void *) lif_common_version}, }; struct if_option_group global_option_group = { diff --git a/cmd/multicall.h b/cmd/multicall.h index 97056a2..aa5752e 100644 --- a/cmd/multicall.h +++ b/cmd/multicall.h @@ -27,6 +27,7 @@ struct if_applet; struct if_option { char short_opt; const char *long_opt; + const char *long_opt_desc; const char *desc; bool require_argument; void (*const handle)(int short_opt, const struct if_option *opt, const char *opt_arg, const struct if_applet *applet); @@ -47,18 +48,23 @@ struct if_applet { }; extern char *argv0; +extern const struct if_applet *self_applet; extern struct if_option_group global_option_group; struct match_options { bool is_auto; - char *exclude_pattern; - char *include_pattern; + const char *exclude_pattern; + const char *include_pattern; bool pretty_print; bool dot; - char *property; + const char *property; }; +extern struct match_options match_opts; + extern void process_options(const struct if_applet *applet, int argc, char *argv[]); extern const struct if_option *lookup_option(const struct if_applet *applet, int opt); +extern struct if_option_group match_option_group; + #endif From fdfe8ac080e38fd064ad501d2c23940c1cc91369 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 11 Aug 2020 22:51:53 -0600 Subject: [PATCH 6/9] multicall: migrate execution options to common code --- Makefile | 1 + cmd/ifquery.c | 24 ++--------- cmd/ifupdown.c | 11 ++--- cmd/multicall-exec-options.c | 77 +++++++++++++++++++++++++++++++++++ cmd/multicall-match-options.c | 57 ++++++++++++++++++++++++++ cmd/multicall.h | 3 ++ 6 files changed, 144 insertions(+), 29 deletions(-) create mode 100644 cmd/multicall-exec-options.c create mode 100644 cmd/multicall-match-options.c diff --git a/Makefile b/Makefile index a0615be..6762eec 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,7 @@ LIBIFUPDOWN_LIB = libifupdown.a MULTICALL_SRC = \ cmd/multicall.c \ cmd/multicall-options.c \ + cmd/multicall-exec-options.c \ cmd/multicall-match-options.c MULTICALL_OBJ = ${MULTICALL_SRC:.c=.o} MULTICALL = ifupdown diff --git a/cmd/ifquery.c b/cmd/ifquery.c index b1df261..89c84d4 100644 --- a/cmd/ifquery.c +++ b/cmd/ifquery.c @@ -21,11 +21,6 @@ #include "libifupdown/libifupdown.h" #include "cmd/multicall.h" -static struct lif_execute_opts exec_opts = { - .interfaces_file = INTERFACES_FILE, - .executor_path = EXECUTOR_PATH -}; - void print_interface(struct lif_interface *iface) { @@ -250,18 +245,14 @@ ifquery_main(int argc, char *argv[]) struct lif_dict state = {}; struct lif_dict collection = {}; struct option long_options[] = { - {"interfaces", required_argument, 0, 'i'}, {"list", no_argument, 0, 'L'}, {"pretty-print", no_argument, 0, 'P'}, - {"state-file", required_argument, 0, 'S'}, {"state", no_argument, 0, 's'}, {"dot", no_argument, 0, 'D'}, {"property", required_argument, 0, 'p'}, - {"executor-path", required_argument, 0, 'E'}, {NULL, 0, 0, 0} }; bool listing = false, listing_stat = false; - char *state_file = STATE_FILE; for (;;) { @@ -270,18 +261,12 @@ ifquery_main(int argc, char *argv[]) break; switch (c) { - case 'i': - exec_opts.interfaces_file = optarg; - break; case 'L': listing = true; break; case 'P': match_opts.pretty_print = true; break; - case 'S': - state_file = optarg; - break; case 's': listing_stat = true; break; @@ -291,15 +276,12 @@ ifquery_main(int argc, char *argv[]) case 'p': match_opts.property = optarg; break; - case 'E': - exec_opts.executor_path = optarg; - break; } } - if (!lif_state_read_path(&state, state_file)) + if (!lif_state_read_path(&state, exec_opts.state_file)) { - fprintf(stderr, "%s: could not parse %s\n", argv0, state_file); + fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.state_file); return EXIT_FAILURE; } @@ -360,5 +342,5 @@ struct if_applet ifquery_applet = { .desc = "query interface configuration", .main = ifquery_main, .usage = ifquery_usage, - .groups = { &global_option_group, &match_option_group, NULL }, + .groups = { &global_option_group, &match_option_group, &exec_option_group }, }; diff --git a/cmd/ifupdown.c b/cmd/ifupdown.c index 75d9c61..2c4143a 100644 --- a/cmd/ifupdown.c +++ b/cmd/ifupdown.c @@ -25,11 +25,6 @@ #include "cmd/multicall.h" static bool up; -static struct lif_execute_opts exec_opts = { - .executor_path = EXECUTOR_PATH, - .interfaces_file = INTERFACES_FILE, - .state_file = STATE_FILE, -}; void ifupdown_usage(int status) @@ -218,9 +213,6 @@ ifupdown_main(int argc, char *argv[]) case 'V': lif_common_version(); break; - case 'i': - exec_opts.interfaces_file = optarg; - break; case 'a': match_opts.is_auto = true; break; @@ -230,6 +222,9 @@ ifupdown_main(int argc, char *argv[]) case 'X': match_opts.exclude_pattern = optarg; break; + case 'i': + exec_opts.interfaces_file = optarg; + break; case 'S': exec_opts.state_file = optarg; break; diff --git a/cmd/multicall-exec-options.c b/cmd/multicall-exec-options.c new file mode 100644 index 0000000..f043167 --- /dev/null +++ b/cmd/multicall-exec-options.c @@ -0,0 +1,77 @@ +/* + * cmd/multicall-exec-options.c + * Purpose: multi-call binary frontend -- option handling + * + * Copyright (c) 2020 Ariadne Conill + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "cmd/multicall.h" + +struct lif_execute_opts exec_opts = { + .interfaces_file = INTERFACES_FILE, + .executor_path = EXECUTOR_PATH, + .state_file = STATE_FILE +}; + +static void handle_exec(int short_opt, const struct if_option *opt, const char *opt_arg, const struct if_applet *applet) +{ + (void) opt; + (void) applet; + + switch (short_opt) + { + case 'i': + exec_opts.interfaces_file = opt_arg; + break; + case 'S': + exec_opts.state_file = opt_arg; + break; + case 'n': + exec_opts.mock = true; + exec_opts.verbose = true; + break; + case 'v': + exec_opts.verbose = true; + break; + case 'E': + exec_opts.executor_path = opt_arg; + break; + case 'f': + break; + case 'L': + exec_opts.no_lock = true; + break; + default: + break; + } +} + +static struct if_option exec_options[] = { + {'f', "force", NULL, "force (de)configuration", true, handle_exec}, + {'i', "interfaces", "interfaces FILE", "use FILE for interface definitions", true, handle_exec}, + {'n', "no-act", NULL, "do not actually run any commands", false, handle_exec}, + {'v', "verbose", NULL, "show what commands are being run", false, handle_exec}, + {'E', "executor-path", "executor-path PATH", "use PATH for executor directory", true, handle_exec}, + {'L', "no-lock", NULL, "do not use a lockfile to serialize state changes", false, handle_exec}, + {'S', "state-file", "state-file FILE", "use FILE for state", true, handle_exec}, +}; + +struct if_option_group exec_option_group = { + .desc = "Execution", + .group_size = ARRAY_SIZE(exec_options), + .group = exec_options +}; diff --git a/cmd/multicall-match-options.c b/cmd/multicall-match-options.c new file mode 100644 index 0000000..d89056a --- /dev/null +++ b/cmd/multicall-match-options.c @@ -0,0 +1,57 @@ +/* + * cmd/multicall-match-options.c + * Purpose: multi-call binary frontend -- option handling + * + * Copyright (c) 2020 Ariadne Conill + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "cmd/multicall.h" + +struct match_options match_opts = {}; + +static void handle_match(int short_opt, const struct if_option *opt, const char *opt_arg, const struct if_applet *applet) +{ + (void) opt; + (void) applet; + + switch (short_opt) + { + case 'a': + match_opts.is_auto = true; + break; + case 'I': + match_opts.include_pattern = opt_arg; + break; + case 'X': + match_opts.exclude_pattern = opt_arg; + break; + default: + break; + } +} + +static struct if_option match_options[] = { + {'a', "auto", NULL, "only match against interfaces hinted as 'auto'", false, handle_match}, + {'I', "include", "include PATTERN", "only match against interfaces matching PATTERN", true, handle_match}, + {'X', "exclude", "exclude PATTERN", "never match against interfaces matching PATTERN", true, handle_match}, +}; + +struct if_option_group match_option_group = { + .desc = "Matching interfaces", + .group_size = ARRAY_SIZE(match_options), + .group = match_options +}; diff --git a/cmd/multicall.h b/cmd/multicall.h index aa5752e..20d2c20 100644 --- a/cmd/multicall.h +++ b/cmd/multicall.h @@ -67,4 +67,7 @@ extern const struct if_option *lookup_option(const struct if_applet *applet, int extern struct if_option_group match_option_group; +extern struct lif_execute_opts exec_opts; +extern struct if_option_group exec_option_group; + #endif From f6d9f652485b3681210fe4f4af357761cc38a7aa Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 11 Aug 2020 23:03:55 -0600 Subject: [PATCH 7/9] ifquery: port to use option groups --- cmd/ifquery.c | 88 +++++++++++++++++------------------- cmd/multicall-exec-options.c | 4 +- cmd/multicall.h | 2 +- 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/cmd/ifquery.c b/cmd/ifquery.c index 89c84d4..dc9cfbe 100644 --- a/cmd/ifquery.c +++ b/cmd/ifquery.c @@ -164,17 +164,6 @@ ifquery_usage(int status) fprintf(stderr, "usage: ifquery [options] \n"); fprintf(stderr, " ifquery [options] --list\n"); - fprintf(stderr, "\nOptions:\n"); - fprintf(stderr, " -h, --help this help\n"); - fprintf(stderr, " -V, --version show this program's version\n"); - fprintf(stderr, " -i, --interfaces FILE use FILE for interface definitions\n"); - fprintf(stderr, " -L, --list list matching interfaces\n"); - fprintf(stderr, " -P, --pretty-print pretty print the interfaces instead of just listing\n"); - fprintf(stderr, " -S, --state-file FILE use FILE for state\n"); - fprintf(stderr, " -s, --state show configured state\n"); - fprintf(stderr, " -D, --dot generate a dependency graph\n"); - fprintf(stderr, " -p, --property PROPERTY print values of properties matching PROPERTY\n"); - exit(status); } @@ -239,45 +228,52 @@ list_state(struct lif_dict *state, struct match_options *opts) } } +static bool listing = false, listing_stat = false; + +static void +handle_local(int short_opt, const struct if_option *opt, const char *opt_arg, const struct if_applet *applet) +{ + (void) opt; + (void) applet; + + switch (short_opt) { + case 'L': + listing = true; + break; + case 'P': + match_opts.pretty_print = true; + break; + case 's': + listing_stat = true; + break; + case 'D': + match_opts.dot = true; + break; + case 'p': + match_opts.property = opt_arg; + break; + } +} + +static struct if_option local_options[] = { + {'s', "state", NULL, "show configured state", false, handle_local}, + {'p', "property", "property PROPERTY", "print values of properties matching PROPERTY", true, handle_local}, + {'D', "dot", NULL, "generate a dependency graph", false, handle_local}, + {'L', "list", NULL, "list matching interfaces", false, handle_local}, + {'P', "pretty-print", NULL, "pretty print the interfaces instead of just listing", false, handle_local}, +}; + +static struct if_option_group local_option_group = { + .desc = "Program-specific options", + .group_size = ARRAY_SIZE(local_options), + .group = local_options +}; + int ifquery_main(int argc, char *argv[]) { struct lif_dict state = {}; struct lif_dict collection = {}; - struct option long_options[] = { - {"list", no_argument, 0, 'L'}, - {"pretty-print", no_argument, 0, 'P'}, - {"state", no_argument, 0, 's'}, - {"dot", no_argument, 0, 'D'}, - {"property", required_argument, 0, 'p'}, - {NULL, 0, 0, 0} - }; - bool listing = false, listing_stat = false; - - for (;;) - { - int c = getopt_long(argc, argv, "hVi:LaI:X:PS:sDp:E:", long_options, NULL); - if (c == -1) - break; - - switch (c) { - case 'L': - listing = true; - break; - case 'P': - match_opts.pretty_print = true; - break; - case 's': - listing_stat = true; - break; - case 'D': - match_opts.dot = true; - break; - case 'p': - match_opts.property = optarg; - break; - } - } if (!lif_state_read_path(&state, exec_opts.state_file)) { @@ -342,5 +338,5 @@ struct if_applet ifquery_applet = { .desc = "query interface configuration", .main = ifquery_main, .usage = ifquery_usage, - .groups = { &global_option_group, &match_option_group, &exec_option_group }, + .groups = { &global_option_group, &match_option_group, &exec_option_group, &local_option_group }, }; diff --git a/cmd/multicall-exec-options.c b/cmd/multicall-exec-options.c index f043167..0ebe85d 100644 --- a/cmd/multicall-exec-options.c +++ b/cmd/multicall-exec-options.c @@ -52,7 +52,7 @@ static void handle_exec(int short_opt, const struct if_option *opt, const char * break; case 'f': break; - case 'L': + case 'l': exec_opts.no_lock = true; break; default: @@ -63,10 +63,10 @@ static void handle_exec(int short_opt, const struct if_option *opt, const char * static struct if_option exec_options[] = { {'f', "force", NULL, "force (de)configuration", true, handle_exec}, {'i', "interfaces", "interfaces FILE", "use FILE for interface definitions", true, handle_exec}, + {'l', "no-lock", NULL, "do not use a lockfile to serialize state changes", false, handle_exec}, {'n', "no-act", NULL, "do not actually run any commands", false, handle_exec}, {'v', "verbose", NULL, "show what commands are being run", false, handle_exec}, {'E', "executor-path", "executor-path PATH", "use PATH for executor directory", true, handle_exec}, - {'L', "no-lock", NULL, "do not use a lockfile to serialize state changes", false, handle_exec}, {'S', "state-file", "state-file FILE", "use FILE for state", true, handle_exec}, }; diff --git a/cmd/multicall.h b/cmd/multicall.h index 20d2c20..cfbadd5 100644 --- a/cmd/multicall.h +++ b/cmd/multicall.h @@ -44,7 +44,7 @@ struct if_applet { const char *desc; int (*const main)(int argc, char *argv[]); void (*const usage)(int status); - const struct if_option_group *groups[4]; + const struct if_option_group *groups[16]; }; extern char *argv0; From fda7bfae577ffd10eb1cad58559d223b005d3a2e Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 11 Aug 2020 23:10:35 -0600 Subject: [PATCH 8/9] ifquery: use generic_usage() instead of ifquery_usage() --- cmd/ifquery.c | 15 +++------------ cmd/ifupdown.c | 2 -- cmd/multicall-options.c | 5 ++++- cmd/multicall.c | 1 - cmd/multicall.h | 4 +++- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/cmd/ifquery.c b/cmd/ifquery.c index dc9cfbe..0612823 100644 --- a/cmd/ifquery.c +++ b/cmd/ifquery.c @@ -158,15 +158,6 @@ print_interface_property(struct lif_interface *iface, const char *property) } } -void -ifquery_usage(int status) -{ - fprintf(stderr, "usage: ifquery [options] \n"); - fprintf(stderr, " ifquery [options] --list\n"); - - exit(status); -} - void list_interfaces(struct lif_dict *collection, struct match_options *opts) { @@ -289,7 +280,7 @@ ifquery_main(int argc, char *argv[]) /* --list --state is not allowed */ if (listing && listing_stat) - ifquery_usage(EXIT_FAILURE); + generic_usage(self_applet, EXIT_FAILURE); if (listing) { @@ -303,7 +294,7 @@ ifquery_main(int argc, char *argv[]) } if (optind >= argc) - ifquery_usage(EXIT_FAILURE); + generic_usage(self_applet, EXIT_FAILURE); int idx = optind; for (; idx < argc; idx++) @@ -337,6 +328,6 @@ struct if_applet ifquery_applet = { .name = "ifquery", .desc = "query interface configuration", .main = ifquery_main, - .usage = ifquery_usage, + .usage = "ifquery [options] \n ifquery [options] --list", .groups = { &global_option_group, &match_option_group, &exec_option_group, &local_option_group }, }; diff --git a/cmd/ifupdown.c b/cmd/ifupdown.c index 2c4143a..45410a7 100644 --- a/cmd/ifupdown.c +++ b/cmd/ifupdown.c @@ -320,11 +320,9 @@ ifupdown_main(int argc, char *argv[]) struct if_applet ifup_applet = { .name = "ifup", .main = ifupdown_main, - .usage = ifupdown_usage }; struct if_applet ifdown_applet = { .name = "ifdown", .main = ifupdown_main, - .usage = ifupdown_usage }; diff --git a/cmd/multicall-options.c b/cmd/multicall-options.c index 30e7db4..9037264 100644 --- a/cmd/multicall-options.c +++ b/cmd/multicall-options.c @@ -21,7 +21,7 @@ #include #include "cmd/multicall.h" -static void +void generic_usage(const struct if_applet *applet, int result) { fprintf(stderr, "%s", applet->name); @@ -30,6 +30,9 @@ generic_usage(const struct if_applet *applet, int result) fprintf(stderr, "\n"); + if (applet->usage != NULL) + fprintf(stderr, "\nUsage:\n %s\n", applet->usage); + size_t iter; for (iter = 0; applet->groups[iter] != NULL; iter++) { diff --git a/cmd/multicall.c b/cmd/multicall.c index 9c8a891..ccb7688 100644 --- a/cmd/multicall.c +++ b/cmd/multicall.c @@ -102,6 +102,5 @@ multicall_usage(int status) struct if_applet ifupdown_applet = { .name = "ifupdown", .main = multicall_main, - .usage = multicall_usage, .groups = { &global_option_group, NULL } }; diff --git a/cmd/multicall.h b/cmd/multicall.h index cfbadd5..23cb836 100644 --- a/cmd/multicall.h +++ b/cmd/multicall.h @@ -42,8 +42,8 @@ struct if_option_group { struct if_applet { const char *name; const char *desc; + const char *usage; int (*const main)(int argc, char *argv[]); - void (*const usage)(int status); const struct if_option_group *groups[16]; }; @@ -70,4 +70,6 @@ extern struct if_option_group match_option_group; extern struct lif_execute_opts exec_opts; extern struct if_option_group exec_option_group; +void generic_usage(const struct if_applet *applet, int result); + #endif From f7d21d4b466e301134f460d4dcd9447aa55f0f35 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 11 Aug 2020 23:14:55 -0600 Subject: [PATCH 9/9] ifupdown: port to use option groups --- cmd/ifupdown.c | 91 ++++---------------------------------------------- 1 file changed, 7 insertions(+), 84 deletions(-) diff --git a/cmd/ifupdown.c b/cmd/ifupdown.c index 45410a7..c1bce3a 100644 --- a/cmd/ifupdown.c +++ b/cmd/ifupdown.c @@ -26,28 +26,6 @@ static bool up; -void -ifupdown_usage(int status) -{ - fprintf(stderr, "usage: %s [options] \n", argv0); - - fprintf(stderr, "\nOptions:\n"); - fprintf(stderr, " -h, --help this help\n"); - fprintf(stderr, " -V, --version show this program's version\n"); - fprintf(stderr, " -i, --interfaces FILE use FILE for interface definitions\n"); - fprintf(stderr, " -S, --state-file FILE use FILE for state\n"); - fprintf(stderr, " -a, --auto only match against interfaces hinted as 'auto'\n"); - fprintf(stderr, " -I, --include PATTERN only match against interfaces matching PATTERN\n"); - fprintf(stderr, " -X, --exclude PATTERN never match against interfaces matching PATTERN\n"); - fprintf(stderr, " -n, --no-act do not actually run any commands\n"); - fprintf(stderr, " -v, --verbose show what commands are being run\n"); - fprintf(stderr, " -E, --executor-path PATH use PATH for executor directory\n"); - fprintf(stderr, " -f, --force force (de)configuration\n"); - fprintf(stderr, " -L, --no-lock do not use a lockfile to serialize state changes\n"); - - exit(status); -} - bool is_ifdown() { @@ -184,67 +162,6 @@ ifupdown_main(int argc, char *argv[]) struct lif_dict state = {}; struct lif_dict collection = {}; - struct option long_options[] = { - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"interfaces", required_argument, 0, 'i'}, - {"auto", no_argument, 0, 'a'}, - {"include", required_argument, 0, 'I'}, - {"exclude", required_argument, 0, 'X'}, - {"state-file", required_argument, 0, 'S'}, - {"no-act", no_argument, 0, 'n'}, - {"verbose", no_argument, 0, 'v'}, - {"executor-path", required_argument, 0, 'E'}, - {"force", no_argument, 0, 'f'}, - {"no-lock", no_argument, 0, 'L'}, - {NULL, 0, 0, 0} - }; - - for (;;) - { - int c = getopt_long(argc, argv, "hVi:aI:X:S:nvE:fL", long_options, NULL); - if (c == -1) - break; - - switch (c) { - case 'h': - ifupdown_usage(EXIT_SUCCESS); - break; - case 'V': - lif_common_version(); - break; - case 'a': - match_opts.is_auto = true; - break; - case 'I': - match_opts.include_pattern = optarg; - break; - case 'X': - match_opts.exclude_pattern = optarg; - break; - case 'i': - exec_opts.interfaces_file = optarg; - break; - case 'S': - exec_opts.state_file = optarg; - break; - case 'n': - exec_opts.mock = true; - exec_opts.verbose = true; - break; - case 'v': - exec_opts.verbose = true; - break; - case 'E': - exec_opts.executor_path = optarg; - break; - case 'f': - break; - case 'L': - exec_opts.no_lock = true; - break; - } - } if (!lif_state_read_path(&state, exec_opts.state_file)) { @@ -272,7 +189,7 @@ ifupdown_main(int argc, char *argv[]) return EXIT_SUCCESS; } else if (optind >= argc) - ifupdown_usage(EXIT_FAILURE); + generic_usage(self_applet, EXIT_FAILURE); int idx = optind; for (; idx < argc; idx++) @@ -319,10 +236,16 @@ ifupdown_main(int argc, char *argv[]) struct if_applet ifup_applet = { .name = "ifup", + .desc = "bring interfaces up", .main = ifupdown_main, + .usage = "ifup [options] ", + .groups = { &global_option_group, &match_option_group, &exec_option_group, }, }; struct if_applet ifdown_applet = { .name = "ifdown", + .desc = "take interfaces down", .main = ifupdown_main, + .usage = "ifdown [options] ", + .groups = { &global_option_group, &match_option_group, &exec_option_group, }, };