From d6da8e8c48feb8faf9287fc86fbbf0890c37a87c Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Fri, 10 Oct 2008 08:37:21 +0000 Subject: sysinit is now a real runlevel that handles things like udev, dmesg and mounting various bits in /dev and /sys. init.sh JUST mounts /lib/rc/init.d (and /proc for Linux systems) To make development of this easier we now return an empty RC_STRINGLIST instead of a NULL for empty things. If you don't have a udev init script installed, don't reboot your box OR roll back to an older OpenRC version. --- src/includes/rc-misc.h | 1 - src/librc/librc-depend.c | 108 ++++---- src/librc/librc-misc.c | 12 +- src/librc/librc.c | 246 +++++++++--------- src/rc/rc-depend.c | 27 +- src/rc/rc-misc.c | 115 +++----- src/rc/rc-service.c | 14 +- src/rc/rc.c | 215 +++------------ src/rc/runscript.c | 663 ++++++++++++++++++++++++++--------------------- 9 files changed, 637 insertions(+), 764 deletions(-) (limited to 'src') diff --git a/src/includes/rc-misc.h b/src/includes/rc-misc.h index 12154b9..e0cfde7 100644 --- a/src/includes/rc-misc.h +++ b/src/includes/rc-misc.h @@ -143,7 +143,6 @@ char *rc_conf_value(const char *var); bool rc_conf_yesno(const char *var); void env_filter(void); void env_config(void); -bool service_plugable(const char *service); int signal_setup(int sig, void (*handler)(int)); pid_t exec_service(const char *, const char *); diff --git a/src/librc/librc-depend.c b/src/librc/librc-depend.c index 20196af..f020e6d 100644 --- a/src/librc/librc-depend.c +++ b/src/librc/librc-depend.c @@ -187,12 +187,21 @@ valid_service(const char *runlevel, const char *service, const char *type) strcmp(type, "needsme") == 0) return true; + if (rc_service_in_runlevel(service, runlevel)) + return true; + if (strcmp(runlevel, RC_LEVEL_SYSINIT) != 0 && + strcmp(runlevel, bootlevel) != 0) + { + if (rc_service_in_runlevel(service, bootlevel)) + return true; + } + state = rc_service_state(service); - return ((strcmp(runlevel, bootlevel) != 0 && - rc_service_in_runlevel(service, bootlevel)) || - rc_service_in_runlevel(service, runlevel) || - state & RC_SERVICE_COLDPLUGGED || - state & RC_SERVICE_STARTED); + if (state & RC_SERVICE_COLDPLUGGED || + state & RC_SERVICE_STARTED) + return true; + + return false; } static bool @@ -344,7 +353,7 @@ get_provided(const RC_DEPINFO *depinfo, const char *runlevel, int options) static void visit_service(const RC_DEPTREE *deptree, const RC_STRINGLIST *types, - RC_STRINGLIST **sorted, + RC_STRINGLIST *sorted, RC_STRINGLIST *visited, const RC_DEPINFO *depinfo, const char *runlevel, int options) @@ -373,9 +382,7 @@ visit_service(const RC_DEPTREE *deptree, if (!(options & RC_DEP_TRACE) || strcmp(type->value, "iprovide") == 0) { - if (!*sorted) - *sorted = rc_stringlist_new(); - rc_stringlist_add(*sorted, service->value); + rc_stringlist_add(sorted, service->value); continue; } @@ -420,12 +427,10 @@ visit_service(const RC_DEPTREE *deptree, /* We've visited everything we need, so add ourselves unless we are also the service calling us or we are provided by something */ svcname = getenv("RC_SVCNAME"); - if (!svcname || strcmp(svcname, depinfo->service) != 0) - if (!get_deptype(depinfo, "providedby")) { - if (!*sorted) - *sorted = rc_stringlist_new(); - rc_stringlist_add(*sorted, depinfo->service); - } + if (!svcname || strcmp(svcname, depinfo->service) != 0) { + if (!get_deptype(depinfo, "providedby")) + rc_stringlist_add(sorted, depinfo->service); + } } RC_STRINGLIST * @@ -437,15 +442,15 @@ rc_deptree_depend(const RC_DEPTREE *deptree, RC_STRINGLIST *svcs; RC_STRING *svc; + svcs = rc_stringlist_new(); if (!(di = get_depinfo(deptree, service)) || !(dt = get_deptype(di, type))) { errno = ENOENT; - return NULL; + return svcs; } /* For consistency, we copy the array */ - svcs = rc_stringlist_new(); TAILQ_FOREACH(svc, dt->services, entries) rc_stringlist_add(svcs, svc->value); return svcs; @@ -458,7 +463,7 @@ rc_deptree_depends(const RC_DEPTREE *deptree, const RC_STRINGLIST *services, const char *runlevel, int options) { - RC_STRINGLIST *sorted = NULL; + RC_STRINGLIST *sorted = rc_stringlist_new(); RC_STRINGLIST *visited = rc_stringlist_new(); RC_DEPINFO *di; const RC_STRING *service; @@ -472,7 +477,7 @@ rc_deptree_depends(const RC_DEPTREE *deptree, continue; } if (types) - visit_service(deptree, types, &sorted, visited, + visit_service(deptree, types, sorted, visited, di, runlevel, options); } rc_stringlist_free(visited); @@ -499,42 +504,25 @@ rc_deptree_order(const RC_DEPTREE *deptree, const char *runlevel, int options) { list = rc_services_in_state(RC_SERVICE_STARTED); list2 = rc_services_in_state(RC_SERVICE_INACTIVE); - if (list2) { - if (list) { - TAILQ_CONCAT(list, list2, entries); - free(list2); - } else - list = list2; - } + TAILQ_CONCAT(list, list2, entries); + free(list2); list2 = rc_services_in_state(RC_SERVICE_STARTING); - if (list2) { - if (list) { - TAILQ_CONCAT(list, list2, entries); - free(list2); - } else - list = list2; - } + TAILQ_CONCAT(list, list2, entries); + free(list2); } else { - list = rc_services_in_runlevel(runlevel); - /* Add coldplugged services */ - list2 = rc_services_in_state(RC_SERVICE_COLDPLUGGED); - if (list2) { - if (list) { + list = rc_services_in_runlevel(RC_LEVEL_SYSINIT); + if (strcmp(runlevel, RC_LEVEL_SYSINIT) != 0) { + list2 = rc_services_in_runlevel(runlevel); + TAILQ_CONCAT(list, list2, entries); + free(list2); + list2 = rc_services_in_state(RC_SERVICE_COLDPLUGGED); + TAILQ_CONCAT(list, list2, entries); + free(list2); + /* If we're not the boot runlevel then add that too */ + if (strcmp(runlevel, bootlevel) != 0) { + list2 = rc_services_in_runlevel(bootlevel); TAILQ_CONCAT(list, list2, entries); free(list2); - } else - list = list2; - } - - /* If we're not the boot runlevel then add that too */ - if (strcmp(runlevel, bootlevel) != 0) { - list2 = rc_services_in_runlevel (bootlevel); - if (list2) { - if (list) { - TAILQ_CONCAT(list, list2, entries); - free(list2); - } else - list = list2; } } } @@ -683,15 +671,13 @@ rc_deptree_update_needed(void) /* Some init scripts dependencies change depending on config files * outside of baselayout, like syslog-ng, so we check those too. */ config = rc_config_list(RC_DEPCONFIG); - if (config) { - TAILQ_FOREACH(s, config, entries) { - if (!rc_newer_than(RC_DEPTREE_CACHE, s->value)) { - newer = true; - break; - } + TAILQ_FOREACH(s, config, entries) { + if (!rc_newer_than(RC_DEPTREE_CACHE, s->value)) { + newer = true; + break; } - rc_stringlist_free(config); } + rc_stringlist_free(config); return newer; } librc_hidden_def(rc_deptree_update_needed) @@ -907,13 +893,11 @@ rc_deptree_update(void) deptype = get_deptype(depinfo, "ibefore"); if (!deptype) continue; - sorted = NULL; + sorted = rc_stringlist_new(); visited = rc_stringlist_new(); - visit_service(deptree, types, &sorted, visited, depinfo, + visit_service(deptree, types, sorted, visited, depinfo, NULL, 0); rc_stringlist_free(visited); - if (!sorted) - continue; TAILQ_FOREACH_SAFE(s2, deptype->services, entries, s2_np) { TAILQ_FOREACH(s3, sorted, entries) { di = get_depinfo(deptree, s3->value); diff --git a/src/librc/librc-misc.c b/src/librc/librc-misc.c index b615700..749fd81 100644 --- a/src/librc/librc-misc.c +++ b/src/librc/librc-misc.c @@ -84,10 +84,10 @@ RC_STRINGLIST *rc_config_list(const char *file) size_t len = 0; char *p; char *token; - RC_STRINGLIST *list = NULL; + RC_STRINGLIST *list = rc_stringlist_new(); if (!(fp = fopen(file, "r"))) - return NULL; + return list; while ((rc_getline(&buffer, &len, fp))) { p = buffer; @@ -104,8 +104,6 @@ RC_STRINGLIST *rc_config_list(const char *file) if (token[strlen(token) - 1] == '\n') token[strlen(token) - 1] = 0; - if (!list) - list = rc_stringlist_new(); rc_stringlist_add(list, token); } } @@ -131,9 +129,6 @@ RC_STRINGLIST *rc_config_load(const char *file) char *p; list = rc_config_list(file); - if (!list) - return NULL; - config = rc_stringlist_new(); TAILQ_FOREACH(line, list, entries) { /* Get entry */ @@ -203,9 +198,6 @@ char *rc_config_value(RC_STRINGLIST *list, const char *entry) RC_STRING *line; char *p; - if (!list) - return NULL; - TAILQ_FOREACH(line, list, entries) { p = strchr(line->value, '='); if (p && diff --git a/src/librc/librc.c b/src/librc/librc.c index e97425e..b625b06 100644 --- a/src/librc/librc.c +++ b/src/librc/librc.c @@ -67,7 +67,8 @@ static const rc_service_state_name_t rc_service_state_names[] = { #define LS_INITD 0x01 #define LS_DIR 0x02 -static RC_STRINGLIST *ls_dir(const char *dir, int options) +static RC_STRINGLIST * +ls_dir(const char *dir, int options) { DIR *dp; struct dirent *d; @@ -77,15 +78,15 @@ static RC_STRINGLIST *ls_dir(const char *dir, int options) char file[PATH_MAX]; int r; + list = rc_stringlist_new(); if ((dp = opendir(dir)) == NULL) - return NULL; - + return list; while (((d = readdir(dp)) != NULL)) { if (d->d_name[0] != '.') { if (options & LS_INITD) { /* Check that our file really exists. - * This is important as a service maybe in a runlevel, but - * could also have been removed. */ + * This is important as a service maybe in a + * runlevel, but could have been removed. */ snprintf(file, sizeof(file), "%s/%s", dir, d->d_name); r = stat(file, &buf); @@ -104,17 +105,15 @@ static RC_STRINGLIST *ls_dir(const char *dir, int options) ! S_ISDIR(buf.st_mode)) continue; } - if (! list) - list = rc_stringlist_new(); rc_stringlist_add(list, d->d_name); } } closedir(dp); - return list; } -static bool rm_dir(const char *pathname, bool top) +static bool +rm_dir(const char *pathname, bool top) { DIR *dp; struct dirent *d; @@ -127,16 +126,17 @@ static bool rm_dir(const char *pathname, bool top) errno = 0; while (((d = readdir(dp)) != NULL) && errno == 0) { - if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) { - snprintf(file, sizeof(file), "%s/%s", pathname, d->d_name); - + if (strcmp(d->d_name, ".") != 0 && + strcmp(d->d_name, "..") != 0) + { + snprintf(file, sizeof(file), + "%s/%s", pathname, d->d_name); if (stat(file, &s) != 0) { retval = false; break; } - if (S_ISDIR(s.st_mode)) { - if (! rm_dir(file, true)) + if (!rm_dir(file, true)) { retval = false; break; @@ -151,7 +151,7 @@ static bool rm_dir(const char *pathname, bool top) } closedir(dp); - if (! retval) + if (!retval) return false; if (top && rmdir(pathname) != 0) @@ -162,7 +162,8 @@ static bool rm_dir(const char *pathname, bool top) /* Other systems may need this at some point, but for now it's Linux only */ #ifdef __linux__ -static bool file_regex(const char *file, const char *regex) +static bool +file_regex(const char *file, const char *regex) { FILE *fp; char *line = NULL; @@ -171,12 +172,12 @@ static bool file_regex(const char *file, const char *regex) bool retval = false; int result; - if (! (fp = fopen(file, "r"))) + if (!(fp = fopen(file, "r"))) return false; if ((result = regcomp(&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) { fclose(fp); - line = xmalloc(sizeof (char) * BUFSIZ); + line = xmalloc(sizeof(char) * BUFSIZ); regerror(result, &re, line, BUFSIZ); fprintf(stderr, "file_regex: %s", line); free(line); @@ -197,8 +198,8 @@ static bool file_regex(const char *file, const char *regex) } #endif - -const char *rc_sys(void) +const char * +rc_sys(void) { #ifdef PREFIX return RC_SYS_PREFIX; @@ -242,7 +243,8 @@ const char *rc_sys(void) } librc_hidden_def(rc_sys) -static const char *rc_parse_service_state(RC_SERVICE state) +static const char * +rc_parse_service_state(RC_SERVICE state) { int i; @@ -250,17 +252,18 @@ static const char *rc_parse_service_state(RC_SERVICE state) if (rc_service_state_names[i].state == state) return rc_service_state_names[i].name; } - return NULL; } -bool rc_runlevel_starting(void) +bool +rc_runlevel_starting(void) { return exists(RC_STARTING); } librc_hidden_def(rc_runlevel_starting) -bool rc_runlevel_stopping(void) +bool +rc_runlevel_stopping(void) { return exists(RC_STOPPING); } @@ -272,15 +275,17 @@ RC_STRINGLIST *rc_runlevel_list(void) } librc_hidden_def(rc_runlevel_list) -char *rc_runlevel_get(void) +char * +rc_runlevel_get(void) { FILE *fp; char *runlevel = NULL; + size_t i; if ((fp = fopen(RC_RUNLEVEL, "r"))) { runlevel = xmalloc(sizeof(char) * PATH_MAX); if (fgets(runlevel, PATH_MAX, fp)) { - int i = strlen(runlevel) - 1; + i = strlen(runlevel) - 1; if (runlevel[i] == '\n') runlevel[i] = 0; } else @@ -288,7 +293,7 @@ char *rc_runlevel_get(void) fclose(fp); } - if (! runlevel || ! *runlevel) { + if (!runlevel || !*runlevel) { free(runlevel); runlevel = xstrdup(RC_LEVEL_SYSINIT); } @@ -297,11 +302,12 @@ char *rc_runlevel_get(void) } librc_hidden_def(rc_runlevel_get) -bool rc_runlevel_set(const char *runlevel) +bool +rc_runlevel_set(const char *runlevel) { FILE *fp = fopen(RC_RUNLEVEL, "w"); - if (! fp) + if (!fp) return false; fprintf(fp, "%s", runlevel); fclose(fp); @@ -309,14 +315,14 @@ bool rc_runlevel_set(const char *runlevel) } librc_hidden_def(rc_runlevel_set) -bool rc_runlevel_exists(const char *runlevel) +bool +rc_runlevel_exists(const char *runlevel) { char path[PATH_MAX]; struct stat buf; - if (! runlevel) + if (!runlevel) return false; - snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel); if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) return true; @@ -325,14 +331,15 @@ bool rc_runlevel_exists(const char *runlevel) librc_hidden_def(rc_runlevel_exists) /* Resolve a service name to it's full path */ -char *rc_service_resolve(const char *service) +char * +rc_service_resolve(const char *service) { char buffer[PATH_MAX]; char file[PATH_MAX]; int r; struct stat buf; - if (! service) + if (!service) return NULL; if (service[0] == '/') @@ -377,14 +384,15 @@ char *rc_service_resolve(const char *service) } librc_hidden_def(rc_service_resolve) -bool rc_service_exists(const char *service) +bool +rc_service_exists(const char *service) { char *file; bool retval = false; int len; struct stat buf; - if (! service) + if (!service) return false; len = strlen(service); @@ -395,7 +403,7 @@ bool rc_service_exists(const char *service) service[len - 1] == 'h') return false; - if (! (file = rc_service_resolve(service))) + if (!(file = rc_service_resolve(service))) return false; if (stat(file, &buf) == 0 && buf.st_mode & S_IXUGO) @@ -406,7 +414,8 @@ bool rc_service_exists(const char *service) librc_hidden_def(rc_service_exists) #define OPTSTR ". '%s'; echo \"${opts}\"" -RC_STRINGLIST *rc_service_extra_commands(const char *service) +RC_STRINGLIST * +rc_service_extra_commands(const char *service) { char *svc; char *cmd = NULL; @@ -418,10 +427,9 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service) FILE *fp; size_t l; - if (! (svc = rc_service_resolve(service))) + if (!(svc = rc_service_resolve(service))) return NULL; - l = strlen(OPTSTR) + strlen(svc) + 1; cmd = xmalloc(sizeof(char) * l); snprintf(cmd, l, OPTSTR, svc); @@ -431,7 +439,7 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service) rc_getline(&buffer, &len, fp); p = buffer; while ((token = strsep(&p, " "))) { - if (! commands) + if (!commands) commands = rc_stringlist_new(); rc_stringlist_add(commands, token); } @@ -444,7 +452,8 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service) librc_hidden_def(rc_service_extra_commands) #define DESCSTR ". '%s'; echo \"${description%s%s}\"" -char *rc_service_description(const char *service, const char *option) +char * +rc_service_description(const char *service, const char *option) { char *svc; char *cmd; @@ -453,7 +462,7 @@ char *rc_service_description(const char *service, const char *option) FILE *fp; size_t l; - if (! (svc = rc_service_resolve(service))) + if (!(svc = rc_service_resolve(service))) return NULL; if (!option) @@ -472,7 +481,8 @@ char *rc_service_description(const char *service, const char *option) } librc_hidden_def(rc_service_description) -bool rc_service_in_runlevel(const char *service, const char *runlevel) +bool +rc_service_in_runlevel(const char *service, const char *runlevel) { char file[PATH_MAX]; @@ -482,7 +492,8 @@ bool rc_service_in_runlevel(const char *service, const char *runlevel) } librc_hidden_def(rc_service_in_runlevel) -bool rc_service_mark(const char *service, const RC_SERVICE state) +bool +rc_service_mark(const char *service, const RC_SERVICE state) { char file[PATH_MAX]; int i = 0; @@ -496,11 +507,10 @@ bool rc_service_mark(const char *service, const RC_SERVICE state) RC_STRING *dir; int serrno; - if (! init) + if (!init) return false; base = basename_c(service); - if (state != RC_SERVICE_STOPPED) { if (!exists(init)) { free(init); @@ -583,29 +593,26 @@ bool rc_service_mark(const char *service, const RC_SERVICE state) if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) { snprintf(file, sizeof(file), RC_SVCDIR "/%s", "scheduled"); dirs = ls_dir(file, 0); - if (dirs) { - TAILQ_FOREACH(dir, dirs, entries) { - snprintf(was, sizeof(was), "%s/%s/%s", - file, dir->value, base); - unlink(was); - - /* Try and remove the dir - we don't care about errors */ - snprintf(was, sizeof(was), "%s/%s", - file, dir->value); - serrno = errno; - rmdir(was); - errno = serrno; - } - rc_stringlist_free(dirs); + TAILQ_FOREACH(dir, dirs, entries) { + snprintf(was, sizeof(was), "%s/%s/%s", + file, dir->value, base); + unlink(was); + + /* Try and remove the dir; we don't care about errors */ + snprintf(was, sizeof(was), "%s/%s", file, dir->value); + serrno = errno; + rmdir(was); + errno = serrno; } + rc_stringlist_free(dirs); } - free(init); return true; } librc_hidden_def(rc_service_mark) -RC_SERVICE rc_service_state(const char *service) +RC_SERVICE +rc_service_state(const char *service) { int i; int state = RC_SERVICE_STOPPED; @@ -627,25 +634,24 @@ RC_SERVICE rc_service_state(const char *service) if (state & RC_SERVICE_STOPPED) { dirs = ls_dir(RC_SVCDIR "/scheduled", 0); - if (dirs) { - TAILQ_FOREACH (dir, dirs, entries) { - snprintf(file, sizeof(file), - RC_SVCDIR "/scheduled/%s/%s", - dir->value, service); - if (exists(file)) { - state |= RC_SERVICE_SCHEDULED; - break; - } + TAILQ_FOREACH (dir, dirs, entries) { + snprintf(file, sizeof(file), + RC_SVCDIR "/scheduled/%s/%s", + dir->value, service); + if (exists(file)) { + state |= RC_SERVICE_SCHEDULED; + break; } - rc_stringlist_free(dirs); } + rc_stringlist_free(dirs); } return state; } librc_hidden_def(rc_service_state) -char *rc_service_value_get(const char *service, const char *option) +char * +rc_service_value_get(const char *service, const char *option) { FILE *fp; char *line = NULL; @@ -663,8 +669,9 @@ char *rc_service_value_get(const char *service, const char *option) } librc_hidden_def(rc_service_value_get) -bool rc_service_value_set(const char *service, const char *option, - const char *value) +bool +rc_service_value_set(const char *service, const char *option, + const char *value) { FILE *fp; char file[PATH_MAX]; @@ -685,8 +692,8 @@ bool rc_service_value_set(const char *service, const char *option, librc_hidden_def(rc_service_value_set) -bool rc_service_schedule_start(const char *service, - const char *service_to_start) +bool +rc_service_schedule_start(const char *service, const char *service_to_start) { char file[PATH_MAX]; char *p = file; @@ -703,32 +710,34 @@ bool rc_service_schedule_start(const char *service, return false; init = rc_service_resolve(service_to_start); - snprintf(p, sizeof(file) - (p - file), "/%s", basename_c(service_to_start)); + snprintf(p, sizeof(file) - (p - file), + "/%s", basename_c(service_to_start)); retval = (exists(file) || symlink(init, file) == 0); free(init); - return retval; } librc_hidden_def(rc_service_schedule_start) -bool rc_service_schedule_clear(const char *service) +bool +rc_service_schedule_clear(const char *service) { char dir[PATH_MAX]; snprintf(dir, sizeof(dir), RC_SVCDIR "/scheduled/%s", basename_c(service)); - if (! rm_dir(dir, true) && errno == ENOENT) + if (!rm_dir(dir, true) && errno == ENOENT) return true; return false; } librc_hidden_def(rc_service_schedule_clear) -RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel) +RC_STRINGLIST * +rc_services_in_runlevel(const char *runlevel) { char dir[PATH_MAX]; - RC_STRINGLIST *list; + RC_STRINGLIST *list = NULL; - if (! runlevel) { + if (!runlevel) { #ifdef RC_PKG_INITDIR RC_STRINGLIST *pkg = ls_dir(RC_PKG_INITDIR, LS_INITD); #endif @@ -739,36 +748,32 @@ RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel) list = ls_dir(RC_INITDIR, LS_INITD); #ifdef RC_PKG_INITDIR - if (pkg) { - TAILQ_CONCAT(list, pkg, entries); - free(pkg); - } + TAILQ_CONCAT(list, pkg, entries); + free(pkg); #endif #ifdef RC_LOCAL_INITDIR - if (local) { - TAILQ_CONCAT(list, local, entries); - free(local); - } + TAILQ_CONCAT(list, local, entries); + free(local); #endif return list; } /* These special levels never contain any services */ - if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 || - strcmp(runlevel, RC_LEVEL_SINGLE) == 0) { - return NULL; + if (strcmp(runlevel, RC_LEVEL_SINGLE) != 0) { + snprintf(dir, sizeof(dir), RC_RUNLEVELDIR "/%s", runlevel); + list = ls_dir(dir, LS_INITD); } - - snprintf(dir, sizeof(dir), RC_RUNLEVELDIR "/%s", runlevel); - list = ls_dir(dir, LS_INITD); + if (!list) + list = rc_stringlist_new(); return list; } librc_hidden_def(rc_services_in_runlevel) -RC_STRINGLIST *rc_services_in_state(RC_SERVICE state) +RC_STRINGLIST * +rc_services_in_state(RC_SERVICE state) { RC_STRINGLIST *services; - RC_STRINGLIST *list = NULL; + RC_STRINGLIST *list; RC_STRINGLIST *dirs; RC_STRING *d; char dir[PATH_MAX]; @@ -780,28 +785,26 @@ RC_STRINGLIST *rc_services_in_state(RC_SERVICE state) if (state != RC_SERVICE_SCHEDULED) return ls_dir(dir, LS_INITD); - dirs = ls_dir(dir, 0); + list = rc_stringlist_new(); if (! dirs) - return NULL; + return list; TAILQ_FOREACH(d, dirs, entries) { snprintf(p, sizeof(dir) - (p - dir), "/%s", d->value); services = ls_dir(dir, LS_INITD); - if (! list) - services = list; - else if (services) { + if (services) { TAILQ_CONCAT(list, services, entries); free(services); } } rc_stringlist_free(dirs); - return list; } librc_hidden_def(rc_services_in_state) -bool rc_service_add(const char *runlevel, const char *service) +bool +rc_service_add(const char *runlevel, const char *service) { bool retval; char *init; @@ -811,7 +814,7 @@ bool rc_service_add(const char *runlevel, const char *service) char binit[PATH_MAX]; char *i; - if (! rc_runlevel_exists(runlevel)) { + if (!rc_runlevel_exists(runlevel)) { errno = ENOENT; return false; } @@ -827,12 +830,11 @@ bool rc_service_add(const char *runlevel, const char *service) /* We need to ensure that only things in /etc/init.d are added * to the boot runlevel */ - if (strcmp (runlevel, RC_LEVEL_BOOT) == 0) { + if (strcmp(runlevel, RC_LEVEL_BOOT) == 0) { p = realpath(dirname(init), path); - if (! *p) { + if (!*p) { free(init); return false; - } if (strcmp(path, RC_INITDIR) != 0) { free(init); @@ -849,7 +851,8 @@ bool rc_service_add(const char *runlevel, const char *service) } librc_hidden_def(rc_service_add) -bool rc_service_delete (const char *runlevel, const char *service) +bool +rc_service_delete(const char *runlevel, const char *service) { char file[PATH_MAX]; @@ -861,32 +864,27 @@ bool rc_service_delete (const char *runlevel, const char *service) } librc_hidden_def(rc_service_delete) -RC_STRINGLIST *rc_services_scheduled_by(const char *service) +RC_STRINGLIST * +rc_services_scheduled_by(const char *service) { RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0); - RC_STRINGLIST *list = NULL; + RC_STRINGLIST *list = rc_stringlist_new(); RC_STRING *dir; char file[PATH_MAX]; - if (! dirs) - return NULL; - TAILQ_FOREACH (dir, dirs, entries) { snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s/%s", dir->value, service); - if (exists(file)) { - if (! list) - list = rc_stringlist_new(); + if (exists(file)) rc_stringlist_add(list, file); - } } rc_stringlist_free(dirs); - return list; } librc_hidden_def(rc_services_scheduled_by) -RC_STRINGLIST *rc_services_scheduled(const char *service) +RC_STRINGLIST * +rc_services_scheduled(const char *service) { char dir[PATH_MAX]; diff --git a/src/rc/rc-depend.c b/src/rc/rc-depend.c index 1166d4c..1cd32ff 100644 --- a/src/rc/rc-depend.c +++ b/src/rc/rc-depend.c @@ -48,7 +48,8 @@ extern const char *applet; -RC_DEPTREE *_rc_deptree_load(int *regen) { +RC_DEPTREE * +_rc_deptree_load(int *regen) { int fd; int retval; int serrno = errno; @@ -65,12 +66,10 @@ RC_DEPTREE *_rc_deptree_load(int *regen) { if (regen) *regen = 1; - ebegin("Caching service dependencies"); retval = rc_deptree_update(); eend (retval ? 0 : -1, "Failed to update the dependency tree"); } - return rc_deptree_load(); } @@ -96,7 +95,8 @@ static const char * const longopts_help[] = { }; #include "_usage.c" -int rc_depend(int argc, char **argv) +int +rc_depend(int argc, char **argv) { RC_STRINGLIST *list; RC_STRINGLIST *types; @@ -112,7 +112,6 @@ int rc_depend(int argc, char **argv) char *token; types = rc_stringlist_new(); - while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { @@ -145,14 +144,14 @@ int rc_depend(int argc, char **argv) ebegin("Caching service dependencies"); update = rc_deptree_update(); eend(update ? 0 : -1, "%s: %s", applet, strerror(errno)); - if (! update) + if (!update) eerrorx("Failed to update the dependency tree"); } - if (! (deptree = _rc_deptree_load(NULL))) + if (!(deptree = _rc_deptree_load(NULL))) eerrorx("failed to load deptree"); - if (! runlevel) + if (!runlevel) runlevel = rc_runlevel_get(); services = rc_stringlist_new(); @@ -161,8 +160,9 @@ int rc_depend(int argc, char **argv) rc_stringlist_add(list, argv[optind]); errno = 0; depends = rc_deptree_depends(deptree, NULL, list, runlevel, 0); - if (! depends && errno == ENOENT) - eerror("no dependency info for service `%s'", argv[optind]); + if (!depends && errno == ENOENT) + eerror("no dependency info for service `%s'", + argv[optind]); else rc_stringlist_add(services, argv[optind]); @@ -170,7 +170,7 @@ int rc_depend(int argc, char **argv) rc_stringlist_free(list); optind++; } - if (! TAILQ_FIRST(services)) { + if (!TAILQ_FIRST(services)) { rc_stringlist_free(services); rc_stringlist_free(types); rc_deptree_free(deptree); @@ -181,12 +181,13 @@ int rc_depend(int argc, char **argv) } /* If we don't have any types, then supply some defaults */ - if (! TAILQ_FIRST(types)) { + if (!TAILQ_FIRST(types)) { rc_stringlist_add(types, "ineed"); rc_stringlist_add(types, "iuse"); } - depends = rc_deptree_depends(deptree, types, services, runlevel, options); + depends = rc_deptree_depends(deptree, types, services, + runlevel, options); if (TAILQ_FIRST(depends)) { TAILQ_FOREACH(s, depends, entries) { diff --git a/src/rc/rc-misc.c b/src/rc/rc-misc.c index 2784638..58af141 100644 --- a/src/rc/rc-misc.c +++ b/src/rc/rc-misc.c @@ -62,13 +62,15 @@ static RC_STRINGLIST *rc_conf = NULL; extern char** environ; #ifdef DEBUG_MEMORY -static void _free_rc_conf(void) +static void +_free_rc_conf(void) { rc_stringlist_free(rc_conf); } #endif -char *rc_conf_value(const char *setting) +char * +rc_conf_value(const char *setting) { RC_STRINGLIST *old; RC_STRING *s; @@ -83,31 +85,28 @@ char *rc_conf_value(const char *setting) /* Support old configs */ if (exists(RC_CONF_OLD)) { old = rc_config_load(RC_CONF_OLD); - if (old) { - if (rc_conf) { - TAILQ_CONCAT(rc_conf, old, entries); - free(old); - } else - rc_conf = old; - } + TAILQ_CONCAT(rc_conf, old, entries); +#ifdef DEBUG_MEMORY + free(old); +#endif } /* Convert old uppercase to lowercase */ - if (rc_conf) - TAILQ_FOREACH(s, rc_conf, entries) { - p = s->value; - while (p && *p && *p != '=') { - if (isupper((unsigned char)*p)) - *p = tolower((unsigned char)*p); - p++; - } + TAILQ_FOREACH(s, rc_conf, entries) { + p = s->value; + while (p && *p && *p != '=') { + if (isupper((unsigned char)*p)) + *p = tolower((unsigned char)*p); + p++; } + } } return rc_config_value(rc_conf, setting); } -bool rc_conf_yesno(const char *setting) +bool +rc_conf_yesno(const char *setting) { return rc_yesno(rc_conf_value (setting)); } @@ -122,10 +121,11 @@ static const char *const env_whitelist[] = { NULL }; -void env_filter(void) +void +env_filter(void) { RC_STRINGLIST *env_allow; - RC_STRINGLIST *profile = NULL; + RC_STRINGLIST *profile; RC_STRINGLIST *env_list; RC_STRING *env; char *e; @@ -133,8 +133,7 @@ void env_filter(void) /* Add the user defined list of vars */ env_allow = rc_stringlist_split(rc_conf_value("rc_env_allow"), " "); - if (exists(PROFILE_ENV)) - profile = rc_config_load(PROFILE_ENV); + profile = rc_config_load(PROFILE_ENV); /* Copy the env and work from this so we can manipulate it safely */ env_list = rc_stringlist_new(); @@ -163,21 +162,22 @@ void env_filter(void) } /* Now add anything missing from the profile */ - if (profile) { - TAILQ_FOREACH(env, profile, entries) { - e = strchr(env->value, '='); - *e = '\0'; - if (!getenv(env->value)) - setenv(env->value, e + 1, 1); - } + TAILQ_FOREACH(env, profile, entries) { + e = strchr(env->value, '='); + *e = '\0'; + if (!getenv(env->value)) + setenv(env->value, e + 1, 1); } - + +#ifdef DEBUG_MEMORY rc_stringlist_free(env_list); rc_stringlist_free(env_allow); rc_stringlist_free(profile); +#endif } -void env_config(void) +void +env_config(void) { size_t pplen = strlen(PATH_PREFIX); char *path; @@ -203,7 +203,8 @@ void env_config(void) e = p = xmalloc(sizeof(char) * l); p += snprintf(p, l, "%s", PATH_PREFIX); - /* Now go through the env var and only add bits not in our PREFIX */ + /* Now go through the env var and only add bits not in our + * PREFIX */ while ((token = strsep(&path, ":"))) { np = npp = xstrdup(PATH_PREFIX); while ((tok = strsep(&npp, ":"))) @@ -259,48 +260,8 @@ void env_config(void) setenv("EINFO_COLOR", "NO", 1); } -bool service_plugable(const char *service) -{ - char *list; - char *p; - char *star; - char *token; - bool allow = true; - char *match = rc_conf_value("rc_plug_services"); - bool truefalse; - - if (! match) - return true; - - list = xstrdup(match); - p = list; - while ((token = strsep(&p, " "))) { - if (token[0] == '!') { - truefalse = false; - token++; - } else - truefalse = true; - - star = strchr(token, '*'); - if (star) { - if (strncmp(service, token, (size_t)(star - token)) == 0) - { - allow = truefalse; - break; - } - } else { - if (strcmp(service, token) == 0) { - allow = truefalse; - break; - } - } - } - - free(list); - return allow; -} - -int signal_setup(int sig, void (*handler)(int)) +int +signal_setup(int sig, void (*handler)(int)) { struct sigaction sa; @@ -310,7 +271,8 @@ int signal_setup(int sig, void (*handler)(int)) return sigaction(sig, &sa, NULL); } -pid_t exec_service(const char *service, const char *arg) +pid_t +exec_service(const char *service, const char *arg) { char *file; char fifo[PATH_MAX]; @@ -320,7 +282,7 @@ pid_t exec_service(const char *service, const char *arg) struct sigaction sa; file = rc_service_resolve(service); - if (! exists(file)) { + if (!exists(file)) { rc_service_mark(service, RC_SERVICE_STOPPED); free(file); return 0; @@ -368,7 +330,6 @@ pid_t exec_service(const char *service, const char *arg) sigprocmask(SIG_SETMASK, &old, NULL); free(file); - return pid; } diff --git a/src/rc/rc-service.c b/src/rc/rc-service.c index 11b6b58..ab3d47b 100644 --- a/src/rc/rc-service.c +++ b/src/rc/rc-service.c @@ -58,7 +58,8 @@ static const char * const longopts_help[] = { }; #include "_usage.c" -int rc_service(int argc, char **argv) +int +rc_service(int argc, char **argv) { int opt; char *service; @@ -75,17 +76,21 @@ int rc_service(int argc, char **argv) case 'e': service = rc_service_resolve(optarg); opt = service ? EXIT_SUCCESS : EXIT_FAILURE; +#ifdef DEBUG_MEMORY free(service); +#endif return opt; /* NOTREACHED */ case 'l': list = rc_services_in_runlevel(NULL); - if (! list) + if (!TAILQ_FIRST(list)) return EXIT_FAILURE; rc_stringlist_sort(&list); TAILQ_FOREACH(s, list, entries) printf("%s\n", s->value); +#ifdef DEBUG_MEMORY rc_stringlist_free(list); +#endif return EXIT_SUCCESS; /* NOTREACHED */ case 'r': @@ -93,7 +98,9 @@ int rc_service(int argc, char **argv) if (!service) return EXIT_FAILURE; printf("%s\n", service); +#ifdef DEBUG_MEMORY free(service); +#endif return EXIT_SUCCESS; /* NOTREACHED */ @@ -103,13 +110,10 @@ int rc_service(int argc, char **argv) argc -= optind; argv += optind; - if (!*argv) eerrorx("%s: you need to specify a service", applet); - if (!(service = rc_service_resolve(*argv))) eerrorx("%s: service `%s' does not exist", applet, *argv); - *argv = service; execv(*argv, argv); eerrorx("%s: %s", applet, strerror(errno)); diff --git a/src/rc/rc.c b/src/rc/rc.c index 4fee700..cb4045f 100644 --- a/src/rc/rc.c +++ b/src/rc/rc.c @@ -43,12 +43,6 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples"; #include #include -/* So we can coldplug net devices */ -#ifdef BSD -# include -# include -#endif - #ifdef __linux__ # include /* for COMMAND_LINE_SIZE */ #endif @@ -519,115 +513,10 @@ static void handle_signal(int sig) errno = serrno; } -static void do_coldplug(void) -{ - size_t l; - DIR *dp; - struct dirent *d; - char *service; - RC_STRING *s; -#ifdef BSD - struct ifaddrs *ifap; - struct ifaddrs *ifa; - char *p; -#endif - - errno = 0; - if (!rc_conf_yesno("rc_coldplug") && errno != ENOENT) - return; - - /* We need to ensure our state dirs exist. - * We should have a better call than this, but oh well. */ - rc_deptree_update_needed(); - -#ifdef BSD - if (getifaddrs(&ifap) == 0) { - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - - l = strlen("net.") + strlen(ifa->ifa_name) + 1; - service = xmalloc(sizeof (char) * l); - snprintf(service, l, "net.%s", ifa->ifa_name); - if (rc_service_exists(service) && - service_plugable(service)) - rc_service_mark(service, RC_SERVICE_COLDPLUGGED); - free(service); - } - freeifaddrs (ifap); - } - - /* The mice are a little more tricky. - * If we coldplug anything else, we'll probably do it here. */ - if ((dp = opendir("/dev"))) { - while ((d = readdir(dp))) { - if (strncmp(d->d_name, "psm", 3) == 0 || - strncmp(d->d_name, "ums", 3) == 0) - { - p = d->d_name + 3; - if (p && isdigit((unsigned char)*p)) { - l = strlen("moused.") + strlen(d->d_name) + 1; - service = xmalloc(sizeof(char) * l); - snprintf (service, l, "moused.%s", d->d_name); - if (rc_service_exists (service) && - service_plugable (service)) - rc_service_mark (service, RC_SERVICE_COLDPLUGGED); - free(service); - } - } - } - closedir (dp); - } - -#else - - /* udev likes to start services before we're ready when it does - * its coldplugging thing. runscript knows when we're not ready so it - * stores a list of coldplugged services in DEVBOOT for us to pick up - * here when we are ready for them */ - if ((dp = opendir(DEVBOOT))) { - while ((d = readdir(dp))) { - if (d->d_name[0] == '.' && - (d->d_name[1] == '\0' || - (d->d_name[1] == '.' && d->d_name[2] == '\0'))) - continue; - - if (rc_service_exists(d->d_name) && - service_plugable(d->d_name)) - rc_service_mark(d->d_name, RC_SERVICE_COLDPLUGGED); - - l = strlen(DEVBOOT "/") + strlen(d->d_name) + 1; - service = xmalloc(sizeof (char) * l); - snprintf(service, l, DEVBOOT "/%s", d->d_name); - if (unlink(service)) - eerror("%s: unlink `%s': %s", applet, service, - strerror(errno)); - free(service); - } - closedir(dp); - rmdir(DEVBOOT); - } -#endif - - if (rc_yesno(getenv("EINFO_QUIET"))) - return; - - /* Load our list of coldplugged services and display them */ - einfon("Device initiated services:%s", ecolor(ECOLOR_HILITE)); - coldplugged_services = rc_services_in_state(RC_SERVICE_COLDPLUGGED); - if (coldplugged_services) - TAILQ_FOREACH(s, coldplugged_services, entries) - printf(" %s", s->value); - printf("%s\n", ecolor(ECOLOR_NORMAL)); -} - static void do_newlevel(const char *newlevel) { struct utsname uts; const char *sys; -#ifdef __linux__ - char *cmd; -#endif if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0 #ifndef PREFIX @@ -669,39 +558,13 @@ static void do_newlevel(const char *newlevel) ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL)); setenv("RC_RUNLEVEL", newlevel, 1); - rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, newlevel); - hook_out = RC_HOOK_RUNLEVEL_START_OUT; run_program(INITSH); - -#ifdef __linux__ - /* If we requested a runlevel, save it now */ - if ((cmd = proc_getent("rc_runlevel"))) { - set_krunlevel(cmd); - free(cmd); - } else if ((cmd = proc_getent("softlevel"))) { - set_krunlevel(cmd); - free(cmd); - } else - set_krunlevel(NULL); -#endif - - /* Setup our coldplugged services now */ - do_coldplug(); - - rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, newlevel); - hook_out = 0; - - if (want_interactive()) - mark_interactive(); - - exit(EXIT_SUCCESS); } else if (strcmp(newlevel, RC_LEVEL_SINGLE) == 0) { #ifndef PREFIX if (! RUNLEVEL || (strcmp(RUNLEVEL, "S") != 0 && strcmp(RUNLEVEL, "1") != 0)) { - /* Remember the current runlevel for when we come back */ set_krunlevel(runlevel); single_user(); } @@ -883,7 +746,12 @@ interactive_option: if (! parallel) { rc_waitpid(pid); remove_pid(pid); + /* Attempt to open the logger as a service may + * mount the needed /dev/pts for this to work */ + if (rc_logger_tty == -1) + rc_logger_open(runlevel); } + } } @@ -1076,7 +944,8 @@ int main(int argc, char **argv) { /* Try not to join boot and krunlevels together */ if (! newlevel || - strcmp(newlevel, getenv("RC_BOOTLEVEL")) != 0) + (strcmp(newlevel, getenv("RC_BOOTLEVEL")) != 0 && + strcmp(newlevel, RC_LEVEL_SYSINIT) != 0)) if (get_krunlevel(krunlevel, sizeof(krunlevel))) newlevel = krunlevel; } else if (! RUNLEVEL || @@ -1135,21 +1004,11 @@ int main(int argc, char **argv) * correct order for stopping them */ stop_services = rc_services_in_state(RC_SERVICE_STARTED); tmplist = rc_services_in_state(RC_SERVICE_INACTIVE); - if (tmplist) { - if (stop_services) { - TAILQ_CONCAT(stop_services, tmplist, entries); - free(tmplist); - } else - stop_services = tmplist; - } + TAILQ_CONCAT(stop_services, tmplist, entries); + free(tmplist); tmplist = rc_services_in_state(RC_SERVICE_STARTING); - if (tmplist) { - if (stop_services) { - TAILQ_CONCAT(stop_services, tmplist, entries); - free(tmplist); - } else - stop_services = tmplist; - } + TAILQ_CONCAT(stop_services, tmplist, entries); + free(tmplist); if (stop_services) rc_stringlist_sort(&stop_services); @@ -1171,24 +1030,30 @@ int main(int argc, char **argv) strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 && strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0) { - /* We need to include the boot runlevel services if we're not in it */ - start_services = rc_services_in_runlevel(bootlevel); - if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) { - tmplist = rc_services_in_runlevel(newlevel ? newlevel : runlevel); - if (tmplist) { - if (start_services) { - TAILQ_CONCAT(start_services, tmplist, entries); - free(tmplist); - } else - start_services = tmplist; + start_services = rc_services_in_runlevel(RC_LEVEL_SYSINIT); + if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SYSINIT) + != 0) + { + /* We need to include the boot runlevel services */ + tmplist = rc_services_in_runlevel(bootlevel); + TAILQ_CONCAT(start_services, tmplist, entries); + free(tmplist); + if (strcmp (newlevel ? newlevel : runlevel, bootlevel) + != 0) + { + tmplist = rc_services_in_runlevel(newlevel ? + newlevel : + runlevel); + TAILQ_CONCAT(start_services, tmplist, entries); + free(tmplist); } - } - if (coldplugged_services) { - if (!start_services) - start_services = rc_stringlist_new(); - TAILQ_FOREACH(service, coldplugged_services, entries) - rc_stringlist_addu(start_services, service->value); + if (coldplugged_services) { + if (!start_services) + start_services = rc_stringlist_new(); + TAILQ_FOREACH(service, coldplugged_services, entries) + rc_stringlist_addu(start_services, service->value); + } } } @@ -1265,14 +1130,15 @@ int main(int argc, char **argv) if (start_services) { do_start_services(parallel); + /* FIXME: If we skip the boot runlevel and go straight + * to default from sysinit, we should now re-evaluate our + * start services + coldplugged services and call + * do_start_services a second time. */ /* Wait for our services to finish */ wait_for_services(); } - rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel); - hook_out = 0; - #ifdef __linux__ /* mark any services skipped as stopped */ if (PREVLEVEL && strcmp(PREVLEVEL, "N") == 0) { @@ -1285,12 +1151,15 @@ int main(int argc, char **argv) } #endif + rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel); + hook_out = 0; + /* If we're in the boot runlevel and we regenerated our dependencies * we need to delete them so that they are regenerated again in the - * default runlevel as they may depend on things that are now available */ + * default runlevel as they may depend on things that are now + * available */ if (regen && strcmp(runlevel, bootlevel) == 0) unlink(RC_DEPTREE_CACHE); return EXIT_SUCCESS; } - diff --git a/src/rc/runscript.c b/src/rc/runscript.c index e263a4f..d0425ab 100644 --- a/src/rc/runscript.c +++ b/src/rc/runscript.c @@ -108,9 +108,8 @@ static RC_STRINGLIST *types_mua = NULL; static void (*selinux_run_init_old)(void); static void (*selinux_run_init_new)(int argc, char **argv); -static void setup_selinux(int argc, char **argv); - -static void setup_selinux(int argc, char **argv) +static void +setup_selinux(int argc, char **argv) { void *lib_handle = NULL; @@ -141,7 +140,8 @@ static void setup_selinux(int argc, char **argv) } #endif -static void handle_signal(int sig) +static void +handle_signal(int sig) { int serrno = errno; char signame[10] = { '\0' }; @@ -155,7 +155,8 @@ static void handle_signal(int sig) case SIGCHLD: if (signal_pipe[1] > -1) { if (write(signal_pipe[1], &sig, sizeof(sig)) == -1) - eerror("%s: send: %s", service, strerror(errno)); + eerror("%s: send: %s", + service, strerror(errno)); } else rc_waitpid(-1); break; @@ -168,15 +169,15 @@ static void handle_signal(int sig) break; case SIGINT: - if (! signame[0]) + if (!signame[0]) snprintf(signame, sizeof(signame), "SIGINT"); /* FALLTHROUGH */ case SIGTERM: - if (! signame[0]) + if (!signame[0]) snprintf(signame, sizeof(signame), "SIGTERM"); /* FALLTHROUGH */ case SIGQUIT: - if (! signame[0]) + if (!signame[0]) snprintf(signame, sizeof(signame), "SIGQUIT"); /* Send the signal to our children too */ if (service_pid > 0) @@ -192,18 +193,17 @@ static void handle_signal(int sig) errno = serrno; } -static time_t get_mtime(const char *pathname, bool follow_link) +static time_t +get_mtime(const char *pathname, bool follow_link) { struct stat buf; int retval; - if (! pathname) + if (!pathname) return 0; - retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf); - if (! retval) + if (!retval) return buf.st_mtime; - errno = 0; return 0; } @@ -211,7 +211,8 @@ static time_t get_mtime(const char *pathname, bool follow_link) static const char *const tests[] = { "starting", "started", "stopping", "inactive", "wasinactive", NULL }; -static bool in_control() +static bool +in_control() { char file[PATH_MAX]; time_t m; @@ -221,17 +222,18 @@ static bool in_control() if (sighup) return false; - if (! *mtime_test || ! exists(mtime_test)) + if (!*mtime_test || !exists(mtime_test)) return false; if (rc_service_state(applet) & RC_SERVICE_STOPPED) return false; - if (! (mtime = get_mtime(mtime_test, false))) + if (!(mtime = get_mtime(mtime_test, false))) return false; while (tests[i]) { - snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", tests[i], applet); + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + tests[i], applet); if (exists(file)) { m = get_mtime(file, false); if (mtime < m && m != 0) @@ -243,7 +245,8 @@ static bool in_control() return true; } -static void uncoldplug() +static void +uncoldplug() { char file[PATH_MAX]; @@ -252,11 +255,13 @@ static void uncoldplug() eerror("%s: unlink `%s': %s", applet, file, strerror(errno)); } -static void start_services(RC_STRINGLIST *list) { +static void +start_services(RC_STRINGLIST *list) +{ RC_STRING *svc; RC_SERVICE state = rc_service_state (service); - if (! list) + if (!list) return; if (state & RC_SERVICE_INACTIVE || @@ -265,28 +270,30 @@ static void start_services(RC_STRINGLIST *list) { state & RC_SERVICE_STARTED) { TAILQ_FOREACH(svc, list, entries) { - if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) { - if (state & RC_SERVICE_INACTIVE || - state & RC_SERVICE_WASINACTIVE) - { - rc_service_schedule_start(service, svc->value); - ewarn("WARNING: %s is scheduled to started" - " when %s has started", - svc->value, applet); - } else - service_start(svc->value); - } + if (!(rc_service_state(svc->value) & + RC_SERVICE_STOPPED)) + continue; + if (state & RC_SERVICE_INACTIVE || + state & RC_SERVICE_WASINACTIVE) + { + rc_service_schedule_start(service, + svc->value); + ewarn("WARNING: %s is scheduled to started" + " when %s has started", + svc->value, applet); + } else + service_start(svc->value); } } } -static void restore_state(void) +static void +restore_state(void) { RC_SERVICE state; - if (rc_in_plugin || ! in_control()) + if (rc_in_plugin || !in_control()) return; - state = rc_service_state(applet); if (state & RC_SERVICE_STOPPING) { if (state & RC_SERVICE_WASINACTIVE) @@ -310,17 +317,20 @@ static void restore_state(void) } } -static void cleanup(void) +static void +cleanup(void) { restore_state(); - if (! rc_in_plugin) { + if (!rc_in_plugin) { if (hook_out) { rc_plugin_run(hook_out, applet); if (hook_out == RC_HOOK_SERVICE_START_DONE) - rc_plugin_run(RC_HOOK_SERVICE_START_OUT, applet); + rc_plugin_run(RC_HOOK_SERVICE_START_OUT, + applet); else if (hook_out == RC_HOOK_SERVICE_STOP_DONE) - rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT, applet); + rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT, + applet); } if (restart_services) @@ -353,7 +363,9 @@ static void cleanup(void) unlink(mtime_test); } -static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) { +static int +write_prefix(const char *buffer, size_t bytes, bool *prefixed) +{ unsigned int i; const char *ec = ecolor(ECOLOR_HILITE); const char *ec_normal = ecolor(ECOLOR_NORMAL); @@ -374,7 +386,7 @@ static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) { if (buffer[i] == '\033') *prefixed = true; - if (! *prefixed) { + if (!*prefixed) { ret += write(fd, ec, strlen(ec)); ret += write(fd, prefix, strlen(prefix)); ret += write(fd, ec_normal, strlen(ec_normal)); @@ -389,11 +401,11 @@ static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) { /* Release the lock */ close(lock_fd); - return ret; } -static bool svc_exec(const char *arg1, const char *arg2) +static bool +svc_exec(const char *arg1, const char *arg2) { bool execok; int fdout = fileno(stdout); @@ -430,7 +442,6 @@ static bool svc_exec(const char *arg1, const char *arg2) /* If the below call fails due to not enough ptys then we don't * prefix the output, but we still work */ openpty(&master_tty, &slave_tty, NULL, &tt, &ws); - if (master_tty >= 0 && (flags = fcntl(master_tty, F_GETFD, 0)) == 0) fcntl(master_tty, F_SETFD, flags | FD_CLOEXEC); @@ -450,13 +461,15 @@ static bool svc_exec(const char *arg1, const char *arg2) } if (exists(RC_SVCDIR "/runscript.sh")) { - execl(RC_SVCDIR "/runscript.sh", RC_SVCDIR "/runscript.sh", + execl(RC_SVCDIR "/runscript.sh", + RC_SVCDIR "/runscript.sh", service, arg1, arg2, (char *) NULL); eerror("%s: exec `" RC_SVCDIR "/runscript.sh': %s", service, strerror(errno)); _exit(EXIT_FAILURE); } else { - execl(RC_LIBDIR "/sh/runscript.sh", RC_LIBDIR "/sh/runscript.sh", + execl(RC_LIBDIR "/sh/runscript.sh", + RC_LIBDIR "/sh/runscript.sh", service, arg1, arg2, (char *) NULL); eerror("%s: exec `" RC_LIBDIR "/sh/runscript.sh': %s", service, strerror(errno)); @@ -474,7 +487,8 @@ static bool svc_exec(const char *arg1, const char *arg2) if ((s = select(selfd, &rset, NULL, NULL, NULL)) == -1) { if (errno != EINTR) { - eerror("%s: select: %s", service, strerror(errno)); + eerror("%s: select: %s", service, + strerror(errno)); break; } } @@ -509,7 +523,8 @@ static bool svc_exec(const char *arg1, const char *arg2) return execok; } -static bool svc_wait(const char *svc) +static bool +svc_wait(const char *svc) { char fifo[PATH_MAX]; struct timespec ts; @@ -525,12 +540,13 @@ static bool svc_wait(const char *svc) forever = true; rc_stringlist_free(keywords); - snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s", basename_c(svc)); + snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s", + basename_c(svc)); ts.tv_sec = 0; ts.tv_nsec = WAIT_INTERVAL; while (nloops) { - if (! exists(fifo)) { + if (!exists(fifo)) { retval = true; break; } @@ -540,7 +556,7 @@ static bool svc_wait(const char *svc) break; } - if (! forever) + if (!forever) nloops --; if (--sloops == 0) { @@ -549,12 +565,13 @@ static bool svc_wait(const char *svc) } } - if (! exists(fifo)) + if (!exists(fifo)) retval = true; return retval; } -static RC_SERVICE svc_status(void) +static RC_SERVICE +svc_status(void) { char status[10]; int (*e) (const char *fmt, ...) EINFO_PRINTF(1, 2) = einfo; @@ -586,19 +603,21 @@ static RC_SERVICE svc_status(void) return state; } -static void make_exclusive(void) +static void +make_exclusive(void) { /* We create a fifo so that other services can wait until we complete */ - if (! *exclusive) - snprintf(exclusive, sizeof(exclusive), RC_SVCDIR "/exclusive/%s", - applet); + if (!*exclusive) + snprintf(exclusive, sizeof(exclusive), + RC_SVCDIR "/exclusive/%s", applet); if (mkfifo(exclusive, 0600) != 0 && errno != EEXIST && (errno != EACCES || geteuid () == 0)) eerrorx ("%s: unable to create fifo `%s': %s", applet, exclusive, strerror(errno)); - snprintf(mtime_test, sizeof(mtime_test), RC_SVCDIR "/exclusive/%s.%d", applet, getpid()); + snprintf(mtime_test, sizeof(mtime_test), + RC_SVCDIR "/exclusive/%s.%d", applet, getpid()); if (exists(mtime_test) && unlink(mtime_test) != 0) { eerror("%s: unlink `%s': %s", @@ -614,28 +633,28 @@ static void make_exclusive(void) } } -static void unlink_mtime_test(void) +static void +unlink_mtime_test(void) { if (unlink(mtime_test) != 0) - eerror("%s: unlink `%s': %s", applet, mtime_test, strerror(errno)); + eerror("%s: unlink `%s': %s", + applet, mtime_test, strerror(errno)); *mtime_test = '\0'; } -static void get_started_services(void) +static void +get_started_services(void) { RC_STRINGLIST *tmp = rc_services_in_state(RC_SERVICE_INACTIVE); + rc_stringlist_free(restart_services); restart_services = rc_services_in_state(RC_SERVICE_STARTED); - if (tmp) { - if (restart_services) { - TAILQ_CONCAT(restart_services, tmp, entries); - free(tmp); - } else - restart_services = tmp; - } + TAILQ_CONCAT(restart_services, tmp, entries); + free(tmp); } -static void setup_types(void) +static void +setup_types(void) { types_b = rc_stringlist_new(); rc_stringlist_add(types_b, "broken"); @@ -661,7 +680,8 @@ static void setup_types(void) rc_stringlist_add(types_mua, "beforeme"); } -static void svc_start(bool deps) +static void +svc_start(bool deps) { bool started; bool background = false; @@ -682,6 +702,10 @@ static void svc_start(bool deps) ! state & RC_SERVICE_STOPPED) exit(EXIT_FAILURE); background = true; + rc_service_mark(service, RC_SERVICE_COLDPLUGGED); + if (rc_runlevel_starting()) + ewarnx("WARNING: %s will be started when the runlevel" + " has finished.", applet); } if (state & RC_SERVICE_STARTED) { @@ -692,16 +716,16 @@ static void svc_start(bool deps) else if (state & RC_SERVICE_STOPPING) ewarnx("WARNING: %s is stopping", applet); else if (state & RC_SERVICE_INACTIVE && ! background) - ewarnx("WARNING: %s has already started, but is inactive", applet); + ewarnx("WARNING: %s has already started, but is inactive", + applet); - if (! rc_service_mark(service, RC_SERVICE_STARTING)) { + if (!rc_service_mark(service, RC_SERVICE_STARTING)) { if (errno == EACCES) eerrorx("%s: superuser access required", applet); eerrorx("ERROR: %s has been started by something else", applet); } make_exclusive(); - hook_out = RC_HOOK_SERVICE_START_OUT; rc_plugin_run(RC_HOOK_SERVICE_START_IN, applet); @@ -710,15 +734,14 @@ static void svc_start(bool deps) depoptions |= RC_DEP_STRICT; if (deps) { - if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL)) + if (!deptree && ((deptree = _rc_deptree_load(NULL)) == NULL)) eerrorx("failed to load deptree"); - - if (! types_b) + if (!types_b) setup_types(); services = rc_deptree_depends(deptree, types_b, applet_list, runlevel, 0); - if (services && TAILQ_FIRST(services)) { + if (TAILQ_FIRST(services)) { eerrorn("ERROR: `%s' needs ", applet); first = true; TAILQ_FOREACH(svc, services, entries) { @@ -733,12 +756,14 @@ static void svc_start(bool deps) rc_stringlist_free(services); services = NULL; - need_services = rc_deptree_depends(deptree, types_n, applet_list, - runlevel, depoptions); - use_services = rc_deptree_depends(deptree, types_nu, applet_list, - runlevel, depoptions); + need_services = rc_deptree_depends(deptree, types_n, + applet_list, runlevel, + depoptions); + use_services = rc_deptree_depends(deptree, types_nu, + applet_list, runlevel, + depoptions); - if (! rc_runlevel_starting() && use_services) + if (!rc_runlevel_starting()) { TAILQ_FOREACH(svc, use_services, entries) { state = rc_service_state(svc->value); /* Don't stop failed services again. @@ -753,90 +778,89 @@ static void svc_start(bool deps) rc_waitpid(pid); } } + } /* Now wait for them to start */ services = rc_deptree_depends(deptree, types_nua, applet_list, runlevel, depoptions); - - if (services) { - /* We use tmplist to hold our scheduled by list */ - tmplist = NULL; - TAILQ_FOREACH(svc, services, entries) { - state = rc_service_state(svc->value); - if (state & RC_SERVICE_STARTED) + /* We use tmplist to hold our scheduled by list */ + tmplist = rc_stringlist_new(); + TAILQ_FOREACH(svc, services, entries) { + state = rc_service_state(svc->value); + if (state & RC_SERVICE_STARTED) + continue; + + /* Don't wait for services which went inactive but are + * now in starting state which we are after */ + if (state & RC_SERVICE_STARTING && + state & RC_SERVICE_WASINACTIVE) + { + if (!rc_stringlist_find(need_services, + svc->value) && + !rc_stringlist_find(use_services, + svc->value)) continue; + } - /* Don't wait for services which went inactive but are now in - * starting state which we are after */ - if (state & RC_SERVICE_STARTING && + if (!svc_wait(svc->value)) + eerror("%s: timed out waiting for %s", + applet, svc->value); + state = rc_service_state(svc->value); + if (state & RC_SERVICE_STARTED) + continue; + if (rc_stringlist_find(need_services, svc->value)) { + if (state & RC_SERVICE_INACTIVE || state & RC_SERVICE_WASINACTIVE) { - if (!rc_stringlist_find(need_services, svc->value) && - !rc_stringlist_find(use_services, svc->value)) - continue; - } - - if (!svc_wait(svc->value)) - eerror ("%s: timed out waiting for %s", + rc_stringlist_add(tmplist, svc->value); + } else if (!TAILQ_FIRST(tmplist)) + eerrorx("ERROR: cannot start %s as" + " %s would not start", applet, svc->value); - state = rc_service_state(svc->value); - if (state & RC_SERVICE_STARTED) - continue; - if (rc_stringlist_find(need_services, svc->value)) { - if (state & RC_SERVICE_INACTIVE || - state & RC_SERVICE_WASINACTIVE) - { - if (! tmplist) - tmplist = rc_stringlist_new(); - rc_stringlist_add(tmplist, svc->value); - } else if (!tmplist) - eerrorx("ERROR: cannot start %s as" - " %s would not start", - applet, svc->value); - } } + } - if (tmplist && TAILQ_FIRST(tmplist)) { - /* Set the state now, then unlink our exclusive so that - our scheduled list is preserved */ - rc_service_mark(service, RC_SERVICE_STOPPED); - unlink_mtime_test(); + if (TAILQ_FIRST(tmplist)) { + /* Set the state now, then unlink our exclusive so that + our scheduled list is preserved */ + rc_service_mark(service, RC_SERVICE_STOPPED); + unlink_mtime_test(); + rc_stringlist_free(use_services); + use_services = NULL; + len = 0; + n = 0; + TAILQ_FOREACH(svc, tmplist, entries) { + rc_service_schedule_start(svc->value, service); + use_services = rc_deptree_depend(deptree, + "iprovide", + svc->value); + TAILQ_FOREACH(svc2, use_services, entries) + rc_service_schedule_start(svc2->value, + service); rc_stringlist_free(use_services); use_services = NULL; - len = 0; - n = 0; - TAILQ_FOREACH(svc, tmplist, entries) { - rc_service_schedule_start(svc->value, service); - use_services = rc_deptree_depend(deptree, "iprovide", - svc->value); - if (use_services) { - TAILQ_FOREACH (svc2, use_services, entries) - rc_service_schedule_start(svc2->value, service); - rc_stringlist_free(use_services); - use_services = NULL; - } - len += strlen(svc->value) + 2; - n++; - } - - len += 5; - tmp = p = xmalloc(sizeof(char) * len); - TAILQ_FOREACH(svc, tmplist, entries) { - if (p != tmp) - p += snprintf(p, len, ", "); - p += snprintf(p, len - (p - tmp), "%s", svc->value); - } - rc_stringlist_free(tmplist); - tmplist = NULL; - ewarnx("WARNING: %s is scheduled to start when %s has started", - applet, tmp); - free(tmp); + len += strlen(svc->value) + 2; + n++; } - rc_stringlist_free(services); - services = NULL; + len += 5; + tmp = p = xmalloc(sizeof(char) * len); + TAILQ_FOREACH(svc, tmplist, entries) { + if (p != tmp) + p += snprintf(p, len, ", "); + p += snprintf(p, len - (p - tmp), + "%s", svc->value); + } + rc_stringlist_free(tmplist); + tmplist = NULL; + ewarnx("WARNING: %s is scheduled to start when " + "%s has started", applet, tmp); + free(tmp); } + + rc_stringlist_free(services); + services = NULL; } if (ibsave) @@ -848,13 +872,15 @@ static void svc_start(bool deps) unsetenv("IN_BACKGROUND"); if (in_control()) { - if (! started) + if (!started) eerrorx("ERROR: %s failed to start", applet); } else { if (rc_service_state(service) & RC_SERVICE_INACTIVE) - ewarnx("WARNING: %s has started, but is inactive", applet); + ewarnx("WARNING: %s has started, but is inactive", + applet); else - ewarnx("WARNING: %s not under our control, aborting", applet); + ewarnx("WARNING: %s not under our control, aborting", + applet); } rc_service_mark(service, RC_SERVICE_STARTED); @@ -865,28 +891,23 @@ static void svc_start(bool deps) /* Now start any scheduled services */ services = rc_services_scheduled(service); - if (services) { - TAILQ_FOREACH(svc, services, entries) - if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) - service_start(svc->value); - rc_stringlist_free(services); - services = NULL; - } + TAILQ_FOREACH(svc, services, entries) + if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + service_start(svc->value); + rc_stringlist_free(services); + services = NULL; /* Do the same for any services we provide */ if (deptree) { tmplist = rc_deptree_depend(deptree, "iprovide", applet); - if (tmplist) { - TAILQ_FOREACH(svc, tmplist, entries) { - services = rc_services_scheduled(svc->value); - if (! services) - continue; - TAILQ_FOREACH(svc2, services, entries) - if (rc_service_state(svc2->value) & RC_SERVICE_STOPPED) - service_start(svc2->value); - rc_stringlist_free(services); - services = NULL; - } + TAILQ_FOREACH(svc, tmplist, entries) { + services = rc_services_scheduled(svc->value); + TAILQ_FOREACH(svc2, services, entries) + if (rc_service_state(svc2->value) & + RC_SERVICE_STOPPED) + service_start(svc2->value); + rc_stringlist_free(services); + services = NULL; } rc_stringlist_free(tmplist); tmplist = NULL; @@ -896,20 +917,21 @@ static void svc_start(bool deps) rc_plugin_run(RC_HOOK_SERVICE_START_OUT, applet); } -static void svc_stop(bool deps) +static void +svc_stop(bool deps) { bool stopped; RC_SERVICE state = rc_service_state(service); int depoptions = RC_DEP_TRACE; RC_STRING *svc; - if (rc_runlevel_stopping() && - state & RC_SERVICE_FAILED) - exit (EXIT_FAILURE); + + if (rc_runlevel_stopping() && state & RC_SERVICE_FAILED) + exit(EXIT_FAILURE); if (rc_yesno(getenv("IN_HOTPLUG")) || in_background) - if (! (state & RC_SERVICE_STARTED) && - ! (state & RC_SERVICE_INACTIVE)) + if (!(state & RC_SERVICE_STARTED) && + !(state & RC_SERVICE_INACTIVE)) exit (EXIT_FAILURE); if (state & RC_SERVICE_STOPPED) { @@ -918,7 +940,7 @@ static void svc_stop(bool deps) } else if (state & RC_SERVICE_STOPPING) ewarnx("WARNING: %s is already stopping", applet); - if (! rc_service_mark(service, RC_SERVICE_STOPPING)) { + if (!rc_service_mark(service, RC_SERVICE_STOPPING)) { if (errno == EACCES) eerrorx("%s: superuser access required", applet); eerrorx("ERROR: %s has been stopped by something else", applet); @@ -929,90 +951,87 @@ static void svc_stop(bool deps) hook_out = RC_HOOK_SERVICE_STOP_OUT; rc_plugin_run(RC_HOOK_SERVICE_STOP_IN, applet); - if (! rc_runlevel_stopping() && + if (!rc_runlevel_stopping() && rc_service_in_runlevel(service, RC_LEVEL_BOOT)) ewarn ("WARNING: you are stopping a boot service"); - if (deps && ! (state & RC_SERVICE_WASINACTIVE)) { + if (deps && !(state & RC_SERVICE_WASINACTIVE)) { errno = 0; if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT) depoptions |= RC_DEP_STRICT; - if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL)) - eerrorx ("failed to load deptree"); + if (!deptree && ((deptree = _rc_deptree_load(NULL)) == NULL)) + eerrorx("failed to load deptree"); - if (! types_m) + if (!types_m) setup_types(); services = rc_deptree_depends(deptree, types_m, applet_list, runlevel, depoptions); - if (services) { - TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) { + tmplist = rc_stringlist_new(); + TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) { + state = rc_service_state(svc->value); + /* Don't stop failed services again. + * If you remove this check, ensure that the + * exclusive file isn't created. */ + if (state & RC_SERVICE_FAILED && + rc_runlevel_stopping()) + continue; + if (state & RC_SERVICE_STARTED || + state & RC_SERVICE_INACTIVE) + { + svc_wait(svc->value); state = rc_service_state(svc->value); - /* Don't stop failed services again. - * If you remove this check, ensure that the - * exclusive file isn't created. */ - if (state & RC_SERVICE_FAILED && - rc_runlevel_stopping()) - continue; if (state & RC_SERVICE_STARTED || state & RC_SERVICE_INACTIVE) { - svc_wait(svc->value); - state = rc_service_state(svc->value); - if (state & RC_SERVICE_STARTED || - state & RC_SERVICE_INACTIVE) - { - pid_t pid = service_stop(svc->value); - if (! rc_conf_yesno("rc_parallel")) - rc_waitpid(pid); - if (! tmplist) - tmplist = rc_stringlist_new(); - rc_stringlist_add(tmplist, svc->value); - } + pid_t pid = service_stop(svc->value); + if (!rc_conf_yesno("rc_parallel")) + rc_waitpid(pid); + rc_stringlist_add(tmplist, svc->value); } } - rc_stringlist_free(services); - services = NULL; } + rc_stringlist_free(services); + services = NULL; - if (tmplist) { - TAILQ_FOREACH(svc, tmplist, entries) { - if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + TAILQ_FOREACH(svc, tmplist, entries) { + if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + continue; + svc_wait(svc->value); + if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + continue; + if (rc_runlevel_stopping()) { + /* If shutting down, we should stop even + * if a dependant failed */ + if (runlevel && + (strcmp(runlevel, + RC_LEVEL_SHUTDOWN) == 0 || + strcmp(runlevel, + RC_LEVEL_REBOOT) == 0 || + strcmp(runlevel, + RC_LEVEL_SINGLE) == 0)) continue; - svc_wait(svc->value); - if (! (rc_service_state(svc->value) & RC_SERVICE_STOPPED)) { - if (rc_runlevel_stopping()) { - /* If shutting down, we should stop even - * if a dependant failed */ - if (runlevel && - (strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 || - strcmp(runlevel, RC_LEVEL_REBOOT) == 0 || - strcmp(runlevel, RC_LEVEL_SINGLE) == 0)) - continue; - rc_service_mark(service, RC_SERVICE_FAILED); - } - eerrorx("ERROR: cannot stop %s as %s is still up", - applet, svc->value); - } + rc_service_mark(service, RC_SERVICE_FAILED); } - rc_stringlist_free(tmplist); - tmplist = NULL; + eerrorx("ERROR: cannot stop %s as %s " + "is still up", applet, svc->value); } + rc_stringlist_free(tmplist); + tmplist = NULL; + - /* We now wait for other services that may use us and are stopping - This is important when a runlevel stops */ + /* We now wait for other services that may use us and are + * stopping. This is important when a runlevel stops */ services = rc_deptree_depends(deptree, types_mua, applet_list, runlevel, depoptions); - if (services) { - TAILQ_FOREACH(svc, services, entries) { - if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) - continue; - svc_wait(svc->value); - } - rc_stringlist_free(services); - services = NULL; + TAILQ_FOREACH(svc, services, entries) { + if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + continue; + svc_wait(svc->value); } + rc_stringlist_free(services); + services = NULL; } /* If we're stopping localmount, set LC_ALL=C so that @@ -1028,10 +1047,10 @@ static void svc_stop(bool deps) if (ibsave) unsetenv("IN_BACKGROUND"); - if (! in_control()) + if (!in_control()) ewarnx("WARNING: %s not under our control, aborting", applet); - if (! stopped) + if (!stopped) eerrorx("ERROR: %s failed to stop", applet); if (in_background) @@ -1047,17 +1066,21 @@ static void svc_stop(bool deps) rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT, applet); } -static void svc_restart(bool deps) +static void +svc_restart(bool deps) { /* This is hairly and a better way needs to be found I think! - The issue is this - openvpn need net and dns. net can restart - dns via resolvconf, so you could have openvpn trying to restart dnsmasq - which in turn is waiting on net which in turn is waiting on dnsmasq. - The work around is for resolvconf to restart it's services with --nodeps - which means just that. The downside is that there is a small window when - our status is invalid. - One workaround would be to introduce a new status, or status locking. */ - if (! deps) { + * The issue is this - openvpn need net and dns. net can restart + * dns via resolvconf, so you could have openvpn trying to restart + * dnsmasq which in turn is waiting on net which in turn is waiting + * on dnsmasq. + * The work around is for resolvconf to restart it's services with + * --nodeps which means just that. + * The downside is that there is a small window when our status is + * invalid. + * One workaround would be to introduce a new status, + * or status locking. */ + if (!deps) { RC_SERVICE state = rc_service_state(service); if (state & RC_SERVICE_STARTED || state & RC_SERVICE_INACTIVE) svc_exec("stop", "start"); @@ -1066,7 +1089,7 @@ static void svc_restart(bool deps) return; } - if (! (rc_service_state(service) & RC_SERVICE_STOPPED)) { + if (!(rc_service_state(service) & RC_SERVICE_STOPPED)) { get_started_services(); svc_stop(deps); } @@ -1077,6 +1100,51 @@ static void svc_restart(bool deps) restart_services = NULL; } +static bool +service_plugable(void) +{ + char *list; + char *p; + char *star; + char *token; + bool allow = true; + char *match = rc_conf_value("rc_plug_services"); + bool truefalse; + + if (! match) + return true; + + list = xstrdup(match); + p = list; + while ((token = strsep(&p, " "))) { + if (token[0] == '!') { + truefalse = false; + token++; + } else + truefalse = true; + + star = strchr(token, '*'); + if (star) { + if (strncmp(applet, token, + (size_t)(star - token)) == 0) + { + allow = truefalse; + break; + } + } else { + if (strcmp(applet, token) == 0) { + allow = truefalse; + break; + } + } + } + +#ifdef DEBUG_MEMORY + free(list); +#endif + return allow; +} + #include "_usage.h" #define getoptstring "dDsv" getoptstring_COMMON #define extraopts "stop | start | restart | describe | zap" @@ -1086,7 +1154,7 @@ static const struct option longopts[] = { { "nodeps", 0, NULL, 'D'}, longopts_COMMON }; -static const char * const longopts_help[] = { +static const char *const longopts_help[] = { "set xtrace when running the script", "only run commands when started", "ignore dependencies", @@ -1094,7 +1162,8 @@ static const char * const longopts_help[] = { }; #include "_usage.c" -int runscript(int argc, char **argv) +int +runscript(int argc, char **argv) { bool deps = true; bool doneone = false; @@ -1112,7 +1181,7 @@ int runscript(int argc, char **argv) struct stat stbuf; /* Show help if insufficient args */ - if (argc < 2 || ! exists(argv[1])) { + if (argc < 2 || !exists(argv[1])) { fprintf(stderr, "runscript should not be run directly\n"); exit(EXIT_FAILURE); } @@ -1165,20 +1234,6 @@ int runscript(int argc, char **argv) /* Change dir to / to ensure all init scripts don't use stuff in pwd */ chdir("/"); -#ifdef __linux__ - /* coldplug events can trigger init scripts, but we don't want to run - * them until after rc sysinit has completed so we punt them to the - * boot runlevel */ - if (exists("/dev/.rcsysinit")) { - eerror("%s: cannot run until sysvinit completes", applet); - if (mkdir("/dev/.rcboot", 0755) != 0 && errno != EEXIST) - eerrorx("%s: mkdir `/dev/.rcboot': %s", applet, strerror(errno)); - snprintf(exclusive, sizeof(exclusive), "/dev/.rcboot/%s", applet); - symlink(service, exclusive); - exit (EXIT_FAILURE); - } -#endif - if ((runlevel = xstrdup (getenv ("RC_RUNLEVEL"))) == NULL) { env_filter(); env_config(); @@ -1198,15 +1253,16 @@ int runscript(int argc, char **argv) if (rc_conf_yesno("rc_parallel")) { /* Get the longest service name */ services = rc_services_in_runlevel(NULL); - if (services) { - TAILQ_FOREACH(svc, services, entries) { - ll = strlen(svc->value); - if (ll > l) - l = ll; - } - rc_stringlist_free(services); - services = NULL; - } else l = strlen(applet); + TAILQ_FOREACH(svc, services, entries) { + ll = strlen(svc->value); + if (ll > l) + l = ll; + } + rc_stringlist_free(services); + services = NULL; + ll = strlen(applet); + if (ll > l) + l = ll; /* Make our prefix string */ prefix = xmalloc(sizeof(char) * l + 1); @@ -1227,13 +1283,14 @@ int runscript(int argc, char **argv) argv++; /* Right then, parse any options there may be */ - while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *)0)) != -1) switch (opt) { case 'd': setenv("RC_DEBUG", "yes", 1); break; case 's': - if (! (rc_service_state(service) & RC_SERVICE_STARTED)) + if (!(rc_service_state(service) & RC_SERVICE_STARTED)) exit(EXIT_FAILURE); break; case 'D': @@ -1251,7 +1308,7 @@ int runscript(int argc, char **argv) } if (rc_yesno(getenv("IN_HOTPLUG"))) { - if (! rc_conf_yesno("rc_hotplug") || ! service_plugable(applet)) + if (!rc_conf_yesno("rc_hotplug") || !service_plugable()) eerrorx("%s: not allowed to be hotplugged", applet); } @@ -1286,8 +1343,8 @@ int runscript(int argc, char **argv) doneone = true; - if (strcmp (optarg, "describe") == 0 || - strcmp (optarg, "help") == 0) + if (strcmp(optarg, "describe") == 0 || + strcmp(optarg, "help") == 0) { save = prefix; eprefix(NULL); @@ -1304,25 +1361,25 @@ int runscript(int argc, char **argv) strcmp(optarg, "iprovide") == 0) { errno = 0; - if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT) + if (rc_conf_yesno("rc_depend_strict") || + errno == ENOENT) depoptions |= RC_DEP_STRICT; - if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL)) + if (!deptree && + ((deptree = _rc_deptree_load(NULL)) == NULL)) eerrorx("failed to load deptree"); tmplist = rc_stringlist_new(); rc_stringlist_add(tmplist, optarg); - services = rc_deptree_depends(deptree, tmplist, applet_list, + services = rc_deptree_depends(deptree, tmplist, + applet_list, runlevel, depoptions); rc_stringlist_free(tmplist); - tmplist = NULL; - if (services) { - TAILQ_FOREACH(svc, services, entries) - printf("%s ", svc->value); - printf ("\n"); - rc_stringlist_free(services); - services = NULL; - } + TAILQ_FOREACH(svc, services, entries) + printf("%s ", svc->value); + printf ("\n"); + rc_stringlist_free(services); + services = NULL; } else if (strcmp (optarg, "status") == 0) { RC_SERVICE r = svc_status(); retval = (int) r; @@ -1332,7 +1389,8 @@ int runscript(int argc, char **argv) if (strcmp(optarg, "conditionalrestart") == 0 || strcmp(optarg, "condrestart") == 0) { - if (rc_service_state(service) & RC_SERVICE_STARTED) + if (rc_service_state(service) & + RC_SERVICE_STARTED) svc_restart(deps); } else if (strcmp(optarg, "restart") == 0) { svc_restart (deps); @@ -1341,37 +1399,44 @@ int runscript(int argc, char **argv) } else if (strcmp(optarg, "stop") == 0) { if (deps && in_background) get_started_services(); - svc_stop(deps); - if (deps) { if (! in_background && ! rc_runlevel_stopping() && - rc_service_state(service) & RC_SERVICE_STOPPED) + rc_service_state(service) & + RC_SERVICE_STOPPED) uncoldplug(); if (in_background && - rc_service_state(service) & RC_SERVICE_INACTIVE) + rc_service_state(service) & + RC_SERVICE_INACTIVE) { - TAILQ_FOREACH(svc, restart_services, entries) - if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + TAILQ_FOREACH(svc, + restart_services, + entries) + if (rc_service_state(svc->value) & + RC_SERVICE_STOPPED) rc_service_schedule_start(service, svc->value); } } } else if (strcmp(optarg, "zap") == 0) { - einfo("Manually resetting %s to stopped state", applet); - if (!rc_service_mark(applet, RC_SERVICE_STOPPED)) - eerrorx("rc_service_mark: %s", strerror(errno)); + einfo("Manually resetting %s to stopped state", + applet); + if (!rc_service_mark(applet, + RC_SERVICE_STOPPED)) + eerrorx("rc_service_mark: %s", + strerror(errno)); uncoldplug(); } else svc_exec(optarg, NULL); - /* We should ensure this list is empty after an action is done */ + /* We should ensure this list is empty after + * an action is done */ rc_stringlist_free(restart_services); restart_services = NULL; } - if (! doneone) + if (!doneone) usage(EXIT_FAILURE); } -- cgit v1.2.3