From 80b1ae32e1cab924086bb5224cde675df623df07 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Apr 2016 21:02:36 +0200 Subject: core: introduce a "control" unit file directory 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 | 168 ++++++++++++++++++++++++++++++++++------------- src/shared/path-lookup.h | 19 +++++- 2 files changed, 139 insertions(+), 48 deletions(-) diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index d3d4243ad4..68b432216e 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -29,51 +29,50 @@ #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) diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 29f74cf211..89254cbac5 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -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; }; -- cgit v1.2.3-54-g00ecf