]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: add {State,Cache,Log,Configuration}Directory= (#6384)
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 18 Jul 2017 12:34:52 +0000 (21:34 +0900)
committerLennart Poettering <lennart@poettering.net>
Tue, 18 Jul 2017 12:34:52 +0000 (14:34 +0200)
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.

17 files changed:
man/systemd.exec.xml
src/basic/exit-status.c
src/basic/exit-status.h
src/core/dbus-execute.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/manager.c
src/core/manager.h
src/core/mount.c
src/core/service.c
src/core/socket.c
src/core/swap.c
src/core/unit-printf.c
src/shared/bus-unit-util.c

index 8356c1baae951e34d205bcfd8f67980ef0da4318..b074331dd59f7fafedb3d7a1dd43c6542ea003fb 100644 (file)
         </para></listitem>
       </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>
         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>
index 1e23c32c3f907cf959022fc60e251bbe476dd751..fba012601d7bbc237a71d8dd8f7d0ef10e1a7b56 100644 (file)
@@ -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";
                 }
         }
 
index d22b2c00e45f7823552f05edd1e17007e8d712d0..e2c76f84f8d32a10113b0f5f3e790f54c4e0612e 100644 (file)
@@ -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 {
index 0958c238f025f13b9a0bae90690fc698c5376cfe..01f2d1134236e72ec3840b34cda9181ab1d6a62c 100644 (file)
@@ -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;
 
index 16da43ccfd1f694eb81ad27fc0b9f54e691d7081..3efd56fefe33882b3591c35f97df1789261b9623 100644 (file)
@@ -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);
index 93713e48ccf0b609919eac2629b002f0c32cc0ae..f7fa3176b13b50019d2c8ec420d403237fdfa38d 100644 (file)
@@ -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_;
index 0e90f9d95171afbb7691cb4758e6658cdf802c7d..134abec72ce0e8614e157b1c263e412c578ff2cb 100644 (file)
@@ -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')
index 00b7f69cd800496a745b73a2bcb6afa3b399d1b5..8cb8023bea13d8d44a40ea6944dfca75ea0a9e5c 100644 (file)
@@ -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;
                 }
 
index 4174f19483557939b1b317434a37f4391aff6db8..400393bcb60ff1f17a4fca61a991e8d5dfc7e9c5 100644 (file)
@@ -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);
index 283720750fc026455a9ac1f3cc17676f89963790..a737ab075402fb338a0c035277ca6f4b0b8c67d6 100644 (file)
@@ -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) {
index 4a9a37caffb1be7ec6d9cb9738d7d20866e9c4fb..6aceed281a1736fb93c9410de482af37770727fc 100644 (file)
@@ -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);
 
index 214364d87d2565aba498c9aaecf3ccfaeaf22066..0e66ffb3b61893780ea9d902e289b204edb64bfd 100644 (file)
@@ -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);
 
index 601ca2eb20e2a2b6f851997d57fb2a58765808d2..1a9044d2dabaf031797d6557b5e137cf584cc26c 100644 (file)
@@ -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);
index 8750643d926c3dcc357aa0aaa9e4ea2817e373a8..ca59a13b66315fbdf65e30f126263b8a032d634c 100644 (file)
@@ -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);
 
index 4c3a74ce00a17bcf1998983c38747b1b2b11a349..e839c26141158baa25075479428019ae2da5108f 100644 (file)
@@ -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);
 
index 746e1a46efd53fddf31432f3d82837c464e55eb8..0480ec6526a710fc6afa33775a409049375d9895 100644 (file)
@@ -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;
 
index 71451758a6a38a333115c071632daf645decf883..1d77c18edbe8525ff40b25c92de153b3694263f2 100644 (file)
@@ -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");