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.c427
1 files changed, 289 insertions, 138 deletions
diff --git a/src/core/manager.c b/src/core/manager.c
index d2be218b00..81c4d5289b 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -21,6 +22,7 @@
#include <fcntl.h>
#include <linux/kd.h>
#include <signal.h>
+#include <stdio_ext.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
@@ -46,6 +48,7 @@
#include "bus-kernel.h"
#include "bus-util.h"
#include "clean-ipc.h"
+#include "clock-util.h"
#include "dbus-job.h"
#include "dbus-manager.h"
#include "dbus-unit.h"
@@ -53,14 +56,15 @@
#include "dirent-util.h"
#include "env-util.h"
#include "escape.h"
-#include "execute.h"
#include "exec-util.h"
+#include "execute.h"
#include "exit-status.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "hashmap.h"
#include "io-util.h"
+#include "label.h"
#include "locale-setup.h"
#include "log.h"
#include "macro.h"
@@ -136,7 +140,7 @@ static void manager_watch_jobs_in_progress(Manager *m) {
(void) sd_event_source_set_description(m->jobs_in_progress_event_source, "manager-jobs-in-progress");
}
-#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED)-1) + sizeof(ANSI_HIGHLIGHT_RED)-1 + 2*(sizeof(ANSI_NORMAL)-1))
+#define CYLON_BUFFER_EXTRA (2*STRLEN(ANSI_RED) + STRLEN(ANSI_HIGHLIGHT_RED) + 2*STRLEN(ANSI_NORMAL))
static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
char *p = buffer;
@@ -600,6 +604,29 @@ static int manager_setup_prefix(Manager *m) {
return 0;
}
+static int manager_setup_run_queue(Manager *m) {
+ int r;
+
+ assert(m);
+ assert(!m->run_queue_event_source);
+
+ r = sd_event_add_defer(m->event, &m->run_queue_event_source, manager_dispatch_run_queue, m);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(m->run_queue_event_source, SD_EVENT_PRIORITY_IDLE);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_enabled(m->run_queue_event_source, SD_EVENT_OFF);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(m->run_queue_event_source, "manager-run-queue");
+
+ return 0;
+}
+
int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
Manager *m;
int r;
@@ -622,7 +649,9 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
#if ENABLE_EFI
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
- boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
+ boot_timestamps(m->timestamps + MANAGER_TIMESTAMP_USERSPACE,
+ m->timestamps + MANAGER_TIMESTAMP_FIRMWARE,
+ m->timestamps + MANAGER_TIMESTAMP_LOADER);
#endif
/* Prepare log fields we can use for structured logging */
@@ -682,20 +711,10 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
if (r < 0)
goto fail;
- r = sd_event_add_defer(m->event, &m->run_queue_event_source, manager_dispatch_run_queue, m);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_priority(m->run_queue_event_source, SD_EVENT_PRIORITY_IDLE);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_enabled(m->run_queue_event_source, SD_EVENT_OFF);
+ r = manager_setup_run_queue(m);
if (r < 0)
goto fail;
- (void) sd_event_source_set_description(m->run_queue_event_source, "manager-run-queue");
-
r = manager_setup_signals(m);
if (r < 0)
goto fail;
@@ -714,15 +733,23 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
goto fail;
}
- /* Note that we do not set up the notify fd here. We do that after deserialization,
- * since they might have gotten serialized across the reexec. */
-
- m->taint_usr = dir_is_empty("/usr") > 0;
-
r = manager_setup_prefix(m);
if (r < 0)
goto fail;
+ if (MANAGER_IS_SYSTEM(m) && test_run_flags == 0) {
+ r = mkdir_label("/run/systemd/units", 0755);
+ if (r < 0 && r != -EEXIST)
+ goto fail;
+ }
+
+ m->taint_usr =
+ !in_initrd() &&
+ dir_is_empty("/usr") > 0;
+
+ /* Note that we do not set up the notify fd here. We do that after deserialization,
+ * since they might have gotten serialized across the reexec. */
+
*_m = m;
return 0;
@@ -934,7 +961,7 @@ static int manager_connect_bus(Manager *m, bool reexecuting) {
u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
try_bus_connect =
- (u && UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) &&
+ (u && SERVICE(u)->deserialized_state == SERVICE_RUNNING) &&
(reexecuting ||
(MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS")));
@@ -967,21 +994,23 @@ enum {
};
static void unit_gc_mark_good(Unit *u, unsigned gc_marker) {
- Iterator i;
Unit *other;
+ Iterator i;
+ void *v;
u->gc_marker = gc_marker + GC_OFFSET_GOOD;
/* Recursively mark referenced units as GOOD as well */
- SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REFERENCES], i)
if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE)
unit_gc_mark_good(other, gc_marker);
}
static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
- Iterator i;
Unit *other;
bool is_bad;
+ Iterator i;
+ void *v;
assert(u);
@@ -999,7 +1028,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
is_bad = true;
- SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REFERENCED_BY], i) {
unit_gc_sweep(other, gc_marker);
if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
@@ -1307,7 +1336,7 @@ static void manager_distribute_fds(Manager *m, FDSet *fds) {
}
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
- int r, q;
+ int r;
assert(m);
@@ -1323,25 +1352,21 @@ 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);
+ dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_GENERATORS_START);
r = manager_run_generators(m);
- dual_timestamp_get(&m->generators_finish_timestamp);
+ dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_GENERATORS_FINISH);
if (r < 0)
return r;
+ /* If this is the first boot, and we are in the host system, then preset everything */
if (m->first_boot > 0 &&
- m->unit_file_scope == UNIT_FILE_SYSTEM &&
+ MANAGER_IS_SYSTEM(m) &&
!m->test_run_flags) {
- q = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
- if (q < 0)
- log_full_errno(q == -EEXIST ? LOG_NOTICE : LOG_WARNING, q, "Failed to populate /etc with preset unit settings, ignoring: %m");
+ r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
+ if (r < 0)
+ log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r,
+ "Failed to populate /etc with preset unit settings, ignoring: %m");
else
log_info("Populated /etc with preset unit settings.");
}
@@ -1356,15 +1381,15 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->n_reloading++;
/* First, enumerate what we can from all config files */
- dual_timestamp_get(&m->units_load_start_timestamp);
+ dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_START);
manager_enumerate(m);
- dual_timestamp_get(&m->units_load_finish_timestamp);
+ dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
/* Second, deserialize if there is something to deserialize */
if (serialization) {
r = manager_deserialize(m, serialization, fds);
if (r < 0)
- log_error_errno(r, "Deserialization failed: %m");
+ return log_error_errno(r, "Deserialization failed: %m");
}
/* Any fds left? Find some unit which wants them. This is
@@ -1375,17 +1400,20 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
/* We might have deserialized the notify fd, but if we didn't
* then let's create the bus now */
- q = manager_setup_notify(m);
- if (q < 0 && r == 0)
- r = q;
+ r = manager_setup_notify(m);
+ if (r < 0)
+ /* No sense to continue without notifications, our children would fail anyway. */
+ return r;
- q = manager_setup_cgroups_agent(m);
- if (q < 0 && r == 0)
- r = q;
+ r = manager_setup_cgroups_agent(m);
+ if (r < 0)
+ /* Likewise, no sense to continue without empty cgroup notifications. */
+ return r;
- q = manager_setup_user_lookup_fd(m);
- if (q < 0 && r == 0)
- r = q;
+ r = manager_setup_user_lookup_fd(m);
+ if (r < 0)
+ /* This shouldn't fail, except if things are really broken. */
+ return r;
/* Let's connect to the bus now. */
(void) manager_connect_bus(m, !!serialization);
@@ -1413,7 +1441,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->send_reloading_done = true;
}
- return r;
+ return 0;
}
int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret) {
@@ -1693,6 +1721,55 @@ void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
unit_dump(u, f, prefix);
}
+void manager_dump(Manager *m, FILE *f, const char *prefix) {
+ ManagerTimestamp q;
+
+ assert(m);
+ assert(f);
+
+ for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
+ char buf[FORMAT_TIMESTAMP_MAX];
+
+ if (dual_timestamp_is_set(m->timestamps + q))
+ fprintf(f, "%sTimestamp %s: %s\n",
+ strempty(prefix),
+ manager_timestamp_to_string(q),
+ format_timestamp(buf, sizeof(buf), m->timestamps[q].realtime));
+ }
+
+ manager_dump_units(m, f, prefix);
+ manager_dump_jobs(m, f, prefix);
+}
+
+int manager_get_dump_string(Manager *m, char **ret) {
+ _cleanup_free_ char *dump = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ size_t size;
+ int r;
+
+ assert(m);
+ assert(ret);
+
+ f = open_memstream(&dump, &size);
+ if (!f)
+ return -errno;
+
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+
+ manager_dump(m, f, NULL);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+
+ f = safe_fclose(f);
+
+ *ret = dump;
+ dump = NULL;
+
+ return 0;
+}
+
void manager_clear_jobs(Manager *m) {
Job *j;
@@ -2097,8 +2174,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
}
- /* Fall through */
-
+ _fallthrough_;
case SIGINT:
if (MANAGER_IS_SYSTEM(m))
manager_handle_ctrl_alt_del(m);
@@ -2141,21 +2217,10 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
case SIGUSR2: {
_cleanup_free_ char *dump = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- size_t size;
- f = open_memstream(&dump, &size);
- if (!f) {
- log_warning_errno(errno, "Failed to allocate memory stream: %m");
- break;
- }
-
- manager_dump_units(m, f, "\t");
- manager_dump_jobs(m, f, "\t");
-
- r = fflush_and_check(f);
+ r = manager_get_dump_string(m, &dump);
if (r < 0) {
- log_warning_errno(r, "Failed to write status stream: %m");
+ log_warning_errno(errno, "Failed to acquire manager dump: %m");
break;
}
@@ -2561,9 +2626,10 @@ int manager_open_serialization(Manager *m, FILE **_f) {
}
int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
+ ManagerTimestamp q;
+ const char *t;
Iterator i;
Unit *u;
- const char *t;
int r;
assert(m);
@@ -2573,24 +2639,22 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
m->n_reloading++;
fprintf(f, "current-job-id=%"PRIu32"\n", m->current_job_id);
- fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr));
fprintf(f, "n-installed-jobs=%u\n", m->n_installed_jobs);
fprintf(f, "n-failed-jobs=%u\n", m->n_failed_jobs);
+ fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr));
+ fprintf(f, "ready-sent=%s\n", yes_no(m->ready_sent));
- dual_timestamp_serialize(f, "firmware-timestamp", &m->firmware_timestamp);
- dual_timestamp_serialize(f, "loader-timestamp", &m->loader_timestamp);
- dual_timestamp_serialize(f, "kernel-timestamp", &m->kernel_timestamp);
- dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp);
+ for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
+ /* The userspace and finish timestamps only apply to the host system, hence only serialize them there */
+ if (in_initrd() && IN_SET(q, MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH))
+ continue;
- if (!in_initrd()) {
- dual_timestamp_serialize(f, "userspace-timestamp", &m->userspace_timestamp);
- dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp);
- dual_timestamp_serialize(f, "security-start-timestamp", &m->security_start_timestamp);
- dual_timestamp_serialize(f, "security-finish-timestamp", &m->security_finish_timestamp);
- dual_timestamp_serialize(f, "generators-start-timestamp", &m->generators_start_timestamp);
- dual_timestamp_serialize(f, "generators-finish-timestamp", &m->generators_finish_timestamp);
- dual_timestamp_serialize(f, "units-load-start-timestamp", &m->units_load_start_timestamp);
- dual_timestamp_serialize(f, "units-load-finish-timestamp", &m->units_load_finish_timestamp);
+ t = manager_timestamp_to_string(q);
+ {
+ char field[strlen(t) + STRLEN("-timestamp") + 1];
+ strcpy(stpcpy(field, t), "-timestamp");
+ dual_timestamp_serialize(f, field, m->timestamps + q);
+ }
}
if (!switching_root)
@@ -2640,15 +2704,15 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
manager_serialize_uid_refs(m, f);
manager_serialize_gid_refs(m, f);
- fputc_unlocked('\n', f);
+ (void) fputc('\n', f);
HASHMAP_FOREACH_KEY(u, t, m->units, i) {
if (u->id != t)
continue;
/* Start marker */
- fputs_unlocked(u->id, f);
- fputc_unlocked('\n', f);
+ fputs(u->id, f);
+ fputc('\n', f);
r = unit_serialize(u, f, fds, !switching_root);
if (r < 0) {
@@ -2732,31 +2796,16 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
else
m->taint_usr = m->taint_usr || b;
- } 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=")) {
+ } else if ((val = startswith(l, "ready-sent="))) {
+ int b;
+
+ b = parse_boolean(val);
+ if (b < 0)
+ log_notice("Failed to parse ready-sent flag %s", val);
+ else
+ m->ready_sent = m->ready_sent || b;
+
+ } else if (startswith(l, "env=")) {
r = deserialize_environment(&m->environment, l);
if (r == -ENOMEM)
goto finish;
@@ -2819,9 +2868,24 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
if (strv_extend(&m->deserialized_subscribed, val) < 0)
log_oom();
+ } else {
+ ManagerTimestamp q;
- } else if (!startswith(l, "kdbus-fd=")) /* ignore this one */
- log_notice("Unknown serialization item '%s'", l);
+ for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
+ val = startswith(l, manager_timestamp_to_string(q));
+ if (!val)
+ continue;
+
+ val = startswith(val, "-timestamp=");
+ if (val)
+ break;
+ }
+
+ if (q < _MANAGER_TIMESTAMP_MAX) /* found it */
+ dual_timestamp_deserialize(val, m->timestamps + q);
+ else if (!startswith(l, "kdbus-fd=")) /* ignore kdbus */
+ log_notice("Unknown serialization item '%s'", l);
+ }
}
for (;;) {
@@ -3007,20 +3071,20 @@ static void manager_notify_finished(Manager *m) {
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) {
- /* Note that m->kernel_usec.monotonic is always at 0,
- * and m->firmware_usec.monotonic and
- * m->loader_usec.monotonic should be considered
+ /* Note that MANAGER_TIMESTAMP_KERNEL's monotonic value is always at 0, and
+ * MANAGER_TIMESTAMP_FIRMWARE's and MANAGER_TIMESTAMP_LOADER's monotonic value should be considered
* negative values. */
- firmware_usec = m->firmware_timestamp.monotonic - m->loader_timestamp.monotonic;
- loader_usec = m->loader_timestamp.monotonic - m->kernel_timestamp.monotonic;
- userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
- total_usec = m->firmware_timestamp.monotonic + m->finish_timestamp.monotonic;
+ firmware_usec = m->timestamps[MANAGER_TIMESTAMP_FIRMWARE].monotonic - m->timestamps[MANAGER_TIMESTAMP_LOADER].monotonic;
+ loader_usec = m->timestamps[MANAGER_TIMESTAMP_LOADER].monotonic - m->timestamps[MANAGER_TIMESTAMP_KERNEL].monotonic;
+ userspace_usec = m->timestamps[MANAGER_TIMESTAMP_FINISH].monotonic - m->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic;
+ total_usec = m->timestamps[MANAGER_TIMESTAMP_FIRMWARE].monotonic + m->timestamps[MANAGER_TIMESTAMP_FINISH].monotonic;
- if (dual_timestamp_is_set(&m->initrd_timestamp)) {
+ if (dual_timestamp_is_set(&m->timestamps[MANAGER_TIMESTAMP_INITRD])) {
- kernel_usec = m->initrd_timestamp.monotonic - m->kernel_timestamp.monotonic;
- initrd_usec = m->userspace_timestamp.monotonic - m->initrd_timestamp.monotonic;
+ /* The initrd case on bare-metal*/
+ kernel_usec = m->timestamps[MANAGER_TIMESTAMP_INITRD].monotonic - m->timestamps[MANAGER_TIMESTAMP_KERNEL].monotonic;
+ initrd_usec = m->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic - m->timestamps[MANAGER_TIMESTAMP_INITRD].monotonic;
log_struct(LOG_INFO,
"MESSAGE_ID=" SD_MESSAGE_STARTUP_FINISHED_STR,
@@ -3034,7 +3098,9 @@ static void manager_notify_finished(Manager *m) {
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),
NULL);
} else {
- kernel_usec = m->userspace_timestamp.monotonic - m->kernel_timestamp.monotonic;
+ /* The initrd-less case on bare-metal*/
+
+ kernel_usec = m->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic - m->timestamps[MANAGER_TIMESTAMP_KERNEL].monotonic;
initrd_usec = 0;
log_struct(LOG_INFO,
@@ -3048,8 +3114,9 @@ static void manager_notify_finished(Manager *m) {
NULL);
}
} else {
+ /* The container case */
firmware_usec = loader_usec = initrd_usec = kernel_usec = 0;
- total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
+ total_usec = userspace_usec = m->timestamps[MANAGER_TIMESTAMP_FINISH].monotonic - m->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic;
log_struct(LOG_INFO,
"MESSAGE_ID=" SD_MESSAGE_USER_STARTUP_FINISHED_STR,
@@ -3062,9 +3129,11 @@ static void manager_notify_finished(Manager *m) {
bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
sd_notifyf(false,
- "READY=1\n"
- "STATUS=Startup finished in %s.",
+ m->ready_sent ? "STATUS=Startup finished in %s."
+ : "READY=1\n"
+ "STATUS=Startup finished in %s.",
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC));
+ m->ready_sent = true;
}
void manager_check_finished(Manager *m) {
@@ -3079,6 +3148,19 @@ void manager_check_finished(Manager *m) {
if (m->exit_code != MANAGER_OK)
return;
+ /* For user managers, send out READY=1 as soon as we reach basic.target */
+ if (MANAGER_IS_USER(m) && !m->ready_sent) {
+ Unit *u;
+
+ u = manager_get_unit(m, SPECIAL_BASIC_TARGET);
+ if (u && !u->job) {
+ sd_notifyf(false,
+ "READY=1\n"
+ "STATUS=Reached " SPECIAL_BASIC_TARGET ".");
+ m->ready_sent = true;
+ }
+ }
+
if (hashmap_size(m->jobs) > 0) {
if (m->jobs_in_progress_event_source)
/* Ignore any failure, this is only for feedback */
@@ -3101,10 +3183,10 @@ void manager_check_finished(Manager *m) {
/* This is no longer the first boot */
manager_set_first_boot(m, false);
- if (dual_timestamp_is_set(&m->finish_timestamp))
+ if (MANAGER_IS_FINISHED(m))
return;
- dual_timestamp_get(&m->finish_timestamp);
+ dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_FINISH);
manager_notify_finished(m);
@@ -3459,7 +3541,7 @@ ManagerState manager_state(Manager *m) {
assert(m);
/* Did we ever finish booting? If not then we are still starting up */
- if (!dual_timestamp_is_set(&m->finish_timestamp)) {
+ if (!MANAGER_IS_FINISHED(m)) {
u = manager_get_unit(m, SPECIAL_BASIC_TARGET);
if (!u || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
@@ -3468,21 +3550,21 @@ ManagerState manager_state(Manager *m) {
return MANAGER_STARTING;
}
- /* Is the special shutdown target queued? If so, we are in shutdown state */
+ /* Is the special shutdown target active or queued? If so, we are in shutdown state */
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
- if (u && u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_RELOAD_OR_START))
+ if (u && unit_active_or_pending(u))
return MANAGER_STOPPING;
- /* Are the rescue or emergency targets active or queued? If so we are in maintenance state */
- u = manager_get_unit(m, SPECIAL_RESCUE_TARGET);
- if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
- (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_RELOAD_OR_START))))
- return MANAGER_MAINTENANCE;
+ if (MANAGER_IS_SYSTEM(m)) {
+ /* Are the rescue or emergency targets active or queued? If so we are in maintenance state */
+ u = manager_get_unit(m, SPECIAL_RESCUE_TARGET);
+ if (u && unit_active_or_pending(u))
+ return MANAGER_MAINTENANCE;
- u = manager_get_unit(m, SPECIAL_EMERGENCY_TARGET);
- if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
- (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_RELOAD_OR_START))))
- return MANAGER_MAINTENANCE;
+ u = manager_get_unit(m, SPECIAL_EMERGENCY_TARGET);
+ if (u && unit_active_or_pending(u))
+ return MANAGER_MAINTENANCE;
+ }
/* Are there any failed units? If so, we are in degraded mode */
if (set_size(m->failed_units) > 0)
@@ -3785,6 +3867,58 @@ int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t re
return 0;
}
+char *manager_taint_string(Manager *m) {
+ _cleanup_free_ char *destination = NULL, *overflowuid = NULL, *overflowgid = NULL;
+ char *buf, *e;
+ int r;
+
+ /* Returns a "taint string", e.g. "local-hwclock:var-run-bad".
+ * Only things that are detected at runtime should be tagged
+ * here. For stuff that is set during compilation, emit a warning
+ * in the configuration phase. */
+
+ assert(m);
+
+ buf = new(char, sizeof("split-usr:"
+ "cgroups-missing:"
+ "local-hwclock:"
+ "var-run-bad:"
+ "overflowuid-not-65534:"
+ "overflowgid-not-65534:"));
+ if (!buf)
+ return NULL;
+
+ e = buf;
+ buf[0] = 0;
+
+ if (m->taint_usr)
+ e = stpcpy(e, "split-usr:");
+
+ if (access("/proc/cgroups", F_OK) < 0)
+ e = stpcpy(e, "cgroups-missing:");
+
+ if (clock_is_localtime(NULL) > 0)
+ e = stpcpy(e, "local-hwclock:");
+
+ r = readlink_malloc("/var/run", &destination);
+ if (r < 0 || !PATH_IN_SET(destination, "../run", "/run"))
+ e = stpcpy(e, "var-run-bad:");
+
+ r = read_one_line_file("/proc/sys/kernel/overflowuid", &overflowuid);
+ if (r >= 0 && !streq(overflowuid, "65534"))
+ e = stpcpy(e, "overflowuid-not-65534:");
+
+ r = read_one_line_file("/proc/sys/kernel/overflowgid", &overflowgid);
+ if (r >= 0 && !streq(overflowgid, "65534"))
+ e = stpcpy(e, "overflowgid-not-65534:");
+
+ /* remove the last ':' */
+ if (e != buf)
+ e[-1] = 0;
+
+ return buf;
+}
+
static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
[MANAGER_INITIALIZING] = "initializing",
[MANAGER_STARTING] = "starting",
@@ -3795,3 +3929,20 @@ static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);
+
+static const char *const manager_timestamp_table[_MANAGER_TIMESTAMP_MAX] = {
+ [MANAGER_TIMESTAMP_FIRMWARE] = "firmware",
+ [MANAGER_TIMESTAMP_LOADER] = "loader",
+ [MANAGER_TIMESTAMP_KERNEL] = "kernel",
+ [MANAGER_TIMESTAMP_INITRD] = "initrd",
+ [MANAGER_TIMESTAMP_USERSPACE] = "userspace",
+ [MANAGER_TIMESTAMP_FINISH] = "finish",
+ [MANAGER_TIMESTAMP_SECURITY_START] = "security-start",
+ [MANAGER_TIMESTAMP_SECURITY_FINISH] = "security-finish",
+ [MANAGER_TIMESTAMP_GENERATORS_START] = "generators-start",
+ [MANAGER_TIMESTAMP_GENERATORS_FINISH] = "generators-finish",
+ [MANAGER_TIMESTAMP_UNITS_LOAD_START] = "units-load-start",
+ [MANAGER_TIMESTAMP_UNITS_LOAD_FINISH] = "units-load-finish",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(manager_timestamp, ManagerTimestamp);