summaryrefslogtreecommitdiff
path: root/src/core/manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/manager.c')
-rw-r--r--src/core/manager.c386
1 files changed, 246 insertions, 140 deletions
diff --git a/src/core/manager.c b/src/core/manager.c
index ffccfdcd5e..cff38e28de 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -17,7 +17,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/kd.h>
@@ -53,6 +52,7 @@
#include "dirent-util.h"
#include "env-util.h"
#include "escape.h"
+#include "exec-util.h"
#include "exit-status.h"
#include "fd-util.h"
#include "fileio.h"
@@ -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) {
@@ -111,6 +112,12 @@ static void manager_watch_jobs_in_progress(Manager *m) {
assert(m);
+ /* We do not want to show the cylon animation if the user
+ * needs to confirm service executions otherwise confirmation
+ * messages will be screwed by the cylon animation. */
+ if (!manager_is_confirm_spawn_disabled(m))
+ return;
+
if (m->jobs_in_progress_event_source)
return;
@@ -227,6 +234,7 @@ static void manager_print_jobs_in_progress(Manager *m) {
static int have_ask_password(void) {
_cleanup_closedir_ DIR *dir;
+ struct dirent *de;
dir = opendir("/run/systemd/ask-password");
if (!dir) {
@@ -236,19 +244,11 @@ static int have_ask_password(void) {
return -errno;
}
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(dir);
- if (!de && errno > 0)
- return -errno;
- if (!de)
- return false;
-
+ FOREACH_DIRENT_ALL(de, dir, return -errno) {
if (startswith(de->d_name, "ask."))
return true;
}
+ return false;
}
static int manager_dispatch_ask_password_fd(sd_event_source *source,
@@ -532,9 +532,9 @@ static int manager_default_environment(Manager *m) {
if (MANAGER_IS_SYSTEM(m)) {
/* The system manager always starts with a clean
* environment for its children. It does not import
- * the kernel or the parents exported variables.
+ * the kernel's or the parents' exported variables.
*
- * The initial passed environ is untouched to keep
+ * The initial passed environment is untouched to keep
* /proc/self/environ valid; it is used for tagging
* the init process inside containers. */
m->environment = strv_new("PATH=" DEFAULT_PATH,
@@ -542,11 +542,10 @@ static int manager_default_environment(Manager *m) {
/* Import locale variables LC_*= from configuration */
locale_setup(&m->environment);
- } else {
+ } else
/* The user manager passes its own environment
* along to its children. */
m->environment = strv_copy(environ);
- }
if (!m->environment)
return -ENOMEM;
@@ -777,7 +776,10 @@ static int manager_setup_cgroups_agent(Manager *m) {
if (!MANAGER_IS_SYSTEM(m))
return 0;
- if (cg_unified(SYSTEMD_CGROUP_CONTROLLER) > 0) /* We don't need this anymore on the unified hierarchy */
+ r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine whether unified cgroups hierarchy is used: %m");
+ if (r > 0) /* We don't need this anymore on the unified hierarchy */
return 0;
if (m->cgroups_agent_fd < 0) {
@@ -981,10 +983,9 @@ good:
unit_gc_mark_good(u, gc_marker);
}
-static unsigned manager_dispatch_gc_queue(Manager *m) {
+static unsigned manager_dispatch_gc_unit_queue(Manager *m) {
+ unsigned n = 0, gc_marker;
Unit *u;
- unsigned n = 0;
- unsigned gc_marker;
assert(m);
@@ -996,12 +997,12 @@ static unsigned manager_dispatch_gc_queue(Manager *m) {
gc_marker = m->gc_marker;
- while ((u = m->gc_queue)) {
+ while ((u = m->gc_unit_queue)) {
assert(u->in_gc_queue);
unit_gc_sweep(u, gc_marker);
- LIST_REMOVE(gc_queue, m->gc_queue, u);
+ LIST_REMOVE(gc_queue, m->gc_unit_queue, u);
u->in_gc_queue = false;
n++;
@@ -1015,7 +1016,29 @@ static unsigned manager_dispatch_gc_queue(Manager *m) {
}
}
- m->n_in_gc_queue = 0;
+ return n;
+}
+
+static unsigned manager_dispatch_gc_job_queue(Manager *m) {
+ unsigned n = 0;
+ Job *j;
+
+ assert(m);
+
+ while ((j = m->gc_job_queue)) {
+ assert(j->in_gc_queue);
+
+ LIST_REMOVE(gc_queue, m->gc_job_queue, j);
+ j->in_gc_queue = false;
+
+ n++;
+
+ if (job_check_gc(j))
+ continue;
+
+ log_unit_debug(j->unit, "Collecting job.");
+ (void) job_finish_and_invalidate(j, JOB_COLLECTED, false, false);
+ }
return n;
}
@@ -1035,7 +1058,8 @@ static void manager_clear_jobs_and_units(Manager *m) {
assert(!m->dbus_unit_queue);
assert(!m->dbus_job_queue);
assert(!m->cleanup_queue);
- assert(!m->gc_queue);
+ assert(!m->gc_unit_queue);
+ assert(!m->gc_job_queue);
assert(hashmap_isempty(m->jobs));
assert(hashmap_isempty(m->units));
@@ -1196,7 +1220,7 @@ static void manager_build_unit_path_cache(Manager *m) {
FOREACH_DIRENT(de, d, r = -errno; goto fail) {
char *p;
- p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
+ p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name);
if (!p) {
r = -ENOMEM;
goto fail;
@@ -1242,6 +1266,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);
@@ -1378,7 +1406,7 @@ tr_abort:
}
int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **ret) {
- Unit *unit;
+ Unit *unit = NULL; /* just to appease gcc, initialization is not really necessary */
int r;
assert(m);
@@ -1389,6 +1417,7 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode
r = manager_load_unit(m, name, NULL, NULL, &unit);
if (r < 0)
return r;
+ assert(unit);
return manager_add_job(m, type, unit, mode, e, ret);
}
@@ -1461,6 +1490,7 @@ int manager_load_unit_prepare(
assert(m);
assert(name || path);
+ assert(_ret);
/* This will prepare the unit for loading, but not actually
* load anything from disk. */
@@ -1508,8 +1538,7 @@ int manager_load_unit_prepare(
unit_add_to_dbus_queue(ret);
unit_add_to_gc_queue(ret);
- if (_ret)
- *_ret = ret;
+ *_ret = ret;
return 0;
}
@@ -1524,6 +1553,7 @@ int manager_load_unit(
int r;
assert(m);
+ assert(_ret);
/* This will load the service information files, but not actually
* start any services or anything. */
@@ -1534,8 +1564,7 @@ int manager_load_unit(
manager_dispatch_load_queue(m);
- if (_ret)
- *_ret = unit_follow_merge(*_ret);
+ *_ret = unit_follow_merge(*_ret);
return 0;
}
@@ -1964,7 +1993,9 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
if (MANAGER_IS_SYSTEM(m)) {
/* This is for compatibility with the
* original sysvinit */
- m->exit_code = MANAGER_REEXECUTE;
+ r = verify_run_space_and_log("Refusing to reexecute");
+ if (r >= 0)
+ m->exit_code = MANAGER_REEXECUTE;
break;
}
@@ -2041,7 +2072,9 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
}
case SIGHUP:
- m->exit_code = MANAGER_RELOAD;
+ r = verify_run_space_and_log("Refusing to reload");
+ if (r >= 0)
+ m->exit_code = MANAGER_RELOAD;
break;
default: {
@@ -2145,8 +2178,8 @@ static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint
assert(m);
assert(m->time_change_fd == fd);
- log_struct(LOG_INFO,
- LOG_MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
+ log_struct(LOG_DEBUG,
+ "MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR,
LOG_MESSAGE("Time has been changed"),
NULL);
@@ -2228,7 +2261,10 @@ int manager_loop(Manager *m) {
if (manager_dispatch_load_queue(m) > 0)
continue;
- if (manager_dispatch_gc_queue(m) > 0)
+ if (manager_dispatch_gc_job_queue(m) > 0)
+ continue;
+
+ if (manager_dispatch_gc_unit_queue(m) > 0)
continue;
if (manager_dispatch_cleanup_queue(m) > 0)
@@ -2409,18 +2445,14 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
}
int manager_open_serialization(Manager *m, FILE **_f) {
- const char *path;
- int fd = -1;
+ int fd;
FILE *f;
assert(_f);
- path = MANAGER_IS_SYSTEM(m) ? "/run/systemd" : "/tmp";
- fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
+ fd = open_serialization_fd("systemd-state");
if (fd < 0)
- return -errno;
-
- log_debug("Serializing state to %s", path);
+ return fd;
f = fdopen(fd, "w+");
if (!f) {
@@ -2429,7 +2461,6 @@ int manager_open_serialization(Manager *m, FILE **_f) {
}
*_f = f;
-
return 0;
}
@@ -2437,7 +2468,6 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
Iterator i;
Unit *u;
const char *t;
- char **e;
int r;
assert(m);
@@ -2467,17 +2497,8 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
dual_timestamp_serialize(f, "units-load-finish-timestamp", &m->units_load_finish_timestamp);
}
- if (!switching_root) {
- STRV_FOREACH(e, m->environment) {
- _cleanup_free_ char *ce;
-
- ce = cescape(*e);
- if (!ce)
- return -ENOMEM;
-
- fprintf(f, "env=%s\n", *e);
- }
- }
+ if (!switching_root)
+ (void) serialize_environment(f, m->environment);
if (m->notify_fd >= 0) {
int copy;
@@ -2565,6 +2586,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
for (;;) {
char line[LINE_MAX], *l;
+ const char *val;
if (!fgets(line, sizeof(line), f)) {
if (feof(f))
@@ -2581,95 +2603,83 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
if (l[0] == 0)
break;
- if (startswith(l, "current-job-id=")) {
+ if ((val = startswith(l, "current-job-id="))) {
uint32_t id;
- if (safe_atou32(l+15, &id) < 0)
- log_debug("Failed to parse current job id value %s", l+15);
+ if (safe_atou32(val, &id) < 0)
+ log_debug("Failed to parse current job id value %s", val);
else
m->current_job_id = MAX(m->current_job_id, id);
- } else if (startswith(l, "n-installed-jobs=")) {
+ } else if ((val = startswith(l, "n-installed-jobs="))) {
uint32_t n;
- if (safe_atou32(l+17, &n) < 0)
- log_debug("Failed to parse installed jobs counter %s", l+17);
+ if (safe_atou32(val, &n) < 0)
+ log_debug("Failed to parse installed jobs counter %s", val);
else
m->n_installed_jobs += n;
- } else if (startswith(l, "n-failed-jobs=")) {
+ } else if ((val = startswith(l, "n-failed-jobs="))) {
uint32_t n;
- if (safe_atou32(l+14, &n) < 0)
- log_debug("Failed to parse failed jobs counter %s", l+14);
+ if (safe_atou32(val, &n) < 0)
+ log_debug("Failed to parse failed jobs counter %s", val);
else
m->n_failed_jobs += n;
- } else if (startswith(l, "taint-usr=")) {
+ } else if ((val = startswith(l, "taint-usr="))) {
int b;
- b = parse_boolean(l+10);
+ b = parse_boolean(val);
if (b < 0)
- log_debug("Failed to parse taint /usr flag %s", l+10);
+ log_debug("Failed to parse taint /usr flag %s", val);
else
m->taint_usr = m->taint_usr || b;
- } else if (startswith(l, "firmware-timestamp="))
- dual_timestamp_deserialize(l+19, &m->firmware_timestamp);
- else if (startswith(l, "loader-timestamp="))
- dual_timestamp_deserialize(l+17, &m->loader_timestamp);
- else if (startswith(l, "kernel-timestamp="))
- dual_timestamp_deserialize(l+17, &m->kernel_timestamp);
- else if (startswith(l, "initrd-timestamp="))
- dual_timestamp_deserialize(l+17, &m->initrd_timestamp);
- else if (startswith(l, "userspace-timestamp="))
- dual_timestamp_deserialize(l+20, &m->userspace_timestamp);
- else if (startswith(l, "finish-timestamp="))
- dual_timestamp_deserialize(l+17, &m->finish_timestamp);
- else if (startswith(l, "security-start-timestamp="))
- dual_timestamp_deserialize(l+25, &m->security_start_timestamp);
- else if (startswith(l, "security-finish-timestamp="))
- dual_timestamp_deserialize(l+26, &m->security_finish_timestamp);
- else if (startswith(l, "generators-start-timestamp="))
- dual_timestamp_deserialize(l+27, &m->generators_start_timestamp);
- else if (startswith(l, "generators-finish-timestamp="))
- dual_timestamp_deserialize(l+28, &m->generators_finish_timestamp);
- else if (startswith(l, "units-load-start-timestamp="))
- dual_timestamp_deserialize(l+27, &m->units_load_start_timestamp);
- else if (startswith(l, "units-load-finish-timestamp="))
- dual_timestamp_deserialize(l+28, &m->units_load_finish_timestamp);
+ } else if ((val = startswith(l, "firmware-timestamp=")))
+ dual_timestamp_deserialize(val, &m->firmware_timestamp);
+ else if ((val = startswith(l, "loader-timestamp=")))
+ dual_timestamp_deserialize(val, &m->loader_timestamp);
+ else if ((val = startswith(l, "kernel-timestamp=")))
+ dual_timestamp_deserialize(val, &m->kernel_timestamp);
+ else if ((val = startswith(l, "initrd-timestamp=")))
+ dual_timestamp_deserialize(val, &m->initrd_timestamp);
+ else if ((val = startswith(l, "userspace-timestamp=")))
+ dual_timestamp_deserialize(val, &m->userspace_timestamp);
+ else if ((val = startswith(l, "finish-timestamp=")))
+ dual_timestamp_deserialize(val, &m->finish_timestamp);
+ else if ((val = startswith(l, "security-start-timestamp=")))
+ dual_timestamp_deserialize(val, &m->security_start_timestamp);
+ else if ((val = startswith(l, "security-finish-timestamp=")))
+ dual_timestamp_deserialize(val, &m->security_finish_timestamp);
+ else if ((val = startswith(l, "generators-start-timestamp=")))
+ dual_timestamp_deserialize(val, &m->generators_start_timestamp);
+ else if ((val = startswith(l, "generators-finish-timestamp=")))
+ dual_timestamp_deserialize(val, &m->generators_finish_timestamp);
+ else if ((val = startswith(l, "units-load-start-timestamp=")))
+ dual_timestamp_deserialize(val, &m->units_load_start_timestamp);
+ else if ((val = startswith(l, "units-load-finish-timestamp=")))
+ dual_timestamp_deserialize(val, &m->units_load_finish_timestamp);
else if (startswith(l, "env=")) {
- _cleanup_free_ char *uce = NULL;
- char **e;
-
- r = cunescape(l + 4, UNESCAPE_RELAX, &uce);
+ r = deserialize_environment(&m->environment, l);
if (r < 0)
- goto finish;
+ return r;
- e = strv_env_set(m->environment, uce);
- if (!e) {
- r = -ENOMEM;
- goto finish;
- }
-
- strv_free(m->environment);
- m->environment = e;
-
- } else if (startswith(l, "notify-fd=")) {
+ } else if ((val = startswith(l, "notify-fd="))) {
int fd;
- if (safe_atoi(l + 10, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug("Failed to parse notify fd: %s", l + 10);
+ if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_debug("Failed to parse notify fd: %s", val);
else {
m->notify_event_source = sd_event_source_unref(m->notify_event_source);
safe_close(m->notify_fd);
m->notify_fd = fdset_remove(fds, fd);
}
- } else if (startswith(l, "notify-socket=")) {
+ } else if ((val = startswith(l, "notify-socket="))) {
char *n;
- n = strdup(l+14);
+ n = strdup(val);
if (!n) {
r = -ENOMEM;
goto finish;
@@ -2678,22 +2688,22 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
free(m->notify_socket);
m->notify_socket = n;
- } else if (startswith(l, "cgroups-agent-fd=")) {
+ } else if ((val = startswith(l, "cgroups-agent-fd="))) {
int fd;
- if (safe_atoi(l + 17, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug("Failed to parse cgroups agent fd: %s", l + 10);
+ if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_debug("Failed to parse cgroups agent fd: %s", val);
else {
m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
safe_close(m->cgroups_agent_fd);
m->cgroups_agent_fd = fdset_remove(fds, fd);
}
- } else if (startswith(l, "user-lookup=")) {
+ } else if ((val = startswith(l, "user-lookup="))) {
int fd0, fd1;
- if (sscanf(l + 12, "%i %i", &fd0, &fd1) != 2 || fd0 < 0 || fd1 < 0 || fd0 == fd1 || !fdset_contains(fds, fd0) || !fdset_contains(fds, fd1))
- log_debug("Failed to parse user lookup fd: %s", l + 12);
+ if (sscanf(val, "%i %i", &fd0, &fd1) != 2 || fd0 < 0 || fd1 < 0 || fd0 == fd1 || !fdset_contains(fds, fd0) || !fdset_contains(fds, fd1))
+ log_debug("Failed to parse user lookup fd: %s", val);
else {
m->user_lookup_event_source = sd_event_source_unref(m->user_lookup_event_source);
safe_close_pair(m->user_lookup_fds);
@@ -2701,15 +2711,15 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
m->user_lookup_fds[1] = fdset_remove(fds, fd1);
}
- } else if (startswith(l, "dynamic-user="))
- dynamic_user_deserialize_one(m, l + 13, fds);
- else if (startswith(l, "destroy-ipc-uid="))
- manager_deserialize_uid_refs_one(m, l + 16);
- else if (startswith(l, "destroy-ipc-gid="))
- manager_deserialize_gid_refs_one(m, l + 16);
- else if (startswith(l, "subscribed=")) {
+ } else if ((val = startswith(l, "dynamic-user=")))
+ dynamic_user_deserialize_one(m, val, fds);
+ else if ((val = startswith(l, "destroy-ipc-uid=")))
+ manager_deserialize_uid_refs_one(m, val);
+ else if ((val = startswith(l, "destroy-ipc-gid=")))
+ manager_deserialize_gid_refs_one(m, val);
+ else if ((val = startswith(l, "subscribed="))) {
- if (strv_extend(&m->deserialized_subscribed, l+11) < 0)
+ if (strv_extend(&m->deserialized_subscribed, val) < 0)
log_oom();
} else if (!startswith(l, "kdbus-fd=")) /* ignore this one */
@@ -2794,6 +2804,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)
@@ -2897,7 +2911,7 @@ static void manager_notify_finished(Manager *m) {
initrd_usec = m->userspace_timestamp.monotonic - m->initrd_timestamp.monotonic;
log_struct(LOG_INFO,
- LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
+ "MESSAGE_ID=" SD_MESSAGE_STARTUP_FINISHED_STR,
"KERNEL_USEC="USEC_FMT, kernel_usec,
"INITRD_USEC="USEC_FMT, initrd_usec,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
@@ -2912,7 +2926,7 @@ static void manager_notify_finished(Manager *m) {
initrd_usec = 0;
log_struct(LOG_INFO,
- LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
+ "MESSAGE_ID=" SD_MESSAGE_STARTUP_FINISHED_STR,
"KERNEL_USEC="USEC_FMT, kernel_usec,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_MESSAGE("Startup finished in %s (kernel) + %s (userspace) = %s.",
@@ -2926,7 +2940,7 @@ static void manager_notify_finished(Manager *m) {
total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
log_struct(LOG_INFO,
- LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
+ "MESSAGE_ID=" SD_MESSAGE_USER_STARTUP_FINISHED_STR,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_MESSAGE("Startup finished in %s.",
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),
@@ -2967,7 +2981,7 @@ void manager_check_finished(Manager *m) {
manager_close_idle_pipe(m);
/* Turn off confirm spawn now */
- m->confirm_spawn = false;
+ m->confirm_spawn = NULL;
/* No need to update ask password status when we're going non-interactive */
manager_close_ask_password(m);
@@ -2985,10 +2999,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);
@@ -3000,18 +3060,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);
- }
-
- return 0;
+ if (!generator_path_any((const char* const*) paths))
+ return 0;
- found:
r = lookup_paths_mkdir_generator(&m->lookup_paths);
if (r < 0)
goto finish;
@@ -3023,7 +3074,8 @@ static int manager_run_generators(Manager *m) {
argv[4] = NULL;
RUN_WITH_UMASK(0022)
- execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, (char**) argv);
+ execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC,
+ NULL, NULL, (char**) argv);
finish:
lookup_paths_trim_generator(&m->lookup_paths);
@@ -3152,6 +3204,49 @@ static bool manager_get_show_status(Manager *m, StatusType type) {
return false;
}
+const char *manager_get_confirm_spawn(Manager *m) {
+ static int last_errno = 0;
+ const char *vc = m->confirm_spawn;
+ struct stat st;
+ int r;
+
+ /* Here's the deal: we want to test the validity of the console but don't want
+ * PID1 to go through the whole console process which might block. But we also
+ * want to warn the user only once if something is wrong with the console so we
+ * cannot do the sanity checks after spawning our children. So here we simply do
+ * really basic tests to hopefully trap common errors.
+ *
+ * If the console suddenly disappear at the time our children will really it
+ * then they will simply fail to acquire it and a positive answer will be
+ * assumed. New children will fallback to /dev/console though.
+ *
+ * Note: TTYs are devices that can come and go any time, and frequently aren't
+ * available yet during early boot (consider a USB rs232 dongle...). If for any
+ * reason the configured console is not ready, we fallback to the default
+ * console. */
+
+ if (!vc || path_equal(vc, "/dev/console"))
+ return vc;
+
+ r = stat(vc, &st);
+ if (r < 0)
+ goto fail;
+
+ if (!S_ISCHR(st.st_mode)) {
+ errno = ENOTTY;
+ goto fail;
+ }
+
+ last_errno = 0;
+ return vc;
+fail:
+ if (last_errno != errno) {
+ last_errno = errno;
+ log_warning_errno(errno, "Failed to open %s: %m, using default console", vc);
+ }
+ return "/dev/console";
+}
+
void manager_set_first_boot(Manager *m, bool b) {
assert(m);
@@ -3168,6 +3263,17 @@ void manager_set_first_boot(Manager *m, bool b) {
m->first_boot = b;
}
+void manager_disable_confirm_spawn(void) {
+ (void) touch("/run/systemd/confirm_spawn_disabled");
+}
+
+bool manager_is_confirm_spawn_disabled(Manager *m) {
+ if (!m->confirm_spawn)
+ return true;
+
+ return access("/run/systemd/confirm_spawn_disabled", F_OK) >= 0;
+}
+
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {
va_list ap;