]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: rework how transient unit files and property drop-ins work
authorLennart Poettering <lennart@poettering.net>
Thu, 7 Apr 2016 13:43:59 +0000 (15:43 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 12 Apr 2016 11:43:32 +0000 (13:43 +0200)
With this change the logic for placing transient unit files and drop-ins
generated via "systemctl set-property" is reworked.

The latter are now placed in the newly introduced "control" unit file
directory. The fomer are now placed in the "transient" unit file directory.

Note that the properties originally set when a transient unit was created will
be written to and stay in the transient unit file directory, while later
changes are done via drop-ins.

This is preparation for a later "systemctl revert" addition, where existing
drop-ins are flushed out, but the original transient definition is restored.

src/basic/strv.c
src/basic/strv.h
src/core/scope.c
src/core/slice.c
src/core/unit.c
src/core/unit.h

index 8282298dcaf93db2d750c8a04c0a373d593bb9e5..97a96e57625602b5d2c06938bfbcaff6866e6e5f 100644 (file)
@@ -558,6 +558,42 @@ int strv_extend(char ***l, const char *value) {
         return strv_consume(l, v);
 }
 
+int strv_extend_front(char ***l, const char *value) {
+        size_t n, m;
+        char *v, **c;
+
+        assert(l);
+
+        /* Like strv_extend(), but prepends rather than appends the new entry */
+
+        if (!value)
+                return 0;
+
+        n = strv_length(*l);
+
+        /* Increase and overflow check. */
+        m = n + 2;
+        if (m < n)
+                return -ENOMEM;
+
+        v = strdup(value);
+        if (!v)
+                return -ENOMEM;
+
+        c = realloc_multiply(*l, sizeof(char*), m);
+        if (!c) {
+                free(v);
+                return -ENOMEM;
+        }
+
+        memmove(c+1, c, n * sizeof(char*));
+        c[0] = v;
+        c[n+1] = NULL;
+
+        *l = c;
+        return 0;
+}
+
 char **strv_uniq(char **l) {
         char **i;
 
index 7bfa54408d25c5fa320e56e143536438985d92d3..f61bbb53869c5ece6ca19d387ef0bd7c103c55e5 100644 (file)
@@ -50,6 +50,7 @@ int strv_extend_strv(char ***a, char **b, bool filter_duplicates);
 int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
 int strv_extend(char ***l, const char *value);
 int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
+int strv_extend_front(char ***l, const char *value);
 int strv_push(char ***l, char *value);
 int strv_push_pair(char ***l, char *a, char *b);
 int strv_push_prepend(char ***l, char *value);
index 92a3aed331b560748781bd608b133efe1d9aca6a..7078d1f7e90b623c2425d96d72c63b22a3b7a60a 100644 (file)
@@ -155,25 +155,26 @@ static int scope_load(Unit *u) {
         assert(u->load_state == UNIT_STUB);
 
         if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
+                /* Refuse to load non-transient scope units, but allow them while reloading. */
                 return -ENOENT;
 
-        u->load_state = UNIT_LOADED;
-
-        r = unit_load_dropin(u);
+        r = unit_load_fragment_and_dropin_optional(u);
         if (r < 0)
                 return r;
 
-        r = unit_patch_contexts(u);
-        if (r < 0)
-                return r;
+        if (u->load_state == UNIT_LOADED) {
+                r = unit_patch_contexts(u);
+                if (r < 0)
+                        return r;
 
-        r = unit_set_default_slice(u);
-        if (r < 0)
-                return r;
+                r = unit_set_default_slice(u);
+                if (r < 0)
+                        return r;
 
-        r = scope_add_default_dependencies(s);
-        if (r < 0)
-                return r;
+                r = scope_add_default_dependencies(s);
+                if (r < 0)
+                        return r;
+        }
 
         return scope_verify(s);
 }
index 667f61bde591a194051bd94ce7e52284f1c23678..63a77c9bca74507c2c6633a767966d594ae33677 100644 (file)
@@ -135,6 +135,7 @@ static int slice_load(Unit *u) {
         int r;
 
         assert(s);
+        assert(u->load_state == UNIT_STUB);
 
         r = unit_load_fragment_and_dropin_optional(u);
         if (r < 0)
index ac29353299dd05a17895b5e48892d0fc86b9df1f..c028f57f139101e615505176c8ea665d48696ed6 100644 (file)
@@ -52,6 +52,7 @@
 #include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "umask-util.h"
 #include "unit-name.h"
 #include "unit.h"
 #include "user-util.h"
@@ -492,6 +493,9 @@ void unit_free(Unit *u) {
 
         assert(u);
 
+        if (u->transient_file)
+                fclose(u->transient_file);
+
         if (!MANAGER_IS_RELOADING(u->manager))
                 unit_remove_transient(u);
 
@@ -1231,6 +1235,15 @@ int unit_load(Unit *u) {
         if (u->load_state != UNIT_STUB)
                 return 0;
 
+        if (u->transient_file) {
+                r = fflush_and_check(u->transient_file);
+                if (r < 0)
+                        goto fail;
+
+                fclose(u->transient_file);
+                u->transient_file = NULL;
+        }
+
         if (UNIT_VTABLE(u)->load) {
                 r = UNIT_VTABLE(u)->load(u);
                 if (r < 0)
@@ -3327,14 +3340,17 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) {
 static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) {
         assert(u);
 
+        if (!IN_SET(mode, UNIT_RUNTIME, UNIT_PERSISTENT))
+                return NULL;
+
         if (u->transient) /* Redirect drop-ins for transient units always into the transient directory. */
                 return u->manager->lookup_paths.transient;
 
         if (mode == UNIT_RUNTIME)
-                return u->manager->lookup_paths.runtime_config;
+                return u->manager->lookup_paths.runtime_control;
 
         if (mode == UNIT_PERSISTENT)
-                return u->manager->lookup_paths.persistent_config;
+                return u->manager->lookup_paths.persistent_control;
 
         return NULL;
 }
@@ -3346,6 +3362,13 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co
 
         assert(u);
 
+        if (u->transient_file) {
+                /* When this is a transient unit file in creation, then let's not create a new drop-in but instead
+                 * write to the transient unit file. */
+                fputs(data, u->transient_file);
+                return 0;
+        }
+
         if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
                 return 0;
 
@@ -3435,24 +3458,50 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const
 }
 
 int unit_make_transient(Unit *u) {
+        FILE *f;
+        char *path;
+
         assert(u);
 
         if (!UNIT_VTABLE(u)->can_transient)
                 return -EOPNOTSUPP;
 
-        u->load_state = UNIT_STUB;
-        u->load_error = 0;
-        u->transient = true;
+        path = strjoin(u->manager->lookup_paths.transient, "/", u->id, NULL);
+        if (!path)
+                return -ENOMEM;
+
+        /* Let's open the file we'll write the transient settings into. This file is kept open as long as we are
+         * creating the transient, and is closed in unit_load(), as soon as we start loading the file. */
+
+        RUN_WITH_UMASK(0022)
+                f = fopen(path, "we");
+        if (!f) {
+                free(path);
+                return -errno;
+        }
+
+        if (u->transient_file)
+                fclose(u->transient_file);
+        u->transient_file = f;
+
+        free(u->fragment_path);
+        u->fragment_path = path;
 
-        u->fragment_path = mfree(u->fragment_path);
         u->source_path = mfree(u->source_path);
         u->dropin_paths = strv_free(u->dropin_paths);
         u->fragment_mtime = u->source_mtime = u->dropin_mtime = 0;
 
+        u->load_state = UNIT_STUB;
+        u->load_error = 0;
+        u->transient = true;
+
         unit_add_to_dbus_queue(u);
         unit_add_to_gc_queue(u);
         unit_add_to_load_queue(u);
 
+        fputs("# This is a transient unit file, created programmatically via the systemd API. Do not edit.\n",
+              u->transient_file);
+
         return 0;
 }
 
index 601e763ce2f8ea886293b43aa81a454c3d154f2a..cfdac852a556c119096c5409fff8c7e19d933cfe 100644 (file)
@@ -95,6 +95,9 @@ struct Unit {
         usec_t source_mtime;
         usec_t dropin_mtime;
 
+        /* If this is a transient unit we are currently writing, this is where we are writing it to */
+        FILE *transient_file;
+
         /* If there is something to do with this unit, then this is the installed job for it */
         Job *job;