summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2008-03-17 13:25:56 +0000
committerRoy Marples <roy@marples.name>2008-03-17 13:25:56 +0000
commit4c1466642351ddb01cc7353601153a79326f18f7 (patch)
treecb9da1a90aa9480ef276626f40c556379222ec51
parent50a7697bf207e4919ce893bfc1604fd3a9d807de (diff)
downloadopenrc-4c1466642351ddb01cc7353601153a79326f18f7.tar.gz
openrc-4c1466642351ddb01cc7353601153a79326f18f7.tar.bz2
openrc-4c1466642351ddb01cc7353601153a79326f18f7.tar.xz
Punt the rc_strcatpaths function and use snprintf instead to save on expensive malloc calls.
-rw-r--r--man/Makefile2
-rw-r--r--man/rc_strcatpaths.345
-rw-r--r--src/librc/librc-daemon.c104
-rw-r--r--src/librc/librc-depend.c67
-rw-r--r--src/librc/librc-misc.c67
-rw-r--r--src/librc/librc-stringlist.c2
-rw-r--r--src/librc/librc.c377
-rw-r--r--src/librc/librc.h1
-rw-r--r--src/librc/rc.h18
-rw-r--r--src/librc/rc.map2
-rw-r--r--src/rc/rc-plugin.c7
-rw-r--r--src/rc/rc.c524
-rw-r--r--src/rc/runscript.c195
-rw-r--r--src/rc/start-stop-daemon.c16
14 files changed, 682 insertions, 745 deletions
diff --git a/man/Makefile b/man/Makefile
index f8c8ded..0357d27 100644
--- a/man/Makefile
+++ b/man/Makefile
@@ -1,6 +1,6 @@
MAN3= einfo.3 \
rc_config.3 rc_deptree.3 rc_find_pids.3 rc_plugin_hook.3 \
- rc_runlevel.3 rc_service.3 rc_strcatpaths.3 rc_stringlist.3
+ rc_runlevel.3 rc_service.3 rc_stringlist.3
MAN8= rc-status.8 rc-update.8 rc.8 runscript.8 start-stop-daemon.8
# Handy macro to create symlinks
diff --git a/man/rc_strcatpaths.3 b/man/rc_strcatpaths.3
deleted file mode 100644
index 118dbfa..0000000
--- a/man/rc_strcatpaths.3
+++ /dev/null
@@ -1,45 +0,0 @@
-.\" Copyright 2007-2008 Roy Marples
-.\" All rights reserved
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.Dd Feb 22, 2008
-.Dt RC_STRCATPATHS 3 SMM
-.Os OpenRC
-.Sh NAME
-.Nm rc_strcatpaths
-.Nd concatenates each elements, seperating each with / as necessary
-.Sh LIBRARY
-Run Command library (librc, -lrc)
-.Sh SYNOPSIS
-.In rc.h
-.Ft "char *" Fn rc_strcatpaths "const char *path" ...
-.Sh DESCRIPTION
-.Fn rc_strcatpaths concatenates each
-.Fa path ,
-seperating each with / as necessary and returns a malloced pointer
-to the result. This should be freed when done.
-.Sh SEE ALSO
-.Xr free 3 ,
-.Xr malloc 3
-.Sh AUTHORS
-.An "Roy Marples" Aq roy@marples.name
diff --git a/src/librc/librc-daemon.c b/src/librc/librc-daemon.c
index 9e58c6a..b174a82 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 7038a3f..a9bf304 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 fac78e2..747a8fb 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 93297ce..44b0379 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 dfee0bf..d3a4685 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 aaad7cc..376a62f 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 bf40e31..ba49e78 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 8ad4e18..55dea00 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 f0ee5a6..034f79d 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 d906870..04b814e 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 e7a094f..704d32f 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 9b1c109..6aec70b 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 */