lifecycle: add support for learning dependents from executors (ref #5)
This commit is contained in:
parent
3a75de9f8c
commit
fb5ff4eac2
6 changed files with 137 additions and 11 deletions
|
@ -21,9 +21,17 @@
|
||||||
#include "libifupdown/libifupdown.h"
|
#include "libifupdown/libifupdown.h"
|
||||||
#include "cmd/multicall.h"
|
#include "cmd/multicall.h"
|
||||||
|
|
||||||
|
static struct lif_execute_opts exec_opts = {
|
||||||
|
.interfaces_file = INTERFACES_FILE,
|
||||||
|
.executor_path = EXECUTOR_PATH
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
print_interface(struct lif_interface *iface)
|
print_interface(struct lif_interface *iface)
|
||||||
{
|
{
|
||||||
|
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
|
||||||
|
return;
|
||||||
|
|
||||||
if (iface->is_auto)
|
if (iface->is_auto)
|
||||||
printf("auto %s\n", iface->ifname);
|
printf("auto %s\n", iface->ifname);
|
||||||
|
|
||||||
|
@ -263,16 +271,16 @@ ifquery_main(int argc, char *argv[])
|
||||||
{"state", no_argument, 0, 's'},
|
{"state", no_argument, 0, 's'},
|
||||||
{"dot", no_argument, 0, 'D'},
|
{"dot", no_argument, 0, 'D'},
|
||||||
{"property", required_argument, 0, 'p'},
|
{"property", required_argument, 0, 'p'},
|
||||||
|
{"executor-path", required_argument, 0, 'E'},
|
||||||
{NULL, 0, 0, 0}
|
{NULL, 0, 0, 0}
|
||||||
};
|
};
|
||||||
struct match_options match_opts = {};
|
struct match_options match_opts = {};
|
||||||
bool listing = false, listing_stat = false;
|
bool listing = false, listing_stat = false;
|
||||||
char *interfaces_file = INTERFACES_FILE;
|
|
||||||
char *state_file = STATE_FILE;
|
char *state_file = STATE_FILE;
|
||||||
|
|
||||||
for (;;)
|
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)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -284,7 +292,7 @@ ifquery_main(int argc, char *argv[])
|
||||||
lif_common_version();
|
lif_common_version();
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
interfaces_file = optarg;
|
exec_opts.interfaces_file = optarg;
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
listing = true;
|
listing = true;
|
||||||
|
@ -313,6 +321,9 @@ ifquery_main(int argc, char *argv[])
|
||||||
case 'p':
|
case 'p':
|
||||||
match_opts.property = optarg;
|
match_opts.property = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'E':
|
||||||
|
exec_opts.executor_path = optarg;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,9 +333,9 @@ ifquery_main(int argc, char *argv[])
|
||||||
return EXIT_FAILURE;
|
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;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
#include "libifupdown/execute.h"
|
#include "libifupdown/execute.h"
|
||||||
|
|
||||||
|
@ -61,7 +62,7 @@ lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const c
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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];
|
char cmdbuf[4096];
|
||||||
va_list va;
|
va_list va;
|
||||||
|
@ -99,8 +100,15 @@ lif_execute_buf_with_result(const struct lif_execute_opts *opts, char *buf, size
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int status;
|
close(pipefds[1]);
|
||||||
waitpid(child, &status, 0);
|
|
||||||
|
struct pollfd pfd = {
|
||||||
|
.fd = pipefds[0],
|
||||||
|
.events = POLLIN
|
||||||
|
};
|
||||||
|
|
||||||
|
if (poll(&pfd, 1, -1) < 1)
|
||||||
|
goto no_result;
|
||||||
|
|
||||||
if (read(pipefds[0], buf, bufsize) < 0)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int status;
|
||||||
|
no_result:
|
||||||
|
waitpid(child, &status, 0);
|
||||||
|
|
||||||
return WIFEXITED(status) && WEXITSTATUS(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);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -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_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_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(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
|
#endif
|
||||||
|
|
|
@ -63,6 +63,89 @@ handle_executors_for_phase(const struct lif_execute_opts *opts, char *const envp
|
||||||
return true;
|
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
|
bool
|
||||||
lif_lifecycle_run_phase(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *phase, const char *lifname, bool up)
|
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)
|
if (lifname == NULL)
|
||||||
lifname = iface->ifname;
|
lifname = iface->ifname;
|
||||||
|
|
||||||
|
if (!lif_lifecycle_query_dependents(opts, iface, lifname))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (up)
|
if (up)
|
||||||
{
|
{
|
||||||
/* when going up, dependents go up first. */
|
/* when going up, dependents go up first. */
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libifupdown/interface.h"
|
#include "libifupdown/interface.h"
|
||||||
#include "libifupdown/execute.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_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_run(const struct lif_execute_opts *opts, struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *lifname, bool up);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
exit 0
|
||||||
echo $0 ${MODE}
|
|
||||||
|
|
Loading…
Reference in a new issue