manager: run environment generators

Environment file generators are a lot like unit file generators, but not
exactly:

1. environment file generators are run for each manager instance, and their
   output is (or at least can be) individualized.

   The generators themselves are system-wide, the same for all users.

2. environment file generators are run sequentially, in priority order.

Thus, the lifetime of those files is tied to lifecycle of the manager
instance. Because generators are run sequentially, later generators can use or
modify the output of earlier generators.

Each generator is run with no arguments, and the whole state is stored in the
environment variables. The generator can echo a set of variable assignments to
standard output:

  VAR_A=something
  VAR_B=something else

This output is parsed, and the next and subsequent generators run with those
updated variables in the environment. After the last generator is done, the
environment that the manager itself exports is updated.

Each generator must return 0, otherwise the output is ignored.

The generators in */user-env-generator are for the user session managers,
including root, and the ones in */system-env-generator are for pid1.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2017-01-22 01:13:47 -05:00
parent 3303d1b2dc
commit 64691d2024
3 changed files with 66 additions and 12 deletions

View File

@ -80,6 +80,8 @@ networkdir=$(rootprefix)/lib/systemd/network
pkgincludedir=$(includedir)/systemd
systemgeneratordir=$(rootlibexecdir)/system-generators
usergeneratordir=$(prefix)/lib/systemd/user-generators
systemenvgeneratordir=$(prefix)/lib/systemd/system-environment-generators
userenvgeneratordir=$(prefix)/lib/systemd/user-environment-generators
systemshutdowndir=$(rootlibexecdir)/system-shutdown
systemsleepdir=$(rootlibexecdir)/system-sleep
systemunitdir=$(rootprefix)/lib/systemd/system
@ -205,6 +207,8 @@ AM_CPPFLAGS = \
-DSYSTEMD_CRYPTSETUP_PATH=\"$(rootlibexecdir)/systemd-cryptsetup\" \
-DSYSTEM_GENERATOR_PATH=\"$(systemgeneratordir)\" \
-DUSER_GENERATOR_PATH=\"$(usergeneratordir)\" \
-DSYSTEM_ENV_GENERATOR_PATH=\"$(systemenvgeneratordir)\" \
-DUSER_ENV_GENERATOR_PATH=\"$(userenvgeneratordir)\" \
-DSYSTEM_SHUTDOWN_PATH=\"$(systemshutdowndir)\" \
-DSYSTEM_SLEEP_PATH=\"$(systemsleepdir)\" \
-DSYSTEMD_KBD_MODEL_MAP=\"$(pkgdatadir)/kbd-model-map\" \
@ -6210,6 +6214,8 @@ substitutions = \
'|sysctldir=$(sysctldir)|' \
'|systemgeneratordir=$(systemgeneratordir)|' \
'|usergeneratordir=$(usergeneratordir)|' \
'|systemenvgeneratordir=$(systemenvgeneratordir)|' \
'|userenvgeneratordir=$(userenvgeneratordir)|' \
'|CERTIFICATEROOT=$(CERTIFICATEROOT)|' \
'|PACKAGE_VERSION=$(PACKAGE_VERSION)|' \
'|PACKAGE_NAME=$(PACKAGE_NAME)|' \

View File

@ -31,6 +31,8 @@
%_binfmtdir @binfmtdir@
%_systemdgeneratordir @systemgeneratordir@
%_systemdusergeneratordir @usergeneratordir@
%_systemd_system_env_generator_dir @systemenvgeneratordir@
%_systemd_user_env_generator_dir @userenvgeneratordir@
%systemd_requires \
Requires(post): systemd \

View File

@ -103,6 +103,7 @@ static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32
static int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
static int manager_run_environment_generators(Manager *m);
static int manager_run_generators(Manager *m);
static void manager_watch_jobs_in_progress(Manager *m) {
@ -1262,6 +1263,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (r < 0)
return r;
r = manager_run_environment_generators(m);
if (r < 0)
return r;
/* Make sure the transient directory always exists, so that it remains in the search path */
if (!m->test_run) {
r = mkdir_p_label(m->lookup_paths.transient, 0755);
@ -2795,6 +2800,10 @@ int manager_reload(Manager *m) {
if (q < 0 && r >= 0)
r = q;
q = manager_run_environment_generators(m);
if (q < 0 && r >= 0)
r = q;
/* Find new unit paths */
q = manager_run_generators(m);
if (q < 0 && r >= 0)
@ -2986,10 +2995,56 @@ void manager_check_finished(Manager *m) {
manager_invalidate_startup_units(m);
}
static bool generator_path_any(const char* const* paths) {
char **path;
bool found = false;
/* Optimize by skipping the whole process by not creating output directories
* if no generators are found. */
STRV_FOREACH(path, (char**) paths)
if (access(*path, F_OK) == 0)
found = true;
else if (errno != ENOENT)
log_warning_errno(errno, "Failed to open generator directory %s: %m", *path);
return found;
}
static const char* 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* 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 **paths;
void* args[] = {&tmp, &tmp, &m->environment};
if (m->test_run)
return 0;
paths = MANAGER_IS_SYSTEM(m) ? system_env_generator_binary_paths : user_env_generator_binary_paths;
if (!generator_path_any(paths))
return 0;
return execute_directories(paths, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL);
}
static int manager_run_generators(Manager *m) {
_cleanup_strv_free_ char **paths = NULL;
const char *argv[5];
char **path;
int r;
assert(m);
@ -3001,18 +3056,9 @@ static int manager_run_generators(Manager *m) {
if (!paths)
return log_oom();
/* Optimize by skipping the whole process by not creating output directories
* if no generators are found. */
STRV_FOREACH(path, paths) {
if (access(*path, F_OK) >= 0)
goto found;
if (errno != ENOENT)
log_warning_errno(errno, "Failed to open generator directory %s: %m", *path);
}
if (!generator_path_any((const char* const*) paths))
return 0;
return 0;
found:
r = lookup_paths_mkdir_generator(&m->lookup_paths);
if (r < 0)
goto finish;