From 39591351391de3ef2fd23cc5aea5bdd6ab712db6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 Feb 2016 01:13:57 +0100 Subject: [PATCH] core: add a separate unit directory for transient units Previously, transient units were created below the normal runtime directory /run/systemd/system. With this change they are created in a special transient directory /run/systemd/transient, which only contains data for transient units. This clarifies the life-cycle of transient units, and makes clear they are distinct from user-provided runtime units. In particular, users may now extend transient units via /run/systemd/system, without systemd interfering with the life-cycle of these files. This change also adds code so that when a transient unit exits only the drop-ins in this new directory are removed, but nothing else. Fixes: #2139 --- src/core/manager.c | 6 ++++ src/core/unit.c | 62 ++++++++++++++++++-------------------- src/shared/path-lookup.c | 64 ++++++++++++++++++++++++++++++++++++++-- src/shared/path-lookup.h | 3 ++ 4 files changed, 99 insertions(+), 36 deletions(-) diff --git a/src/core/manager.c b/src/core/manager.c index c72b46be30..1bc7921abe 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -63,6 +63,7 @@ #include "manager.h" #include "missing.h" #include "mkdir.h" +#include "mkdir.h" #include "parse-util.h" #include "path-lookup.h" #include "path-util.h" @@ -1108,6 +1109,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { if (r < 0) return r; + /* Make sure the transient directory always exists, so that it remains in the search path */ + r = mkdir_p_label(m->lookup_paths.transient, 0755); + if (r < 0) + return r; + dual_timestamp_get(&m->generators_start_timestamp); r = manager_run_generators(m); dual_timestamp_get(&m->generators_finish_timestamp); diff --git a/src/core/unit.c b/src/core/unit.c index 565704851b..f6c9891aad 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -418,13 +418,22 @@ static void unit_remove_transient(Unit *u) { (void) unlink(u->fragment_path); STRV_FOREACH(i, u->dropin_paths) { - _cleanup_free_ char *p = NULL; + _cleanup_free_ char *p = NULL, *pp = NULL; + + p = dirname_malloc(*i); /* Get the drop-in directory from the drop-in file */ + if (!p) + continue; + + pp = dirname_malloc(p); /* Get the config directory from the drop-in directory */ + if (!pp) + continue; + + /* Only drop transient drop-ins */ + if (!path_equal(u->manager->lookup_paths.transient, pp)) + continue; (void) unlink(*i); - - p = dirname_malloc(*i); - if (p) - (void) rmdir(p); + (void) rmdir(p); } } @@ -3315,35 +3324,24 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) { return *(ExecRuntime**) ((uint8_t*) u + offset); } -static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, char **dir) { +static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) { assert(u); - if (MANAGER_IS_USER(u->manager)) { - int r; + if (u->transient) /* Redirect drop-ins for transient units always into the transient directory. */ + return u->manager->lookup_paths.transient; - if (mode == UNIT_PERSISTENT && !transient) - r = user_config_home(dir); - else - r = user_runtime_dir(dir); - if (r == 0) - return -ENOENT; + if (mode == UNIT_RUNTIME) + return u->manager->lookup_paths.runtime_config; - return r; - } + if (mode == UNIT_PERSISTENT) + return u->manager->lookup_paths.persistent_config; - if (mode == UNIT_PERSISTENT && !transient) - *dir = strdup("/etc/systemd/system"); - else - *dir = strdup("/run/systemd/system"); - if (!*dir) - return -ENOMEM; - - return 0; + return NULL; } int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) { - - _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL; + _cleanup_free_ char *p = NULL, *q = NULL; + const char *dir; int r; assert(u); @@ -3351,9 +3349,9 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) return 0; - r = unit_drop_in_dir(u, mode, u->transient, &dir); - if (r < 0) - return r; + dir = unit_drop_in_dir(u, mode); + if (!dir) + return -EINVAL; r = write_drop_in(dir, u->id, 50, name, data); if (r < 0) @@ -3398,7 +3396,7 @@ int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *n } int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) { - _cleanup_free_ char *ndata = NULL; + const char *ndata; assert(u); assert(name); @@ -3410,9 +3408,7 @@ int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char * if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) return 0; - ndata = strjoin("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL); - if (!ndata) - return -ENOMEM; + ndata = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL); return unit_write_drop_in(u, mode, name, ndata); } diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 11b9bb6107..f437de370c 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -111,7 +111,8 @@ static char** user_dirs( const char *runtime_config, const char *generator, const char *generator_early, - const char *generator_late) { + const char *generator_late, + const char *transient) { const char * const config_unit_paths[] = { USER_CONFIG_UNIT_PATH, @@ -172,6 +173,10 @@ static char** user_dirs( return NULL; /* Now merge everything we found. */ + if (transient) + if (strv_extend(&res, transient) < 0) + return NULL; + if (generator_early) if (strv_extend(&res, generator_early) < 0) return NULL; @@ -305,6 +310,42 @@ static int acquire_generator_dirs( return 0; } +static int acquire_transient_dir(UnitFileScope scope, char **ret) { + char *transient; + + assert(ret); + + switch (scope) { + + case UNIT_FILE_SYSTEM: + transient = strdup("/run/systemd/transient"); + break; + + case UNIT_FILE_USER: { + const char *e; + + e = getenv("XDG_RUNTIME_DIR"); + if (!e) + return -ENXIO; + + transient = strjoin(e, "/systemd/transient", NULL); + break; + } + + case UNIT_FILE_GLOBAL: + return -EOPNOTSUPP; + + default: + assert_not_reached("Hmm, unexpected scope value."); + } + + if (!transient) + return -ENOMEM; + + *ret = transient; + return 0; +} + static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) { _cleanup_free_ char *a = NULL, *b = NULL; int r; @@ -377,8 +418,9 @@ int lookup_paths_init( _cleanup_free_ char *root = NULL, + *persistent_config = NULL, *runtime_config = NULL, *generator = NULL, *generator_early = NULL, *generator_late = NULL, - *persistent_config = NULL, *runtime_config = NULL; + *transient = NULL; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ char **l = NULL; const char *e; @@ -411,6 +453,10 @@ int lookup_paths_init( if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO) return r; + r = acquire_transient_dir(scope, &transient); + 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"); @@ -449,6 +495,7 @@ int lookup_paths_init( add = strv_new( /* If you modify this you also want to modify * systemdsystemunitpath= in systemd.pc.in! */ + STRV_IFNOTNULL(transient), STRV_IFNOTNULL(generator_early), persistent_config, SYSTEM_CONFIG_UNIT_PATH, @@ -471,6 +518,7 @@ 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(transient), STRV_IFNOTNULL(generator_early), persistent_config, USER_CONFIG_UNIT_PATH, @@ -489,7 +537,8 @@ int lookup_paths_init( case UNIT_FILE_USER: add = user_dirs(persistent_config, runtime_config, - generator, generator_early, generator_late); + generator, generator_early, generator_late, + transient); break; default: @@ -526,6 +575,10 @@ int lookup_paths_init( if (r < 0) return r; + r = patch_root_prefix(&transient, root); + if (r < 0) + return r; + if (!path_strv_resolve_uniq(l, root)) return -ENOMEM; @@ -554,6 +607,9 @@ int lookup_paths_init( p->generator_late = generator_late; generator = generator_early = generator_late = NULL; + p->transient = transient; + transient = NULL; + p->root_dir = root; root = NULL; @@ -573,5 +629,7 @@ void lookup_paths_free(LookupPaths *p) { p->generator_early = mfree(p->generator_early); p->generator_late = mfree(p->generator_late); + p->transient = mfree(p->transient); + p->root_dir = mfree(p->root_dir); } diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 078c3484f5..b0603c0c99 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -38,6 +38,9 @@ struct LookupPaths { char *generator_early; char *generator_late; + /* Where to place transient unit files */ + char *transient; + /* The root directory prepended to all items above, or NULL */ char *root_dir; };