diff --git a/man/systemd.xml b/man/systemd.xml index 28bf49e131..8b1b6e6c6b 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -649,9 +649,17 @@ $SYSTEMD_UNIT_PATH + $SYSTEMD_GENERATOR_PATH + $SYSTEMD_ENVIRONMENT_GENERATOR_PATH - Controls where systemd looks for unit - files. + Controls where systemd looks for unit files and + generators. + These variables may contain a list of paths, separated by colons + (:). When set, if the list ends with an empty + component (...:), this list is prepended to the + usual set of of paths. Otherwise, the specified list replaces the usual + set of paths. + diff --git a/src/core/manager.c b/src/core/manager.c index 25afdbea04..38f7ba1eb8 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -3826,25 +3826,9 @@ static bool generator_path_any(const char* const* paths) { return found; } -static const char *const system_env_generator_binary_paths[] = { - "/run/systemd/system-environment-generators", - "/etc/systemd/system-environment-generators", - "/usr/local/lib/systemd/system-environment-generators", - SYSTEM_ENV_GENERATOR_PATH, - NULL -}; - -static const char *const user_env_generator_binary_paths[] = { - "/run/systemd/user-environment-generators", - "/etc/systemd/user-environment-generators", - "/usr/local/lib/systemd/user-environment-generators", - USER_ENV_GENERATOR_PATH, - NULL -}; - static int manager_run_environment_generators(Manager *m) { char **tmp = NULL; /* this is only used in the forked process, no cleanup here */ - const char *const *paths; + _cleanup_strv_free_ char **paths = NULL; void* args[] = { [STDOUT_GENERATE] = &tmp, [STDOUT_COLLECT] = &tmp, @@ -3855,13 +3839,15 @@ static int manager_run_environment_generators(Manager *m) { if (MANAGER_IS_TEST_RUN(m) && !(m->test_run_flags & MANAGER_TEST_RUN_ENV_GENERATORS)) return 0; - paths = MANAGER_IS_SYSTEM(m) ? system_env_generator_binary_paths : user_env_generator_binary_paths; + paths = env_generator_binary_paths(MANAGER_IS_SYSTEM(m)); + if (!paths) + return log_oom(); - if (!generator_path_any(paths)) + if (!generator_path_any((const char* const*) paths)) return 0; RUN_WITH_UMASK(0022) - r = execute_directories(paths, DEFAULT_TIMEOUT_USEC, gather_environment, + r = execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS); return r; } diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 5b16209745..20d6c03a9a 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -479,6 +479,36 @@ static int patch_root_prefix_strv(char **l, const char *root_dir) { return 0; } +static int get_paths_from_environ(const char *var, char ***paths, bool *append) { + const char *e; + int r; + + assert(var); + assert(paths); + assert(append); + + *append = false; + + e = getenv(var); + if (e) { + const char *k; + + k = endswith(e, ":"); + if (k) { + e = strndupa(e, k - e); + *append = true; + } + + /* FIXME: empty components in other places should be rejected. */ + + r = path_split_and_make_absolute(e, paths); + if (r < 0) + return r; + } + + return 0; +} + int lookup_paths_init( LookupPaths *p, UnitFileScope scope, @@ -496,7 +526,6 @@ int lookup_paths_init( *persistent_attached = NULL, *runtime_attached = NULL; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ _cleanup_strv_free_ char **paths = NULL; - const char *e; int r; assert(p); @@ -562,22 +591,9 @@ int lookup_paths_init( return r; /* First priority is whatever has been passed to us via env vars */ - e = getenv("SYSTEMD_UNIT_PATH"); - if (e) { - const char *k; - - k = endswith(e, ":"); - if (k) { - e = strndupa(e, k - e); - append = true; - } - - /* FIXME: empty components in other places should be rejected. */ - - r = path_split_and_make_absolute(e, &paths); - if (r < 0) - return r; - } + r = get_paths_from_environ("SYSTEMD_UNIT_PATH", &paths, &append); + if (r < 0) + return r; if (!paths || append) { /* Let's figure something out. */ @@ -817,23 +833,90 @@ void lookup_paths_flush_generator(LookupPaths *p) { } char **generator_binary_paths(UnitFileScope scope) { + bool append = false; /* Add items from SYSTEMD_GENERATOR_PATH before normal directories */ + _cleanup_strv_free_ char **paths = NULL; + int r; - switch (scope) { + /* First priority is whatever has been passed to us via env vars */ + r = get_paths_from_environ("SYSTEMD_GENERATOR_PATH", &paths, &append); + if (r < 0) + return NULL; - case UNIT_FILE_SYSTEM: - return strv_new("/run/systemd/system-generators", - "/etc/systemd/system-generators", - "/usr/local/lib/systemd/system-generators", - SYSTEM_GENERATOR_PATH); + if (!paths || append) { + _cleanup_strv_free_ char **add = NULL; - case UNIT_FILE_GLOBAL: - case UNIT_FILE_USER: - return strv_new("/run/systemd/user-generators", - "/etc/systemd/user-generators", - "/usr/local/lib/systemd/user-generators", - USER_GENERATOR_PATH); + switch (scope) { - default: - assert_not_reached("Hmm, unexpected scope."); + case UNIT_FILE_SYSTEM: + add = strv_new("/run/systemd/system-generators", + "/etc/systemd/system-generators", + "/usr/local/lib/systemd/system-generators", + SYSTEM_GENERATOR_PATH); + break; + + case UNIT_FILE_GLOBAL: + case UNIT_FILE_USER: + add = strv_new("/run/systemd/user-generators", + "/etc/systemd/user-generators", + "/usr/local/lib/systemd/user-generators", + USER_GENERATOR_PATH); + break; + + default: + assert_not_reached("Hmm, unexpected scope."); + } + + if (!add) + return NULL; + + if (paths) { + r = strv_extend_strv(&paths, add, true); + if (r < 0) + return NULL; + } else + /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it, + * and don't have to copy anything */ + paths = TAKE_PTR(add); } + + return TAKE_PTR(paths); +} + +char **env_generator_binary_paths(bool is_system) { + bool append = false; /* Add items from SYSTEMD_ENVIRONMENT_GENERATOR_PATH before normal directories */ + _cleanup_strv_free_ char **paths = NULL; + _cleanup_strv_free_ char **add = NULL; + int r; + + /* First priority is whatever has been passed to us via env vars */ + r = get_paths_from_environ("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", &paths, &append); + if (r < 0) + return NULL; + + if (!paths || append) { + if (is_system) + add = strv_new("/run/systemd/system-environment-generators", + "/etc/systemd/system-environment-generators", + "/usr/local/lib/systemd/system-environment-generators", + SYSTEM_ENV_GENERATOR_PATH); + else + add = strv_new("/run/systemd/user-environment-generators", + "/etc/systemd/user-environment-generators", + "/usr/local/lib/systemd/user-environment-generators", + USER_ENV_GENERATOR_PATH); + + if (!add) + return NULL; + } + + if (paths) { + r = strv_extend_strv(&paths, add, true); + if (r < 0) + return NULL; + } else + /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it, + * and don't have to copy anything */ + paths = TAKE_PTR(add); + + return TAKE_PTR(paths); } diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index f0762d248a..b99e918144 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -72,3 +72,4 @@ void lookup_paths_flush_generator(LookupPaths *p); void lookup_paths_free(LookupPaths *p); char **generator_binary_paths(UnitFileScope scope); +char **env_generator_binary_paths(bool is_system); diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index 62ebc9c923..b9111e9259 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -67,15 +67,54 @@ static void test_user_and_global_paths(void) { log_info("+ %s", *p); } -static void print_generator_binary_paths(UnitFileScope scope) { - _cleanup_strv_free_ char **paths; +static void test_generator_binary_paths(UnitFileScope scope) { + char template[] = "/tmp/test-path-lookup.XXXXXXX"; + + _cleanup_strv_free_ char **gp_without_env = NULL; + _cleanup_strv_free_ char **env_gp_without_env = NULL; + _cleanup_strv_free_ char **gp_with_env = NULL; + _cleanup_strv_free_ char **env_gp_with_env = NULL; + char *systemd_generator_path = NULL; + char *systemd_env_generator_path = NULL; char **dir; - log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); + assert_se(mkdtemp(template)); - paths = generator_binary_paths(scope); - STRV_FOREACH(dir, paths) + assert_se(unsetenv("SYSTEMD_GENERATOR_PATH") == 0); + assert_se(unsetenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH") == 0); + + gp_without_env = generator_binary_paths(scope); + env_gp_without_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false); + + log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); + STRV_FOREACH(dir, gp_without_env) log_info(" %s", *dir); + + log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); + STRV_FOREACH(dir, env_gp_without_env) + log_info(" %s", *dir); + + assert_se(!strv_isempty(gp_without_env)); + assert_se(!strv_isempty(env_gp_without_env)); + + systemd_generator_path = strjoina(template, "/systemd-generator-path"); + systemd_env_generator_path = strjoina(template, "/systemd-environment-generator-path"); + assert_se(setenv("SYSTEMD_GENERATOR_PATH", systemd_generator_path, 1) == 0); + assert_se(setenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", systemd_env_generator_path, 1) == 0); + + gp_with_env = generator_binary_paths(scope); + env_gp_with_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false); + + log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); + STRV_FOREACH(dir, gp_with_env) + log_info(" %s", *dir); + + log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); + STRV_FOREACH(dir, env_gp_with_env) + log_info(" %s", *dir); + + assert_se(strv_equal(gp_with_env, STRV_MAKE(systemd_generator_path))); + assert_se(strv_equal(env_gp_with_env, STRV_MAKE(systemd_env_generator_path))); } int main(int argc, char **argv) { @@ -87,8 +126,8 @@ int main(int argc, char **argv) { test_user_and_global_paths(); - print_generator_binary_paths(UNIT_FILE_SYSTEM); - print_generator_binary_paths(UNIT_FILE_USER); + test_generator_binary_paths(UNIT_FILE_SYSTEM); + test_generator_binary_paths(UNIT_FILE_USER); return EXIT_SUCCESS; }