core: introduce a "control" unit file directory
authorLennart Poettering <lennart@poettering.net>
Wed, 6 Apr 2016 19:02:36 +0000 (21:02 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 12 Apr 2016 11:43:31 +0000 (13:43 +0200)
This patch adds a concept of a "control" unit file directory, which is supposed
to be used as place for unit file drop-ins created by "systemctl set-property"
(note that this directory is not actually hooked up to "systemctl set-property"
yet, that's coming in a later patch).

The rationale for this: previously changes made by the user and by "systemctl
set-property" were done in the same directory, which made semantics very
unclear: the changes made by "systemctl set-property" were applied instantly,
and their drop-ins only written to not lose settings on a later "systemctl
daemon-reload", while drop-ins made by the user would only be in effect after
"systemctl daemon-reload". This is particular problematic as the changes made
by "systemctl set-property" would really apply immediately without any respect
for the unit search path. This meant that using "set-property" could have an
effect that is lsot as soon as "daemon-reload" is issued, in case there was a
"later" drop-in already in place.

With this change the directories are seperated, and the "control" directory
always takes the highest priority of all, to avoid any confusion.

src/shared/path-lookup.c
src/shared/path-lookup.h

index d3d4243..68b4322 100644 (file)
 #include "mkdir.h"
 #include "path-lookup.h"
 #include "path-util.h"
+#include "rm-rf.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
-static int user_config_home(char **ret) {
+static int user_runtime_dir(char **ret, const char *suffix) {
         const char *e;
         char *j;
 
         assert(ret);
+        assert(suffix);
 
-        e = getenv("XDG_CONFIG_HOME");
-        if (e) {
-                j = strappend(e, "/systemd/user");
-                if (!j)
-                        return -ENOMEM;
-
-        } else {
-                const char *home;
-
-                home = getenv("HOME");
-                if (!home)
-                        return -ENXIO;
+        e = getenv("XDG_RUNTIME_DIR");
+        if (!e)
+                return -ENXIO;
 
-                j = strappend(home, "/.config/systemd/user");
-                if (!j)
-                        return -ENOMEM;
-        }
+        j = strappend(e, suffix);
+        if (!j)
+                return -ENOMEM;
 
         *ret = j;
         return 0;
 }
 
-static int user_runtime_dir(char **ret, const char *suffix) {
+static int user_config_dir(char **ret, const char *suffix) {
         const char *e;
         char *j;
 
         assert(ret);
-        assert(suffix);
 
-        e = getenv("XDG_RUNTIME_DIR");
-        if (!e)
-                return -ENXIO;
+        e = getenv("XDG_CONFIG_HOME");
+        if (e)
+                j = strappend(e, suffix);
+        else {
+                const char *home;
+
+                home = getenv("HOME");
+                if (!home)
+                        return -ENXIO;
+
+                j = strjoin(home, "/.config", suffix, NULL);
+        }
 
-        j = strappend(e, suffix);
         if (!j)
                 return -ENOMEM;
 
@@ -81,7 +80,7 @@ static int user_runtime_dir(char **ret, const char *suffix) {
         return 0;
 }
 
-static int user_data_home_dir(char **ret, const char *suffix) {
+static int user_data_dir(char **ret, const char *suffix) {
         const char *e;
         char *j;
 
@@ -118,7 +117,9 @@ static char** user_dirs(
                 const char *generator,
                 const char *generator_early,
                 const char *generator_late,
-                const char *transient) {
+                const char *transient,
+                const char *persistent_control,
+                const char *runtime_control) {
 
         const char * const config_unit_paths[] = {
                 USER_CONFIG_UNIT_PATH,
@@ -158,7 +159,7 @@ static char** user_dirs(
                         return NULL;
         }
 
-        r = user_data_home_dir(&data_home, "/systemd/user");
+        r = user_data_dir(&data_home, "/systemd/user");
         if (r < 0 && r != -ENXIO)
                 return NULL;
 
@@ -173,13 +174,17 @@ static char** user_dirs(
                 return NULL;
 
         /* Now merge everything we found. */
-        if (transient)
-                if (strv_extend(&res, transient) < 0)
-                        return NULL;
+        if (strv_extend(&res, persistent_control) < 0)
+                return NULL;
 
-        if (generator_early)
-                if (strv_extend(&res, generator_early) < 0)
-                        return NULL;
+        if (strv_extend(&res, runtime_control) < 0)
+                return NULL;
+
+        if (strv_extend(&res, transient) < 0)
+                return NULL;
+
+        if (strv_extend(&res, generator_early) < 0)
+                return NULL;
 
         if (!strv_isempty(config_dirs))
                 if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
@@ -194,13 +199,11 @@ static char** user_dirs(
         if (strv_extend(&res, runtime_config) < 0)
                 return NULL;
 
-        if (generator)
-                if (strv_extend(&res, generator) < 0)
-                        return NULL;
+        if (strv_extend(&res, generator) < 0)
+                return NULL;
 
-        if (data_home)
-                if (strv_extend(&res, data_home) < 0)
-                        return NULL;
+        if (strv_extend(&res, data_home) < 0)
+                return NULL;
 
         if (!strv_isempty(data_dirs))
                 if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
@@ -209,9 +212,8 @@ static char** user_dirs(
         if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
                 return NULL;
 
-        if (generator_late)
-                if (strv_extend(&res, generator_late) < 0)
-                        return NULL;
+        if (strv_extend(&res, generator_late) < 0)
+                return NULL;
 
         if (path_strv_make_absolute_cwd(res) < 0)
                 return NULL;
@@ -327,7 +329,6 @@ static int acquire_transient_dir(UnitFileScope scope, char **ret) {
         default:
                 assert_not_reached("Hmm, unexpected scope value.");
         }
-
 }
 
 static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
@@ -350,7 +351,7 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru
                 break;
 
         case UNIT_FILE_USER:
-                r = user_config_home(&a);
+                r = user_config_dir(&a, "/systemd/user");
                 if (r < 0)
                         return r;
 
@@ -377,6 +378,56 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru
         return 0;
 }
 
+static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
+        _cleanup_free_ char *a = NULL;
+        int r;
+
+        assert(persistent);
+        assert(runtime);
+
+        switch (scope) {
+
+        case UNIT_FILE_SYSTEM:  {
+                _cleanup_free_ char *b = NULL;
+
+                a = strdup("/etc/systemd/system.control");
+                if (!a)
+                        return -ENOMEM;
+
+                b = strdup("/run/systemd/system.control");
+                if (!b)
+                        return -ENOMEM;
+
+                *runtime = b;
+                b = NULL;
+
+                break;
+        }
+
+        case UNIT_FILE_USER:
+                r = user_config_dir(&a, "/systemd/system.control");
+                if (r < 0)
+                        return r;
+
+                r = user_runtime_dir(runtime, "/systemd/system.control");
+                if (r < 0)
+                        return r;
+
+                break;
+
+        case UNIT_FILE_GLOBAL:
+                return -EOPNOTSUPP;
+
+        default:
+                assert_not_reached("Hmm, unexpected scope value.");
+        }
+
+        *persistent = a;
+        a = NULL;
+
+        return 0;
+}
+
 static int patch_root_prefix(char **p, const char *root_dir) {
         char *c;
 
@@ -420,7 +471,8 @@ int lookup_paths_init(
                 *root = NULL,
                 *persistent_config = NULL, *runtime_config = NULL,
                 *generator = NULL, *generator_early = NULL, *generator_late = NULL,
-                *transient = NULL;
+                *transient = NULL,
+                *persistent_control = NULL, *runtime_control = NULL;
         bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
         char **l = NULL;
         const char *e;
@@ -457,6 +509,10 @@ int lookup_paths_init(
         if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
                 return r;
 
+        r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
+        if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
+                return r;
+
         /* First priority is whatever has been passed to us via env vars */
         e = getenv("SYSTEMD_UNIT_PATH");
         if (e) {
@@ -494,6 +550,8 @@ int lookup_paths_init(
                         add = strv_new(
                                         /* If you modify this you also want to modify
                                          * systemdsystemunitpath= in systemd.pc.in! */
+                                        STRV_IFNOTNULL(persistent_control),
+                                        STRV_IFNOTNULL(runtime_control),
                                         STRV_IFNOTNULL(transient),
                                         STRV_IFNOTNULL(generator_early),
                                         persistent_config,
@@ -517,6 +575,8 @@ int lookup_paths_init(
                                         /* If you modify this you also want to modify
                                          * systemduserunitpath= in systemd.pc.in, and
                                          * the arrays in user_dirs() above! */
+                                        STRV_IFNOTNULL(persistent_control),
+                                        STRV_IFNOTNULL(runtime_control),
                                         STRV_IFNOTNULL(transient),
                                         STRV_IFNOTNULL(generator_early),
                                         persistent_config,
@@ -537,7 +597,8 @@ int lookup_paths_init(
                 case UNIT_FILE_USER:
                         add = user_dirs(persistent_config, runtime_config,
                                         generator, generator_early, generator_late,
-                                        transient);
+                                        transient,
+                                        persistent_config, runtime_control);
                         break;
 
                 default:
@@ -578,6 +639,14 @@ int lookup_paths_init(
         if (r < 0)
                 return r;
 
+        r = patch_root_prefix(&persistent_control, root);
+        if (r < 0)
+                return r;
+
+        r = patch_root_prefix(&runtime_control, root);
+        if (r < 0)
+                return r;
+
         r = patch_root_prefix_strv(l, root);
         if (r < 0)
                 return -ENOMEM;
@@ -597,6 +666,10 @@ int lookup_paths_init(
         p->transient = transient;
         transient = NULL;
 
+        p->persistent_control = persistent_control;
+        p->runtime_control = runtime_control;
+        persistent_control = runtime_control = NULL;
+
         p->root_dir = root;
         root = NULL;
 
@@ -618,6 +691,9 @@ void lookup_paths_free(LookupPaths *p) {
 
         p->transient = mfree(p->transient);
 
+        p->persistent_control = mfree(p->persistent_control);
+        p->runtime_control = mfree(p->runtime_control);
+
         p->root_dir = mfree(p->root_dir);
 }
 
@@ -730,6 +806,8 @@ void lookup_paths_trim_generator(LookupPaths *p) {
 void lookup_paths_flush_generator(LookupPaths *p) {
         assert(p);
 
+        /* Flush the generated unit files in full */
+
         if (p->generator)
                 (void) rm_rf(p->generator, REMOVE_ROOT);
         if (p->generator_early)
index 29f74cf..89254cb 100644 (file)
@@ -27,20 +27,33 @@ typedef struct LookupPaths LookupPaths;
 #include "macro.h"
 
 struct LookupPaths {
+        /* Where we look for unit files. This includes the individual special paths below, but also any vendor
+         * supplied, static unit file paths. */
         char **search_path;
 
-        /* Where we shall create or remove our installation symlinks, aka "configuration". */
+        /* Where we shall create or remove our installation symlinks, aka "configuration", and where the user/admin
+         * shall place his own unit files. */
         char *persistent_config;
         char *runtime_config;
 
-        /* Where to place generated unit files */
+        /* Where to place generated unit files (i.e. those a "generator" tool generated). Note the special semantics of
+         * this directory: the generators are flushed each time a "systemctl daemon-reload" is issued. The user should
+         * not alter these directories directly. */
         char *generator;
         char *generator_early;
         char *generator_late;
 
-        /* Where to place transient unit files */
+        /* Where to place transient unit files (i.e. those created dynamically via the bus API). Note the special
+         * semantics of this directory: all units created transiently have their unit files removed as the transient
+         * unit is unloaded. The user should not alter this directory directly. */
         char *transient;
 
+        /* Where the snippets created by "systemctl set-property" are placed. Note that for transient units, the
+         * snippets are placed in the transient directory though (see above). The user should not alter this directory
+         * directly. */
+        char *persistent_control;
+        char *runtime_control;
+
         /* The root directory prepended to all items above, or NULL */
         char *root_dir;
 };