From 38537339ab4e5959dbaf9f85af35d798a149bddc Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Fri, 24 Jul 2020 03:42:34 -0600 Subject: [PATCH] lifecycle: implement requires keyword --- cmd/ifupdown.c | 8 +++--- libifupdown/interface.h | 2 ++ libifupdown/lifecycle.c | 64 +++++++++++++++++++++++++++++++++++++++-- libifupdown/lifecycle.h | 2 +- 4 files changed, 68 insertions(+), 8 deletions(-) diff --git a/cmd/ifupdown.c b/cmd/ifupdown.c index 24bd70b..e9de1b7 100644 --- a/cmd/ifupdown.c +++ b/cmd/ifupdown.c @@ -60,7 +60,7 @@ is_ifdown() } bool -change_interface(struct lif_interface *iface, struct lif_dict *state, const char *ifname) +change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname) { if (exec_opts.verbose) { @@ -68,7 +68,7 @@ change_interface(struct lif_interface *iface, struct lif_dict *state, const char argv0, ifname, up ? "up" : "down"); } - if (!lif_lifecycle_run(&exec_opts, iface, state, ifname, up)) + if (!lif_lifecycle_run(&exec_opts, iface, collection, state, ifname, up)) { fprintf(stderr, "%s: failed to change interface %s state to '%s'\n", argv0, ifname, up ? "up" : "down"); @@ -99,7 +99,7 @@ change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, stru fnmatch(opts->include_pattern, iface->ifname, 0)) continue; - if (!change_interface(iface, state, iface->ifname)) + if (!change_interface(iface, collection, state, iface->ifname)) return false; } @@ -220,7 +220,7 @@ ifupdown_main(int argc, char *argv[]) iface = entry->data; } - if (!change_interface(iface, &state, ifname)) + if (!change_interface(iface, &collection, &state, ifname)) return EXIT_FAILURE; } diff --git a/libifupdown/interface.h b/libifupdown/interface.h index 37c6151..6d811c8 100644 --- a/libifupdown/interface.h +++ b/libifupdown/interface.h @@ -52,6 +52,8 @@ struct lif_interface { bool is_auto; struct lif_dict vars; + + bool is_up; }; #define LIF_INTERFACE_COLLECTION_FOREACH(iter, collection) \ diff --git a/libifupdown/lifecycle.c b/libifupdown/lifecycle.c index 8892fc3..b25e0d3 100644 --- a/libifupdown/lifecycle.c +++ b/libifupdown/lifecycle.c @@ -264,16 +264,66 @@ on_error: return false; } +static char * +next_token(char **buf) +{ + char *out = *buf; + + while (*out && isspace(*out)) + out++; + + char *end = out; + while (*end && !isspace(*end)) + end++; + + *end++ = '\0'; + *buf = end; + + return out; +} + +static bool +handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *parent, struct lif_dict *collection, struct lif_dict *state, bool up) +{ + struct lif_dict_entry *requires = lif_dict_find(&parent->vars, "requires"); + + /* no dependents, nothing to worry about */ + if (requires == NULL) + return true; + + char require_ifs[4096]; + strlcpy(require_ifs, requires->data, sizeof require_ifs); + char *bufp = require_ifs; + + for (char *tokenp = next_token(&bufp); *tokenp; tokenp = next_token(&bufp)) + { + fprintf(stderr, "next iface: %s\n", tokenp); + + struct lif_interface *iface = lif_interface_collection_find(collection, tokenp); + + /* already up or down, skip */ + if (up == iface->is_up) + continue; + + if (!lif_lifecycle_run(opts, iface, collection, state, iface->ifname, up)) + return false; + } + + return true; +} + bool -lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *iface, struct lif_dict *state, const char *lifname, bool up) +lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *lifname, bool up) { if (lifname == NULL) lifname = iface->ifname; - /* XXX: actually handle dependents here */ - if (up) { + /* when going up, dependents go up first. */ + if (!handle_dependents(opts, iface, collection, state, up)) + return false; + /* XXX: we should try to recover (take the iface down) if bringing it up fails. * but, right now neither debian ifupdown or busybox ifupdown do any recovery, * so we wont right now. @@ -288,6 +338,8 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa return false; lif_state_upsert(state, lifname, iface); + + iface->is_up = true; } else { @@ -300,7 +352,13 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa if (!lif_lifecycle_run_phase(opts, iface, "post-down", lifname, up)) return false; + /* when going up, dependents go down last. */ + if (!handle_dependents(opts, iface, collection, state, up)) + return false; + lif_state_delete(state, lifname); + + iface->is_up = false; } return true; diff --git a/libifupdown/lifecycle.h b/libifupdown/lifecycle.h index fd4cb3a..e5b0adc 100644 --- a/libifupdown/lifecycle.h +++ b/libifupdown/lifecycle.h @@ -20,7 +20,7 @@ #include "libifupdown/execute.h" extern bool lif_lifecycle_run_phase(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *phase, const char *lifname, bool up); -extern bool lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *iface, struct lif_dict *state, const char *lifname, bool up); +extern bool lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *lifname, bool up); #endif