diff options
author | Michael Biebl <biebl@debian.org> | 2017-12-14 23:22:02 +0100 |
---|---|---|
committer | Michael Biebl <biebl@debian.org> | 2017-12-14 23:22:02 +0100 |
commit | 52ad194e0b816b8273dd8d0fea3e6d467f6ca34e (patch) | |
tree | 1a3b3117e015f200ca0ce23f5ad27be6d0a7b0fb /src/core/manager.c | |
parent | f5e65279187b6aa0c0c5a00b14dca9eab441ffb2 (diff) | |
download | systemd-52ad194e0b816b8273dd8d0fea3e6d467f6ca34e.tar.gz |
New upstream version 236
Diffstat (limited to 'src/core/manager.c')
-rw-r--r-- | src/core/manager.c | 427 |
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); |