From 3536f49e8fa281539798a7bc5004d73302f39673 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 18 Jul 2017 21:34:52 +0900 Subject: [PATCH] core: add {State,Cache,Log,Configuration}Directory= (#6384) This introduces {State,Cache,Log,Configuration}Directory= those are similar to RuntimeDirectory=. They create the directories under /var/lib, /var/cache/, /var/log, or /etc, respectively, with the mode specified in {State,Cache,Log,Configuration}DirectoryMode=. This also fixes #6391. --- man/systemd.exec.xml | 27 +++++++- src/basic/exit-status.c | 12 ++++ src/basic/exit-status.h | 4 ++ src/core/dbus-execute.c | 44 +++++++++--- src/core/execute.c | 125 +++++++++++++++++++++++++--------- src/core/execute.h | 23 ++++++- src/core/load-fragment-gperf.gperf.m4 | 12 +++- src/core/load-fragment.c | 4 +- src/core/load-fragment.h | 2 +- src/core/manager.c | 69 +++++++++++++++---- src/core/manager.h | 5 +- src/core/mount.c | 10 +-- src/core/service.c | 11 +-- src/core/socket.c | 11 +-- src/core/swap.c | 13 ++-- src/core/unit-printf.c | 6 +- src/shared/bus-unit-util.c | 4 +- 17 files changed, 286 insertions(+), 96 deletions(-) diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 8356c1b..b074331 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1682,11 +1682,32 @@ + StateDirectory= + CacheDirectory= + LogsDirectory= + ConfigurationDirectory= + + Takes a whitespace-separated list of directory names. If set, as similar to + RuntimeDirectory=, one or more directories including their parents by the specified names + will be created below /var/lib, /var/cache, /var/log, + or /etc, respectively, when the unit is started. + Unlike RuntimeDirectory=, the directories are not removed when the unit is stopped. + The lowest subdirectories will be owned by the user and group specified in User= + and Group=. The options imply ReadWritePaths=. + + + + RuntimeDirectoryMode= + StateDirectoryMode= + CacheDirectoryMode= + LogsDirectoryMode= + ConfigurationDirectoryMode= Specifies the access mode of the directories specified in - RuntimeDirectory= as an octal number. Defaults to - 0755. See "Permissions" in + RuntimeDirectory=, StateDirectory=, CacheDirectory=, + LogsDirectory=, or ConfigurationDirectory=, respectively, as an octal number. + Defaults to 0755. See "Permissions" in path_resolution7 for a discussion of the meaning of permission bits. @@ -1727,7 +1748,7 @@ services, so that they cannot be used to circumvent the restrictions of this option. Specifically, it is recommended to combine this option with SystemCallArchitectures=native or similar. If running in user mode, or in system mode, but without the CAP_SYS_ADMIN capability - (e.g. setting User=), NoNewPrivileges=yes is implied. + (e.g. setting User=), NoNewPrivileges=yes is implied. diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c index 1e23c32..fba0126 100644 --- a/src/basic/exit-status.c +++ b/src/basic/exit-status.c @@ -151,6 +151,18 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) { case EXIT_KEYRING: return "KEYRING"; + + case EXIT_STATE_DIRECTORY: + return "STATE_DIRECTORY"; + + case EXIT_CACHE_DIRECTORY: + return "CACHE_DIRECTORY"; + + case EXIT_LOGS_DIRECTORY: + return "LOGS_DIRECTORY"; + + case EXIT_CONFIGURATION_DIRECTORY: + return "CONFIGURATION_DIRECTORY"; } } diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h index d22b2c0..e2c76f8 100644 --- a/src/basic/exit-status.h +++ b/src/basic/exit-status.h @@ -83,6 +83,10 @@ enum { EXIT_CHOWN, EXIT_SMACK_PROCESS_LABEL, EXIT_KEYRING, + EXIT_STATE_DIRECTORY, + EXIT_CACHE_DIRECTORY, + EXIT_LOGS_DIRECTORY, /* 240 */ + EXIT_CONFIGURATION_DIRECTORY, }; typedef enum ExitStatusLevel { diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 0958c23..01f2d11 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -851,9 +851,17 @@ 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("RuntimeDirectoryPreserve", "s", property_get_exec_preserve_mode, offsetof(ExecContext, runtime_directory_preserve_mode), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME].mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME].paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DataDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DataDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CacheDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CacheDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LogsDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LogsDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ConfigurationDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ConfigurationDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].paths), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RestrictNamespaces", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1701,7 +1709,7 @@ int bus_exec_context_set_transient_property( return 1; - } else if (streq(name, "RuntimeDirectoryMode")) { + } else if (STR_IN_SET(name, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode")) { mode_t m; r = sd_bus_message_read(message, "u", &m); @@ -1709,14 +1717,20 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - c->runtime_directory_mode = m; + ExecDirectoryType i; - unit_write_drop_in_private_format(u, mode, name, "RuntimeDirectoryMode=%040o", m); + for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) + if (startswith(name, exec_directory_type_to_string(i))) { + c->directories[i].mode = m; + break; + } + + unit_write_drop_in_private_format(u, mode, name, "%s=%040o", name, m); } return 1; - } else if (streq(name, "RuntimeDirectory")) { + } else if (STR_IN_SET(name, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) { _cleanup_strv_free_ char **l = NULL; char **p; @@ -1726,22 +1740,32 @@ int bus_exec_context_set_transient_property( STRV_FOREACH(p, l) { if (!filename_is_valid(*p)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Runtime directory is not valid %s", *p); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s is not valid %s", name, *p); } if (mode != UNIT_CHECK) { _cleanup_free_ char *joined = NULL; + char ***dirs = NULL; + ExecDirectoryType i; + + for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) + if (streq(name, exec_directory_type_to_string(i))) { + dirs = &c->directories[i].paths; + break; + } + + assert(dirs); if (strv_isempty(l)) { - c->runtime_directory = strv_free(c->runtime_directory); + *dirs = strv_free(*dirs); unit_write_drop_in_private_format(u, mode, name, "%s=", name); } else { - r = strv_extend_strv(&c->runtime_directory, l, true); + r = strv_extend_strv(dirs, l, true); if (r < 0) return -ENOMEM; - joined = strv_join_quoted(c->runtime_directory); + joined = strv_join_quoted(*dirs); if (!joined) return -ENOMEM; diff --git a/src/core/execute.c b/src/core/execute.c index 16da43c..3efd56f 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1839,39 +1839,68 @@ static int setup_private_users(uid_t uid, gid_t gid) { return 0; } -static int setup_runtime_directory( +static int setup_exec_directory( const ExecContext *context, const ExecParameters *params, uid_t uid, - gid_t gid) { + gid_t gid, + bool manager_is_system, + ExecDirectoryType type, + int *exit_status) { + static const int exit_status_table[_EXEC_DIRECTORY_MAX] = { + [EXEC_DIRECTORY_RUNTIME] = EXIT_RUNTIME_DIRECTORY, + [EXEC_DIRECTORY_STATE] = EXIT_STATE_DIRECTORY, + [EXEC_DIRECTORY_CACHE] = EXIT_CACHE_DIRECTORY, + [EXEC_DIRECTORY_LOGS] = EXIT_LOGS_DIRECTORY, + [EXEC_DIRECTORY_CONFIGURATION] = EXIT_CONFIGURATION_DIRECTORY, + }; char **rt; int r; assert(context); assert(params); + assert(type >= 0 && type < _EXEC_DIRECTORY_MAX); + assert(exit_status); - STRV_FOREACH(rt, context->runtime_directory) { + if (!params->prefix[type]) + return 0; + + if (manager_is_system) { + if (!uid_is_valid(uid)) + uid = 0; + if (!gid_is_valid(gid)) + gid = 0; + } + + STRV_FOREACH(rt, context->directories[type].paths) { _cleanup_free_ char *p; - p = strjoin(params->runtime_prefix, "/", *rt); - if (!p) - return -ENOMEM; + p = strjoin(params->prefix[type], "/", *rt); + if (!p) { + r = -ENOMEM; + goto fail; + } r = mkdir_parents_label(p, 0755); if (r < 0) - return r; + goto fail; - r = mkdir_p_label(p, context->runtime_directory_mode); + r = mkdir_p_label(p, context->directories[type].mode); if (r < 0) - return r; + goto fail; - r = chmod_and_chown(p, context->runtime_directory_mode, uid, gid); + r = chmod_and_chown(p, context->directories[type].mode, uid, gid); if (r < 0) - return r; + goto fail; } return 0; + +fail: + *exit_status = exit_status_table[type]; + + return r; } static int setup_smack( @@ -1917,29 +1946,40 @@ static int compile_read_write_paths( _cleanup_strv_free_ char **l = NULL; char **rt; + ExecDirectoryType i; /* Compile the list of writable paths. This is the combination of * the explicitly configured paths, plus all runtime directories. */ - if (strv_isempty(context->read_write_paths) && - strv_isempty(context->runtime_directory)) { - *ret = NULL; /* NOP if neither is set */ - return 0; + if (strv_isempty(context->read_write_paths)) { + for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) + if (!strv_isempty(context->directories[i].paths)) + break; + + if (i == _EXEC_DIRECTORY_MAX) { + *ret = NULL; /* NOP if neither is set */ + return 0; + } } l = strv_copy(context->read_write_paths); if (!l) return -ENOMEM; - STRV_FOREACH(rt, context->runtime_directory) { - char *s; + for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) { + if (!params->prefix[i]) + continue; - s = strjoin(params->runtime_prefix, "/", *rt); - if (!s) - return -ENOMEM; + STRV_FOREACH(rt, context->directories[i].paths) { + char *s; - if (strv_consume(&l, s) < 0) - return -ENOMEM; + s = strjoin(params->prefix[i], "/", *rt); + if (!s) + return -ENOMEM; + + if (strv_consume(&l, s) < 0) + return -ENOMEM; + } } *ret = l; @@ -2269,6 +2309,7 @@ static int exec_child( gid_t gid = GID_INVALID; int i, r, ngids = 0; unsigned n_fds; + ExecDirectoryType dt; assert(unit); assert(command); @@ -2556,12 +2597,10 @@ static int exec_child( } } - if (!strv_isempty(context->runtime_directory) && params->runtime_prefix) { - r = setup_runtime_directory(context, params, uid, gid); - if (r < 0) { - *exit_status = EXIT_RUNTIME_DIRECTORY; + for (dt = 0; dt < _EXEC_DIRECTORY_MAX; dt++) { + r = setup_exec_directory(context, params, uid, gid, MANAGER_IS_SYSTEM(unit->manager), dt, exit_status); + if (r < 0) return r; - } } r = build_environment( @@ -3049,6 +3088,8 @@ int exec_spawn(Unit *unit, } void exec_context_init(ExecContext *c) { + ExecDirectoryType i; + assert(c); c->umask = 0022; @@ -3059,13 +3100,15 @@ void exec_context_init(ExecContext *c) { c->ignore_sigpipe = true; c->timer_slack_nsec = NSEC_INFINITY; c->personality = PERSONALITY_INVALID; - c->runtime_directory_mode = 0755; + for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) + c->directories[i].mode = 0755; c->capability_bounding_set = CAP_ALL; c->restrict_namespaces = NAMESPACE_FLAGS_ALL; } void exec_context_done(ExecContext *c) { unsigned l; + ExecDirectoryType i; assert(c); @@ -3109,7 +3152,8 @@ void exec_context_done(ExecContext *c) { c->syscall_archs = set_free(c->syscall_archs); c->address_families = set_free(c->address_families); - c->runtime_directory = strv_free(c->runtime_directory); + for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) + c->directories[i].paths = strv_free(c->directories[i].paths); } int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) { @@ -3120,7 +3164,7 @@ int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_p if (!runtime_prefix) return 0; - STRV_FOREACH(i, c->runtime_directory) { + STRV_FOREACH(i, c->directories[EXEC_DIRECTORY_RUNTIME].paths) { _cleanup_free_ char *p; p = strjoin(runtime_prefix, "/", *i); @@ -3376,6 +3420,7 @@ static void strv_fprintf(FILE *f, char **l) { void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { char **e, **d; unsigned i; + ExecDirectoryType dt; int r; assert(c); @@ -3431,12 +3476,14 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { STRV_FOREACH(e, c->pass_environment) fprintf(f, "%sPassEnvironment: %s\n", prefix, *e); - fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode); - fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode)); - STRV_FOREACH(d, c->runtime_directory) - fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d); + for (dt = 0; dt < _EXEC_DIRECTORY_MAX; dt++) { + fprintf(f, "%s%sMode: %04o\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].mode); + + STRV_FOREACH(d, c->directories[dt].paths) + fprintf(f, "%s%s: %s\n", prefix, exec_directory_type_to_string(dt), *d); + } if (c->nice_set) fprintf(f, @@ -4185,3 +4232,13 @@ static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES); + +static const char* const exec_directory_type_table[_EXEC_DIRECTORY_MAX] = { + [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectory", + [EXEC_DIRECTORY_STATE] = "StateDirectory", + [EXEC_DIRECTORY_CACHE] = "CacheDirectory", + [EXEC_DIRECTORY_LOGS] = "LogsDirectory", + [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory", +}; + +DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType); diff --git a/src/core/execute.h b/src/core/execute.h index 93713e4..f7fa317 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -108,6 +108,21 @@ struct ExecRuntime { int netns_storage_socket[2]; }; +typedef enum ExecDirectoryType { + EXEC_DIRECTORY_RUNTIME = 0, + EXEC_DIRECTORY_STATE, + EXEC_DIRECTORY_CACHE, + EXEC_DIRECTORY_LOGS, + EXEC_DIRECTORY_CONFIGURATION, + _EXEC_DIRECTORY_MAX, + _EXEC_DIRECTORY_INVALID = -1, +} ExecDirectoryType; + +typedef struct ExecDirectory { + char **paths; + mode_t mode; +} ExecDirectory; + struct ExecContext { char **environment; char **environment_files; @@ -217,9 +232,8 @@ struct ExecContext { Set *address_families; bool address_families_whitelist:1; - char **runtime_directory; - mode_t runtime_directory_mode; ExecPreserveMode runtime_directory_preserve_mode; + ExecDirectory directories[_EXEC_DIRECTORY_MAX]; bool memory_deny_write_execute; bool restrict_realtime; @@ -265,7 +279,7 @@ struct ExecParameters { CGroupMask cgroup_supported; const char *cgroup_path; - const char *runtime_prefix; + char **prefix; const char *confirm_spawn; @@ -342,3 +356,6 @@ ExecUtmpMode exec_utmp_mode_from_string(const char *s) _pure_; const char* exec_preserve_mode_to_string(ExecPreserveMode i) _const_; ExecPreserveMode exec_preserve_mode_from_string(const char *s) _pure_; + +const char* exec_directory_type_to_string(ExecDirectoryType i) _const_; +ExecDirectoryType exec_directory_type_from_string(const char *s) _pure_; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 0e90f9d..134abec 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -104,9 +104,17 @@ $1.ProtectHome, config_parse_protect_home, 0, $1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context) $1.MountAPIVFS, config_parse_bool, 0, offsetof($1, exec_context.mount_apivfs) $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.RuntimeDirectoryPreserve, config_parse_runtime_preserve_mode, 0, offsetof($1, exec_context.runtime_directory_preserve_mode) -$1.RuntimeDirectory, config_parse_runtime_directory, 0, offsetof($1, exec_context.runtime_directory) +$1.RuntimeDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].mode) +$1.RuntimeDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].paths) +$1.DataDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_STATE].mode) +$1.DataDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_STATE].paths) +$1.CacheDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CACHE].mode) +$1.CacheDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CACHE].paths) +$1.LogsDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].mode) +$1.LogsDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].paths) +$1.ConfigurationDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].mode) +$1.ConfigurationDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].paths) m4_ifdef(`HAVE_PAM', `$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name)', `$1.PAMName, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 00b7f69..8cb8023 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3703,7 +3703,7 @@ int config_parse_job_mode_isolate( DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode"); -int config_parse_runtime_directory( +int config_parse_exec_directories( const char *unit, const char *filename, unsigned line, @@ -3754,7 +3754,7 @@ int config_parse_runtime_directory( if (!path_is_safe(k) || path_is_absolute(k)) { log_syntax(unit, LOG_ERR, filename, line, 0, - "Runtime directory is not valid, ignoring assignment: %s", rvalue); + "%s is not valid, ignoring assignment: %s", lvalue, rvalue); continue; } diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 4174f19..400393b 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -103,7 +103,7 @@ int config_parse_exec_apparmor_profile(const char *unit, const char *filename, u int config_parse_exec_smack_process_label(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_preserve_mode(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); +int config_parse_exec_directories(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_set_status(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_namespace_path_strv(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_no_new_privileges(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); diff --git a/src/core/manager.c b/src/core/manager.c index 2837207..a737ab0 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -36,6 +36,7 @@ #include "sd-daemon.h" #include "sd-messages.h" +#include "sd-path.h" #include "alloc-util.h" #include "audit-fd.h" @@ -52,6 +53,7 @@ #include "dirent-util.h" #include "env-util.h" #include "escape.h" +#include "execute.h" #include "exec-util.h" #include "exit-status.h" #include "fd-util.h" @@ -556,6 +558,48 @@ static int manager_default_environment(Manager *m) { return 0; } +static int manager_setup_prefix(Manager *m) { + struct table_entry { + uint64_t type; + const char *suffix; + }; + + static const struct table_entry paths_system[_EXEC_DIRECTORY_MAX] = { + [EXEC_DIRECTORY_RUNTIME] = { SD_PATH_SYSTEM_RUNTIME, NULL }, + [EXEC_DIRECTORY_STATE] = { SD_PATH_SYSTEM_STATE_PRIVATE, NULL }, + [EXEC_DIRECTORY_CACHE] = { SD_PATH_SYSTEM_STATE_CACHE, NULL }, + [EXEC_DIRECTORY_LOGS] = { SD_PATH_SYSTEM_STATE_LOGS, NULL }, + [EXEC_DIRECTORY_CONFIGURATION] = { SD_PATH_SYSTEM_CONFIGURATION, NULL }, + }; + + static const struct table_entry paths_user[_EXEC_DIRECTORY_MAX] = { + [EXEC_DIRECTORY_RUNTIME] = { SD_PATH_USER_RUNTIME, NULL }, + [EXEC_DIRECTORY_STATE] = { SD_PATH_USER_CONFIGURATION, NULL }, + [EXEC_DIRECTORY_CACHE] = { SD_PATH_SYSTEM_STATE_CACHE, NULL }, + [EXEC_DIRECTORY_LOGS] = { SD_PATH_SYSTEM_CONFIGURATION, "log" }, + [EXEC_DIRECTORY_CONFIGURATION] = { SD_PATH_SYSTEM_CONFIGURATION, NULL }, + }; + + const struct table_entry *p; + ExecDirectoryType i; + int r; + + assert(m); + + if (MANAGER_IS_SYSTEM(m)) + p = paths_system; + else + p = paths_user; + + for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) { + r = sd_path_home(p[i].type, p[i].suffix, &m->prefix[i]); + if (r < 0) + return r; + } + + return 0; +} + int manager_new(UnitFileScope scope, bool test_run, Manager **_m) { Manager *m; int r; @@ -672,6 +716,10 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) { m->taint_usr = dir_is_empty("/usr") > 0; + r = manager_setup_prefix(m); + if (r < 0) + goto fail; + *_m = m; return 0; @@ -692,7 +740,6 @@ static int manager_setup_notify(Manager *m) { .sa.sa_family = AF_UNIX, }; static const int one = 1; - const char *e; /* First free all secondary fields */ m->notify_socket = mfree(m->notify_socket); @@ -704,13 +751,7 @@ static int manager_setup_notify(Manager *m) { fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE); - e = manager_get_runtime_prefix(m); - if (!e) { - log_error("Failed to determine runtime prefix."); - return -EINVAL; - } - - m->notify_socket = strappend(e, "/systemd/notify"); + m->notify_socket = strappend(m->prefix[EXEC_DIRECTORY_RUNTIME], "/systemd/notify"); if (!m->notify_socket) return log_oom(); @@ -3309,12 +3350,16 @@ 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) { +int manager_set_exec_params(Manager *m, ExecParameters *p) { assert(m); + assert(p); + + p->environment = m->environment; + p->confirm_spawn = manager_get_confirm_spawn(m); + p->cgroup_supported = m->cgroup_supported; + p->prefix = m->prefix; - return MANAGER_IS_SYSTEM(m) ? - "/run" : - getenv("XDG_RUNTIME_DIR"); + return 0; } int manager_update_failed_units(Manager *m, Unit *u, bool failed) { diff --git a/src/core/manager.h b/src/core/manager.h index 4a9a37c..6aceed2 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -316,6 +316,9 @@ struct Manager { const char *invocation_log_format_string; int first_boot; /* tri-state */ + + /* prefixes of e.g. RuntimeDirectory= */ + char *prefix[_EXEC_DIRECTORY_MAX]; }; #define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM) @@ -380,7 +383,7 @@ 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); +int manager_set_exec_params(Manager *m, ExecParameters *p); ManagerState manager_state(Manager *m); diff --git a/src/core/mount.c b/src/core/mount.c index 214364d..0e66ffb 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -770,12 +770,12 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { if (r < 0) return r; - exec_params.environment = UNIT(m)->manager->environment; - exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(m)->manager); - exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported; + r = manager_set_exec_params(UNIT(m)->manager, &exec_params); + if (r < 0) + return r; + exec_params.cgroup_path = UNIT(m)->cgroup_path; exec_params.cgroup_delegate = m->cgroup_context.delegate; - exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(m)->manager); r = exec_spawn(UNIT(m), c, @@ -808,7 +808,7 @@ 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)); + exec_context_destroy_runtime_directory(&m->exec_context, UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME]); unit_unref_uid_gid(UNIT(m), true); diff --git a/src/core/service.c b/src/core/service.c index 601ca2e..1a9044d 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1342,7 +1342,11 @@ static int service_spawn( } } - final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL); + r = manager_set_exec_params(UNIT(s)->manager, &exec_params); + if (r < 0) + return r; + + final_env = strv_env_merge(2, exec_params.environment, our_env, NULL); if (!final_env) return -ENOMEM; @@ -1359,11 +1363,8 @@ static int service_spawn( exec_params.fd_names = fd_names; exec_params.n_storage_fds = n_storage_fds; exec_params.n_socket_fds = n_socket_fds; - exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager); - exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported; exec_params.cgroup_path = path; exec_params.cgroup_delegate = s->cgroup_context.delegate; - exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); exec_params.watchdog_usec = s->watchdog_usec; exec_params.selinux_context_net = s->socket_fd_selinux_context_net; if (s->type == SERVICE_IDLE) @@ -1525,7 +1526,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) if (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_NO || (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_RESTART && !service_will_restart(s))) /* Also, remove the runtime directory */ - exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager)); + exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]); /* Get rid of the IPC bits of the user */ unit_unref_uid_gid(UNIT(s), true); diff --git a/src/core/socket.c b/src/core/socket.c index 8750643..ca59a13 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1790,13 +1790,13 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { if (r < 0) return r; + r = manager_set_exec_params(UNIT(s)->manager, &exec_params); + if (r < 0) + return r; + exec_params.argv = c->argv; - exec_params.environment = UNIT(s)->manager->environment; - exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager); - exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported; exec_params.cgroup_path = UNIT(s)->cgroup_path; exec_params.cgroup_delegate = s->cgroup_context.delegate; - exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); r = exec_spawn(UNIT(s), c, @@ -1814,6 +1814,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { return r; *_pid = pid; + return 0; } @@ -1912,7 +1913,7 @@ 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)); + exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]); unit_unref_uid_gid(UNIT(s), true); diff --git a/src/core/swap.c b/src/core/swap.c index 4c3a74c..e839c26 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -630,18 +630,18 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { r = unit_setup_dynamic_creds(UNIT(s)); if (r < 0) - return r; + goto fail; r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec)); if (r < 0) goto fail; - exec_params.environment = UNIT(s)->manager->environment; - exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager); - exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported; + r = manager_set_exec_params(UNIT(s)->manager, &exec_params); + if (r < 0) + goto fail; + exec_params.cgroup_path = UNIT(s)->cgroup_path; exec_params.cgroup_delegate = s->cgroup_context.delegate; - exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); r = exec_spawn(UNIT(s), c, @@ -664,6 +664,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { fail: s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return r; } @@ -678,7 +679,7 @@ 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)); + exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]); unit_unref_uid_gid(UNIT(s), true); diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index 746e1a4..0480ec6 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -145,15 +145,11 @@ static int specifier_cgroup_slice(char specifier, void *data, void *userdata, ch static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) { Unit *u = userdata; - const char *e; char *n = NULL; assert(u); - e = manager_get_runtime_prefix(u->manager); - if (!e) - return -EOPNOTSUPP; - n = strdup(e); + n = strdup(u->manager->prefix[EXEC_DIRECTORY_RUNTIME]); if (!n) return -ENOMEM; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 7145175..1d77c18 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -548,7 +548,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_close_container(m); - } else if (streq(field, "RuntimeDirectoryMode")) { + } else if (STR_IN_SET(field, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode")) { mode_t mode; r = parse_mode(eq, &mode); @@ -557,7 +557,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "u", mode); - } else if (streq(field, "RuntimeDirectory")) { + } else if (STR_IN_SET(field, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) { const char *p; r = sd_bus_message_open_container(m, 'v', "as"); -- 2.7.4