aboutsummaryrefslogtreecommitdiff
path: root/src/librc/librc.c
diff options
context:
space:
mode:
authorDoug Freed <dwfreed@mtu.edu>2016-12-19 00:43:27 +0000
committerWilliam Hubbs <w.d.hubbs@gmail.com>2016-12-19 18:24:31 -0600
commit45aa36cc623eeeb15fb6827b57e0c07a37cdef41 (patch)
tree6e50402f98f973673143df0933aae6aff9bf85e8 /src/librc/librc.c
parentd3f833179b39368442221c448f90b87f76d28ee8 (diff)
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
Diffstat (limited to 'src/librc/librc.c')
-rw-r--r--src/librc/librc.c35
1 files changed, 29 insertions, 6 deletions
diff --git a/src/librc/librc.c b/src/librc/librc.c
index fdde3d5a..3d3277db 100644
--- a/src/librc/librc.c
+++ b/src/librc/librc.c
@@ -367,11 +367,12 @@ rc_parse_service_state(RC_SERVICE state)
* specified runlevel in dependency order, including the
* specified runlevel. */
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];
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
@@ -395,8 +396,27 @@ get_runlevel_chain(const char *runlevel, RC_STRINGLIST *level_list)
*/
snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel);
dirs = ls_dir(path, LS_DIR);
- TAILQ_FOREACH_SAFE(d, dirs, entries, dn)
- get_runlevel_chain(d->value, level_list);
+ TAILQ_FOREACH(d, dirs, entries) {
+ 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
@@ -500,9 +520,12 @@ librc_hidden_def(rc_runlevel_unstack)
RC_STRINGLIST *
rc_runlevel_stacks(const char *runlevel)
{
- RC_STRINGLIST *stack;
+ RC_STRINGLIST *stack, *ancestor_list;
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;
}
librc_hidden_def(rc_runlevel_stacks)