diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/librc/librc-daemon.c | 104 | ||||
-rw-r--r-- | src/librc/librc-depend.c | 67 | ||||
-rw-r--r-- | src/librc/librc-misc.c | 67 | ||||
-rw-r--r-- | src/librc/librc-stringlist.c | 2 | ||||
-rw-r--r-- | src/librc/librc.c | 377 | ||||
-rw-r--r-- | src/librc/librc.h | 1 | ||||
-rw-r--r-- | src/librc/rc.h | 18 | ||||
-rw-r--r-- | src/librc/rc.map | 2 | ||||
-rw-r--r-- | src/rc/rc-plugin.c | 7 | ||||
-rw-r--r-- | src/rc/rc.c | 524 | ||||
-rw-r--r-- | src/rc/runscript.c | 195 | ||||
-rw-r--r-- | src/rc/start-stop-daemon.c | 16 |
12 files changed, 681 insertions, 699 deletions
diff --git a/src/librc/librc-daemon.c b/src/librc/librc-daemon.c index 9e58c6a9..b174a82b 100644 --- a/src/librc/librc-daemon.c +++ b/src/librc/librc-daemon.c @@ -31,6 +31,30 @@ #include "librc.h" +#ifdef __GLIBC__ +# if ! defined (__UCLIBC__) && ! defined (__dietlibc__) +static size_t strlcpy(char *dst, const char *src, size_t size) +{ + const char *s = src; + size_t n = size; + + if (n && --n) + do { + if (! (*dst++ = *src++)) + break; + } while (--n); + + if (! n) { + if (size) + *dst = '\0'; + while (*src++); + } + + return src - s - 1; +} +# endif +#endif + #if defined(__linux__) static bool pid_is_cmd(pid_t pid, const char *cmd) { @@ -289,12 +313,12 @@ static bool _match_daemon(const char *path, const char *file, RC_STRINGLIST *match) { char *line; - char *ffile = rc_strcatpaths(path, file, (char *) NULL); + char ffile[PATH_MAX]; FILE *fp; RC_STRING *m; + snprintf(ffile, sizeof(ffile), "%s/%s", path, file); fp = fopen(ffile, "r"); - free(ffile); if (! fp) return false; @@ -352,16 +376,15 @@ static RC_STRINGLIST *_match_list(const char* const* argv, bool rc_service_daemon_set(const char *service, const char *const *argv, const char *name, const char *pidfile, bool started) { - char *dirpath; - char *file = NULL; + char dirpath[PATH_MAX]; + char file[PATH_MAX]; int nfiles = 0; - char *oldfile = NULL; + char oldfile[PATH_MAX] = { '\0' }; bool retval = false; DIR *dp; struct dirent *d; RC_STRINGLIST *match; int i = 0; - char buffer[10]; FILE *fp; if (!(argv && *argv) && ! name && ! pidfile) { @@ -369,40 +392,40 @@ bool rc_service_daemon_set(const char *service, const char *const *argv, return false; } - dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", - basename_c(service), (char *) NULL); - - match = _match_list(argv, name, pidfile); + snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", + basename_c(service)); /* Regardless, erase any existing daemon info */ if ((dp = opendir(dirpath))) { + match = _match_list(argv, name, pidfile); while ((d = readdir(dp))) { if (d->d_name[0] == '.') continue; - file = rc_strcatpaths(dirpath, d->d_name, (char *) NULL); + + snprintf(file, sizeof(file), "%s/%s", + dirpath, d->d_name); nfiles++; - if (! oldfile) { + if (! *oldfile) { if (_match_daemon(dirpath, d->d_name, match)) { - unlink (file); - oldfile = file; + unlink(file); + strlcpy(oldfile, file, sizeof(oldfile)); nfiles--; } } else { rename(file, oldfile); - free(oldfile); - oldfile = file; + strlcpy(oldfile, file, sizeof(oldfile)); } } - free(file); closedir(dp); + rc_stringlist_free(match); } /* Now store our daemon info */ if (started) { if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) { - snprintf(buffer, sizeof(buffer), "%03d", nfiles + 1); - file = rc_strcatpaths(dirpath, buffer, (char *) NULL); + snprintf(file, sizeof(file), "%s/%03d", + dirpath, nfiles + 1); if ((fp = fopen(file, "w"))) { while (argv && argv[i]) { fprintf(fp, "argv_%d=%s\n", i, argv[i]); @@ -418,25 +441,19 @@ bool rc_service_daemon_set(const char *service, const char *const *argv, fclose(fp); retval = true; } - free(file); } } else retval = true; - rc_stringlist_free(match); - free(dirpath); - return retval; } librc_hidden_def(rc_service_daemon_set) -bool -rc_service_started_daemon (const char *service, const char *const *argv, - int indx) +bool rc_service_started_daemon(const char *service, const char *const *argv, + int indx) { - char *dirpath; - char *file; - size_t l; + char dirpath[PATH_MAX]; + char file[16]; RC_STRINGLIST *match; bool retval = false; DIR *dp; @@ -445,17 +462,13 @@ rc_service_started_daemon (const char *service, const char *const *argv, if (!service || !(argv && *argv)) return false; - dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service), - (char *) NULL); - + snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", + basename_c(service)); match = _match_list(argv, NULL, NULL); if (indx > 0) { - l = sizeof (char) * 10; - file = xmalloc(l); - snprintf(file, l, "%03d", indx); + snprintf(file, sizeof(file), "%03d", indx); retval = _match_daemon(dirpath, file, match); - free(file); } else { if ((dp = opendir(dirpath))) { while ((d = readdir(dp))) { @@ -469,7 +482,6 @@ rc_service_started_daemon (const char *service, const char *const *argv, } } - free(dirpath); rc_stringlist_free(match); return retval; } @@ -477,10 +489,10 @@ librc_hidden_def(rc_service_started_daemon) bool rc_service_daemons_crashed(const char *service) { - char *dirpath; + char dirpath[PATH_MAX]; DIR *dp; struct dirent *d; - char *path; + char *path = dirpath; FILE *fp; char *line; char **argv = NULL; @@ -498,21 +510,19 @@ bool rc_service_daemons_crashed(const char *service) RC_STRING *s; size_t i; - dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service), - (char *) NULL); + path += snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", + basename_c(service)); - if (! (dp = opendir(dirpath))) { - free(dirpath); + if (! (dp = opendir(dirpath))) return false; - } while ((d = readdir(dp))) { if (d->d_name[0] == '.') continue; - path = rc_strcatpaths(dirpath, d->d_name, (char *) NULL); - fp = fopen(path, "r"); - free(path); + snprintf(path, sizeof(dirpath) - (path - dirpath), "/%s", + d->d_name); + fp = fopen(dirpath, "r"); if (! fp) break; diff --git a/src/librc/librc-depend.c b/src/librc/librc-depend.c index 7038a3fc..a9bf3045 100644 --- a/src/librc/librc-depend.c +++ b/src/librc/librc-depend.c @@ -360,12 +360,12 @@ static RC_STRINGLIST *get_provided (const RC_DEPINFO *depinfo, return providers; } -static void visit_service (const RC_DEPTREE *deptree, - const RC_STRINGLIST *types, - RC_STRINGLIST *sorted, - RC_STRINGLIST *visited, - 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 *visited, + const RC_DEPINFO *depinfo, + const char *runlevel, int options) { RC_STRING *type; RC_STRING *service; @@ -392,7 +392,9 @@ static void visit_service (const RC_DEPTREE *deptree, if (! options & RC_DEP_TRACE || strcmp(type->value, "iprovide") == 0) { - rc_stringlist_add(sorted, service->value); + if (! *sorted) + *sorted = rc_stringlist_new(); + rc_stringlist_add(*sorted, service->value); continue; } @@ -445,8 +447,11 @@ static void visit_service (const RC_DEPTREE *deptree, are also the service calling us or we are provided by something */ svcname = getenv("SVCNAME"); if (! svcname || strcmp(svcname, depinfo->service) != 0) - if (! get_deptype(depinfo, "providedby")) - rc_stringlist_add(sorted, depinfo->service); + if (! get_deptype(depinfo, "providedby")) { + if (! *sorted) + *sorted = rc_stringlist_new(); + rc_stringlist_add(*sorted, depinfo->service); + } } RC_STRINGLIST *rc_deptree_depend(const RC_DEPTREE *deptree, @@ -478,7 +483,7 @@ RC_STRINGLIST *rc_deptree_depends (const RC_DEPTREE *deptree, const RC_STRINGLIST *services, const char *runlevel, int options) { - RC_STRINGLIST *sorted = rc_stringlist_new(); + RC_STRINGLIST *sorted = NULL; RC_STRINGLIST *visited = rc_stringlist_new(); RC_DEPINFO *di; const RC_STRING *service; @@ -493,11 +498,11 @@ RC_STRINGLIST *rc_deptree_depends (const RC_DEPTREE *deptree, continue; } if (types) - visit_service (deptree, types, sorted, visited, - di, runlevel, options); + visit_service(deptree, types, &sorted, visited, + di, runlevel, options); } - rc_stringlist_free (visited); + rc_stringlist_free(visited); return sorted; } librc_hidden_def(rc_deptree_depends) @@ -522,12 +527,23 @@ RC_STRINGLIST *rc_deptree_order(const RC_DEPTREE *deptree, list = rc_services_in_state(RC_SERVICE_STARTED); list2 = rc_services_in_state (RC_SERVICE_INACTIVE); - TAILQ_CONCAT(list, list2, entries); - free(list2); + if (list2) { + if (list) { + TAILQ_CONCAT(list, list2, entries); + free(list2); + } else + list = 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); @@ -567,7 +583,7 @@ bool rc_newer_than(const char *source, const char *target) bool newer = true; DIR *dp; struct dirent *d; - char *path; + char path[PATH_MAX]; int serrno = errno; /* We have to exist */ @@ -594,9 +610,8 @@ bool rc_newer_than(const char *source, const char *target) if (d->d_name[0] == '.') continue; - path = rc_strcatpaths(target, d->d_name, (char *) NULL); + snprintf(path, sizeof(path), "%s/%s", target, d->d_name); newer = rc_newer_than(source, path); - free(path); if (! newer) break; } @@ -671,14 +686,16 @@ bool 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); - TAILQ_FOREACH(s, config, entries) { - if (! rc_newer_than(RC_DEPTREE_CACHE, s->value)) { - newer = true; - break; + 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; + } } + rc_stringlist_free(config); } - rc_stringlist_free(config); return newer; } diff --git a/src/librc/librc-misc.c b/src/librc/librc-misc.c index fac78e2a..747a8fb6 100644 --- a/src/librc/librc-misc.c +++ b/src/librc/librc-misc.c @@ -54,57 +54,6 @@ bool rc_yesno (const char *value) } librc_hidden_def(rc_yesno) -char *rc_strcatpaths (const char *path1, const char *paths, ...) -{ - va_list ap; - size_t length; - size_t i; - char *p; - char *path; - char *pathp; - - if (! path1 || ! paths) - return NULL; - - length = strlen (path1) + strlen (paths) + 1; - if (*paths != '/') - length ++; - - va_start (ap, paths); - while ((p = va_arg (ap, char *)) != NULL) { - if (*p != '/') - length ++; - length += strlen (p); - } - va_end (ap); - - pathp = path = xmalloc (length * sizeof (char)); - memset (path, 0, length); - i = strlen (path1); - memcpy (path, path1, i); - pathp += i; - if (*paths != '/') - *pathp ++ = '/'; - i = strlen (paths); - memcpy (pathp, paths, i); - pathp += i; - - va_start (ap, paths); - while ((p = va_arg (ap, char *)) != NULL) { - if (*p != '/') - *pathp ++= '/'; - i = strlen (p); - memcpy (pathp, p, i); - pathp += i; - } - va_end (ap); - - *pathp++ = 0; - - return path; -} -librc_hidden_def(rc_strcatpaths) - char *rc_getline (FILE *fp) { char *line = NULL; @@ -138,13 +87,11 @@ RC_STRINGLIST *rc_config_list(const char *file) char *buffer; char *p; char *token; - RC_STRINGLIST *list; + RC_STRINGLIST *list = NULL; if (!(fp = fopen(file, "r"))) return NULL; - list = rc_stringlist_new(); - while ((p = buffer = rc_getline(fp))) { /* Strip leading spaces/tabs */ while ((*p == ' ') || (*p == '\t')) @@ -159,6 +106,8 @@ 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); } } @@ -172,8 +121,8 @@ librc_hidden_def(rc_config_list) RC_STRINGLIST *rc_config_load(const char *file) { - RC_STRINGLIST *list = NULL; - RC_STRINGLIST *config = NULL; + RC_STRINGLIST *list; + RC_STRINGLIST *config; char *token; RC_STRING *line; RC_STRING *cline; @@ -183,9 +132,11 @@ RC_STRINGLIST *rc_config_load(const char *file) char *newline; char *p; - config = rc_stringlist_new(); - list = rc_config_list(file); + if (! list) + return NULL; + + config = rc_stringlist_new(); TAILQ_FOREACH(line, list, entries) { /* Get entry */ p = line->value; diff --git a/src/librc/librc-stringlist.c b/src/librc/librc-stringlist.c index 93297ce9..44b03791 100644 --- a/src/librc/librc-stringlist.c +++ b/src/librc/librc-stringlist.c @@ -62,7 +62,7 @@ RC_STRING *rc_stringlist_addu (RC_STRINGLIST *list, const char *value) } librc_hidden_def(rc_stringlist_addu) -bool rc_stringlist_delete (RC_STRINGLIST *list, const char *value) +bool rc_stringlist_delete(RC_STRINGLIST *list, const char *value) { RC_STRING *s; diff --git a/src/librc/librc.c b/src/librc/librc.c index dfee0bfc..d3a4685b 100644 --- a/src/librc/librc.c +++ b/src/librc/librc.c @@ -72,25 +72,24 @@ static RC_STRINGLIST *ls_dir(const char *dir, int options) { DIR *dp; struct dirent *d; - RC_STRINGLIST *list; + RC_STRINGLIST *list = NULL; struct stat buf; size_t l; - char *file; + char file[PATH_MAX]; int r; if ((dp = opendir(dir)) == NULL) return NULL; - list = rc_stringlist_new(); 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. */ - file = rc_strcatpaths(dir, d->d_name, NULL); + snprintf(file, sizeof(file), "%s/%s", + dir, d->d_name); r = stat(file, &buf); - free(file); if (r != 0) continue; @@ -106,6 +105,8 @@ 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); } } @@ -118,7 +119,7 @@ static bool rm_dir(const char *pathname, bool top) { DIR *dp; struct dirent *d; - char *tmp = NULL; + char file[PATH_MAX]; struct stat s; bool retval = true; @@ -128,22 +129,21 @@ 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) { - free(tmp); - tmp = rc_strcatpaths(pathname, d->d_name, (char *) NULL); + snprintf(file, sizeof(file), "%s/%s", pathname, d->d_name); - if (stat(tmp, &s) != 0) { + if (stat(file, &s) != 0) { retval = false; break; } if (S_ISDIR(s.st_mode)) { - if (! rm_dir(tmp, true)) + if (! rm_dir(file, true)) { retval = false; break; } } else { - if (unlink(tmp)) { + if (unlink(file)) { retval = false; break; } @@ -151,7 +151,6 @@ static bool rm_dir(const char *pathname, bool top) } } closedir(dp); - free(tmp); if (! retval) return false; @@ -302,18 +301,16 @@ librc_hidden_def(rc_runlevel_set) bool rc_runlevel_exists(const char *runlevel) { - char *path; + char path[PATH_MAX]; struct stat buf; - bool retval = false; if (! runlevel) return false; - path = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, (char *) NULL); + snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel); if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) - retval = true; - free(path); - return retval; + return true; + return false; } librc_hidden_def(rc_runlevel_exists) @@ -321,8 +318,8 @@ librc_hidden_def(rc_runlevel_exists) char *rc_service_resolve(const char *service) { char buffer[PATH_MAX]; - char *file; - int r = 0; + char file[PATH_MAX]; + int r; struct stat buf; if (! service) @@ -332,43 +329,41 @@ char *rc_service_resolve(const char *service) return xstrdup(service); /* First check started services */ - file = rc_strcatpaths(RC_SVCDIR, "started", service, (char *) NULL); + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", "started", service); if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) { - free(file); - file = rc_strcatpaths(RC_SVCDIR, "inactive", service, (char *) NULL); - if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) { - free(file); - file = NULL; - } + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + "inactive", service); + if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) + *file = '\0'; } - memset(buffer, 0, sizeof(buffer)); - - /* Nope, so lets see if the user has written it */ -#ifdef RC_LOCAL_INITDIR - snprintf(buffer, sizeof(buffer), RC_LOCAL_INITDIR "/%s", service); - if (stat(buffer, &buf) == 0) - return xstrdup(buffer); -#endif - - if (file) { + if (*file) { + memset(buffer, 0, sizeof(buffer)); r = readlink(file, buffer, sizeof(buffer)); - free(file); if (r > 0) return xstrdup(buffer); } - snprintf(buffer, sizeof(buffer), RC_INITDIR "/%s", service); - /* So we don't exist in /etc/init.d - check RC_PKG_INITDIR */ +#ifdef RC_LOCAL_INITDIR + /* Nope, so lets see if the user has written it */ + snprintf(file, sizeof(file), RC_LOCAL_INITDIR "/%s", service); + if (stat(file, &buf) == 0) + return xstrdup(file); +#endif + + /* System scripts take precedence over 3rd party ones */ + snprintf(file, sizeof(file), RC_INITDIR "/%s", service); + if (stat(file, &buf) == 0) + return xstrdup(file); + #ifdef RC_PKG_INITDIR - if (stat(buffer, &buf) != 0) { - snprintf(buffer, sizeof(buffer), RC_PKG_INITDIR "/%s", service); - if (stat(buffer, &buf) != 0) - return NULL; - } + /* Check RC_PKG_INITDIR */ + snprintf(file, sizeof(file), RC_PKG_INITDIR "/%s", service); + if (stat(file, &buf) == 0) + return xstrdup(file); #endif - return xstrdup(buffer); + return NULL; } librc_hidden_def(rc_service_resolve) @@ -406,7 +401,7 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service) char *svc; char *cmd = NULL; char *buffer = NULL; - RC_STRINGLIST *commands; + RC_STRINGLIST *commands = NULL; char *token; char *p; FILE *fp; @@ -415,7 +410,6 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service) if (! (svc = rc_service_resolve(service))) return NULL; - commands = rc_stringlist_new(); l = strlen(OPTSTR) + strlen(svc) + 1; cmd = xmalloc(sizeof(char) * l); @@ -424,8 +418,11 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service) if ((fp = popen(cmd, "r"))) { p = buffer = rc_getline(fp); - while ((token = strsep(&p, " "))) + while ((token = strsep(&p, " "))) { + if (! commands) + commands = rc_stringlist_new(); rc_stringlist_add(commands, token); + } pclose(fp); free(buffer); } @@ -464,24 +461,17 @@ librc_hidden_def(rc_service_description) bool rc_service_in_runlevel(const char *service, const char *runlevel) { - char *file; - bool retval; - - if (! runlevel || ! service) - return false; - - file = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, basename_c(service), - (char *) NULL); - retval = exists(file); - free(file); + char file[PATH_MAX]; - return retval; + snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s", + runlevel, basename_c(service)); + return exists(file); } librc_hidden_def(rc_service_in_runlevel) bool rc_service_mark(const char *service, const RC_SERVICE state) { - char *file; + char file[PATH_MAX]; int i = 0; int skip_state = -1; const char *base; @@ -504,18 +494,16 @@ bool rc_service_mark(const char *service, const RC_SERVICE state) return false; } - file = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state (state), base, - (char *) NULL); + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + rc_parse_service_state (state), base); if (exists(file)) unlink(file); i = symlink(init, file); if (i != 0) { - free(file); free(init); return false; } - free(file); skip_state = state; } @@ -534,24 +522,22 @@ bool rc_service_mark(const char *service, const RC_SERVICE state) s != RC_SERVICE_SCHEDULED) && (! skip_wasinactive || s != RC_SERVICE_WASINACTIVE)) { - file = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state(s), base, - (char *) NULL); + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + rc_parse_service_state(s), base); if (exists(file)) { if ((state == RC_SERVICE_STARTING || state == RC_SERVICE_STOPPING) && s == RC_SERVICE_INACTIVE) { - was = rc_strcatpaths(RC_SVCDIR, - rc_parse_service_state(RC_SERVICE_WASINACTIVE), - base, (char *) NULL); - + snprintf(was, sizeof(was), + RC_SVCDIR "/%s/%s", + rc_parse_service_state(RC_SERVICE_WASINACTIVE), + base); symlink(init, was); skip_wasinactive = true; - free(was); } unlink(file); } - free(file); } } @@ -560,42 +546,43 @@ bool rc_service_mark(const char *service, const RC_SERVICE state) state == RC_SERVICE_STOPPED || state == RC_SERVICE_INACTIVE) { - file = rc_strcatpaths(RC_SVCDIR, "exclusive", base, (char *) NULL); + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + "exclusive", base); unlink(file); - free(file); } /* Remove any options and daemons the service may have stored */ if (state == RC_SERVICE_STOPPED) { - file = rc_strcatpaths(RC_SVCDIR, "options", base, (char *) NULL); + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + "options", base); rm_dir(file, true); - free(file); - file = rc_strcatpaths(RC_SVCDIR, "daemons", base, (char *) NULL); + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + "daemons", base); rm_dir(file, true); - free(file); rc_service_schedule_clear(service); } /* These are final states, so remove us from scheduled */ if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) { - file = rc_strcatpaths(RC_SVCDIR, "scheduled", (char *) NULL); + snprintf(file, sizeof(file), RC_SVCDIR "/%s", "scheduled"); dirs = ls_dir(file, 0); - - TAILQ_FOREACH(dir, dirs, entries) { - was = rc_strcatpaths(file, dir->value, base, (char *) NULL); - unlink(was); - free(was); - - /* Try and remove the dir - we don't care about errors */ - was = rc_strcatpaths(file, dir->value, (char *) NULL); - serrno = errno; - rmdir(was); - errno = serrno; - free(was); + 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); } - rc_stringlist_free(dirs); } free(init); @@ -607,35 +594,36 @@ RC_SERVICE rc_service_state(const char *service) { int i; int state = RC_SERVICE_STOPPED; - char *file; + char file[PATH_MAX]; RC_STRINGLIST *dirs; RC_STRING *dir; + const char *base = basename_c(service); for (i = 0; rc_service_state_names[i].name; i++) { - file = rc_strcatpaths(RC_SVCDIR, rc_service_state_names[i].name, - basename_c(service), (char*) NULL); + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", + rc_service_state_names[i].name, base); if (exists(file)) { if (rc_service_state_names[i].state <= 0x10) state = rc_service_state_names[i].state; else state |= rc_service_state_names[i].state; } - free(file); } if (state & RC_SERVICE_STOPPED) { dirs = ls_dir(RC_SVCDIR "/scheduled", 0); - TAILQ_FOREACH (dir, dirs, entries) { - file = rc_strcatpaths(RC_SVCDIR, "scheduled", - dir->value, - service, (char *) NULL); - if (exists(file)) - state |= RC_SERVICE_SCHEDULED; - free(file); - if (state & RC_SERVICE_SCHEDULED) - break; + 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; + } + } + rc_stringlist_free(dirs); } - rc_stringlist_free(dirs); } return state; @@ -646,14 +634,14 @@ char *rc_service_value_get(const char *service, const char *option) { FILE *fp; char *line = NULL; - char *file = rc_strcatpaths(RC_SVCDIR, "options", service, option, - (char *) NULL); + char file[PATH_MAX]; + snprintf(file, sizeof(file), RC_SVCDIR "/options/%s/%s", + service, option); if ((fp = fopen(file, "r"))) { line = rc_getline(fp); fclose(fp); } - free(file); return line; } @@ -663,33 +651,27 @@ bool rc_service_value_set(const char *service, const char *option, const char *value) { FILE *fp; - char *path = rc_strcatpaths(RC_SVCDIR, "options", service, (char *) NULL); - char *file = rc_strcatpaths(path, option, (char *) NULL); - bool retval = false; + char file[PATH_MAX]; + char *p = file; - if (mkdir(path, 0755) != 0 && errno != EEXIST) { - free(path); - free(file); + p += snprintf(file, sizeof(file), RC_SVCDIR "/options/%s", service); + if (mkdir(file, 0755) != 0 && errno != EEXIST) return false; - } - - if ((fp = fopen(file, "w"))) { - if (value) - fprintf(fp, "%s", value); - fclose(fp); - retval = true; - } - free(path); - free(file); - return retval; + snprintf(p, sizeof(file) - (p - file), "/%s", option); + if (!(fp = fopen(file, "w"))) + return false; + if (value) + fprintf(fp, "%s", value); + fclose(fp); + return true; } librc_hidden_def(rc_service_value_set) static pid_t _exec_service(const char *service, const char *arg) { char *file; - char *fifo; + char fifo[PATH_MAX]; pid_t pid = -1; sigset_t full; sigset_t old; @@ -703,11 +685,9 @@ static pid_t _exec_service(const char *service, const char *arg) } /* We create a fifo so that other services can wait until we complete */ - fifo = rc_strcatpaths(RC_SVCDIR, "exclusive", basename_c(service), - (char *) NULL); - + snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s", + basename_c(service)); if (mkfifo(fifo, 0600) != 0 && errno != EEXIST) { - free(fifo); free(file); return -1; } @@ -745,7 +725,6 @@ static pid_t _exec_service(const char *service, const char *arg) sigprocmask(SIG_SETMASK, &old, NULL); - free(fifo); free(file); return pid; @@ -782,28 +761,24 @@ librc_hidden_def(rc_service_start) bool rc_service_schedule_start(const char *service, const char *service_to_start) { - char *dir; + char file[PATH_MAX]; + char *p = file; char *init; - char *file; bool retval; /* service may be a provided service, like net */ if (! service || ! rc_service_exists(service_to_start)) return false; - dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service), - (char *) NULL); - if (mkdir(dir, 0755) != 0 && errno != EEXIST) { - free(dir); + p += snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s", + basename_c(service)); + if (mkdir(file, 0755) != 0 && errno != EEXIST) return false; - } init = rc_service_resolve(service_to_start); - file = rc_strcatpaths(dir, basename_c(service_to_start), (char *) NULL); + snprintf(p, sizeof(file) - (p - file), "/%s", basename_c(service_to_start)); retval = (exists(file) || symlink(init, file) == 0); free(init); - free(file); - free(dir); return retval; } @@ -811,20 +786,19 @@ librc_hidden_def(rc_service_schedule_start) bool rc_service_schedule_clear(const char *service) { - char *dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service), - (char *) NULL); - bool retval; + char dir[PATH_MAX]; - if (! (retval = rm_dir(dir, true)) && errno == ENOENT) - retval = true; - free(dir); - return retval; + snprintf(dir, sizeof(dir), RC_SVCDIR "/scheduled/%s", + basename_c(service)); + 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) { - char *dir; + char dir[PATH_MAX]; RC_STRINGLIST *list; if (! runlevel) { @@ -855,43 +829,47 @@ RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel) /* These special levels never contain any services */ if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 || strcmp(runlevel, RC_LEVEL_SINGLE) == 0) { - list = rc_stringlist_new(); - return list; + return NULL; } - dir = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, (char *) NULL); + snprintf(dir, sizeof(dir), RC_RUNLEVELDIR "/%s", runlevel); list = ls_dir(dir, LS_INITD); - free(dir); return list; } librc_hidden_def(rc_services_in_runlevel) RC_STRINGLIST *rc_services_in_state(RC_SERVICE state) { - char *dir = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state(state), - (char *) NULL); RC_STRINGLIST *services; RC_STRINGLIST *list; RC_STRINGLIST *dirs; RC_STRING *d; - char *p; + char dir[PATH_MAX]; + char *p = dir; + + p += snprintf(dir, sizeof(dir), RC_SVCDIR "/%s", + rc_parse_service_state(state)); + + if (state != RC_SERVICE_SCHEDULED) + return ls_dir(dir, LS_INITD); + + + dirs = ls_dir(dir, 0); + if (! dirs) + return NULL; - if (state == RC_SERVICE_SCHEDULED) { - dirs = ls_dir(dir, 0); - list = rc_stringlist_new(); - TAILQ_FOREACH(d, dirs, entries) { - p = rc_strcatpaths(dir, d->value, (char *) NULL); - services = ls_dir(p, LS_INITD); - free(p); + 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) { TAILQ_CONCAT(list, services, entries); free(services); } - rc_stringlist_free(dirs); - } else { - list = ls_dir(dir, LS_INITD); } + rc_stringlist_free(dirs); - free(dir); return list; } librc_hidden_def(rc_services_in_state) @@ -900,9 +878,11 @@ bool rc_service_add(const char *runlevel, const char *service) { bool retval; char *init; - char *file; + char file[PATH_MAX]; char path[MAXPATHLEN] = { '\0' }; - char *p; + char *p = NULL; + char binit[PATH_MAX]; + char *i; if (! rc_runlevel_exists(runlevel)) { errno = ENOENT; @@ -914,13 +894,15 @@ bool rc_service_add(const char *runlevel, const char *service) return false; } - init = rc_service_resolve(service); + i = init = rc_service_resolve(service); + snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s", + runlevel, basename_c(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) { - p = realpath(dirname (init), path); free(init); + p = realpath(dirname (init), path); if (! *p) return false; @@ -929,33 +911,25 @@ bool rc_service_add(const char *runlevel, const char *service) errno = EPERM; return false; } - init = rc_strcatpaths(RC_INITDIR, service, (char *) NULL); + snprintf(binit, sizeof(binit), RC_INITDIR "/%s", service); + i = binit; } - file = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, basename_c(service), - (char *) NULL); - retval = (symlink(init, file) == 0); + retval = (symlink(i, file) == 0); free(init); - free(file); return retval; } librc_hidden_def(rc_service_add) bool rc_service_delete (const char *runlevel, const char *service) { - char *file; - bool retval = false; + char file[PATH_MAX]; - if (! runlevel || ! service) - return false; - - file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c(service), - (char *) NULL); + snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s", + runlevel, basename_c(service)); if (unlink(file) == 0) - retval = true; - - free(file); - return retval; + return true; + return false; } librc_hidden_def(rc_service_delete) @@ -964,15 +938,19 @@ RC_STRINGLIST *rc_services_scheduled_by(const char *service) RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0); RC_STRINGLIST *list; RC_STRING *dir; - char *file; + char file[PATH_MAX]; + + if (! dirs) + return NULL; - list = rc_stringlist_new(); TAILQ_FOREACH (dir, dirs, entries) { - file = rc_strcatpaths(RC_SVCDIR, "scheduled", dir->value, - service, (char *) NULL); - if (exists(file)) + snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s/%s", + dir->value, service); + if (exists(file)) { + if (! list) + list = rc_stringlist_new(); rc_stringlist_add(list, file); - free(file); + } } rc_stringlist_free(dirs); @@ -982,11 +960,10 @@ librc_hidden_def(rc_services_scheduled_by) RC_STRINGLIST *rc_services_scheduled(const char *service) { - char *dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service), - (char *) NULL); - RC_STRINGLIST *list = ls_dir(dir, LS_INITD); + char dir[PATH_MAX]; - free(dir); - return list; + snprintf(dir, sizeof(dir), "RC_SVCDIR/scheduled/%s", + basename_c(service)); + return ls_dir(dir, LS_INITD); } librc_hidden_def(rc_services_scheduled) diff --git a/src/librc/librc.h b/src/librc/librc.h index aaad7ccd..376a62ff 100644 --- a/src/librc/librc.h +++ b/src/librc/librc.h @@ -112,7 +112,6 @@ librc_hidden_proto(rc_service_started_daemon) librc_hidden_proto(rc_service_state) librc_hidden_proto(rc_service_value_get) librc_hidden_proto(rc_service_value_set) -librc_hidden_proto(rc_strcatpaths) librc_hidden_proto(rc_stringlist_add) librc_hidden_proto(rc_stringlist_addu) librc_hidden_proto(rc_stringlist_delete) diff --git a/src/librc/rc.h b/src/librc/rc.h index bf40e31c..ba49e78d 100644 --- a/src/librc/rc.h +++ b/src/librc/rc.h @@ -27,17 +27,6 @@ #ifndef __RC_H__ #define __RC_H__ -#ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 1000 + __GNUC__MINOR) -# if (GCC_VERSION >= 3005) -# define SENTINEL __attribute__ ((__sentinel__)) -# endif -# define DEPRECATED __attribute__ ((deprecated)) -#endif -#ifndef SENTINEL -# define SENTINEL -#endif - #include <sys/types.h> #include <sys/queue.h> #include <stdbool.h> @@ -444,13 +433,6 @@ void rc_stringlist_sort(RC_STRINGLIST **); * @param list to free */ void rc_stringlist_free(RC_STRINGLIST *); -/*! Concatenate paths adding '/' if needed. The resultant pointer should be - * freed when finished with. - * @param path1 starting path - * @param paths NULL terminated list of paths to add - * @return pointer to the new path */ -char *rc_strcatpaths(const char *, const char *, ...) SENTINEL; - typedef struct rc_pid { pid_t pid; diff --git a/src/librc/rc.map b/src/librc/rc.map index 8ad4e187..55dea008 100644 --- a/src/librc/rc.map +++ b/src/librc/rc.map @@ -26,6 +26,7 @@ global: rc_service_delete; rc_service_description; rc_service_exists; + rc_service_extra_commands; rc_service_in_runlevel; rc_service_mark; rc_service_options; @@ -42,7 +43,6 @@ global: rc_service_state; rc_service_value_get; rc_service_value_set; - rc_strcatpaths; rc_stringlist_add; rc_stringlist_addu; rc_stringlist_delete; diff --git a/src/rc/rc-plugin.c b/src/rc/rc-plugin.c index f0ee5a61..034f79d2 100644 --- a/src/rc/rc-plugin.c +++ b/src/rc/rc-plugin.c @@ -79,7 +79,7 @@ void rc_plugin_load(void) DIR *dp; struct dirent *d; PLUGIN *plugin; - char *p; + char file[PATH_MAX]; void *h; int (*fptr)(RC_HOOK, const char *); @@ -96,9 +96,8 @@ void rc_plugin_load(void) if (d->d_name[0] == '.') continue; - p = rc_strcatpaths(RC_PLUGINDIR, d->d_name, NULL); - h = dlopen(p, RTLD_LAZY); - free(p); + snprintf(file, sizeof(file), RC_PLUGINDIR "/%s", d->d_name); + h = dlopen(file, RTLD_LAZY); if (! h) { eerror("dlopen: %s", dlerror()); continue; diff --git a/src/rc/rc.c b/src/rc/rc.c index d906870c..04b814e6 100644 --- a/src/rc/rc.c +++ b/src/rc/rc.c @@ -633,6 +633,116 @@ static void do_coldplug(void) 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 + && RUNLEVEL && + (strcmp(RUNLEVEL, "S") == 0 || + strcmp(RUNLEVEL, "1") == 0) +#endif + ) + { + /* OK, we're either in runlevel 1 or single user mode */ + + /* exec init-early.sh if it exists + * This should just setup the console to use the correct + * font. Maybe it should setup the keyboard too? */ + if (exists(INITEARLYSH)) + run_script(INITEARLYSH); + + uname(&uts); + printf("\n %sOpenRC %s" VERSION "%s is starting up %s", + ecolor(ECOLOR_GOOD), ecolor(ECOLOR_HILITE), + ecolor(ECOLOR_NORMAL), ecolor(ECOLOR_BRACKET)); +#ifdef BRANDING + printf(BRANDING " (%s)", uts.machine); +#else + printf("%s %s (%s)", + uts.sysname, + uts.release, + uts.machine); +#endif + + if ((sys = rc_sys())) + printf(" [%s]", sys); + + printf("%s\n\n", ecolor(ECOLOR_NORMAL)); + + if (! rc_yesno(getenv ("EINFO_QUIET")) && + rc_conf_yesno("rc_interactive")) + printf("Press %sI%s to enter interactive boot mode\n\n", + ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL)); + + setenv("RC_SOFTLEVEL", newlevel, 1); + rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, newlevel); + hook_out = RC_HOOK_RUNLEVEL_START_OUT; + run_script(INITSH); + +#ifdef __linux__ + /* If we requested a softlevel, save it now */ + set_ksoftlevel(NULL); + if ((cmd = proc_getent("softlevel"))) { + set_ksoftlevel(cmd); + free(cmd); + } +#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_ksoftlevel(runlevel); + single_user(); + } +#endif + } else if (strcmp(newlevel, RC_LEVEL_REBOOT) == 0) { + if (! RUNLEVEL || + strcmp(RUNLEVEL, "6") != 0) + { + rc_logger_close(); + execl(SHUTDOWN, SHUTDOWN, "-r", "now", (char *) NULL); + eerrorx("%s: unable to exec `" SHUTDOWN "': %s", + applet, strerror(errno)); + } + } else if (strcmp(newlevel, RC_LEVEL_SHUTDOWN) == 0) { + if (! RUNLEVEL || + strcmp(RUNLEVEL, "0") != 0) + { + rc_logger_close(); + execl(SHUTDOWN, SHUTDOWN, +#ifdef __linux__ + "-h", +#else + "-p", +#endif + "now", (char *) NULL); + eerrorx("%s: unable to exec `" SHUTDOWN "': %s", + applet, strerror(errno)); + } + } +} + + static bool runlevel_config(const char *service, const char *level) { char *init = rc_service_resolve(service); @@ -651,6 +761,140 @@ static bool runlevel_config(const char *service, const char *level) return retval; } +static void do_stop_services(const char *newlevel, bool going_down, bool parallel) +{ + pid_t pid; + RC_STRING *service, *svc1, *svc2; + RC_STRINGLIST *deporder, *tmplist; + + if (! types_n) { + types_n = rc_stringlist_new(); + rc_stringlist_add(types_n, "needsme"); + } + + TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries) + { + if (rc_service_state(service->value) & RC_SERVICE_STOPPED) + continue; + + /* We always stop the service when in these runlevels */ + if (going_down) { + pid = rc_service_stop(service->value); + if (pid > 0 && ! parallel) + rc_waitpid(pid); + continue; + } + + /* If we're in the start list then don't bother stopping us */ + TAILQ_FOREACH(svc1, start_services, entries) + if (strcmp (svc1->value, service->value) == 0) + break; + + if (svc1) { + if (newlevel && strcmp(runlevel, newlevel) != 0) { + /* So we're in the start list. But we should + * be stopped if we have a runlevel + * configuration file for either the current + * or next so we use the correct one. */ + if (! runlevel_config(service->value, runlevel) && + ! runlevel_config(service->value, newlevel)) + continue; + } + else + continue; + } + + /* We got this far! Or last check is to see if any any service + * that going to be started depends on us */ + if (! svc1) { + tmplist = rc_stringlist_new(); + rc_stringlist_add(tmplist, service->value); + deporder = rc_deptree_depends(deptree, types_n, tmplist, + runlevel, RC_DEP_STRICT); + rc_stringlist_free(tmplist); + svc2 = NULL; + TAILQ_FOREACH (svc1, deporder, entries) { + TAILQ_FOREACH(svc2, start_services, entries) + if (strcmp (svc1->value, svc2->value) == 0) + break; + if (svc2) + break; + } + rc_stringlist_free(deporder); + + if (svc2) + continue; + } + + /* After all that we can finally stop the blighter! */ + pid = rc_service_stop(service->value); + if (pid > 0) { + add_pid(pid); + if (! parallel) { + rc_waitpid(pid); + remove_pid(pid); + } + } + } +} + +static void do_start_services(bool parallel) +{ + RC_STRING *service; + pid_t pid; + bool interactive = false; + + if (! rc_yesno(getenv("EINFO_QUIET"))) + interactive = exists(INTERACTIVE); + + TAILQ_FOREACH(service, start_services, entries) { + if (rc_service_state(service->value) & RC_SERVICE_STOPPED) { + if (! interactive) + interactive = want_interactive(); + + if (interactive) { +interactive_retry: + printf("\n"); + einfo("About to start the service %s", + service->value); + eindent(); + einfo("1) Start the service\t\t2) Skip the service"); + einfo("3) Continue boot process\t\t4) Exit to shell"); + eoutdent(); +interactive_option: + switch (read_key(true)) { + case '1': break; + case '2': continue; + case '3': interactive = false; break; + case '4': sulogin(true); goto interactive_retry; + default: goto interactive_option; + } + } + + pid = rc_service_start(service->value); + + /* Remember the pid if we're running in parallel */ + if (pid > 0) { + add_pid(pid); + + if (! parallel) { + rc_waitpid(pid); + remove_pid(pid); + } + } + } + } + + /* Store our interactive status for boot */ + if (interactive && strcmp(runlevel, getenv("RC_BOOTLEVEL")) == 0) + mark_interactive(); + else { + if (exists(INTERACTIVE)) + unlink(INTERACTIVE); + } + +} + #include "_usage.h" #define getoptstring "o:" getoptstring_COMMON static const struct option longopts[] = { @@ -666,25 +910,18 @@ static const char * const longopts_help[] = { int main(int argc, char **argv) { const char *bootlevel = NULL; - const char *sys = rc_sys(); char *newlevel = NULL; RC_STRINGLIST *deporder = NULL; RC_STRINGLIST *tmplist; RC_STRING *service; bool going_down = false; - bool interactive = false; int depoptions = RC_DEP_STRICT | RC_DEP_TRACE; char ksoftbuffer [PATH_MAX]; char pidstr[6]; int opt; bool parallel; int regen = 0; - pid_t pid; - RC_STRING *svc1; - RC_STRING *svc2 = NULL; - struct utsname uts; #ifdef __linux__ - char *cmd; char *proc; char *p; char *token; @@ -698,8 +935,8 @@ int main(int argc, char **argv) if (argc > 1 && (strcmp(argv[1], "--version") == 0)) { printf("%s (OpenRC", applet); - if (sys) - printf(" [%s]", sys); + if ((bootlevel = rc_sys())) + printf(" [%s]", bootlevel); printf(") " VERSION #ifdef BRANDING " (" BRANDING ")" @@ -765,8 +1002,6 @@ int main(int argc, char **argv) signal_setup(SIGUSR1, handle_signal); signal_setup(SIGWINCH, handle_signal); - if (! rc_yesno(getenv("EINFO_QUIET"))) - interactive = exists(INTERACTIVE); rc_plugin_load(); /* Check we're in the runlevel requested, ie from @@ -774,107 +1009,8 @@ int main(int argc, char **argv) * rc shutdown * rc reboot */ - if (newlevel) { - if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0 -#ifndef PREFIX - && RUNLEVEL && - (strcmp(RUNLEVEL, "S") == 0 || - strcmp(RUNLEVEL, "1") == 0) -#endif - ) - { - /* OK, we're either in runlevel 1 or single user mode */ - - /* exec init-early.sh if it exists - * This should just setup the console to use the correct - * font. Maybe it should setup the keyboard too? */ - if (exists(INITEARLYSH)) - run_script(INITEARLYSH); - - uname(&uts); - printf("\n %sOpenRC %s" VERSION "%s is starting up %s", - ecolor(ECOLOR_GOOD), ecolor(ECOLOR_HILITE), - ecolor(ECOLOR_NORMAL), ecolor(ECOLOR_BRACKET)); -#ifdef BRANDING - printf(BRANDING " (%s)", uts.machine); -#else - printf("%s %s (%s)", - uts.sysname, - uts.release, - uts.machine); -#endif - - if (sys) - printf(" [%s]", sys); - - printf("%s\n\n", ecolor(ECOLOR_NORMAL)); - - if (! rc_yesno(getenv ("EINFO_QUIET")) && - rc_conf_yesno("rc_interactive")) - printf("Press %sI%s to enter interactive boot mode\n\n", - ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL)); - - setenv("RC_SOFTLEVEL", newlevel, 1); - rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, newlevel); - hook_out = RC_HOOK_RUNLEVEL_START_OUT; - run_script(INITSH); - -#ifdef __linux__ - /* If we requested a softlevel, save it now */ - set_ksoftlevel(NULL); - if ((cmd = proc_getent("softlevel"))) { - set_ksoftlevel(cmd); - free(cmd); - } -#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_ksoftlevel(runlevel); - single_user(); - } -#endif - } else if (strcmp(newlevel, RC_LEVEL_REBOOT) == 0) { - if (! RUNLEVEL || - strcmp(RUNLEVEL, "6") != 0) - { - rc_logger_close(); - execl(SHUTDOWN, SHUTDOWN, "-r", "now", (char *) NULL); - eerrorx("%s: unable to exec `" SHUTDOWN "': %s", - applet, strerror(errno)); - } - } else if (strcmp(newlevel, RC_LEVEL_SHUTDOWN) == 0) { - if (! RUNLEVEL || - strcmp(RUNLEVEL, "0") != 0) - { - rc_logger_close(); - execl(SHUTDOWN, SHUTDOWN, -#ifdef __linux__ - "-h", -#else - "-p", -#endif - "now", (char *) NULL); - eerrorx("%s: unable to exec `" SHUTDOWN "': %s", - applet, strerror(errno)); - } - } - } + if (newlevel) + do_newlevel(newlevel); /* Now we start handling our children */ signal_setup(SIGCHLD, handle_signal); @@ -946,15 +1082,23 @@ 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); - TAILQ_CONCAT(stop_services, tmplist, entries); - free(tmplist); + if (tmplist) { + if (stop_services) { + TAILQ_CONCAT(stop_services, tmplist, entries); + free(tmplist); + } else + stop_services = tmplist; + } tmplist = rc_services_in_state(RC_SERVICE_STARTING); - TAILQ_CONCAT(stop_services, tmplist, entries); - free(tmplist); + if (tmplist) { + if (stop_services) { + TAILQ_CONCAT(stop_services, tmplist, entries); + free(tmplist); + } else + stop_services = tmplist; + } rc_stringlist_sort(&stop_services); - types_n = rc_stringlist_new(); - rc_stringlist_add(types_n, "needsme"); types_nua = rc_stringlist_new(); rc_stringlist_add(types_nua, "ineed"); @@ -976,12 +1120,18 @@ int main(int argc, char **argv) start_services = rc_services_in_runlevel(bootlevel); if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) { tmplist = rc_services_in_runlevel(newlevel ? newlevel : runlevel); - TAILQ_CONCAT(start_services, tmplist, entries); - free(tmplist); + if (tmplist) { + if (start_services) { + TAILQ_CONCAT(start_services, tmplist, entries); + free(tmplist); + } else + start_services = tmplist; + } } - TAILQ_FOREACH(service, coldplugged_services, entries) - rc_stringlist_addu(start_services, service->value); + if (coldplugged_services) + TAILQ_FOREACH(service, coldplugged_services, entries) + rc_stringlist_addu(start_services, service->value); } /* Save our softlevel now */ @@ -991,69 +1141,8 @@ int main(int argc, char **argv) parallel = rc_conf_yesno("rc_parallel"); /* Now stop the services that shouldn't be running */ - TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries) { - if (rc_service_state(service->value) & RC_SERVICE_STOPPED) - continue; - - /* We always stop the service when in these runlevels */ - if (going_down) { - pid = rc_service_stop(service->value); - if (pid > 0 && ! parallel) - rc_waitpid(pid); - continue; - } - - /* If we're in the start list then don't bother stopping us */ - TAILQ_FOREACH(svc1, start_services, entries) - if (strcmp (svc1->value, service->value) == 0) - break; - - if (svc1) { - if (newlevel && strcmp(runlevel, newlevel) != 0) { - /* So we're in the start list. But we should - * be stopped if we have a runlevel - * configuration file for either the current - * or next so we use the correct one. */ - if (! runlevel_config(service->value, runlevel) && - ! runlevel_config(service->value, newlevel)) - continue; - } - else - continue; - } - - /* We got this far! Or last check is to see if any any service - * that going to be started depends on us */ - if (! svc1) { - tmplist = rc_stringlist_new(); - rc_stringlist_add(tmplist, service->value); - deporder = rc_deptree_depends(deptree, types_n, tmplist, - runlevel, RC_DEP_STRICT); - rc_stringlist_free(tmplist); - svc2 = NULL; - TAILQ_FOREACH (svc1, deporder, entries) { - TAILQ_FOREACH(svc2, start_services, entries) - if (strcmp (svc1->value, svc2->value) == 0) - break; - if (svc2) - break; - } - rc_stringlist_free(deporder); - - if (svc2) - continue; - } - - /* After all that we can finally stop the blighter! */ - pid = rc_service_stop(service->value); - if (pid > 0) { - add_pid(pid); - if (! parallel) { - rc_waitpid(pid); - remove_pid(pid); - } - } - } + if (stop_services) + do_stop_services(newlevel, parallel, going_down); /* Wait for our services to finish */ wait_for_services(); @@ -1094,15 +1183,18 @@ int main(int argc, char **argv) hook_out = RC_HOOK_RUNLEVEL_START_OUT; /* Re-add our coldplugged services if they stopped */ - TAILQ_FOREACH(service, coldplugged_services, entries) - rc_service_mark(service->value, RC_SERVICE_COLDPLUGGED); + if (coldplugged_services) + TAILQ_FOREACH(service, coldplugged_services, entries) + rc_service_mark(service->value, RC_SERVICE_COLDPLUGGED); /* Order the services to start */ - rc_stringlist_sort(&start_services); - deporder = rc_deptree_depends(deptree, types_nua, start_services, + if (start_services) { + rc_stringlist_sort(&start_services); + deporder = rc_deptree_depends(deptree, types_nua, start_services, runlevel, depoptions | RC_DEP_START); - rc_stringlist_free(start_services); - start_services = deporder; + rc_stringlist_free(start_services); + start_services = deporder; + } #ifdef __linux__ /* mark any services skipped as started */ @@ -1116,47 +1208,13 @@ int main(int argc, char **argv) } #endif - TAILQ_FOREACH(service, start_services, entries) { - if (rc_service_state(service->value) & RC_SERVICE_STOPPED) { - if (! interactive) - interactive = want_interactive(); - - if (interactive) { -interactive_retry: - printf("\n"); - einfo("About to start the service %s", - service->value); - eindent(); - einfo("1) Start the service\t\t2) Skip the service"); - einfo("3) Continue boot process\t\t4) Exit to shell"); - eoutdent(); -interactive_option: - switch (read_key(true)) { - case '1': break; - case '2': continue; - case '3': interactive = false; break; - case '4': sulogin(true); goto interactive_retry; - default: goto interactive_option; - } - } - - pid = rc_service_start(service->value); - - /* Remember the pid if we're running in parallel */ - if (pid > 0) { - add_pid(pid); + if (start_services) { + do_start_services(parallel); - if (! parallel) { - rc_waitpid(pid); - remove_pid(pid); - } - } - } + /* Wait for our services to finish */ + wait_for_services(); } - /* Wait for our services to finish */ - wait_for_services(); - rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel); hook_out = 0; @@ -1172,14 +1230,6 @@ interactive_option: } #endif - /* Store our interactive status for boot */ - if (interactive && strcmp(runlevel, bootlevel) == 0) - mark_interactive(); - else { - if (exists(INTERACTIVE)) - unlink(INTERACTIVE); - } - /* 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 */ diff --git a/src/rc/runscript.c b/src/rc/runscript.c index e7a094f8..704d32fe 100644 --- a/src/rc/runscript.c +++ b/src/rc/runscript.c @@ -82,8 +82,8 @@ static RC_STRINGLIST *use_services = NULL; static RC_STRINGLIST *services = NULL; static RC_STRINGLIST *tmplist = NULL; static char *service = NULL; -static char *exclusive = NULL; -static char *mtime_test = NULL; +static char exclusive[PATH_MAX] = { '\0' }; +static char mtime_test[PATH_MAX] = { '\0' }; static RC_DEPTREE *deptree = NULL; static char *runlevel = NULL; static bool sighup = false; @@ -212,7 +212,7 @@ static const char *const tests[] = { }; static bool in_control() { - char *path; + char file[PATH_MAX]; time_t m; time_t mtime; int i = 0; @@ -230,15 +230,12 @@ static bool in_control() return false; while (tests[i]) { - path = rc_strcatpaths(RC_SVCDIR, tests[i], applet, (char *) NULL); - if (exists(path)) { - m = get_mtime(path, false); - if (mtime < m && m != 0) { - free(path); + snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", tests[i], applet); + if (exists(file)) { + m = get_mtime(file, false); + if (mtime < m && m != 0) return false; - } } - free(path); i++; } @@ -247,10 +244,11 @@ static bool in_control() static void uncoldplug() { - char *cold = rc_strcatpaths(RC_SVCDIR, "coldplugged", applet, (char *) NULL); - if (exists(cold) && unlink(cold) != 0) - eerror("%s: unlink `%s': %s", applet, cold, strerror(errno)); - free(cold); + char file[PATH_MAX]; + + snprintf(file, sizeof(file), RC_SVCDIR "/coldplugged/%s", applet); + if (exists(file) && unlink(file) != 0) + eerror("%s: unlink `%s': %s", applet, file, strerror(errno)); } static void start_services(RC_STRINGLIST *list) { @@ -305,10 +303,10 @@ static void restore_state(void) rc_service_mark(applet, RC_SERVICE_FAILED); } - if (exclusive) + if (*exclusive) { unlink(exclusive); - free(exclusive); - exclusive = NULL; + *exclusive = '\0'; + } } static void cleanup(void) @@ -347,17 +345,12 @@ static void cleanup(void) rc_stringlist_free(applet_list); rc_stringlist_free(tmplist); free (ibsave); - - if (mtime_test) - { - if (! rc_in_plugin) - unlink(mtime_test); - free(mtime_test); - } - free(exclusive); free(service); free(prefix); free(runlevel); + + if (*mtime_test && ! rc_in_plugin) + unlink(mtime_test); } static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) { @@ -580,37 +573,29 @@ static RC_SERVICE svc_status(void) static void make_exclusive(void) { - char *path; - size_t l; - /* We create a fifo so that other services can wait until we complete */ - if (! exclusive) - exclusive = rc_strcatpaths(RC_SVCDIR, "exclusive", applet, (char *) NULL); + 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)); - path = rc_strcatpaths(RC_SVCDIR, "exclusive", applet, (char *) NULL); - l = strlen (path) + 16; - mtime_test = xmalloc(sizeof (char) * l); - snprintf(mtime_test, l, "%s.%d", path, getpid()); - free(path); + 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", applet, mtime_test, strerror(errno)); - free(mtime_test); - mtime_test = NULL; + *mtime_test = '\0'; return; } if (symlink(service, mtime_test) != 0) { eerror("%s: symlink `%s' to `%s': %s", applet, service, mtime_test, strerror(errno)); - free(mtime_test); - mtime_test = NULL; + *mtime_test = '\0'; } } @@ -618,8 +603,7 @@ static void unlink_mtime_test(void) { if (unlink(mtime_test) != 0) eerror("%s: unlink `%s': %s", applet, mtime_test, strerror(errno)); - free(mtime_test); - mtime_test = NULL; + *mtime_test = '\0'; } static void get_started_services(void) @@ -627,8 +611,13 @@ 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); - TAILQ_CONCAT(restart_services, tmp, entries); - free(tmp); + if (tmp) { + if (restart_services) { + TAILQ_CONCAT(restart_services, tmp, entries); + free(tmp); + } else + restart_services = tmp; + } } static void setup_types(void) @@ -713,8 +702,8 @@ static void svc_start(bool deps) services = rc_deptree_depends(deptree, types_b, applet_list, runlevel, 0); - if (TAILQ_FIRST(services)) { - eerrorn ("ERROR: `%s' needs ", applet); + if (services && TAILQ_FIRST(services)) { + eerrorn("ERROR: `%s' needs ", applet); first = true; TAILQ_FOREACH(svc, services, entries) { if (first) @@ -733,7 +722,7 @@ static void svc_start(bool deps) use_services = rc_deptree_depends(deptree, types_nu, applet_list, runlevel, depoptions); - if (! rc_runlevel_starting()) + if (! rc_runlevel_starting() && use_services) TAILQ_FOREACH(svc, use_services, entries) if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) { pid_t pid = rc_service_start(svc->value); @@ -746,8 +735,7 @@ static void svc_start(bool deps) runlevel, depoptions); /* We use tmplist to hold our scheduled by list */ - tmplist = rc_stringlist_new(); - + tmplist = NULL; TAILQ_FOREACH(svc, services, entries) { RC_SERVICE svcs = rc_service_state(svc->value); if (svcs & RC_SERVICE_STARTED) @@ -768,14 +756,19 @@ static void svc_start(bool deps) if (! svc_wait(svc->value)) eerror ("%s: timed out waiting for %s", applet, svc->value); + if (! need_services) + continue; if ((svcs = rc_service_state(svc->value)) & RC_SERVICE_STARTED) continue; TAILQ_FOREACH(svc2, need_services, entries) { if (strcmp (svc->value, svc2->value) == 0) { if (svcs & RC_SERVICE_INACTIVE || svcs & RC_SERVICE_WASINACTIVE) - rc_stringlist_add(tmplist, svc->value); - else + { + if (! tmplist) + tmplist = rc_stringlist_new(); + rc_stringlist_add(tmplist, svc->value); + } else eerrorx("ERROR: cannot start %s as" " %s would not start", applet, svc->value); @@ -783,7 +776,7 @@ static void svc_start(bool deps) } } - if (TAILQ_FIRST(tmplist)) { + 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); @@ -813,14 +806,14 @@ static void svc_start(bool deps) p += snprintf(p, len, "%s", svc->value); } free(tmp); + rc_stringlist_free(tmplist); + tmplist = NULL; ewarnx("WARNING: %s is scheduled to start when %s has started", - applet, tmp); + applet, tmp); } rc_stringlist_free(services); services = NULL; - rc_stringlist_free(tmplist); - tmplist = NULL; } if (ibsave) @@ -928,65 +921,73 @@ static void svc_stop(bool deps) if (! types_m) setup_types(); - tmplist = rc_stringlist_new(); + tmplist = NULL; services = rc_deptree_depends(deptree, types_m, applet_list, runlevel, depoptions); - TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) { - RC_SERVICE svcs = rc_service_state(svc->value); - if (svcs & RC_SERVICE_STARTED || - svcs & RC_SERVICE_INACTIVE) - { - svc_wait(svc->value); - svcs = rc_service_state(svc->value); + if (services) { + TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) { + RC_SERVICE svcs = rc_service_state(svc->value); if (svcs & RC_SERVICE_STARTED || - svcs & RC_SERVICE_INACTIVE) + svcs & RC_SERVICE_INACTIVE) { - pid_t pid = rc_service_stop(svc->value); - if (! rc_conf_yesno("rc_parallel")) - rc_waitpid(pid); - rc_stringlist_add(tmplist, svc->value); + svc_wait(svc->value); + svcs = rc_service_state(svc->value); + if (svcs & RC_SERVICE_STARTED || + svcs & RC_SERVICE_INACTIVE) + { + pid_t pid = rc_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); + } } } + rc_stringlist_free(services); + services = NULL; } - rc_stringlist_free(services); - services = NULL; - TAILQ_FOREACH(svc, tmplist, entries) { - if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) - continue; + if (tmplist) { + TAILQ_FOREACH(svc, tmplist, entries) { + if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) + continue; - /* We used to loop 3 times here - maybe re-do this if needed */ - 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); - } + /* We used to loop 3 times here - maybe re-do this if needed */ + 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); + eerrorx("ERROR: cannot stop %s as %s is still up", + applet, svc->value); + } } + rc_stringlist_free(tmplist); + tmplist = NULL; } - 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 */ services = rc_deptree_depends(deptree, types_mua, applet_list, runlevel, depoptions); - TAILQ_FOREACH(svc, services, entries) { - if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) - continue; - svc_wait(svc->value); + 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; } - rc_stringlist_free (services); - services = NULL; } /* If we're stopping localmount, set LC_ALL=C so that @@ -1114,8 +1115,8 @@ int runscript(int argc, char **argv) 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)); - prefix = rc_strcatpaths("/dev/.rcboot", applet, (char *) NULL); - symlink(service, prefix); + snprintf(exclusive, sizeof(exclusive), "/dev/.rcboot/%s", applet); + symlink(service, exclusive); exit (EXIT_FAILURE); } #endif diff --git a/src/rc/start-stop-daemon.c b/src/rc/start-stop-daemon.c index 9b1c109e..6aec70b5 100644 --- a/src/rc/start-stop-daemon.c +++ b/src/rc/start-stop-daemon.c @@ -51,6 +51,7 @@ #include <errno.h> #include <fcntl.h> #include <getopt.h> +#include <limits.h> #include <grp.h> #include <pwd.h> #include <signal.h> @@ -590,6 +591,7 @@ int start_stop_daemon(int argc, char **argv) bool setuser = false; char *p; char *tmp; + char exec_file[PATH_MAX]; struct passwd *pw; struct group *gr; char line[130]; @@ -773,14 +775,13 @@ int start_stop_daemon(int argc, char **argv) /* Validate that the binary exists if we are starting */ if (exec) { - if (ch_root) - tmp = rc_strcatpaths(ch_root, exec, (char *) NULL); - else + if (ch_root) { + snprintf(exec_file, sizeof(exec_file), "%s/%s", ch_root, exec); + tmp = exec_file; + } else tmp = exec; if (start && ! exists(tmp)) { eerror("%s: %s does not exist", applet, tmp); - if (ch_root) - free(tmp); exit(EXIT_FAILURE); } @@ -807,15 +808,10 @@ int start_stop_daemon(int argc, char **argv) applet, line + 2, exec); eerror("%s: or you should specify a pidfile" " or process name", applet); - if (ch_root) - free(tmp); exit(EXIT_FAILURE); } } } - - if (ch_root) - free(tmp); } /* Add exec to our arguments */ |