librc: detect loops in stacked runlevels and abort

This fixes #109.
X-Gentoo-Bug: 558700
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=558700
This commit is contained in:
Doug Freed 2016-12-19 00:43:27 +00:00 committed by William Hubbs
parent d3f833179b
commit 45aa36cc62

View File

@ -367,11 +367,12 @@ rc_parse_service_state(RC_SERVICE state)
* specified runlevel in dependency order, including the * specified runlevel in dependency order, including the
* specified runlevel. */ * specified runlevel. */
static void static void
get_runlevel_chain(const char *runlevel, RC_STRINGLIST *level_list) get_runlevel_chain(const char *runlevel, RC_STRINGLIST *level_list, RC_STRINGLIST *ancestor_list)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
RC_STRINGLIST *dirs; RC_STRINGLIST *dirs;
RC_STRING *d, *dn; RC_STRING *d, *parent;
const char *nextlevel;
/* /*
* If we haven't been passed a runlevel or a level list, or * If we haven't been passed a runlevel or a level list, or
@ -395,8 +396,27 @@ get_runlevel_chain(const char *runlevel, RC_STRINGLIST *level_list)
*/ */
snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel); snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel);
dirs = ls_dir(path, LS_DIR); dirs = ls_dir(path, LS_DIR);
TAILQ_FOREACH_SAFE(d, dirs, entries, dn) TAILQ_FOREACH(d, dirs, entries) {
get_runlevel_chain(d->value, level_list); nextlevel = d->value;
/* Check for loop */
if (rc_stringlist_find(ancestor_list, nextlevel)) {
fprintf(stderr, "Loop detected in stacked runlevels attempting to enter runlevel %s!\n",
nextlevel);
fprintf(stderr, "Ancestors:\n");
TAILQ_FOREACH(parent, ancestor_list, entries)
fprintf(stderr, "\t%s\n", parent->value);
exit(1);
}
/* Add new ancestor */
rc_stringlist_add(ancestor_list, nextlevel);
get_runlevel_chain(nextlevel, level_list, ancestor_list);
rc_stringlist_delete(ancestor_list, nextlevel);
}
rc_stringlist_free(dirs);
} }
bool bool
@ -500,9 +520,12 @@ librc_hidden_def(rc_runlevel_unstack)
RC_STRINGLIST * RC_STRINGLIST *
rc_runlevel_stacks(const char *runlevel) rc_runlevel_stacks(const char *runlevel)
{ {
RC_STRINGLIST *stack; RC_STRINGLIST *stack, *ancestor_list;
stack = rc_stringlist_new(); stack = rc_stringlist_new();
get_runlevel_chain(runlevel, stack); ancestor_list = rc_stringlist_new();
rc_stringlist_add(ancestor_list, runlevel);
get_runlevel_chain(runlevel, stack, ancestor_list);
rc_stringlist_free(ancestor_list);
return stack; return stack;
} }
librc_hidden_def(rc_runlevel_stacks) librc_hidden_def(rc_runlevel_stacks)