summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2017-07-18 21:34:52 +0900
committerLennart Poettering <lennart@poettering.net>2017-07-18 14:34:52 +0200
commit3536f49e8fa281539798a7bc5004d73302f39673 (patch)
tree8cb49fc448d6b88ccf8d01e9a094dd64aa7b6dbb
parent5230e31918a939e503536ecb6b2a83f55181e9f8 (diff)
downloadsystemd-3536f49e8fa281539798a7bc5004d73302f39673.tar.gz
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.
-rw-r--r--man/systemd.exec.xml27
-rw-r--r--src/basic/exit-status.c12
-rw-r--r--src/basic/exit-status.h4
-rw-r--r--src/core/dbus-execute.c44
-rw-r--r--src/core/execute.c125
-rw-r--r--src/core/execute.h23
-rw-r--r--src/core/load-fragment-gperf.gperf.m412
-rw-r--r--src/core/load-fragment.c4
-rw-r--r--src/core/load-fragment.h2
-rw-r--r--src/core/manager.c69
-rw-r--r--src/core/manager.h5
-rw-r--r--src/core/mount.c10
-rw-r--r--src/core/service.c11
-rw-r--r--src/core/socket.c11
-rw-r--r--src/core/swap.c13
-rw-r--r--src/core/unit-printf.c6
-rw-r--r--src/shared/bus-unit-util.c4
17 files changed, 286 insertions, 96 deletions
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 8356c1baae..b074331dd5 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1682,11 +1682,32 @@
</varlistentry>
<varlistentry>
+ <term><varname>StateDirectory=</varname></term>
+ <term><varname>CacheDirectory=</varname></term>
+ <term><varname>LogsDirectory=</varname></term>
+ <term><varname>ConfigurationDirectory=</varname></term>
+
+ <listitem><para>Takes a whitespace-separated list of directory names. If set, as similar to
+ <varname>RuntimeDirectory=</varname>, one or more directories including their parents by the specified names
+ will be created below <filename>/var/lib</filename>, <filename>/var/cache</filename>, <filename>/var/log</filename>,
+ or <filename>/etc</filename>, respectively, when the unit is started.
+ Unlike <varname>RuntimeDirectory=</varname>, the directories are not removed when the unit is stopped.
+ The lowest subdirectories will be owned by the user and group specified in <varname>User=</varname>
+ and <varname>Group=</varname>. The options imply <varname>ReadWritePaths=</varname>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>RuntimeDirectoryMode=</varname></term>
+ <term><varname>StateDirectoryMode=</varname></term>
+ <term><varname>CacheDirectoryMode=</varname></term>
+ <term><varname>LogsDirectoryMode=</varname></term>
+ <term><varname>ConfigurationDirectoryMode=</varname></term>
<listitem><para>Specifies the access mode of the directories specified in
- <varname>RuntimeDirectory=</varname> as an octal number. Defaults to
- <constant>0755</constant>. See "Permissions" in
+ <varname>RuntimeDirectory=</varname>, <varname>StateDirectory=</varname>, <varname>CacheDirectory=</varname>,
+ <varname>LogsDirectory=</varname>, or <varname>ConfigurationDirectory=</varname>, respectively, as an octal number.
+ Defaults to <constant>0755</constant>. See "Permissions" in
<citerefentry project='man-pages'><refentrytitle>path_resolution</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for a discussion of the meaning of permission bits.
</para></listitem>
@@ -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 <varname>SystemCallArchitectures=native</varname> or similar. If
running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant> capability
- (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname> is implied. </para></listitem>
+ (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname> is implied.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c
index 1e23c32c3f..fba012601d 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 d22b2c00e4..e2c76f84f8 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 0958c238f0..01f2d11342 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 16da43ccfd..3efd56fefe 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 93713e48cc..f7fa3176b1 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 0e90f9d951..134abec72c 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 00b7f69cd8..8cb8023bea 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 4174f19483..400393bcb6 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 283720750f..a737ab0754 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 4a9a37caff..6aceed281a 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 214364d87d..0e66ffb3b6 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 601ca2eb20..1a9044d2da 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 8750643d92..ca59a13b66 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 4c3a74ce00..e839c26141 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 746e1a46ef..0480ec6526 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 71451758a6..1d77c18edb 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");