diff --git a/cmd/ifquery.c b/cmd/ifquery.c index 8968d86..855cbb0 100644 --- a/cmd/ifquery.c +++ b/cmd/ifquery.c @@ -290,6 +290,12 @@ ifquery_main(int argc, char *argv[]) return EXIT_FAILURE; } + if (!lif_lifecycle_count_rdepends(&exec_opts, &collection)) + { + fprintf(stderr, "%s: could not validate dependency tree\n", argv0); + return EXIT_FAILURE; + } + /* --list --state is not allowed */ if (listing && listing_stat) generic_usage(self_applet, EXIT_FAILURE); diff --git a/cmd/ifupdown.c b/cmd/ifupdown.c index bc8b657..18bf8eb 100644 --- a/cmd/ifupdown.c +++ b/cmd/ifupdown.c @@ -229,6 +229,12 @@ ifupdown_main(int argc, char *argv[]) return EXIT_FAILURE; } + if (!lif_lifecycle_count_rdepends(&exec_opts, &collection)) + { + fprintf(stderr, "%s: could not validate dependency tree\n", argv0); + return EXIT_FAILURE; + } + if (!lif_state_sync(&state, &collection)) { fprintf(stderr, "%s: could not sync state\n", argv0); diff --git a/libifupdown/lifecycle.c b/libifupdown/lifecycle.c index 5d50248..75f5743 100644 --- a/libifupdown/lifecycle.c +++ b/libifupdown/lifecycle.c @@ -389,3 +389,58 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa return true; } + +static bool +count_interface_rdepends(const struct lif_execute_opts *opts, struct lif_dict *collection, struct lif_interface *parent, size_t depth) +{ + /* query our dependents if we don't have them already */ + if (!lif_lifecycle_query_dependents(opts, parent, parent->ifname)) + return false; + + /* set rdepends_count to depth, dependents will be depth + 1 */ + parent->rdepends_count = depth; + + struct lif_dict_entry *requires = lif_dict_find(&parent->vars, "requires"); + + /* no dependents, nothing to worry about */ + if (requires == NULL) + return true; + + /* walk any dependents */ + char require_ifs[4096] = {}; + strlcpy(require_ifs, requires->data, sizeof require_ifs); + char *bufp = require_ifs; + + for (char *tokenp = lif_next_token(&bufp); *tokenp; tokenp = lif_next_token(&bufp)) + { + struct lif_interface *iface = lif_interface_collection_find(collection, tokenp); + + if (!count_interface_rdepends(opts, collection, iface, depth + 1)) + return false; + } + + return true; +} + +bool +lif_lifecycle_count_rdepends(const struct lif_execute_opts *opts, struct lif_dict *collection) +{ + struct lif_node *iter; + + LIF_DICT_FOREACH(iter, collection) + { + struct lif_dict_entry *entry = iter->data; + struct lif_interface *iface = entry->data; + + /* start depth at interface's rdepends_count, which will be 0 for the root, + * but will be more if additional rdepends are found... + */ + if (!count_interface_rdepends(opts, collection, iface, iface->rdepends_count)) + { + fprintf(stderr, "ifupdown: dependency graph is broken for interface %s\n", iface->ifname); + return false; + } + } + + return true; +} diff --git a/libifupdown/lifecycle.h b/libifupdown/lifecycle.h index aebbf6e..1dcf2e9 100644 --- a/libifupdown/lifecycle.h +++ b/libifupdown/lifecycle.h @@ -22,6 +22,7 @@ extern bool lif_lifecycle_query_dependents(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *lifname); 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 *collection, struct lif_dict *state, const char *lifname, bool up); +extern bool lif_lifecycle_count_rdepends(const struct lif_execute_opts *opts, struct lif_dict *collection); #endif