Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Services 2.0 #723

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions service-script-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,3 +509,9 @@ This is a sensible default for daemons that are happy with `0.0.0.0`,
but lets the user specify something else, like `rc_need="net.wan"` if
he needs it. The burden is on the user to determine the appropriate
service whenever he changes the daemon's configuration file.

# User services

User services are ran as the user that starts them. A few things to note
then, are that command_user shouldn't be set, runtime data (such as pidfiles
and sockets) should be placed in XDG_RUNTIME_DIR.
2 changes: 1 addition & 1 deletion sh/openrc-run.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,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
Expand Down
6 changes: 6 additions & 0 deletions src/librc/librc-depend.c
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,12 @@ rc_deptree_update_needed(time_t *newest, char *file)
newer |= !deep_mtime_check(path, true, &mtime, file);
free(path);

if (rc_is_user()) {
xasprintf(&path, "%s/rc.conf", rc_usrconfdir());
newer |= !deep_mtime_check(path, true, &mtime, file);
free(path);
}

/* Some init scripts dependencies change depending on config files
* outside of baselayout, like syslog-ng, so we check those too. */
xasprintf(&depconfig, "%s/depconfig", service_dir);
Expand Down
35 changes: 27 additions & 8 deletions src/librc/librc-misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ static RC_STRINGLIST *rc_config_kcl(RC_STRINGLIST *config)
return config;
}

static RC_STRINGLIST * rc_config_directory(RC_STRINGLIST *config, char *dir)
static RC_STRINGLIST * rc_config_directory(RC_STRINGLIST *config, const char *dir)
{
DIR *dp;
struct dirent *d;
Expand Down Expand Up @@ -383,28 +383,47 @@ _free_rc_conf(void)
rc_stringlist_free(rc_conf);
}

static void
rc_conf_append(const char *file)
{
RC_STRINGLIST *conf = rc_config_load(file);
TAILQ_CONCAT(rc_conf, conf, entries);
rc_stringlist_free(conf);
}

char *
rc_conf_value(const char *setting)
{
const char *sysconfdir = rc_sysconfdir();
const char *usrconfdir = rc_usrconfdir();
RC_STRING *s;
char *conf;

if (rc_conf)
return rc_config_value(rc_conf, setting);

xasprintf(&conf, "%s/%s", sysconfdir, "rc.conf");
rc_conf = rc_config_load(conf);
rc_conf = rc_stringlist_new();
atexit(_free_rc_conf);

/* Load user configurations first, as they should override
* system wide configs. */
if (usrconfdir) {
xasprintf(&conf, "%s/%s", usrconfdir, "rc.conf");
rc_conf_append(conf);
free(conf);

xasprintf(&conf, "%s/%s", usrconfdir, "rc.conf.d");
rc_conf = rc_config_directory(rc_conf, conf);
free(conf);
}

xasprintf(&conf, "%s/%s", sysconfdir, "rc.conf");
rc_conf_append(sysconfdir);
free(conf);

/* Support old configs. */
if (exists(RC_CONF_OLD)) {
RC_STRINGLIST *old_conf = rc_config_load(RC_CONF_OLD);
TAILQ_CONCAT(rc_conf, old_conf, entries);
rc_stringlist_free(old_conf);
}
if (exists(RC_CONF_OLD))
rc_conf_append(RC_CONF_OLD);

xasprintf(&conf, "%s/%s", sysconfdir, "rc.conf.d");
rc_conf = rc_config_directory(rc_conf, conf);
Expand Down
77 changes: 77 additions & 0 deletions src/librc/librc.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "librc.h"
#include "misc.h"
#include "rc.h"
#include "einfo.h"
#ifdef __FreeBSD__
# include <sys/sysctl.h>
#endif
Expand Down Expand Up @@ -567,30 +568,106 @@ static const char * const scriptdirs[] = {
#ifdef RC_PKG_PREFIX
RC_PKG_PREFIX "/etc",
#endif
NULL, /* slot for userconf dir */
NULL
};

static struct {
bool set;
char *svcdir;
char *usrconfdir;
char *runleveldir;
char *scriptdirs[ARRAY_SIZE(scriptdirs)];
} rc_dirs;

static void
free_rc_dirs(void)
{
free(rc_dirs.runleveldir);
rc_dirs.runleveldir = NULL;
free(rc_dirs.svcdir);
rc_dirs.svcdir = NULL;
for (size_t i = 0; rc_dirs.scriptdirs[i]; i++)
free(rc_dirs.scriptdirs[i]);
}

static bool is_user = false;

bool
rc_is_user(void)
{
return is_user;
}

void
rc_set_user(void)
{
char *env;
if (is_user)
return;

is_user = true;
rc_dirs.set = true;
setenv("RC_USER_SERVICES", "yes", true);

if ((env = getenv("XDG_CONFIG_HOME")))
xasprintf(&rc_dirs.scriptdirs[0], "%s/openrc", env);
else if ((env = getenv("HOME")))
xasprintf(&rc_dirs.scriptdirs[0], "%s/.config/openrc", env);
else
eerrorx("XDG_CONFIG_HOME and HOME unset");

rc_dirs.usrconfdir = rc_dirs.scriptdirs[0];

for (size_t i = 0; scriptdirs[i]; i++)
xasprintf(&rc_dirs.scriptdirs[i + 1], "%s/user.d", scriptdirs[i]);

xasprintf(&rc_dirs.runleveldir, "%s/runlevels", rc_dirs.scriptdirs[0]);

if (!(env = getenv("XDG_RUNTIME_DIR")))
eerrorx("XDG_RUNTIME_DIR unset."); /* FIXME: fallback to something else? */
xasprintf(&rc_dirs.svcdir, "%s/openrc", env);
atexit(free_rc_dirs);
}

const char * const *
rc_scriptdirs(void)
{
if (rc_dirs.set)
return (const char * const *) rc_dirs.scriptdirs;
return scriptdirs;
}

const char *
rc_sysconfdir(void)
{
if (is_user)
return RC_SYSCONFDIR "/user.d";
return RC_SYSCONFDIR;
}

const char *
rc_usrconfdir(void)
{
if (rc_dirs.set)
return rc_dirs.usrconfdir;

return NULL;
}

const char *
rc_runleveldir(void)
{
if (rc_dirs.set)
return rc_dirs.runleveldir;
return RC_RUNLEVELDIR;
}

const char *
rc_svcdir(void)
{
if (rc_dirs.set)
return rc_dirs.svcdir;
return RC_SVCDIR;
}

Expand Down
1 change: 1 addition & 0 deletions src/librc/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,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)
Expand Down
12 changes: 12 additions & 0 deletions src/librc/rc.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ typedef TAILQ_HEAD(rc_stringlist, rc_string) RC_STRINGLIST;
#define RC_LEVEL_SINGLE "single"
#define RC_LEVEL_SHUTDOWN "shutdown"

/*! Set user-wide paths for the rc_*dir functions. */
void rc_set_user(void);

/*! @return true if rc_set_user was called, false otherwise. */
bool rc_is_user(void);

/*! Sets the root prefix for all librc operations
* it should be called before any other operation
* @param root path to prefix */
Expand All @@ -134,6 +140,12 @@ const char * const *rc_scriptdirs(void);
* @return Path to the system configuration directory */
const char *rc_sysconfdir(void);

/*! The user configuration directory is where rc.conf
* will be located for user-mode openrc. It is meant to
* override the system wide configs where applicable.
* @return Path to the user configuration directory, or NULL if in system mode */
const char *rc_usrconfdir(void);

/*! @return Path to runlevel directory */
const char *rc_runleveldir(void);

Expand Down
3 changes: 3 additions & 0 deletions src/mark_service/mark_service.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ int main(int argc, char **argv)
if (service == NULL || *service == '\0')
eerrorx("%s: no service specified", applet);

if (rc_yesno(getenv("RC_USER_SERVICES")))
rc_set_user();

if (!strncmp(applet, "mark_", 5) &&
(bit = lookup_service_state(applet + 5)))
ok = rc_service_mark(service, bit);
Expand Down
90 changes: 49 additions & 41 deletions src/openrc-run/openrc-run.c
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,7 @@ int main(int argc, char **argv)
char *path = NULL;
char *lnk = NULL;
char *dir, *save = NULL, *saveLnk = NULL;
const char *workingdir = "/";
char *pidstr = NULL;
size_t l = 0, ll;
const char *file;
Expand All @@ -1118,7 +1119,8 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}

atexit(cleanup);
if (rc_yesno(getenv("RC_USER_SERVICES")))
rc_set_user();

/* We need to work out the real full path to our service.
* This works fine, provided that we ONLY allow multiplexed services
Expand Down Expand Up @@ -1160,10 +1162,54 @@ int main(int argc, char **argv)
if (argc < 3)
usage(EXIT_FAILURE);

/* Change dir to / to ensure all init scripts don't use stuff in pwd */
if (chdir("/") == -1)
/* Ok, we are ready to go, so setup selinux if applicable */
selinux_setup(argv);

deps = true;

/* Punt the first arg as its our service name */
argc--;
argv++;

/* Right then, parse any options there may be */
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *)0)) != -1)
switch (opt) {
case 'd':
setenv("RC_DEBUG", "YES", 1);
break;
case 'l':
exclusive_fd = atoi(optarg);
fcntl(exclusive_fd, F_SETFD,
fcntl(exclusive_fd, F_GETFD, 0) | FD_CLOEXEC);
break;
case 's':
if (!(rc_service_state(service) & RC_SERVICE_STARTED))
exit(EXIT_FAILURE);
break;
case 'S':
if (!(rc_service_state(service) & RC_SERVICE_STOPPED))
exit(EXIT_FAILURE);
break;
case 'D':
deps = false;
break;
case 'Z':
dry_run = true;
break;
case_RC_COMMON_GETOPT
}

/* Change dir to / to ensure all init scripts don't use stuff in pwd
* For user services, change to the user's HOME instead. */
if (rc_is_user() && !(workingdir = getenv("HOME")))
eerrorx("HOME is unset.");

if (chdir(workingdir) == -1)
eerror("chdir: %s", strerror(errno));

atexit(cleanup);

if ((runlevel = xstrdup(getenv("RC_RUNLEVEL"))) == NULL) {
env_filter();
env_config();
Expand Down Expand Up @@ -1207,44 +1253,6 @@ int main(int argc, char **argv)
eprefix(prefix);
}

/* Ok, we are ready to go, so setup selinux if applicable */
selinux_setup(argv);

deps = true;

/* Punt the first arg as its our service name */
argc--;
argv++;

/* Right then, parse any options there may be */
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *)0)) != -1)
switch (opt) {
case 'd':
setenv("RC_DEBUG", "YES", 1);
break;
case 'l':
exclusive_fd = atoi(optarg);
fcntl(exclusive_fd, F_SETFD,
fcntl(exclusive_fd, F_GETFD, 0) | FD_CLOEXEC);
break;
case 's':
if (!(rc_service_state(service) & RC_SERVICE_STARTED))
exit(EXIT_FAILURE);
break;
case 'S':
if (!(rc_service_state(service) & RC_SERVICE_STOPPED))
exit(EXIT_FAILURE);
break;
case 'D':
deps = false;
break;
case 'Z':
dry_run = true;
break;
case_RC_COMMON_GETOPT
}

if (rc_yesno(getenv("RC_NODEPS")))
deps = false;

Expand Down
Loading
Loading