From d36a522470bf37a327974627149f6a021b59d880 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Thu, 20 Aug 2020 03:34:59 -0600 Subject: [PATCH 1/6] interface-file: add and use report_error() --- libifupdown/interface-file.c | 65 +++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/libifupdown/interface-file.c b/libifupdown/interface-file.c index 1f2d19d..3e0dc6e 100644 --- a/libifupdown/interface-file.c +++ b/libifupdown/interface-file.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include "libifupdown/libifupdown.h" @@ -57,6 +58,37 @@ maybe_remap_token(const char *token) return tokbuf; } +/* map keywords to parser functions */ +struct parser_keyword { + const char *token; + bool (*handle)(struct lif_dict *collection, struct lif_interface *cur_iface, const char *filename, size_t lineno, char *token, char *bufp); +}; + +static const struct parser_keyword keywords[] = { +}; + +static int +keyword_cmp(const void *a, const void *b) +{ + const char *key = a; + const struct parser_keyword *token = b; + + return strcmp(key, token->token); +} + +static void +report_error(const char *filename, size_t lineno, const char *errfmt, ...) +{ + char errbuf[4096]; + + va_list va; + va_start(va, errfmt); + vsnprintf(errbuf, sizeof errbuf, errfmt, va); + va_end(va); + + fprintf(stderr, "%s:%zu: %s\n", filename, lineno, errbuf); +} + bool lif_interface_file_parse(struct lif_dict *collection, const char *filename) { @@ -68,15 +100,26 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) return false; char linebuf[4096]; + size_t lineno = 0; while (lif_fgetline(linebuf, sizeof linebuf, f) != NULL) { + lineno++; + char *bufp = linebuf; char *token = lif_next_token(&bufp); if (!*token || !isalpha(*token)) continue; - if (!strcmp(token, "source")) + const struct parser_keyword *parserkw = + bsearch(token, keywords, ARRAY_SIZE(keywords), sizeof(*keywords), keyword_cmp); + + if (parserkw != NULL) + { + if (!parserkw->handle(collection, cur_iface, filename, lineno, token, bufp)) + goto parse_error; + } + else if (!strcmp(token, "source")) { char *source_filename = lif_next_token(&bufp); if (!*source_filename) @@ -84,8 +127,8 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) if (!strcmp(filename, source_filename)) { - fprintf(stderr, "%s: attempt to source %s would create infinite loop\n", - filename, source_filename); + report_error(filename, lineno, "attempt to source %s would create infinite loop", + source_filename); goto parse_error; } @@ -132,13 +175,13 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) if (!*token) { - fprintf(stderr, "%s: inherits without interface\n", filename); + report_error(filename, lineno, "inherits without interface"); goto parse_error; } if (!lif_interface_collection_inherit(cur_iface, collection, token)) { - fprintf(stderr, "%s: could not inherit %s\n", filename, token); + report_error(filename, lineno, "could not inherit %s", token); goto parse_error; } } @@ -152,7 +195,7 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) if (cur_iface == NULL) { - fprintf(stderr, "%s: use '%s' without interface\n", filename, executor); + report_error(filename, lineno, "use '%s' without interface", executor); goto parse_error; } @@ -170,13 +213,13 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) if (!*token) { - fprintf(stderr, "%s: inherits without interface\n", filename); + report_error(filename, lineno, "inherits without interface"); goto parse_error; } if (!lif_interface_collection_inherit(cur_iface, collection, token)) { - fprintf(stderr, "%s: could not inherit %s\n", filename, token); + report_error(filename, lineno, "could not inherit %s", token); goto parse_error; } } @@ -186,7 +229,7 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) if (cur_iface == NULL) { - fprintf(stderr, "%s: address '%s' without interface\n", filename, addr); + report_error(filename, lineno, "%s: address '%s' without interface", filename, addr); goto parse_error; } @@ -198,7 +241,7 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) if (cur_iface == NULL) { - fprintf(stderr, "%s: gateway '%s' without interface\n", filename, addr); + report_error(filename, lineno, "%s: gateway '%s' without interface", filename, addr); goto parse_error; } @@ -233,8 +276,6 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) return true; parse_error: - fprintf(stderr, "libifupdown: %s: failed to parse line \"%s\"\n", - filename, linebuf); fclose(f); return false; } From b57aba1a97913668d6b98996cc137cff56201b93 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Thu, 20 Aug 2020 03:41:07 -0600 Subject: [PATCH 2/6] interface-file: split out auto keyword handling --- libifupdown/interface-file.c | 76 ++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/libifupdown/interface-file.c b/libifupdown/interface-file.c index 3e0dc6e..a28ae43 100644 --- a/libifupdown/interface-file.c +++ b/libifupdown/interface-file.c @@ -58,23 +58,8 @@ maybe_remap_token(const char *token) return tokbuf; } -/* map keywords to parser functions */ -struct parser_keyword { - const char *token; - bool (*handle)(struct lif_dict *collection, struct lif_interface *cur_iface, const char *filename, size_t lineno, char *token, char *bufp); -}; - -static const struct parser_keyword keywords[] = { -}; - -static int -keyword_cmp(const void *a, const void *b) -{ - const char *key = a; - const struct parser_keyword *token = b; - - return strcmp(key, token->token); -} +/* XXX: remove this global variable somehow */ +static struct lif_interface *cur_iface = NULL; static void report_error(const char *filename, size_t lineno, const char *errfmt, ...) @@ -89,11 +74,50 @@ report_error(const char *filename, size_t lineno, const char *errfmt, ...) fprintf(stderr, "%s:%zu: %s\n", filename, lineno, errbuf); } +static bool +handle_auto(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp) +{ + (void) filename; + (void) lineno; + (void) token; + + char *ifname = lif_next_token(&bufp); + if (!*ifname && cur_iface == NULL) + return false; + else + { + cur_iface = lif_interface_collection_find(collection, ifname); + if (cur_iface == NULL) + return false; + } + + cur_iface->is_auto = true; + return true; +} + +/* map keywords to parser functions */ +struct parser_keyword { + const char *token; + bool (*handle)(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp); +}; + +static const struct parser_keyword keywords[] = { + {"auto", handle_auto}, +}; + +static int +keyword_cmp(const void *a, const void *b) +{ + const char *key = a; + const struct parser_keyword *token = b; + + return strcmp(key, token->token); +} + bool lif_interface_file_parse(struct lif_dict *collection, const char *filename) { lif_interface_collection_init(collection); - struct lif_interface *cur_iface = NULL; FILE *f = fopen(filename, "r"); if (f == NULL) @@ -116,7 +140,7 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) if (parserkw != NULL) { - if (!parserkw->handle(collection, cur_iface, filename, lineno, token, bufp)) + if (!parserkw->handle(collection, filename, lineno, token, bufp)) goto parse_error; } else if (!strcmp(token, "source")) @@ -134,20 +158,6 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) lif_interface_file_parse(collection, source_filename); } - else if (!strcmp(token, "auto")) - { - char *ifname = lif_next_token(&bufp); - if (!*ifname && cur_iface == NULL) - goto parse_error; - else - { - cur_iface = lif_interface_collection_find(collection, ifname); - if (cur_iface == NULL) - goto parse_error; - } - - cur_iface->is_auto = true; - } else if (!strcmp(token, "iface")) { char *ifname = lif_next_token(&bufp); From df9c0284b1ca0676b3f94a3568f01c2245c909e9 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Thu, 20 Aug 2020 03:45:56 -0600 Subject: [PATCH 3/6] interface-file: let commands initialize the interface collection themselves --- cmd/ifquery.c | 2 ++ cmd/ifupdown.c | 2 ++ libifupdown/interface-file.c | 2 -- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/ifquery.c b/cmd/ifquery.c index 1e52247..ac07cbd 100644 --- a/cmd/ifquery.c +++ b/cmd/ifquery.c @@ -275,6 +275,8 @@ ifquery_main(int argc, char *argv[]) struct lif_dict state = {}; struct lif_dict collection = {}; + lif_interface_collection_init(&collection); + if (!lif_state_read_path(&state, exec_opts.state_file)) { fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.state_file); diff --git a/cmd/ifupdown.c b/cmd/ifupdown.c index 0fa7e29..bd9a68e 100644 --- a/cmd/ifupdown.c +++ b/cmd/ifupdown.c @@ -163,6 +163,8 @@ ifupdown_main(int argc, char *argv[]) struct lif_dict state = {}; struct lif_dict collection = {}; + lif_interface_collection_init(&collection); + if (!lif_state_read_path(&state, exec_opts.state_file)) { fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.state_file); diff --git a/libifupdown/interface-file.c b/libifupdown/interface-file.c index a28ae43..8a1f002 100644 --- a/libifupdown/interface-file.c +++ b/libifupdown/interface-file.c @@ -117,8 +117,6 @@ keyword_cmp(const void *a, const void *b) bool lif_interface_file_parse(struct lif_dict *collection, const char *filename) { - lif_interface_collection_init(collection); - FILE *f = fopen(filename, "r"); if (f == NULL) return false; From 4a11d4fdd8fddca706f2ae9f4c64a52a38feb3b5 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Thu, 20 Aug 2020 03:46:31 -0600 Subject: [PATCH 4/6] interface-file: break out source keyword handling --- libifupdown/interface-file.c | 38 ++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/libifupdown/interface-file.c b/libifupdown/interface-file.c index 8a1f002..f1f18ce 100644 --- a/libifupdown/interface-file.c +++ b/libifupdown/interface-file.c @@ -95,6 +95,28 @@ handle_auto(struct lif_dict *collection, const char *filename, size_t lineno, ch return true; } +static bool +handle_source(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp) +{ + (void) token; + + char *source_filename = lif_next_token(&bufp); + if (!*source_filename) + { + report_error(filename, lineno, "missing filename to source"); + return false; + } + + if (!strcmp(filename, source_filename)) + { + report_error(filename, lineno, "attempt to source %s would create infinite loop", + source_filename); + return false; + } + + return lif_interface_file_parse(collection, source_filename); +} + /* map keywords to parser functions */ struct parser_keyword { const char *token; @@ -103,6 +125,7 @@ struct parser_keyword { static const struct parser_keyword keywords[] = { {"auto", handle_auto}, + {"source", handle_source}, }; static int @@ -141,21 +164,6 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) if (!parserkw->handle(collection, filename, lineno, token, bufp)) goto parse_error; } - else if (!strcmp(token, "source")) - { - char *source_filename = lif_next_token(&bufp); - if (!*source_filename) - goto parse_error; - - if (!strcmp(filename, source_filename)) - { - report_error(filename, lineno, "attempt to source %s would create infinite loop", - source_filename); - goto parse_error; - } - - lif_interface_file_parse(collection, source_filename); - } else if (!strcmp(token, "iface")) { char *ifname = lif_next_token(&bufp); From aba140a9770f3527973565489e97ee1e0445b93c Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Thu, 20 Aug 2020 04:04:34 -0600 Subject: [PATCH 5/6] interface-file: use bsearch to find parser functions --- libifupdown/interface-file.c | 292 ++++++++++++++++++++--------------- 1 file changed, 170 insertions(+), 122 deletions(-) diff --git a/libifupdown/interface-file.c b/libifupdown/interface-file.c index f1f18ce..7b2766e 100644 --- a/libifupdown/interface-file.c +++ b/libifupdown/interface-file.c @@ -74,6 +74,25 @@ report_error(const char *filename, size_t lineno, const char *errfmt, ...) fprintf(stderr, "%s:%zu: %s\n", filename, lineno, errbuf); } +static bool +handle_address(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp) +{ + (void) collection; + (void) token; + + char *addr = lif_next_token(&bufp); + + if (cur_iface == NULL) + { + report_error(filename, lineno, "%s '%s' without interface", token, addr); + return false; + } + + lif_interface_address_add(cur_iface, addr); + + return true; +} + static bool handle_auto(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp) { @@ -95,6 +114,127 @@ handle_auto(struct lif_dict *collection, const char *filename, size_t lineno, ch return true; } +static bool +handle_gateway(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp) +{ + (void) collection; + (void) token; + + char *addr = lif_next_token(&bufp); + + if (cur_iface == NULL) + { + report_error(filename, lineno, "%s '%s' without interface", token, addr); + return false; + } + + lif_interface_use_executor(cur_iface, "static"); + lif_dict_add(&cur_iface->vars, token, strdup(addr)); + + return true; +} + +static bool +handle_generic(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp) +{ + (void) collection; + (void) filename; + (void) lineno; + + if (cur_iface == NULL) + return true; + + token = maybe_remap_token(token); + + lif_dict_add(&cur_iface->vars, token, strdup(bufp)); + + /* Check if token looks like - and assume is an addon */ + char *word_end = strchr(token, '-'); + if (word_end != NULL) + { + /* Copy word1 to not mangle *token */ + char *addon = strndup(token, word_end - token); + lif_interface_use_executor(cur_iface, addon); + free(addon); + + /* pass requires as compatibility env vars to appropriate executors (bridge, bond) */ + if (!strcmp(addon, "bridge")) + cur_iface->is_bridge = true; + else if (!strcmp(addon, "bond")) + cur_iface->is_bond = true; + } + + return true; +} + +static bool handle_inherit(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp); + +static bool +handle_iface(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp) +{ + char *ifname = lif_next_token(&bufp); + if (!*ifname) + { + report_error(filename, lineno, "%s without any other tokens", token); + return false; + } + + cur_iface = lif_interface_collection_find(collection, ifname); + if (cur_iface == NULL) + { + report_error(filename, lineno, "could not upsert interface %s", ifname); + return false; + } + + /* in original ifupdown config, we can have "inet loopback" + * or "inet dhcp" or such to designate hints. lets pick up + * those hints here. + */ + token = lif_next_token(&bufp); + while (*token) + { + if (!strcmp(token, "dhcp")) + lif_interface_use_executor(cur_iface, "dhcp"); + else if (!strcmp(token, "ppp")) + lif_interface_use_executor(cur_iface, "ppp"); + else if (!strcmp(token, "inherits")) + { + if (!handle_inherit(collection, filename, lineno, token, bufp)) + return false; + } + + token = lif_next_token(&bufp); + } + + return true; +} + +static bool +handle_inherit(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp) +{ + char *target = lif_next_token(&bufp); + + if (cur_iface == NULL) + { + report_error(filename, lineno, "%s '%s' without interface", token, target); + return false; + } + + if (!*target) + { + report_error(filename, lineno, "%s: unspecified interface"); + return false; + } + + if (!lif_interface_collection_inherit(cur_iface, collection, target)) + { + report_error(filename, lineno, "could not inherit %s", target); + return false; + } + + return true; +} + static bool handle_source(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp) { @@ -117,6 +257,29 @@ handle_source(struct lif_dict *collection, const char *filename, size_t lineno, return lif_interface_file_parse(collection, source_filename); } +static bool +handle_use(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp) +{ + (void) collection; + + char *executor = lif_next_token(&bufp); + + if (cur_iface == NULL) + { + report_error(filename, lineno, "%s '%s' without interface", token, executor); + return false; + } + + /* pass requires as compatibility env vars to appropriate executors (bridge, bond) */ + if (!strcmp(executor, "bridge")) + cur_iface->is_bridge = true; + else if (!strcmp(executor, "bond")) + cur_iface->is_bond = true; + + lif_interface_use_executor(cur_iface, executor); + return true; +} + /* map keywords to parser functions */ struct parser_keyword { const char *token; @@ -124,8 +287,13 @@ struct parser_keyword { }; static const struct parser_keyword keywords[] = { + {"address", handle_address}, {"auto", handle_auto}, + {"gateway", handle_gateway}, + {"iface", handle_iface}, + {"inherit", handle_inherit}, {"source", handle_source}, + {"use", handle_use}, }; static int @@ -164,128 +332,8 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename) if (!parserkw->handle(collection, filename, lineno, token, bufp)) goto parse_error; } - else if (!strcmp(token, "iface")) - { - char *ifname = lif_next_token(&bufp); - if (!*ifname) - goto parse_error; - - cur_iface = lif_interface_collection_find(collection, ifname); - if (cur_iface == NULL) - goto parse_error; - - /* in original ifupdown config, we can have "inet loopback" - * or "inet dhcp" or such to designate hints. lets pick up - * those hints here. - */ - char *token = lif_next_token(&bufp); - while (*token) - { - if (!strcmp(token, "dhcp")) - lif_interface_use_executor(cur_iface, "dhcp"); - else if (!strcmp(token, "ppp")) - lif_interface_use_executor(cur_iface, "ppp"); - else if (!strcmp(token, "inherits")) - { - token = lif_next_token(&bufp); - - if (!*token) - { - report_error(filename, lineno, "inherits without interface"); - goto parse_error; - } - - if (!lif_interface_collection_inherit(cur_iface, collection, token)) - { - report_error(filename, lineno, "could not inherit %s", token); - goto parse_error; - } - } - - token = lif_next_token(&bufp); - } - } - else if (!strcmp(token, "use")) - { - char *executor = lif_next_token(&bufp); - - if (cur_iface == NULL) - { - report_error(filename, lineno, "use '%s' without interface", executor); - goto parse_error; - } - - /* pass requires as compatibility env vars to appropriate executors (bridge, bond) */ - if (!strcmp(executor, "bridge")) - cur_iface->is_bridge = true; - else if (!strcmp(executor, "bond")) - cur_iface->is_bond = true; - - lif_interface_use_executor(cur_iface, executor); - } - else if (!strcmp(token, "inherit")) - { - token = lif_next_token(&bufp); - - if (!*token) - { - report_error(filename, lineno, "inherits without interface"); - goto parse_error; - } - - if (!lif_interface_collection_inherit(cur_iface, collection, token)) - { - report_error(filename, lineno, "could not inherit %s", token); - goto parse_error; - } - } - else if (!strcmp(token, "address")) - { - char *addr = lif_next_token(&bufp); - - if (cur_iface == NULL) - { - report_error(filename, lineno, "%s: address '%s' without interface", filename, addr); - goto parse_error; - } - - lif_interface_address_add(cur_iface, addr); - } - else if (!strcmp(token, "gateway")) - { - char *addr = lif_next_token(&bufp); - - if (cur_iface == NULL) - { - report_error(filename, lineno, "%s: gateway '%s' without interface", filename, addr); - goto parse_error; - } - - lif_interface_use_executor(cur_iface, "static"); - lif_dict_add(&cur_iface->vars, token, strdup(addr)); - } - else if (cur_iface != NULL) - { - token = maybe_remap_token(token); - - lif_dict_add(&cur_iface->vars, token, strdup(bufp)); - - /* Check if token looks like - and assume is an addon */ - char *word_end = strchr(token, '-'); - if (word_end != NULL) - { - /* Copy word1 to not mangle *token */ - char *addon = strndup(token, word_end - token); - lif_interface_use_executor(cur_iface, addon); - free(addon); - - /* pass requires as compatibility env vars to appropriate executors (bridge, bond) */ - if (!strcmp(addon, "bridge")) - cur_iface->is_bridge = true; - else if (!strcmp(addon, "bond")) - cur_iface->is_bond = true; - } - } + else if (!handle_generic(collection, filename, lineno, token, bufp)) + goto parse_error; } fclose(f); From 6d15f21073c969749dd1eae8f687abfe41cf6eca Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Thu, 20 Aug 2020 04:07:51 -0600 Subject: [PATCH 6/6] interface: handle is_bridge and is_bond hacks in a single place --- libifupdown/interface-file.c | 12 ------------ libifupdown/interface.c | 6 ++++++ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/libifupdown/interface-file.c b/libifupdown/interface-file.c index 7b2766e..06a3c66 100644 --- a/libifupdown/interface-file.c +++ b/libifupdown/interface-file.c @@ -156,12 +156,6 @@ handle_generic(struct lif_dict *collection, const char *filename, size_t lineno, char *addon = strndup(token, word_end - token); lif_interface_use_executor(cur_iface, addon); free(addon); - - /* pass requires as compatibility env vars to appropriate executors (bridge, bond) */ - if (!strcmp(addon, "bridge")) - cur_iface->is_bridge = true; - else if (!strcmp(addon, "bond")) - cur_iface->is_bond = true; } return true; @@ -270,12 +264,6 @@ handle_use(struct lif_dict *collection, const char *filename, size_t lineno, cha return false; } - /* pass requires as compatibility env vars to appropriate executors (bridge, bond) */ - if (!strcmp(executor, "bridge")) - cur_iface->is_bridge = true; - else if (!strcmp(executor, "bond")) - cur_iface->is_bond = true; - lif_interface_use_executor(cur_iface, executor); return true; } diff --git a/libifupdown/interface.c b/libifupdown/interface.c index fe9acea..b662199 100644 --- a/libifupdown/interface.c +++ b/libifupdown/interface.c @@ -137,6 +137,12 @@ lif_interface_use_executor(struct lif_interface *interface, const char *executor if (lif_dict_add_once(&interface->vars, "use", exec_addon, (lif_dict_cmp_t) strcmp) == NULL) free(exec_addon); + + /* pass requires as compatibility env vars to appropriate executors (bridge, bond) */ + if (!strcmp(executor, "bridge")) + interface->is_bridge = true; + else if (!strcmp(executor, "bond")) + interface->is_bond = true; } void