diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-03-03 17:14:07 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-03-03 17:55:32 +0100 |
commit | e66cf1a3f94fff48a572f6dbd19b43c9bcf7b8c7 (patch) | |
tree | e3580f7a1e9aaca01ada8575a1ea50a7a32dd2d3 | |
parent | execute: no need to include seccomp.h from execute.h (diff) | |
download | systemd-e66cf1a3f94fff48a572f6dbd19b43c9bcf7b8c7.tar.xz systemd-e66cf1a3f94fff48a572f6dbd19b43c9bcf7b8c7.zip |
core: introduce new RuntimeDirectory= and RuntimeDirectoryMode= unit settings
As discussed on the ML these are useful to manage runtime directories
below /run for services.
-rw-r--r-- | man/systemd.exec.xml | 41 | ||||
-rw-r--r-- | man/tmpfiles.d.xml | 20 | ||||
-rw-r--r-- | src/core/dbus-execute.c | 2 | ||||
-rw-r--r-- | src/core/execute.c | 51 | ||||
-rw-r--r-- | src/core/execute.h | 6 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.m4 | 2 | ||||
-rw-r--r-- | src/core/load-fragment.c | 50 | ||||
-rw-r--r-- | src/core/load-fragment.h | 1 | ||||
-rw-r--r-- | src/core/manager.c | 7 | ||||
-rw-r--r-- | src/core/manager.h | 2 | ||||
-rw-r--r-- | src/core/mount.c | 3 | ||||
-rw-r--r-- | src/core/service.c | 6 | ||||
-rw-r--r-- | src/core/socket.c | 3 | ||||
-rw-r--r-- | src/core/swap.c | 3 | ||||
-rw-r--r-- | src/shared/exit-status.c | 3 | ||||
-rw-r--r-- | src/shared/exit-status.h | 1 | ||||
-rw-r--r-- | src/shared/mkdir.c | 4 |
17 files changed, 201 insertions, 4 deletions
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 9224f1ef3d..f1bcf9b7bd 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1195,6 +1195,46 @@ kernel.</para></listitem> </varlistentry> + <varlistentry> + <term><varname>RuntimeDirectory=</varname></term> + <term><varname>RuntimeDirectoryMode=</varname></term> + + <listitem><para>Takes a list of + directory names. If set one or more + directories by the specified names + will be created below + <filename>/run</filename> (for system + services) or below + <varname>$XDG_RUNTIME_DIR</varname> + (for user services) when the unit is + started and removed when the unit is + stopped. The directories will have the + access mode specified in + <varname>RuntimeDirectoryMode=</varname>, + and will be owned by the user and + group specified in + <varname>User=</varname> and + <varname>Group=</varname>. Use this to + manage one or more runtime directories + of the unit and bind their lifetime to + the daemon runtime. The specified + directory names must be relative, and + may not include a + <literal>/</literal>, i.e. must refer + to simple directories to create or + remove. This is particularly useful + for unpriviliges daemons that cannot + create runtime directories in + <filename>/run</filename> due to lack + of privileges, and to make sure the + runtime directory is cleaned up + automatically after use. For runtime + directories that require more complex + or different configuration or lifetime + guarantees, please consider using + <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem> + </varlistentry> + </variablelist> </refsect1> @@ -1352,6 +1392,7 @@ <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>, + <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>exec</refentrytitle><manvolnum>3</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index 0a006d17ab..343fad163c 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -61,6 +61,23 @@ temporary files and directories which usually reside in directories such as <filename>/run</filename> or <filename>/tmp</filename>.</para> + + <para>Volatile and temporary files and directories are + those located in <filename>/run</filename> (and its + alias <filename>/var/run</filename>), + <filename>/tmp</filename>, + <filename>/var/tmp</filename>, the API file systems + such as <filename>/sys</filename> or + <filename>/proc</filename>, as well as some other + directories below <filename>/var</filename>.</para> + + <para>System daemons frequently require private + runtime directories below <filename>/run</filename> to + place communication sockets and similar in. For these + consider declaring them in their unit files using + <varname>RuntimeDirectory=</varname> + (see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details), + if this is feasible.</para> </refsect1> <refsect1> @@ -458,7 +475,8 @@ x /var/tmp/abrt/*</programlisting> <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd-delta</refentrytitle><manvolnum>1</manvolnum></citerefentry> + <citerefentry><refentrytitle>systemd-delta</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> </para> </refsect1> diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 02e2a6d3df..6d0bdce9dc 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -635,6 +635,8 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; diff --git a/src/core/execute.c b/src/core/execute.c index 3312885b87..fec4b3b13a 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -82,6 +82,7 @@ #include "selinux-util.h" #include "errno-list.h" #include "af-list.h" +#include "mkdir.h" #include "apparmor-util.h" #ifdef HAVE_SECCOMP @@ -1247,6 +1248,7 @@ int exec_spawn(ExecCommand *command, bool confirm_spawn, CGroupControllerMask cgroup_supported, const char *cgroup_path, + const char *runtime_prefix, const char *unit_id, usec_t watchdog_usec, int idle_pipe[4], @@ -1544,6 +1546,27 @@ int exec_spawn(ExecCommand *command, } #endif + if (!strv_isempty(context->runtime_directory) && runtime_prefix) { + char **rt; + + STRV_FOREACH(rt, context->runtime_directory) { + _cleanup_free_ char *p; + + p = strjoin(runtime_prefix, "/", *rt, NULL); + if (!p) { + r = EXIT_RUNTIME_DIRECTORY; + err = -ENOMEM; + goto fail_child; + } + + err = mkdir_safe(p, context->runtime_directory_mode, uid, gid); + if (err < 0) { + r = EXIT_RUNTIME_DIRECTORY; + goto fail_child; + } + } + } + if (apply_permissions) { err = enforce_groups(context, username, gid); if (err < 0) { @@ -1840,6 +1863,7 @@ void exec_context_init(ExecContext *c) { c->ignore_sigpipe = true; c->timer_slack_nsec = (nsec_t) -1; c->personality = 0xffffffffUL; + c->runtime_directory_mode = 0755; } void exec_context_done(ExecContext *c) { @@ -1918,6 +1942,33 @@ void exec_context_done(ExecContext *c) { set_free(c->address_families); c->address_families = NULL; + + strv_free(c->runtime_directory); + c->runtime_directory = NULL; +} + +int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) { + char **i; + + assert(c); + + if (!runtime_prefix) + return 0; + + STRV_FOREACH(i, c->runtime_directory) { + _cleanup_free_ char *p; + + p = strjoin(runtime_prefix, "/", *i, NULL); + if (!p) + return -ENOMEM; + + /* We execute this synchronously, since we need to be + * sure this is gone when we start the service + * next. */ + rm_rf_dangerous(p, false, true, false); + } + + return 0; } void exec_command_done(ExecCommand *c) { diff --git a/src/core/execute.h b/src/core/execute.h index efda23f9d8..2c5d8bbf76 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -177,6 +177,9 @@ struct ExecContext { Set *address_families; bool address_families_whitelist:1; + char **runtime_directory; + mode_t runtime_directory_mode; + bool oom_score_adjust_set:1; bool nice_set:1; bool ioprio_set:1; @@ -196,6 +199,7 @@ int exec_spawn(ExecCommand *command, bool confirm_spawn, CGroupControllerMask cgroup_mask, const char *cgroup_path, + const char *runtime_prefix, const char *unit_id, usec_t watchdog_usec, int pipe_fd[2], @@ -219,6 +223,8 @@ void exec_context_init(ExecContext *c); void exec_context_done(ExecContext *c); void exec_context_dump(ExecContext *c, FILE* f, const char *prefix); +int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_root); + int exec_context_load_environment(const ExecContext *c, char ***l); bool exec_context_may_touch_console(ExecContext *c); diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index beff290251..c9ab5c33e2 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -82,6 +82,8 @@ $1.PrivateNetwork, config_parse_bool, 0, $1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices) $1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context) $1.Personality, config_parse_personality, 0, offsetof($1, exec_context.personality) +$1.RuntimeDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.runtime_directory_mode) +$1.RuntimeDirectory, config_parse_runtime_directory, 0, offsetof($1, exec_context.runtime_directory) m4_ifdef(`HAVE_LIBWRAP', `$1.TCPWrapName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.tcpwrap_name)', `$1.TCPWrapName, config_parse_warn_compat, 0, 0') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 478d22c4b5..6f0027bf9b 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2719,6 +2719,56 @@ int config_parse_personality( return 0; } +int config_parse_runtime_directory( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char***rt = data, *w, *state; + size_t l; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + strv_free(*rt); + *rt = NULL; + return 0; + } + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + _cleanup_free_ char *n; + + n = strndup(w, l); + if (!n) + return log_oom(); + + if (!filename_is_safe(n)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue); + continue; + } + + r = strv_push(rt, n); + if (r < 0) + return log_oom(); + + n = NULL; + } + + return 0; +} + #define FOLLOW_MAX 8 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index c5dbe6157e..5488f1d704 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -91,6 +91,7 @@ int config_parse_exec_selinux_context(const char *unit, const char *filename, un int config_parse_personality(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_apparmor_profile(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_address_families(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_runtime_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); diff --git a/src/core/manager.c b/src/core/manager.c index 9172a244ae..822c7ccfee 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2851,3 +2851,10 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) { return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p); } + +const char *manager_get_runtime_prefix(Manager *m) { + + return m->running_as == SYSTEMD_SYSTEM ? + "/run" : + getenv("XDG_RUNTIME_DIR"); +} diff --git a/src/core/manager.h b/src/core/manager.h index 398c8e642e..3192b63dfd 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -318,3 +318,5 @@ void manager_status_printf(Manager *m, bool ephemeral, const char *status, const void manager_flip_auto_status(Manager *m, bool enable); Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path); + +const char *manager_get_runtime_prefix(Manager *m); diff --git a/src/core/mount.c b/src/core/mount.c index 7a92e1ca60..60067d4d75 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -788,6 +788,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { UNIT(m)->manager->confirm_spawn, UNIT(m)->manager->cgroup_supported, UNIT(m)->cgroup_path, + manager_get_runtime_prefix(UNIT(m)->manager), UNIT(m)->id, 0, NULL, @@ -820,6 +821,8 @@ static void mount_enter_dead(Mount *m, MountResult f) { exec_runtime_destroy(m->exec_runtime); m->exec_runtime = exec_runtime_unref(m->exec_runtime); + exec_context_destroy_runtime_directory(&m->exec_context, manager_get_runtime_prefix(UNIT(m)->manager)); + mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD); } diff --git a/src/core/service.c b/src/core/service.c index 6de24ec5bd..121ddec6ad 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1770,6 +1770,7 @@ static int service_spawn( UNIT(s)->manager->confirm_spawn, UNIT(s)->manager->cgroup_supported, path, + manager_get_runtime_prefix(UNIT(s)->manager), UNIT(s)->id, s->watchdog_usec, s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL, @@ -1871,10 +1872,13 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) s->forbid_restart = false; - /* we want fresh tmpdirs in case service is started again immediately */ + /* We want fresh tmpdirs in case service is started again immediately */ exec_runtime_destroy(s->exec_runtime); s->exec_runtime = exec_runtime_unref(s->exec_runtime); + /* Also, remove the runtime directory in */ + exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager)); + /* Try to delete the pid file. At this point it will be * out-of-date, and some software might be confused by it, so * let's remove it. */ diff --git a/src/core/socket.c b/src/core/socket.c index 8e39032db6..35531edb75 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1255,6 +1255,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { UNIT(s)->manager->confirm_spawn, UNIT(s)->manager->cgroup_supported, UNIT(s)->cgroup_path, + manager_get_runtime_prefix(UNIT(s)->manager), UNIT(s)->id, 0, NULL, @@ -1289,6 +1290,8 @@ static void socket_enter_dead(Socket *s, SocketResult f) { exec_runtime_destroy(s->exec_runtime); s->exec_runtime = exec_runtime_unref(s->exec_runtime); + exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager)); + socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD); } diff --git a/src/core/swap.c b/src/core/swap.c index 96cf38aae2..7004ede70e 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -646,6 +646,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { UNIT(s)->manager->confirm_spawn, UNIT(s)->manager->cgroup_supported, UNIT(s)->cgroup_path, + manager_get_runtime_prefix(UNIT(s)->manager), UNIT(s)->id, 0, NULL, @@ -678,6 +679,8 @@ static void swap_enter_dead(Swap *s, SwapResult f) { exec_runtime_destroy(s->exec_runtime); s->exec_runtime = exec_runtime_unref(s->exec_runtime); + exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager)); + swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD); } diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c index c1b04a3868..c1c0861168 100644 --- a/src/shared/exit-status.c +++ b/src/shared/exit-status.c @@ -142,6 +142,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { case EXIT_ADDRESS_FAMILIES: return "ADDRESS_FAMILIES"; + + case EXIT_RUNTIME_DIRECTORY: + return "RUNTIME_DIRECTORY"; } } diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h index e7f12032ec..9dc3fce0bf 100644 --- a/src/shared/exit-status.h +++ b/src/shared/exit-status.h @@ -72,6 +72,7 @@ typedef enum ExitStatus { EXIT_PERSONALITY, /* 230 */ EXIT_APPARMOR_PROFILE, EXIT_ADDRESS_FAMILIES, + EXIT_RUNTIME_DIRECTORY } ExitStatus; typedef enum ExitStatusLevel { diff --git a/src/shared/mkdir.c b/src/shared/mkdir.c index 43c6ea6d4a..4a2cd5e662 100644 --- a/src/shared/mkdir.c +++ b/src/shared/mkdir.c @@ -42,8 +42,8 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkd return -errno; if ((st.st_mode & 0777) != mode || - st.st_uid != uid || - st.st_gid != gid || + (uid != (uid_t) -1 && st.st_uid != uid) || + (gid != (gid_t) -1 && st.st_gid != gid) || !S_ISDIR(st.st_mode)) { errno = EEXIST; return -errno; |