diff --git a/cmd/ifquery.c b/cmd/ifquery.c index 7e49578..eb01cf5 100644 --- a/cmd/ifquery.c +++ b/cmd/ifquery.c @@ -21,9 +21,17 @@ #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) { + if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname)) + return; + if (iface->is_auto) printf("auto %s\n", iface->ifname); @@ -263,16 +271,16 @@ ifquery_main(int argc, char *argv[]) {"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} }; struct match_options match_opts = {}; bool listing = false, listing_stat = false; - char *interfaces_file = INTERFACES_FILE; char *state_file = STATE_FILE; for (;;) { - int c = getopt_long(argc, argv, "hVi:LaI:X:PS:sDp:", long_options, NULL); + int c = getopt_long(argc, argv, "hVi:LaI:X:PS:sDp:E:", long_options, NULL); if (c == -1) break; @@ -284,7 +292,7 @@ ifquery_main(int argc, char *argv[]) lif_common_version(); break; case 'i': - interfaces_file = optarg; + exec_opts.interfaces_file = optarg; break; case 'L': listing = true; @@ -313,6 +321,9 @@ ifquery_main(int argc, char *argv[]) case 'p': match_opts.property = optarg; break; + case 'E': + exec_opts.executor_path = optarg; + break; } } @@ -322,9 +333,9 @@ ifquery_main(int argc, char *argv[]) return EXIT_FAILURE; } - if (!lif_interface_file_parse(&collection, interfaces_file)) + if (!lif_interface_file_parse(&collection, exec_opts.interfaces_file)) { - fprintf(stderr, "%s: could not parse %s\n", argv0, interfaces_file); + fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file); return EXIT_FAILURE; } diff --git a/libifupdown/execute.c b/libifupdown/execute.c index 09e2d98..9b73df9 100644 --- a/libifupdown/execute.c +++ b/libifupdown/execute.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "libifupdown/execute.h" @@ -61,7 +62,7 @@ lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const c } bool -lif_execute_buf_with_result(const struct lif_execute_opts *opts, char *buf, size_t bufsize, char *const envp[], const char *fmt, ...) +lif_execute_fmt_with_result(const struct lif_execute_opts *opts, char *buf, size_t bufsize, char *const envp[], const char *fmt, ...) { char cmdbuf[4096]; va_list va; @@ -99,8 +100,15 @@ lif_execute_buf_with_result(const struct lif_execute_opts *opts, char *buf, size return false; } - int status; - waitpid(child, &status, 0); + close(pipefds[1]); + + struct pollfd pfd = { + .fd = pipefds[0], + .events = POLLIN + }; + + if (poll(&pfd, 1, -1) < 1) + goto no_result; if (read(pipefds[0], buf, bufsize) < 0) { @@ -108,6 +116,10 @@ lif_execute_buf_with_result(const struct lif_execute_opts *opts, char *buf, size return false; } + int status; +no_result: + waitpid(child, &status, 0); + return WIFEXITED(status) && WEXITSTATUS(status) == 0; } @@ -140,3 +152,19 @@ lif_maybe_run_executor(const struct lif_execute_opts *opts, char *const envp[], return lif_execute_fmt(opts, envp, "%s", pathbuf); } + +bool +lif_maybe_run_executor_with_result(const struct lif_execute_opts *opts, char *const envp[], const char *executor, char *buf, size_t bufsize) +{ + if (opts->verbose) + fprintf(stderr, "ifupdown: attempting to run %s executor\n", executor); + + char pathbuf[4096]; + + snprintf(pathbuf, sizeof pathbuf, "%s/%s", opts->executor_path, executor); + + if (!lif_file_is_executable(pathbuf)) + return true; + + return lif_execute_fmt_with_result(opts, buf, bufsize, envp, "%s", pathbuf); +} diff --git a/libifupdown/execute.h b/libifupdown/execute.h index 44391c9..3fbde45 100644 --- a/libifupdown/execute.h +++ b/libifupdown/execute.h @@ -27,8 +27,9 @@ struct lif_execute_opts { }; extern bool lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...); -extern bool lif_execute_buf_with_result(const struct lif_execute_opts *opts, char *buf, size_t bufsize, char *const envp[], const char *fmt, ...); +extern bool lif_execute_fmt_with_result(const struct lif_execute_opts *opts, char *buf, size_t bufsize, char *const envp[], const char *fmt, ...); extern bool lif_file_is_executable(const char *path); extern bool lif_maybe_run_executor(const struct lif_execute_opts *opts, char *const envp[], const char *executor); +extern bool lif_maybe_run_executor_with_result(const struct lif_execute_opts *opts, char *const envp[], const char *executor, char *buf, size_t bufsize); #endif diff --git a/libifupdown/lifecycle.c b/libifupdown/lifecycle.c index 494d5cb..ffd8c41 100644 --- a/libifupdown/lifecycle.c +++ b/libifupdown/lifecycle.c @@ -63,6 +63,89 @@ handle_executors_for_phase(const struct lif_execute_opts *opts, char *const envp return true; } +static bool +query_dependents_from_executors(const struct lif_execute_opts *opts, char *const envp[], struct lif_interface *iface, char *buf, size_t bufsize) +{ + struct lif_node *iter; + + LIF_DICT_FOREACH(iter, &iface->vars) + { + char resbuf[1024] = {}; + struct lif_dict_entry *entry = iter->data; + struct lif_execute_opts exec_opts = { + .verbose = opts->verbose, + .executor_path = opts->executor_path, + .interfaces_file = opts->interfaces_file + }; + + if (strcmp(entry->key, "use")) + continue; + + const char *cmd = entry->data; + if (!lif_maybe_run_executor_with_result(&exec_opts, envp, cmd, resbuf, sizeof resbuf)) + return false; + + if (!*resbuf) + continue; + + strlcat(buf, " ", bufsize); + strlcat(buf, resbuf, bufsize); + } + + return true; +} + +bool +lif_lifecycle_query_dependents(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *lifname) +{ + char deps[4096] = {}; + char final_deps[4096] = {}; + + if (lifname == NULL) + lifname = iface->ifname; + + char **envp = NULL; + + lif_environment_push(&envp, "IFACE", lifname); + lif_environment_push(&envp, "PHASE", "depend"); + lif_environment_push(&envp, "MODE", "depend"); + + if (opts->verbose) + lif_environment_push(&envp, "VERBOSE", "1"); + + if (opts->interfaces_file) + lif_environment_push(&envp, "INTERFACES_FILE", opts->interfaces_file); + + struct lif_dict_entry *entry = lif_dict_find(&iface->vars, "requires"); + if (entry != NULL) + strlcpy(deps, entry->data, sizeof deps); + + if (!query_dependents_from_executors(opts, envp, iface, deps, sizeof deps)) + return false; + + char *p = deps; + while (*p) + { + char *token = lif_next_token(&p); + + if (strstr(final_deps, token) != NULL) + continue; + + strlcat(final_deps, token, sizeof final_deps); + strlcat(final_deps, " ", sizeof final_deps); + } + + if (entry != NULL) + { + free(entry->data); + entry->data = strdup(final_deps); + } + else + lif_dict_add(&iface->vars, "requires", strdup(final_deps)); + + return true; +} + bool lif_lifecycle_run_phase(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *phase, const char *lifname, bool up) { @@ -196,6 +279,9 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa if (lifname == NULL) lifname = iface->ifname; + if (!lif_lifecycle_query_dependents(opts, iface, lifname)) + return false; + if (up) { /* when going up, dependents go up first. */ diff --git a/libifupdown/lifecycle.h b/libifupdown/lifecycle.h index e5b0adc..aebbf6e 100644 --- a/libifupdown/lifecycle.h +++ b/libifupdown/lifecycle.h @@ -19,6 +19,7 @@ #include "libifupdown/interface.h" #include "libifupdown/execute.h" +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); diff --git a/tests/executors/mock-executor b/tests/executors/mock-executor index ba185da..039e4d0 100755 --- a/tests/executors/mock-executor +++ b/tests/executors/mock-executor @@ -1,3 +1,2 @@ #!/bin/sh - -echo $0 ${MODE} +exit 0