aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sh/gendepends.sh.in19
-rw-r--r--sh/openrc-run.sh.in2
-rw-r--r--src/librc/librc-daemon.c10
-rw-r--r--src/librc/librc-depend.c115
-rw-r--r--src/librc/librc-misc.c56
-rw-r--r--src/librc/librc.c268
-rw-r--r--src/librc/meson.build1
-rw-r--r--src/librc/rc.h.in41
-rw-r--r--src/mark_service/mark_service.c2
-rw-r--r--src/openrc-run/openrc-run.c36
-rw-r--r--src/openrc/rc-logger.c25
-rw-r--r--src/openrc/rc.c83
-rw-r--r--src/service/service.c3
-rw-r--r--src/shared/_usage.h9
-rw-r--r--src/shared/misc.c44
-rw-r--r--src/shared/misc.h13
-rw-r--r--src/supervise-daemon/supervise-daemon.c6
-rw-r--r--src/value/value.c3
18 files changed, 528 insertions, 208 deletions
diff --git a/sh/gendepends.sh.in b/sh/gendepends.sh.in
index 5852c772..8ce1c87f 100644
--- a/sh/gendepends.sh.in
+++ b/sh/gendepends.sh.in
@@ -53,11 +53,21 @@ depend() {
:
}
+_dirs="
+ @SYSCONFDIR@/init.d
+ @PKG_PREFIX@/etc/init.d
+ @LOCAL_PREFIX@/etc/init.d
+"
+
+if yesno "$RC_USER_SERVICES"; then
+ _dirs="
+ @SYSCONFDIR@/user.d/init.d
+ ${XDG_CONFIG_HOME:-${HOME}/.config}/openrc/init.d
+ "
+fi
+
_done_dirs=
-for _dir in \
-@SYSCONFDIR@/init.d \
-@PKG_PREFIX@/etc/init.d \
-@LOCAL_PREFIX@/etc/init.d
+for _dir in ${_dirs}
do
[ -d "$_dir" ] || continue
@@ -127,3 +137,4 @@ do
)
done
done
+unset _dirs
diff --git a/sh/openrc-run.sh.in b/sh/openrc-run.sh.in
index 5d0eeffa..cd81f3fb 100644
--- a/sh/openrc-run.sh.in
+++ b/sh/openrc-run.sh.in
@@ -43,7 +43,7 @@ sourcex "@LIBEXECDIR@/sh/functions.sh"
sourcex "@LIBEXECDIR@/sh/rc-functions.sh"
case $RC_SYS in
PREFIX|SYSTEMD-NSPAWN) ;;
- *) sourcex -e "@LIBEXECDIR@/sh/rc-cgroup.sh";;
+ *) yesno "$RC_USER_SERVICES" || sourcex -e "@LIBEXECDIR@/sh/rc-cgroup.sh";;
esac
# Support LiveCD foo
diff --git a/src/librc/librc-daemon.c b/src/librc/librc-daemon.c
index e23593b9..96609786 100644
--- a/src/librc/librc-daemon.c
+++ b/src/librc/librc-daemon.c
@@ -411,9 +411,8 @@ rc_service_daemon_set(const char *service, const char *exec,
return false;
}
- xasprintf(&dirpath, RC_SVCDIR "/daemons/%s", basename_c(service));
-
/* Regardless, erase any existing daemon info */
+ xasprintf(&dirpath, "%s/daemons/%s", rc_service_dir(), basename_c(service));
if ((dp = opendir(dirpath))) {
match = _match_list(exec, argv, pidfile);
renamelist = rc_stringlist_new();
@@ -491,7 +490,7 @@ rc_service_started_daemon(const char *service,
if (!service || !exec)
return false;
- xasprintf(&dirpath, RC_SVCDIR "/daemons/%s", basename_c(service));
+ xasprintf(&dirpath, "%s/daemons/%s", rc_service_dir(), basename_c(service));
match = _match_list(exec, argv, NULL);
if (indx > 0) {
@@ -543,9 +542,8 @@ rc_service_daemons_crashed(const char *service)
char *ch_root;
char *spidfile;
- path += snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s",
- basename_c(service));
-
+ path += snprintf(dirpath, sizeof(dirpath),
+ "%s/daemons/%s", rc_service_dir(), basename_c(service));
if (!(dp = opendir(dirpath)))
return false;
diff --git a/src/librc/librc-depend.c b/src/librc/librc-depend.c
index d584af2c..32286c51 100644
--- a/src/librc/librc-depend.c
+++ b/src/librc/librc-depend.c
@@ -35,10 +35,10 @@
#define GENDEP RC_LIBEXECDIR "/sh/gendepends.sh"
-#define RC_DEPCONFIG RC_SVCDIR "/depconfig"
-
static const char *bootlevel = NULL;
+#define RC_DEPCONFIG "depconfig"
+
static char *
get_shell_value(char *string)
{
@@ -120,8 +120,16 @@ get_deptype(const RC_DEPINFO *depinfo, const char *type)
}
RC_DEPTREE *
-rc_deptree_load(void) {
- return rc_deptree_load_file(RC_DEPTREE_CACHE);
+rc_deptree_load(void)
+{
+ char *deptree_cache;
+ RC_DEPTREE *deptree;
+
+ xasprintf(&deptree_cache, "%s/%s", rc_service_dir(), RC_DEPTREE_CACHE);
+ deptree = rc_deptree_load_file(deptree_cache);
+ free(deptree_cache);
+
+ return deptree;
}
RC_DEPTREE *
@@ -668,19 +676,19 @@ static const DEPPAIR deppairs[] = {
static const char *const depdirs[] =
{
- RC_SVCDIR,
- RC_SVCDIR "/starting",
- RC_SVCDIR "/started",
- RC_SVCDIR "/stopping",
- RC_SVCDIR "/inactive",
- RC_SVCDIR "/wasinactive",
- RC_SVCDIR "/failed",
- RC_SVCDIR "/hotplugged",
- RC_SVCDIR "/daemons",
- RC_SVCDIR "/options",
- RC_SVCDIR "/exclusive",
- RC_SVCDIR "/scheduled",
- RC_SVCDIR "/tmp",
+ "",
+ "starting",
+ "started",
+ "stopping",
+ "inactive",
+ "wasinactive",
+ "failed",
+ "hotplugged",
+ "daemons",
+ "options",
+ "exclusive",
+ "scheduled",
+ "tmp",
NULL
};
@@ -690,19 +698,27 @@ rc_deptree_update_needed(time_t *newest, char *file)
bool newer = false;
RC_STRINGLIST *config;
RC_STRING *s;
- int i;
struct stat buf;
time_t mtime;
+ char *depconfig;
+ char *deptree_cache;
+ const char * const dirs[] = { RC_INIT_SUBDIR, RC_CONF_SUBDIR, RC_CONF_FILE, NULL };
+ char *dir;
+ const char *service_dir = rc_service_dir();
+ const char *sysconf_dir = rc_sysconf_dir();
/* Create base directories if needed */
- for (i = 0; depdirs[i]; i++)
- if (mkdir(depdirs[i], 0755) != 0 && errno != EEXIST)
- fprintf(stderr, "mkdir `%s': %s\n", depdirs[i], strerror(errno));
+ for (int i = 0; depdirs[i]; i++) {
+ xasprintf(&dir, "%s/%s", service_dir, depdirs[i]);
+ if (mkdir(dir, 0755) != 0 && errno != EEXIST)
+ fprintf(stderr, "mkdir '%s': %s\n", dir, strerror(errno));
+ free(dir);
+ }
/* Quick test to see if anything we use has changed and we have
* data in our deptree. */
-
- if (stat(RC_DEPTREE_CACHE, &buf) == 0) {
+ xasprintf(&deptree_cache, "%s/%s", service_dir, RC_DEPTREE_CACHE);
+ if (stat(deptree_cache, &buf) == 0) {
mtime = buf.st_mtime;
} else {
/* No previous cache found.
@@ -712,30 +728,48 @@ rc_deptree_update_needed(time_t *newest, char *file)
newer = true;
mtime = time(NULL);
}
+ free(deptree_cache);
+
+ for (int i = 0; dirs[i]; i++) {
+ xasprintf(&dir, "%s/%s", sysconf_dir, dirs[i]);
+ newer |= !deep_mtime_check(dir, true, &mtime, file);
+ free(dir);
+ }
- newer |= !deep_mtime_check(RC_INITDIR,true,&mtime,file);
- newer |= !deep_mtime_check(RC_CONFDIR,true,&mtime,file);
+ /* Test user configs */
+ if (rc_is_user()) {
+ const char *userconf_dir = rc_userconf_dir();
+ for (int i = 0; dirs[i]; i++) {
+ xasprintf(&dir, "%s/%s", userconf_dir, dirs[i]);
+ newer |= !deep_mtime_check(dir, true, &mtime, file);
+ free(dir);
+ }
+ newer |= !deep_mtime_check(RC_CONF, true, &mtime, file);
+ /* RC_USER doesn't have those paths */
+ } else {
#ifdef RC_PKG_INITDIR
- newer |= !deep_mtime_check(RC_PKG_INITDIR,true,&mtime,file);
+ newer |= !deep_mtime_check(RC_PKG_INITDIR, true, &mtime, file);
#endif
#ifdef RC_PKG_CONFDIR
- newer |= !deep_mtime_check(RC_PKG_CONFDIR,true,&mtime,file);
+ newer |= !deep_mtime_check(RC_PKG_CONFDIR, true, &mtime, file);
#endif
-#ifdef RC_LOCAL_INITDIRs
- newer |= !deep_mtime_check(RC_LOCAL_INITDIR,true,&mtime,file);
+#ifdef RC_LOCAL_INITDIR
+ newer |= !deep_mtime_check(RC_LOCAL_INITDIR, true, &mtime, file);
#endif
#ifdef RC_LOCAL_CONFDIR
- newer |= !deep_mtime_check(RC_LOCAL_CONFDIR,true,&mtime,file);
+ newer |= !deep_mtime_check(RC_LOCAL_CONFDIR, true, &mtime, file);
#endif
- newer |= !deep_mtime_check(RC_CONF,true,&mtime,file);
+ }
/* 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);
+ xasprintf(&depconfig, "%s/depconfig", service_dir);
+ config = rc_config_list(depconfig);
TAILQ_FOREACH(s, config, entries) {
newer |= !deep_mtime_check(s->value, true, &mtime, file);
}
rc_stringlist_free(config);
+ free(depconfig);
/* Return newest file time, if requested */
if ((newer) && (newest != NULL)) {
@@ -768,6 +802,8 @@ rc_deptree_update(void)
char *line = NULL;
size_t len = 0;
char *depend, *depends, *service, *type, *nosys, *onosys;
+ char *deptree_cache;
+ char *depconfig;
size_t i, k, l;
bool retval = true;
const char *sys = rc_sys();
@@ -1048,7 +1084,8 @@ rc_deptree_update(void)
This works and should be entirely shell parseable provided that depend
names don't have any non shell variable characters in
*/
- if ((fp = fopen(RC_DEPTREE_CACHE, "w"))) {
+ xasprintf(&deptree_cache, "%s/%s", rc_service_dir(), RC_DEPTREE_CACHE);
+ if ((fp = fopen(deptree_cache, "w"))) {
i = 0;
TAILQ_FOREACH(depinfo, deptree, entries) {
fprintf(fp, "depinfo_%zu_service='%s'\n",
@@ -1066,27 +1103,29 @@ rc_deptree_update(void)
}
fclose(fp);
} else {
- fprintf(stderr, "fopen `%s': %s\n",
- RC_DEPTREE_CACHE, strerror(errno));
+ fprintf(stderr, "fopen `%s': %s\n", deptree_cache, strerror(errno));
retval = false;
}
+ free(deptree_cache);
/* Save our external config files to disk */
+ xasprintf(&depconfig, "%s/depconfig", rc_service_dir());
if (TAILQ_FIRST(config)) {
- if ((fp = fopen(RC_DEPCONFIG, "w"))) {
+ if ((fp = fopen(depconfig, "w"))) {
TAILQ_FOREACH(s, config, entries)
fprintf(fp, "%s\n", s->value);
fclose(fp);
} else {
fprintf(stderr, "fopen `%s': %s\n",
- RC_DEPCONFIG, strerror(errno));
+ depconfig, strerror(errno));
retval = false;
}
} else {
- unlink(RC_DEPCONFIG);
+ unlink(depconfig);
}
rc_stringlist_free(config);
+ free(depconfig);
free(deptree);
return retval;
}
diff --git a/src/librc/librc-misc.c b/src/librc/librc-misc.c
index ce658f5c..538a67c2 100644
--- a/src/librc/librc-misc.c
+++ b/src/librc/librc-misc.c
@@ -358,9 +358,10 @@ static RC_STRINGLIST * rc_config_directory(RC_STRINGLIST *config)
rc_config_set_value(config, line->value);
rc_stringlist_free(rc_conf_d_list);
}
- rc_stringlist_free(rc_conf_d_files);
}
}
+
+ rc_stringlist_free(rc_conf_d_files);
return config;
}
@@ -412,32 +413,47 @@ _free_rc_conf(void)
char *
rc_conf_value(const char *setting)
{
- RC_STRINGLIST *old;
+ RC_STRINGLIST *tmp;
RC_STRING *s;
char *p;
+ const char *userconf_dir;
+
+ if (rc_conf)
+ return rc_config_value(rc_conf, setting);
+
+ rc_conf = rc_config_load(RC_CONF);
+ atexit(_free_rc_conf);
+
+ /* Support old configs. */
+ if (exists(RC_CONF_OLD)) {
+ tmp = rc_config_load(RC_CONF_OLD);
+ TAILQ_CONCAT(rc_conf, tmp, entries);
+ rc_stringlist_free(tmp);
+ }
- if (!rc_conf) {
- rc_conf = rc_config_load(RC_CONF);
- atexit(_free_rc_conf);
+ /* Overlay user-specific configuration */
+ if ((userconf_dir = rc_userconf_dir())) {
+ char *user_config;
+ xasprintf(&user_config, "%s/%s", userconf_dir, RC_CONF_FILE);
- /* Support old configs. */
- if (exists(RC_CONF_OLD)) {
- old = rc_config_load(RC_CONF_OLD);
- TAILQ_CONCAT(rc_conf, old, entries);
- rc_stringlist_free(old);
+ if (exists(user_config)) {
+ tmp = rc_config_load(user_config);
+ TAILQ_CONCAT(rc_conf, tmp, entries);
+ rc_stringlist_free(tmp);
}
+ free(user_config);
+ }
- rc_conf = rc_config_directory(rc_conf);
- rc_conf = rc_config_kcl(rc_conf);
+ rc_conf = rc_config_directory(rc_conf);
+ rc_conf = rc_config_kcl(rc_conf);
- /* Convert old uppercase to lowercase */
- TAILQ_FOREACH(s, rc_conf, entries) {
- p = s->value;
- while (p && *p && *p != '=') {
- if (isupper((unsigned char)*p))
- *p = tolower((unsigned char)*p);
- p++;
- }
+ /* Convert old uppercase to lowercase */
+ TAILQ_FOREACH(s, rc_conf, entries) {
+ p = s->value;
+ while (p && *p && *p != '=') {
+ if (isupper((unsigned char)*p))
+ *p = tolower((unsigned char)*p);
+ p++;
}
}
diff --git a/src/librc/librc.c b/src/librc/librc.c
index 118726df..d218c8be 100644
--- a/src/librc/librc.c
+++ b/src/librc/librc.c
@@ -35,12 +35,11 @@
#include "librc.h"
#include "misc.h"
#include "rc.h"
+#include "einfo.h"
#ifdef __FreeBSD__
# include <sys/sysctl.h>
#endif
-#define RC_RUNLEVEL RC_SVCDIR "/softlevel"
-
#ifndef S_IXUGO
# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
#endif
@@ -412,7 +411,7 @@ get_runlevel_chain(const char *runlevel, RC_STRINGLIST *level_list, RC_STRINGLIS
* We can now do exactly the above procedure for our chained
* runlevels.
*/
- xasprintf(&path, "%s/%s", RC_RUNLEVELDIR, runlevel);
+ xasprintf(&path, "%s/%s", rc_runlevel_dir(), runlevel);
dirs = ls_dir(path, LS_DIR);
TAILQ_FOREACH(d, dirs, entries) {
nextlevel = d->value;
@@ -441,28 +440,44 @@ get_runlevel_chain(const char *runlevel, RC_STRINGLIST *level_list, RC_STRINGLIS
bool
rc_runlevel_starting(void)
{
- return exists(RC_STARTING);
+ char *stopping_dir;
+ bool found;
+
+ xasprintf(&stopping_dir, "%s/%s", rc_service_dir(), RC_STARTING);
+ found = exists(stopping_dir);
+ free(stopping_dir);
+
+ return found;
}
bool
rc_runlevel_stopping(void)
{
- return exists(RC_STOPPING);
+ char *stopping_dir;
+ bool found;
+
+ xasprintf(&stopping_dir, "%s/%s", rc_service_dir(), RC_STOPPING);
+ found = exists(stopping_dir);
+ free(stopping_dir);
+
+ return found;
}
RC_STRINGLIST *rc_runlevel_list(void)
{
- return ls_dir(RC_RUNLEVELDIR, LS_DIR);
+ return ls_dir(rc_runlevel_dir(), LS_DIR);
}
char *
rc_runlevel_get(void)
{
FILE *fp;
+ char *softlevel;
char *runlevel = NULL;
size_t i;
- if ((fp = fopen(RC_RUNLEVEL, "r"))) {
+ xasprintf(&softlevel, "%s/softlevel", rc_service_dir());
+ if ((fp = fopen(softlevel, "r"))) {
runlevel = xmalloc(sizeof(char) * PATH_MAX);
if (fgets(runlevel, PATH_MAX, fp)) {
i = strlen(runlevel) - 1;
@@ -472,6 +487,7 @@ rc_runlevel_get(void)
*runlevel = '\0';
fclose(fp);
}
+ free(softlevel);
if (!runlevel || !*runlevel) {
free(runlevel);
@@ -484,12 +500,16 @@ rc_runlevel_get(void)
bool
rc_runlevel_set(const char *runlevel)
{
- FILE *fp = fopen(RC_RUNLEVEL, "w");
+ char *softlevel;
+ FILE *fp;
+ xasprintf(&softlevel, "%s/softlevel", rc_service_dir());
+ fp = fopen(softlevel, "w");
if (!fp)
return false;
fprintf(fp, "%s", runlevel);
fclose(fp);
+ free(softlevel);
return true;
}
@@ -503,7 +523,7 @@ rc_runlevel_exists(const char *runlevel)
if (!runlevel || strcmp(runlevel, "") == 0 || strcmp(runlevel, ".") == 0 ||
strcmp(runlevel, "..") == 0)
return false;
- xasprintf(&path, "%s/%s", RC_RUNLEVELDIR, runlevel);
+ xasprintf(&path, "%s/%s", rc_runlevel_dir(), runlevel);
r = stat(path, &buf);
free(path);
if (r == 0 && S_ISDIR(buf.st_mode))
@@ -520,7 +540,7 @@ rc_runlevel_stack(const char *dst, const char *src)
if (!rc_runlevel_exists(dst) || !rc_runlevel_exists(src))
return false;
xasprintf(&s, "../%s", src);
- xasprintf(&d, "%s/%s/%s", RC_RUNLEVELDIR, dst, src);
+ xasprintf(&d, "%s/%s/%s", rc_runlevel_dir(), dst, src);
r = symlink(s, d);
free(d);
free(s);
@@ -533,7 +553,7 @@ rc_runlevel_unstack(const char *dst, const char *src)
char *path;
int r;
- xasprintf(&path, "%s/%s/%s", RC_RUNLEVELDIR, dst, src);
+ xasprintf(&path, "%s/%s/%s", rc_runlevel_dir(), dst, src);
r = unlink(path);
free(path);
return (r == 0);
@@ -551,6 +571,105 @@ rc_runlevel_stacks(const char *runlevel)
return stack;
}
+static struct {
+ char *userconf;
+ char *runlevels;
+ char *service;
+} rc_user_dirs;
+
+static void
+free_rc_user_dirs(void)
+{
+ free(rc_user_dirs.userconf);
+ rc_user_dirs.userconf = NULL;
+ free(rc_user_dirs.runlevels);
+ rc_user_dirs.runlevels = NULL;
+ free(rc_user_dirs.service);
+ rc_user_dirs.service = NULL;
+}
+
+static void
+init_rc_user_dirs(void)
+{
+ char *env;
+
+ if ((env = getenv("XDG_CONFIG_HOME")))
+ xasprintf(&rc_user_dirs.userconf, "%s/openrc", env);
+ else if ((env = getenv("HOME")))
+ xasprintf(&rc_user_dirs.userconf, "%s/.config/openrc", env);
+ else
+ eerrorx("XDG_CONFIG_HOME and HOME unset");
+
+ xasprintf(&rc_user_dirs.runlevels, "%s/%s", rc_user_dirs.userconf, RC_RUNLEVEL_SUBDIR);
+
+ if (!(env = getenv("XDG_RUNTIME_DIR")))
+ eerrorx("XDG_RUNTIME_DIR unset."); /* FIXME: fallback to something else? */
+ xasprintf(&rc_user_dirs.service, "%s/openrc", env);
+ atexit(free_rc_user_dirs);
+}
+
+static bool is_user = false;
+
+void
+rc_set_user(void)
+{
+ if (!is_user)
+ init_rc_user_dirs();
+ is_user = true;
+ setenv("RC_USER_SERVICES", "yes", true);
+}
+
+bool
+rc_is_user(void)
+{
+ return is_user;
+}
+
+const char *
+rc_sysconf_dir(void)
+{
+ if (rc_is_user())
+ return RC_SYSCONFDIR "/" RC_USER_SUBDIR;
+ else
+ return RC_SYSCONFDIR;
+}
+
+const char *
+rc_userconf_dir(void)
+{
+ if (!rc_is_user())
+ return NULL;
+
+ if (!rc_user_dirs.userconf)
+ eerrorx("rc_userconf_dir called in user mode without paths set");
+
+ return rc_user_dirs.userconf;
+}
+
+const char *
+rc_runlevel_dir(void)
+{
+ if (!rc_is_user())
+ return RC_RUNLEVELDIR;
+
+ if (!rc_user_dirs.runlevels)
+ eerrorx("rc_runlevel_dir called in user mode without paths set");
+
+ return rc_user_dirs.runlevels;
+}
+
+const char *
+rc_service_dir(void)
+{
+ if (!rc_is_user())
+ return RC_SVCDIR;
+
+ if (!rc_user_dirs.service)
+ eerrorx("rc_service_dir called in user mode without paths set");
+
+ return rc_user_dirs.service;
+}
+
static ssize_t
safe_readlink(const char *path, char **buf, size_t bufsiz)
{
@@ -582,6 +701,7 @@ rc_service_resolve(const char *service)
char *buffer;
char *file = NULL;
struct stat buf;
+ const char *sysconf_dir = rc_sysconf_dir();
if (!service)
return NULL;
@@ -590,10 +710,10 @@ rc_service_resolve(const char *service)
return xstrdup(service);
/* First check started services */
- xasprintf(&file, "%s/%s/%s", RC_SVCDIR, "started", service);
+ xasprintf(&file, "%s/%s/%s", rc_service_dir(), "started", service);
if (lstat(file, &buf) || !S_ISLNK(buf.st_mode)) {
free(file);
- xasprintf(&file, "%s/%s/%s", RC_SVCDIR, "inactive", service);
+ xasprintf(&file, "%s/%s/%s", rc_service_dir(), "inactive", service);
if (lstat(file, &buf) || !S_ISLNK(buf.st_mode)) {
free(file);
file = NULL;
@@ -605,6 +725,22 @@ rc_service_resolve(const char *service)
return buffer;
}
+ /* Check user specific scripts */
+ if (rc_is_user()) {
+ /* Local user config takes priority */
+ xasprintf(&file, "%s/%s/%s", rc_userconf_dir(), RC_INIT_SUBDIR, service);
+ if (stat(file, &buf) == 0)
+ return file;
+
+ free(file);
+ xasprintf(&file, "%s/%s/%s", sysconf_dir, RC_INIT_SUBDIR, service);
+ if (stat(file, &buf) == 0)
+ return file;
+
+ free(file);
+ return NULL;
+ }
+
#ifdef RC_LOCAL_INITDIR
/* Nope, so lets see if the user has written it */
free(file);
@@ -615,7 +751,7 @@ rc_service_resolve(const char *service)
/* System scripts take precedence over 3rd party ones */
free(file);
- xasprintf(&file, "%s/%s", RC_INITDIR, service);
+ xasprintf(&file, "%s/%s/%s", sysconf_dir, RC_INIT_SUBDIR, service);
if (stat(file, &buf) == 0)
return file;
@@ -745,8 +881,7 @@ rc_service_in_runlevel(const char *service, const char *runlevel)
char *file;
bool r;
- xasprintf(&file, "%s/%s/%s", RC_RUNLEVELDIR, runlevel,
- basename_c(service));
+ xasprintf(&file, "%s/%s/%s", rc_runlevel_dir(), runlevel, basename_c(service));
r = exists(file);
free(file);
return r;
@@ -760,6 +895,7 @@ rc_service_mark(const char *service, const RC_SERVICE state)
int skip_state = -1;
const char *base;
char *init = rc_service_resolve(service);
+ const char *svc_dir = rc_service_dir();
bool skip_wasinactive = false;
int s;
RC_STRINGLIST *dirs;
@@ -776,7 +912,7 @@ rc_service_mark(const char *service, const RC_SERVICE state)
return false;
}
- xasprintf(&file, "%s/%s/%s", RC_SVCDIR,
+ xasprintf(&file, "%s/%s/%s", svc_dir,
rc_parse_service_state(state), base);
if (exists(file))
unlink(file);
@@ -804,14 +940,14 @@ rc_service_mark(const char *service, const RC_SERVICE state)
s != RC_SERVICE_SCHEDULED) &&
(!skip_wasinactive || s != RC_SERVICE_WASINACTIVE))
{
- xasprintf(&file, "%s/%s/%s", RC_SVCDIR,
+ xasprintf(&file, "%s/%s/%s", rc_service_dir(),
rc_service_state_names[i].name, base);
if (exists(file)) {
if ((state == RC_SERVICE_STARTING ||
state == RC_SERVICE_STOPPING) &&
s == RC_SERVICE_INACTIVE)
{
- xasprintf(&was, "%s/%s/%s", RC_SVCDIR,
+ xasprintf(&was, "%s/%s/%s", rc_service_dir(),
rc_parse_service_state(RC_SERVICE_WASINACTIVE),
base);
i = symlink(init, was);
@@ -838,18 +974,18 @@ rc_service_mark(const char *service, const RC_SERVICE state)
state == RC_SERVICE_STOPPED ||
state == RC_SERVICE_INACTIVE)
{
- xasprintf(&file, "%s/%s/%s", RC_SVCDIR, "exclusive", base);
+ xasprintf(&file, "%s/%s/%s", svc_dir, "exclusive", base);
unlink(file);
free(file);
}
/* Remove any options and daemons the service may have stored */
if (state == RC_SERVICE_STOPPED) {
- xasprintf(&file, "%s/%s/%s", RC_SVCDIR, "options", base);
+ xasprintf(&file, "%s/%s/%s", svc_dir, "options", base);
rm_dir(file, true);
free(file);
- xasprintf(&file, "%s/%s/%s", RC_SVCDIR, "daemons", base);
+ xasprintf(&file, "%s/%s/%s", svc_dir, "daemons", base);
rm_dir(file, true);
free(file);
@@ -858,7 +994,7 @@ rc_service_mark(const char *service, const RC_SERVICE state)
/* These are final states, so remove us from scheduled */
if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) {
- xasprintf(&file, "%s/%s", RC_SVCDIR, "scheduled");
+ xasprintf(&file, "%s/%s", svc_dir, "scheduled");
dirs = ls_dir(file, 0);
TAILQ_FOREACH(dir, dirs, entries) {
xasprintf(&was, "%s/%s/%s", file, dir->value, base);
@@ -888,10 +1024,10 @@ rc_service_state(const char *service)
RC_STRINGLIST *dirs;
RC_STRING *dir;
const char *base = basename_c(service);
+ const char *svc_dir = rc_service_dir();
for (i = 0; rc_service_state_names[i].name; i++) {
- xasprintf(&file, "%s/%s/%s", RC_SVCDIR,
- rc_service_state_names[i].name, base);
+ xasprintf(&file, "%s/%s/%s", svc_dir, 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;
@@ -906,11 +1042,12 @@ rc_service_state(const char *service)
state |= RC_SERVICE_CRASHED;
}
if (state & RC_SERVICE_STOPPED) {
- dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
+ char *path;
+ xasprintf(&path, "%s/scheduled", svc_dir);
+ dirs = ls_dir(path, 0);
+ free(path);
TAILQ_FOREACH(dir, dirs, entries) {
- xasprintf(&file,
- "%s/scheduled/%s/%s", RC_SVCDIR,
- dir->value, service);
+ xasprintf(&file, "%s/scheduled/%s/%s", svc_dir, dir->value, service);
i = exists(file);
free(file);
if (i) {
@@ -931,7 +1068,7 @@ rc_service_value_get(const char *service, const char *option)
size_t len = 0;
char *file;
- xasprintf(&file, "%s/options/%s/%s", RC_SVCDIR, service, option);
+ xasprintf(&file, "%s/options/%s/%s", rc_service_dir(), service, option);
rc_getfile(file, &buffer, &len);
free(file);
@@ -945,7 +1082,7 @@ rc_service_value_set(const char *service, const char *option,
FILE *fp;
char *file1, *file2;
- xasprintf(&file1, "%s/options/%s", RC_SVCDIR, service);
+ xasprintf(&file1, "%s/options/%s", rc_service_dir(), service);
if (mkdir(file1, 0755) != 0 && errno != EEXIST) {
free(file1);
return false;
@@ -978,7 +1115,7 @@ rc_service_schedule_start(const char *service, const char *service_to_start)
if (!service || !rc_service_exists(service_to_start))
return false;
- xasprintf(&file1, "%s/scheduled/%s", RC_SVCDIR, basename_c(service));
+ xasprintf(&file1, "%s/scheduled/%s", rc_service_dir(), basename_c(service));
if (mkdir(file1, 0755) != 0 && errno != EEXIST) {
free(file1);
return false;
@@ -999,7 +1136,7 @@ rc_service_schedule_clear(const char *service)
char *dir;
bool r;
- xasprintf(&dir, "%s/scheduled/%s", RC_SVCDIR, basename_c(service));
+ xasprintf(&dir, "%s/scheduled/%s", rc_service_dir(), basename_c(service));
r = rm_dir(dir, true);
free(dir);
if (!r && errno == ENOENT)
@@ -1012,34 +1149,52 @@ rc_services_in_runlevel(const char *runlevel)
{
char *dir;
RC_STRINGLIST *list = NULL;
+ const char *sysconf_dir = rc_sysconf_dir();
if (!runlevel) {
-#ifdef RC_PKG_INITDIR
- RC_STRINGLIST *pkg = ls_dir(RC_PKG_INITDIR, LS_INITD);
-#endif
-#ifdef RC_LOCAL_INITDIR
- RC_STRINGLIST *local = ls_dir(RC_LOCAL_INITDIR, LS_INITD);
-#endif
+ const char *userconf_dir;
+ char *init_dir;
- list = ls_dir(RC_INITDIR, LS_INITD);
+ xasprintf(&init_dir, "%s/%s", sysconf_dir, RC_INIT_SUBDIR);
+ list = ls_dir(init_dir, LS_INITD);
+ free(init_dir);
+
+ if ((userconf_dir = rc_userconf_dir())) {
+ RC_STRINGLIST *usr = NULL;
+ xasprintf(&init_dir, "%s/%s", userconf_dir, RC_INIT_SUBDIR);
+
+ usr = ls_dir(init_dir, LS_INITD);
+ TAILQ_CONCAT(list, usr, entries);
+ rc_stringlist_free(usr);
+
+ free(init_dir);
+ return list;
+ }
#ifdef RC_PKG_INITDIR
- TAILQ_CONCAT(list, pkg, entries);
- rc_stringlist_free(pkg);
+ {
+ RC_STRINGLIST *pkg = ls_dir(RC_PKG_INITDIR, LS_INITD);
+ TAILQ_CONCAT(list, pkg, entries);
+ rc_stringlist_free(pkg);
+ }
#endif
#ifdef RC_LOCAL_INITDIR
- TAILQ_CONCAT(list, local, entries);
- rc_stringlist_free(local);
+ {
+ RC_STRINGLIST *local = ls_dir(RC_LOCAL_INITDIR, LS_INITD);
+ TAILQ_CONCAT(list, local, entries);
+ rc_stringlist_free(local);
+ }
#endif
return list;
}
/* These special levels never contain any services */
if (strcmp(runlevel, RC_LEVEL_SINGLE) != 0) {
- xasprintf(&dir, "%s/%s", RC_RUNLEVELDIR, runlevel);
+ xasprintf(&dir, "%s/%s", rc_runlevel_dir(), runlevel);
list = ls_dir(dir, LS_INITD);
free(dir);
}
+
if (!list)
list = rc_stringlist_new();
return list;
@@ -1071,8 +1226,7 @@ rc_services_in_state(RC_SERVICE state)
RC_STRING *d;
char *dir, *dir2;
- xasprintf(&dir, "%s/%s", RC_SVCDIR,
- rc_parse_service_state(state));
+ xasprintf(&dir, "%s/%s", rc_service_dir(), rc_parse_service_state(state));
if (state != RC_SERVICE_SCHEDULED) {
dirs = ls_dir(dir, LS_INITD);
@@ -1125,7 +1279,7 @@ rc_service_add(const char *runlevel, const char *service)
/* We need to ensure that only things in /etc/init.d are added
* to the boot runlevel */
- if (strcmp(runlevel, RC_LEVEL_BOOT) == 0) {
+ if (!rc_is_user() && strcmp(runlevel, RC_LEVEL_BOOT) == 0) {
path = realpath(dirname(init), NULL);
if (path == NULL) {
free(init);
@@ -1138,7 +1292,7 @@ rc_service_add(const char *runlevel, const char *service)
errno = EPERM;
return false;
}
- xasprintf(&binit, "%s/%s", RC_INITDIR, service);
+ xasprintf(&binit, "%s/%s/%s", rc_service_dir(), RC_INIT_SUBDIR, service);
i = binit;
}
@@ -1157,8 +1311,7 @@ rc_service_delete(const char *runlevel, const char *service)
char *file;
int r;
- xasprintf(&file, "%s/%s/%s", RC_RUNLEVELDIR, runlevel,
- basename_c(service));
+ xasprintf(&file, "%s/%s/%s", rc_runlevel_dir(), runlevel, basename_c(service));
r = unlink(file);
free(file);
return (r == 0);
@@ -1167,14 +1320,17 @@ rc_service_delete(const char *runlevel, const char *service)
RC_STRINGLIST *
rc_services_scheduled_by(const char *service)
{
- RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
+ RC_STRINGLIST *dirs;
RC_STRINGLIST *list = rc_stringlist_new();
RC_STRING *dir;
- char *file;
+ char *file, *scheduled_dir;
+
+ xasprintf(&scheduled_dir, "%s/scheduled", rc_service_dir());
+ dirs = ls_dir(scheduled_dir, 0);
+ free(scheduled_dir);
TAILQ_FOREACH(dir, dirs, entries) {
- xasprintf(&file, "%s/scheduled/%s/%s", RC_SVCDIR, dir->value,
- service);
+ xasprintf(&file, "%s/scheduled/%s/%s", rc_service_dir(), dir->value, service);
if (exists(file))
rc_stringlist_add(list, file);
free(file);
@@ -1189,7 +1345,7 @@ rc_services_scheduled(const char *service)
char *dir;
RC_STRINGLIST *list;
- xasprintf(&dir, "%s/scheduled/%s", RC_SVCDIR, basename_c(service));
+ xasprintf(&dir, "%s/scheduled/%s", rc_service_dir(), basename_c(service));
list = ls_dir(dir, LS_INITD);
free(dir);
return list;
diff --git a/src/librc/meson.build b/src/librc/meson.build
index 30caa1f3..8d963208 100644
--- a/src/librc/meson.build
+++ b/src/librc/meson.build
@@ -27,6 +27,7 @@ librc = library('rc', librc_sources,
dependencies: kvm_dep,
include_directories : [incdir, einfo_incdir],
link_depends : 'rc.map',
+ link_with : libeinfo,
version : librc_version,
install : true,
install_dir : libdir)
diff --git a/src/librc/rc.h.in b/src/librc/rc.h.in
index 69d9d0e4..59fdfda3 100644
--- a/src/librc/rc.h.in
+++ b/src/librc/rc.h.in
@@ -34,18 +34,27 @@ extern "C" {
#else
#define RC_SVCDIR RC_LIBEXECDIR "/init.d"
#endif
-#define RC_RUNLEVELDIR RC_SYSCONFDIR "/runlevels"
-#define RC_INITDIR RC_SYSCONFDIR "/init.d"
-#define RC_CONFDIR RC_SYSCONFDIR "/conf.d"
+
+#define RC_RUNLEVEL_SUBDIR "runlevels"
+#define RC_INIT_SUBDIR "init.d"
+#define RC_CONF_SUBDIR "conf.d"
+#define RC_USER_SUBDIR "user.d"
+
+#define RC_RUNLEVELDIR RC_SYSCONFDIR "/" RC_RUNLEVEL_SUBDIR
+#define RC_INITDIR RC_SYSCONFDIR "/" RC_INIT_SUBDIR
+#define RC_CONFDIR RC_SYSCONFDIR "/" RC_CONF_SUBDIR
#define RC_PLUGINDIR RC_LIBDIR "/plugins"
+#define RC_CONF_FILE "rc.conf"
+#define RC_CONF_D_SUBDIR "rc.conf.d"
+
#define RC_INIT_FIFO RC_SVCDIR"/init.ctl"
#define RC_PROFILE_ENV RC_SYSCONFDIR "/profile.env"
#define RC_SYS_WHITELIST RC_LIBEXECDIR "/conf.d/env_whitelist"
#define RC_USR_WHITELIST RC_SYSCONFDIR "/conf.d/env_whitelist"
-#define RC_CONF RC_SYSCONFDIR "/rc.conf"
-#define RC_CONF_D RC_SYSCONFDIR "/rc.conf.d"
-#define RC_CONF_OLD RC_SYSCONFDIR "/conf.d/rc"
+#define RC_CONF RC_SYSCONFDIR "/" RC_CONF_FILE
+#define RC_CONF_D RC_SYSCONFDIR "/" RC_CONF_D_SUBDIR
+#define RC_CONF_OLD RC_SYSCONFDIR "/conf.d/rc"
#define RC_PATH_PREFIX RC_LIBEXECDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin"
@@ -123,6 +132,10 @@ typedef TAILQ_HEAD(rc_stringlist, rc_string) RC_STRINGLIST;
#define RC_LEVEL_SINGLE "single"
#define RC_LEVEL_SHUTDOWN "shutdown"
+/* !TODO: documentation */
+void rc_set_user(void);
+bool rc_is_user(void);
+
/*! Return the current runlevel.
* @return the current runlevel */
char *rc_runlevel_get(void);
@@ -192,6 +205,22 @@ typedef enum
RC_SERVICE_CRASHED = 0x1000,
} RC_SERVICE;
+/*! Returns a path to the system configuration directory
+ * @return path string */
+const char *rc_sysconf_dir(void);
+
+/*! Returns a path to the current user's configuration directory
+ * @return path string */
+const char *rc_userconf_dir(void);
+
+/*! Returns a path to the runlevel directory, systemwide or for the current user
+ * @return path string */
+const char *rc_runlevel_dir(void);
+
+/*! Returns a path to the services directory, systemwide or for the current user
+ * @return path string */
+const char *rc_service_dir(void);
+
/*! Add the service to the runlevel
* @param runlevel to add to
* @param service to add
diff --git a/src/mark_service/mark_service.c b/src/mark_service/mark_service.c
index 7d4d9d97..36f32c28 100644
--- a/src/mark_service/mark_service.c
+++ b/src/mark_service/mark_service.c
@@ -37,6 +37,8 @@ int main(int argc, char **argv)
/* size_t l; */
applet = basename_c(argv[0]);
+ if (rc_yesno(getenv("RC_USER_SERVICES")))
+ rc_set_user();
if (argc > 1)
service = argv[1];
else
diff --git a/src/openrc-run/openrc-run.c b/src/openrc-run/openrc-run.c
index 7c5d50a1..5856a368 100644
--- a/src/openrc-run/openrc-run.c
+++ b/src/openrc-run/openrc-run.c
@@ -54,7 +54,8 @@
#include "_usage.h"
#include "helpers.h"
-#define PREFIX_LOCK RC_SVCDIR "/prefix.lock"
+#define PREFIX_LOCK_FILE "prefix.lock"
+#define OPENRC_SH_FILE "openrc-run.sh"
#define WAIT_INTERVAL 20000000 /* usecs to poll the lock file */
#define WAIT_TIMEOUT 60 /* seconds until we timeout */
@@ -165,7 +166,7 @@ unhotplug(void)
{
char *file = NULL;
- xasprintf(&file, RC_SVCDIR "/hotplugged/%s", applet);
+ xasprintf(&file, "%s/hotplugged/%s", rc_service_dir(), applet);
if (exists(file) && unlink(file) != 0)
eerror("%s: unlink `%s': %s", applet, file, strerror(errno));
free(file);
@@ -175,7 +176,7 @@ static void
start_services(RC_STRINGLIST *list)
{
RC_STRING *svc;
- RC_SERVICE state = rc_service_state (service);
+ RC_SERVICE state = rc_service_state(service);
if (!list)
return;
@@ -286,12 +287,16 @@ write_prefix(const char *buffer, size_t bytes, bool *prefixed)
const char *ec_normal = ecolor(ECOLOR_NORMAL);
ssize_t ret = 0;
int fd = fileno(stdout), lock_fd = -1;
+ char *prefix_lock;
+
/*
* Lock the prefix.
- * open() may fail here when running as user, as RC_SVCDIR may not be writable.
+ * open() may fail here when running as user, as RC_SVCDIR may not be writable. FIXME: Inaccurate comment?
*/
- lock_fd = open(PREFIX_LOCK, O_WRONLY | O_CREAT, 0664);
+ xasprintf(&prefix_lock, "%s/%s", rc_service_dir(), PREFIX_LOCK_FILE);
+ lock_fd = open(prefix_lock, O_WRONLY | O_CREAT, 0664);
+ free(prefix_lock);
if (lock_fd != -1) {
while (flock(lock_fd, LOCK_EX) != 0) {
@@ -385,25 +390,24 @@ svc_exec(const char *arg1, const char *arg2)
if (service_pid == -1)
eerrorx("%s: fork: %s", service, strerror(errno));
if (service_pid == 0) {
+ char *openrc_sh_path;
+ xasprintf(&openrc_sh_path, "%s/%s", rc_service_dir(), OPENRC_SH_FILE);
if (slave_tty >= 0) {
dup2(slave_tty, STDOUT_FILENO);
dup2(slave_tty, STDERR_FILENO);
}
- if (exists(RC_SVCDIR "/openrc-run.sh")) {
+ if (exists(openrc_sh_path)) {
if (arg2)
einfov("Executing: %s %s %s %s %s",
- RC_SVCDIR "/openrc-run.sh", RC_SVCDIR "/openrc-run.sh",
+ openrc_sh_path, openrc_sh_path,
service, arg1, arg2);
else
einfov("Executing: %s %s %s %s",
- RC_SVCDIR "/openrc-run.sh", RC_SVCDIR "/openrc-run.sh",
+ openrc_sh_path, openrc_sh_path,
service, arg1);
- execl(RC_SVCDIR "/openrc-run.sh",
- RC_SVCDIR "/openrc-run.sh",
- service, arg1, arg2, (char *) NULL);
- eerror("%s: exec `" RC_SVCDIR "/openrc-run.sh': %s",
- service, strerror(errno));
+ execl(openrc_sh_path, openrc_sh_path, service, arg1, arg2, (char *) NULL);
+ eerror("%s: exec %s: %s", openrc_sh_path, service, strerror(errno));
_exit(EXIT_FAILURE);
} else {
if (arg2)
@@ -423,6 +427,7 @@ svc_exec(const char *arg1, const char *arg2)
service, strerror(errno));
_exit(EXIT_FAILURE);
}
+ free(openrc_sh_path); /* UNREACHED: only for safe keeping */
}
buffer = xmalloc(sizeof(char) * BUFSIZ);
@@ -508,7 +513,7 @@ svc_wait(const char *svc)
forever = true;
rc_stringlist_free(keywords);
- xasprintf(&file, RC_SVCDIR "/exclusive/%s", basename_c(svc));
+ xasprintf(&file, "%s/exclusive/%s", rc_service_dir(), basename_c(svc));
interval.tv_sec = 0;
interval.tv_nsec = WAIT_INTERVAL;
@@ -1115,6 +1120,9 @@ int main(int argc, char **argv)
applet = basename_c(argv[0]);
+ if (rc_yesno(getenv("RC_USER_SERVICES")))
+ rc_set_user();
+
if (stat(argv[1], &stbuf) != 0) {
fprintf(stderr, "openrc-run `%s': %s\n",
argv[1], strerror(errno));
diff --git a/src/openrc/rc-logger.c b/src/openrc/rc-logger.c
index 974147f9..34cf2e82 100644
--- a/src/openrc/rc-logger.c
+++ b/src/openrc/rc-logger.c
@@ -46,7 +46,7 @@
#include "misc.h"
#include "helpers.h"
-#define TMPLOG RC_SVCDIR "/rc.log"
+#define TMPLOG_FILE "rc.log"
#define DEFAULTLOG "/var/log/rc.log"
static int signal_pipe[2] = { -1, -1 };
@@ -145,6 +145,7 @@ rc_logger_open(const char *level)
int i;
FILE *log = NULL;
FILE *plog = NULL;
+ char *logfile_path;
const char *logfile;
int log_error = 0;
@@ -184,7 +185,8 @@ rc_logger_open(const char *level)
signal_pipe[1] = -1;
runlevel = level;
- if ((log = fopen(TMPLOG, "ae")))
+ xasprintf(&logfile_path, "%s/%s", rc_service_dir(), TMPLOG_FILE);
+ if ((log = fopen(logfile_path, "ae")))
write_time(log, "started");
else {
free(logbuf);
@@ -234,7 +236,7 @@ rc_logger_open(const char *level)
break;
}
if (logbuf) {
- if ((log = fopen(TMPLOG, "ae"))) {
+ if ((log = fopen(logfile_path, "ae"))) {
write_time(log, "started");
write_log(fileno(log), logbuf, logbuf_len);
}
@@ -249,13 +251,13 @@ rc_logger_open(const char *level)
logfile = rc_conf_value("rc_log_path");
if (logfile == NULL)
logfile = DEFAULTLOG;
- if (!strcmp(logfile, TMPLOG)) {
+ if (!strcmp(logfile, logfile_path)) {
eerror("Cowardly refusing to concatenate a logfile into itself.");
- eerrorx("Please change rc_log_path to something other than %s to get rid of this message", TMPLOG);
+ eerrorx("Please change rc_log_path to something other than %s to get rid of this message", logfile_path);
}
if ((plog = fopen(logfile, "ae"))) {
- if ((log = fopen(TMPLOG, "re"))) {
+ if ((log = fopen(logfile_path, "re"))) {
while ((bytes = fread(buffer, sizeof(*buffer), BUFSIZ, log)) > 0) {
if (fwrite(buffer, sizeof(*buffer), bytes, plog) < bytes) {
log_error = 1;
@@ -266,7 +268,7 @@ rc_logger_open(const char *level)
fclose(log);
} else {
log_error = 1;
- eerror("Error: fopen(%s) failed: %s", TMPLOG, strerror(errno));
+ eerror("Error: fopen(%s) failed: %s", logfile_path, strerror(errno));
}
fclose(plog);
@@ -284,11 +286,12 @@ rc_logger_open(const char *level)
/* Try to keep the temporary log in case of errors */
if (!log_error) {
if (errno != EROFS && ((strcmp(level, RC_LEVEL_SHUTDOWN) != 0) && (strcmp(level, RC_LEVEL_SYSINIT) != 0)))
- if (unlink(TMPLOG) == -1)
- eerror("Error: unlink(%s) failed: %s", TMPLOG, strerror(errno));
- } else if (exists(TMPLOG))
- eerrorx("Warning: temporary logfile left behind: %s", TMPLOG);
+ if (unlink(logfile_path) == -1)
+ eerror("Error: unlink(%s) failed: %s", logfile_path, strerror(errno));
+ } else if (exists(logfile_path))
+ eerrorx("Warning: temporary logfile left behind: %s", logfile_path);
+ free(logfile_path);
exit(0);
/* NOTREACHED */
diff --git a/src/openrc/rc.c b/src/openrc/rc.c
index 15777c60..46e3022d 100644
--- a/src/openrc/rc.c
+++ b/src/openrc/rc.c
@@ -70,7 +70,7 @@ const char *usagestring = "" \
#define INITSH RC_LIBEXECDIR "/sh/init.sh"
#define INITEARLYSH RC_LIBEXECDIR "/sh/init-early.sh"
-#define INTERACTIVE RC_SVCDIR "/interactive"
+#define INTERACTIVE_SUBDIR "/interactive"
#define DEVBOOT "/dev/.rcboot"
@@ -95,16 +95,18 @@ clean_failed(void)
DIR *dp;
struct dirent *d;
char *path;
+ char *failed_dir;
+ xasprintf(&failed_dir, "%s/failed", rc_service_dir());
/* Clean the failed services state dir now */
- if ((dp = opendir(RC_SVCDIR "/failed"))) {
+ if ((dp = opendir(failed_dir))) {
while ((d = readdir(dp))) {
if (d->d_name[0] == '.' &&
(d->d_name[1] == '\0' ||
(d->d_name[1] == '.' && d->d_name[2] == '\0')))
continue;
- xasprintf(&path, RC_SVCDIR "/failed/%s", d->d_name);
+ xasprintf(&path, "%s/%s", failed_dir, d->d_name);
if (unlink(path))
eerror("%s: unlink `%s': %s",
applet, path, strerror(errno));
@@ -112,16 +114,17 @@ clean_failed(void)
}
closedir(dp);
}
+ free(failed_dir);
}
static void
cleanup(void)
{
RC_PID *p, *tmp;
+ char *dir;
- if (!rc_in_logger && !rc_in_plugin &&
- applet && (strcmp(applet, "rc") == 0 || strcmp(applet, "openrc") == 0))
- {
+ if (!rc_in_logger && !rc_in_plugin && applet &&
+ (strcmp(applet, "rc") == 0 || strcmp(applet, "openrc") == 0)) {
if (hook_out)
rc_plugin_run(hook_out, runlevel);
@@ -133,8 +136,14 @@ cleanup(void)
}
/* Clean runlevel start, stop markers */
- rmdir(RC_STARTING);
- rmdir(RC_STOPPING);
+ xasprintf(&dir, "%s/%s", rc_service_dir(), RC_STARTING);
+ rmdir(dir);
+ free(dir);
+
+ xasprintf(&dir, "%s/%s", rc_service_dir(), RC_STOPPING);
+ rmdir(dir);
+ free(dir);
+
clean_failed();
rc_logger_close();
}
@@ -211,9 +220,14 @@ want_interactive(void)
static void
mark_interactive(void)
{
- FILE *fp = fopen(INTERACTIVE, "w");
+ char *interactive_dir;
+ FILE *fp;
+
+ xasprintf(&interactive_dir, "%s/%s", rc_service_dir(), INTERACTIVE_SUBDIR);
+ fp = fopen(interactive_dir, "w");
if (fp)
fclose(fp);
+ free(interactive_dir);
}
static void
@@ -649,9 +663,11 @@ do_start_services(const RC_STRINGLIST *start_services, bool parallel)
bool interactive = false;
RC_SERVICE state;
bool crashed = false;
+ char *interactive_dir;
+ xasprintf(&interactive_dir, "%s/%s", rc_service_dir(), INTERACTIVE_SUBDIR);
if (!rc_yesno(getenv("EINFO_QUIET")))
- interactive = exists(INTERACTIVE);
+ interactive = exists(interactive_dir);
errno = 0;
crashed = rc_conf_yesno("rc_crashed_start");
if (errno == ENOENT)
@@ -710,10 +726,10 @@ do_start_services(const RC_STRINGLIST *start_services, bool parallel)
strcmp(runlevel, getenv("RC_BOOTLEVEL")) == 0))
mark_interactive();
else {
- if (exists(INTERACTIVE))
- unlink(INTERACTIVE);
+ if (exists(interactive_dir))
+ unlink(interactive_dir);
}
-
+ free(interactive_dir);
}
#ifdef RC_DEBUG
@@ -754,6 +770,9 @@ int main(int argc, char **argv)
int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
char *krunlevel = NULL;
char *pidstr = NULL;
+ char *deptree_skewed;
+ char *stopping_dir;
+ char *starting_dir;
int opt;
bool parallel;
int regen = 0;
@@ -773,7 +792,6 @@ int main(int argc, char **argv)
applet = basename_c(argv[0]);
LIST_INIT(&service_pids);
LIST_INIT(&free_these_pids);
- atexit(cleanup);
if (!applet)
eerrorx("arguments required");
@@ -784,10 +802,6 @@ int main(int argc, char **argv)
if (chdir("/") == -1)
eerror("chdir: %s", strerror(errno));
- /* Ensure our environment is pure
- * Also, add our configuration to it */
- env_filter();
- env_config();
/* complain about old configuration settings if they exist */
if (exists(RC_CONF_OLD)) {
@@ -836,6 +850,14 @@ int main(int argc, char **argv)
case_RC_COMMON_GETOPT
}
}
+ /* Register cleanup and set up env after flag parsing
+ * to assure user paths are still valid */
+ atexit(cleanup);
+
+ /* Ensure our environment is pure
+ * Also, add our configuration to it */
+ env_filter();
+ env_config();
newlevel = argv[optind++];
/* To make life easier, we only have the shutdown runlevel as
@@ -952,17 +974,21 @@ int main(int argc, char **argv)
/* Load our deptree */
if ((main_deptree = _rc_deptree_load(0, &regen)) == NULL)
eerrorx("failed to load deptree");
- if (exists(RC_DEPTREE_SKEWED))
+
+ xasprintf(&deptree_skewed, "%s/%s", rc_service_dir(), RC_DEPTREE_SKEWED);
+ if (exists(deptree_skewed))
ewarn("WARNING: clock skew detected!");
+ free(deptree_skewed);
/* Clean the failed services state dir */
clean_failed();
- if (mkdir(RC_STOPPING, 0755) != 0) {
+ xasprintf(&stopping_dir, "%s/%s", rc_service_dir(), RC_STOPPING);
+ if (mkdir(stopping_dir, 0755) != 0) {
if (errno == EACCES)
eerrorx("%s: superuser access required", applet);
eerrorx("%s: failed to create stopping dir `%s': %s",
- applet, RC_STOPPING, strerror(errno));
+ applet, stopping_dir, strerror(errno));
}
/* Create a list of all services which we could stop (assuming
@@ -1044,7 +1070,8 @@ int main(int argc, char **argv)
going_down ? newlevel : runlevel);
hook_out = 0;
- rmdir(RC_STOPPING);
+ rmdir(stopping_dir);
+ free(stopping_dir);
/* Store the new runlevel */
if (newlevel) {
@@ -1061,7 +1088,9 @@ int main(int argc, char **argv)
rc_logger_close();
#endif
- mkdir(RC_STARTING, 0755);
+ xasprintf(&starting_dir, "%s/%s", rc_service_dir(), RC_STARTING);
+ mkdir(starting_dir, 0755);
+ free(starting_dir);
rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, runlevel);
hook_out = RC_HOOK_RUNLEVEL_START_OUT;
@@ -1130,8 +1159,12 @@ int main(int argc, char **argv)
* 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 */
- if (regen && strcmp(runlevel, bootlevel) == 0)
- unlink(RC_DEPTREE_CACHE);
+ if (regen && strcmp(runlevel, bootlevel) == 0) {
+ char *deptree_cache;
+ xasprintf(&deptree_cache, "%s/%s", rc_service_dir(), RC_DEPTREE_CACHE);
+ unlink(deptree_cache);
+ free(deptree_cache);
+ }
return EXIT_SUCCESS;
}
diff --git a/src/service/service.c b/src/service/service.c
index 2545a022..18da90cd 100644
--- a/src/service/service.c
+++ b/src/service/service.c
@@ -32,6 +32,9 @@ int main(int argc, char **argv)
RC_SERVICE state, bit;
applet = basename_c(argv[0]);
+ if (rc_yesno(getenv("RC_USER_SERVICES")))
+ rc_set_user();
+
if (argc > 1)
service = argv[1];
else
diff --git a/src/shared/_usage.h b/src/shared/_usage.h
index 91b956e0..eb80bb3c 100644
--- a/src/shared/_usage.h
+++ b/src/shared/_usage.h
@@ -12,8 +12,9 @@
#include <getopt.h>
#include <stdlib.h>
+#include <librc.h>
-#define getoptstring_COMMON "ChqVv"
+#define getoptstring_COMMON "ChqVvU"
#define longopts_COMMON \
{ "help", 0, NULL, 'h'}, \
@@ -21,6 +22,7 @@
{ "version", 0, NULL, 'V'}, \
{ "verbose", 0, NULL, 'v'}, \
{ "quiet", 0, NULL, 'q'}, \
+ { "user", 0, NULL, 'U'}, \
{ NULL, 0, NULL, 0 }
#define longopts_help_COMMON \
@@ -28,13 +30,15 @@
"Disable color output", \
"Display software version", \
"Run verbosely", \
- "Run quietly (repeat to suppress errors)"
+ "Run quietly (repeat to suppress errors)", \
+ "Run in user mode"
#define case_RC_COMMON_getopt_case_C setenv ("EINFO_COLOR", "NO", 1);
#define case_RC_COMMON_getopt_case_h usage (EXIT_SUCCESS);
#define case_RC_COMMON_getopt_case_V if (argc == 2) show_version();
#define case_RC_COMMON_getopt_case_v setenv ("EINFO_VERBOSE", "YES", 1);
#define case_RC_COMMON_getopt_case_q set_quiet_options();
+#define case_RC_COMMON_getopt_case_U rc_set_user();
#define case_RC_COMMON_getopt_default usage (EXIT_FAILURE);
#define case_RC_COMMON_GETOPT \
@@ -43,6 +47,7 @@
case 'V': case_RC_COMMON_getopt_case_V; break; \
case 'v': case_RC_COMMON_getopt_case_v; break; \
case 'q': case_RC_COMMON_getopt_case_q; break; \
+ case 'U': case_RC_COMMON_getopt_case_U; break; \
default: case_RC_COMMON_getopt_default; break;
extern const char *applet;
diff --git a/src/shared/misc.c b/src/shared/misc.c
index 28f4e235..e946c911 100644
--- a/src/shared/misc.c
+++ b/src/shared/misc.c
@@ -64,6 +64,8 @@ static const char *const env_whitelist[] = {
"RC_DEBUG", "RC_NODEPS",
"LANG", "LC_MESSAGES", "TERM",
"EINFO_COLOR", "EINFO_VERBOSE",
+ "RC_USER_SERVICES", "HOME",
+ "XDG_RUNTIME_DIR", "XDG_CONFIG_HOME",
NULL
};
@@ -142,9 +144,11 @@ env_config(void)
char *np;
char *npp;
char *tok;
+ char *dir;
const char *sys = rc_sys();
char *buffer = NULL;
size_t size = 0;
+ const char *svc_dir = rc_service_dir();
/* Ensure our PATH is prefixed with the system locations first
for a little extra security */
@@ -175,8 +179,10 @@ env_config(void)
setenv("RC_VERSION", VERSION, 1);
setenv("RC_LIBEXECDIR", RC_LIBEXECDIR, 1);
- setenv("RC_SVCDIR", RC_SVCDIR, 1);
- setenv("RC_TMPDIR", RC_SVCDIR "/tmp", 1);
+ setenv("RC_SVCDIR", svc_dir, 1);
+ xasprintf(&dir, "%s/tmp", svc_dir);
+ setenv("RC_TMPDIR", dir, 1);
+ free(dir);
setenv("RC_BOOTLEVEL", RC_LEVEL_BOOT, 1);
e = rc_runlevel_get();
setenv("RC_RUNLEVEL", e, 1);
@@ -248,7 +254,7 @@ svc_lock(const char *applet, bool ignore_lock_failure)
char *file = NULL;
int fd;
- xasprintf(&file, RC_SVCDIR "/exclusive/%s", applet);
+ xasprintf(&file, "%s/exclusive/%s", rc_service_dir(), applet);
fd = open(file, O_WRONLY | O_CREAT | O_NONBLOCK, 0664);
free(file);
if (fd == -1)
@@ -274,10 +280,11 @@ svc_unlock(const char *applet, int fd)
{
char *file = NULL;
- xasprintf(&file, RC_SVCDIR "/exclusive/%s", applet);
+ xasprintf(&file, "%s/exclusive/%s", rc_service_dir(), applet);
close(fd);
unlink(file);
free(file);
+
return -1;
}
@@ -388,12 +395,16 @@ RC_DEPTREE * _rc_deptree_load(int force, int *regen)
t = 0;
if (rc_deptree_update_needed(&t, file) || force != 0) {
+ char *deptree_cache;
+ xasprintf(&deptree_cache, "%s/%s", rc_service_dir(), RC_DEPTREE_CACHE);
/* Test if we have permission to update the deptree */
- fd = open(RC_DEPTREE_CACHE, O_WRONLY);
+ fd = open(deptree_cache, O_WRONLY);
merrno = errno;
errno = serrno;
- if (fd == -1 && merrno == EACCES)
+ if (fd == -1 && merrno == EACCES) {
+ free(deptree_cache);
return rc_deptree_load();
+ }
close(fd);
if (regen)
@@ -403,29 +414,34 @@ RC_DEPTREE * _rc_deptree_load(int force, int *regen)
eend (retval, "Failed to update the dependency tree");
if (retval == 0) {
- if (stat(RC_DEPTREE_CACHE, &st) != 0) {
- eerror("stat(%s): %s", RC_DEPTREE_CACHE, strerror(errno));
+ char *deptree_skewed;
+ if (stat(deptree_cache, &st) != 0) {
+ eerror("stat(%s): %s", deptree_cache, strerror(errno));
+ free(deptree_cache);
return NULL;
}
+
+ xasprintf(&deptree_skewed, "%s/%s", rc_service_dir(), RC_DEPTREE_SKEWED);
if (st.st_mtime < t) {
eerror("Clock skew detected with `%s'", file);
- eerrorn("Adjusting mtime of `" RC_DEPTREE_CACHE
- "' to %s", ctime(&t));
- fp = fopen(RC_DEPTREE_SKEWED, "w");
+ eerrorn("Adjusting mtime of %s to %s", deptree_cache, ctime(&t));
+ fp = fopen(deptree_skewed, "w");
if (fp != NULL) {
fprintf(fp, "%s\n", file);
fclose(fp);
}
ut.actime = t;
ut.modtime = t;
- utime(RC_DEPTREE_CACHE, &ut);
+ utime(deptree_cache, &ut);
} else {
- if (exists(RC_DEPTREE_SKEWED))
- unlink(RC_DEPTREE_SKEWED);
+ if (exists(deptree_skewed))
+ unlink(deptree_skewed);
}
+ free(deptree_skewed);
}
if (force == -1 && regen != NULL)
*regen = retval;
+ free(deptree_cache);
}
return rc_deptree_load();
}
diff --git a/src/shared/misc.h b/src/shared/misc.h
index b158a786..9171a881 100644
--- a/src/shared/misc.h
+++ b/src/shared/misc.h
@@ -33,16 +33,11 @@
#define RC_LEVEL_BOOT "boot"
#define RC_LEVEL_DEFAULT "default"
-#define RC_DEPTREE_CACHE RC_SVCDIR "/deptree"
-#define RC_DEPTREE_SKEWED RC_SVCDIR "/clock-skewed"
+#define RC_DEPTREE_CACHE "deptree"
+#define RC_DEPTREE_SKEWED "clock-skewed"
#define RC_KRUNLEVEL RC_SVCDIR "/krunlevel"
-#define RC_STARTING RC_SVCDIR "/rc.starting"
-#define RC_STOPPING RC_SVCDIR "/rc.stopping"
-
-#define RC_SVCDIR_STARTING RC_SVCDIR "/starting"
-#define RC_SVCDIR_INACTIVE RC_SVCDIR "/inactive"
-#define RC_SVCDIR_STARTED RC_SVCDIR "/started"
-#define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "/coldplugged"
+#define RC_STARTING "rc.starting"
+#define RC_STOPPING "rc.stopping"
char *rc_conf_value(const char *var);
bool rc_conf_yesno(const char *var);
diff --git a/src/supervise-daemon/supervise-daemon.c b/src/supervise-daemon/supervise-daemon.c
index adf35630..9bc3c029 100644
--- a/src/supervise-daemon/supervise-daemon.c
+++ b/src/supervise-daemon/supervise-daemon.c
@@ -817,6 +817,7 @@ int main(int argc, char **argv)
char **child_argv = NULL;
char *str = NULL;
char *cmdline = NULL;
+ const char *svc_dir;
applet = basename_c(argv[0]);
atexit(cleanup);
@@ -1084,9 +1085,10 @@ int main(int argc, char **argv)
ch_root = expand_home(home, ch_root);
umask(numask);
+ svc_dir = rc_service_dir();
if (!pidfile)
- xasprintf(&pidfile, "/var/run/supervise-%s.pid", svcname);
- xasprintf(&fifopath, "%s/supervise-%s.ctl", RC_SVCDIR, svcname);
+ xasprintf(&pidfile, "%s/supervise-%s.pid", rc_is_user() ? svc_dir : "/var/run", svcname); /* FIXME: improve */
+ xasprintf(&fifopath, "%s/supervise-%s.ctl", svc_dir, svcname);
if (mkfifo(fifopath, 0600) == -1 && errno != EEXIST)
eerrorx("%s: unable to create control fifo: %s",
applet, strerror(errno));
diff --git a/src/value/value.c b/src/value/value.c
index e5190379..7cd17a31 100644
--- a/src/value/value.c
+++ b/src/value/value.c
@@ -30,6 +30,9 @@ int main(int argc, char **argv)
char *option;
applet = basename_c(argv[0]);
+ if (rc_yesno(getenv("RC_USER_SERVICES")))
+ rc_set_user();
+
if (service == NULL)
eerrorx("%s: no service specified", applet);