lifecycle: add support for learning dependents from executors (ref #5)

This commit is contained in:
Ariadne Conill 2020-07-28 13:46:25 -06:00
parent 3a75de9f8c
commit fb5ff4eac2
6 changed files with 137 additions and 11 deletions

View file

@ -24,6 +24,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <poll.h>
#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);
}

View file

@ -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

View file

@ -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. */

View file

@ -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);