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/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 ++++++++++++++++++++++++++++------------------------ 5 files changed, 467 insertions(+), 567 deletions(-) (limited to 'src/rc') 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