diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/automount.c | 8 | ||||
-rw-r--r-- | src/core/job.c | 50 | ||||
-rw-r--r-- | src/core/main.c | 1 | ||||
-rw-r--r-- | src/core/manager-serialize.c | 536 | ||||
-rw-r--r-- | src/core/manager-serialize.h | 13 | ||||
-rw-r--r-- | src/core/manager.c | 719 | ||||
-rw-r--r-- | src/core/manager.h | 10 | ||||
-rw-r--r-- | src/core/meson.build | 2 | ||||
-rw-r--r-- | src/core/mount.c | 16 | ||||
-rw-r--r-- | src/core/path.c | 14 | ||||
-rw-r--r-- | src/core/scope.c | 4 | ||||
-rw-r--r-- | src/core/service.c | 83 | ||||
-rw-r--r-- | src/core/socket.c | 28 | ||||
-rw-r--r-- | src/core/swap.c | 14 | ||||
-rw-r--r-- | src/core/timer.c | 14 | ||||
-rw-r--r-- | src/core/unit.h | 9 |
16 files changed, 801 insertions, 720 deletions
diff --git a/src/core/automount.c b/src/core/automount.c index 68e794ac2e..30226b9bde 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -1065,11 +1065,11 @@ static bool automount_supported(void) { } static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { - [AUTOMOUNT_SUCCESS] = "success", - [AUTOMOUNT_FAILURE_RESOURCES] = "resources", - [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [AUTOMOUNT_SUCCESS] = "success", + [AUTOMOUNT_FAILURE_RESOURCES] = "resources", + [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit", - [AUTOMOUNT_FAILURE_UNMOUNTED] = "unmounted", + [AUTOMOUNT_FAILURE_UNMOUNTED] = "unmounted", }; DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult); diff --git a/src/core/job.c b/src/core/job.c index eb6728ad87..a526e5e4ee 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -1511,44 +1511,44 @@ static const char* const job_state_table[_JOB_STATE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(job_state, JobState); static const char* const job_type_table[_JOB_TYPE_MAX] = { - [JOB_START] = "start", - [JOB_VERIFY_ACTIVE] = "verify-active", - [JOB_STOP] = "stop", - [JOB_RELOAD] = "reload", + [JOB_START] = "start", + [JOB_VERIFY_ACTIVE] = "verify-active", + [JOB_STOP] = "stop", + [JOB_RELOAD] = "reload", [JOB_RELOAD_OR_START] = "reload-or-start", - [JOB_RESTART] = "restart", - [JOB_TRY_RESTART] = "try-restart", - [JOB_TRY_RELOAD] = "try-reload", - [JOB_NOP] = "nop", + [JOB_RESTART] = "restart", + [JOB_TRY_RESTART] = "try-restart", + [JOB_TRY_RELOAD] = "try-reload", + [JOB_NOP] = "nop", }; DEFINE_STRING_TABLE_LOOKUP(job_type, JobType); static const char* const job_mode_table[_JOB_MODE_MAX] = { - [JOB_FAIL] = "fail", - [JOB_REPLACE] = "replace", + [JOB_FAIL] = "fail", + [JOB_REPLACE] = "replace", [JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly", - [JOB_ISOLATE] = "isolate", - [JOB_FLUSH] = "flush", - [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies", - [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements", - [JOB_TRIGGERING] = "triggering", + [JOB_ISOLATE] = "isolate", + [JOB_FLUSH] = "flush", + [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies", + [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements", + [JOB_TRIGGERING] = "triggering", }; DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode); static const char* const job_result_table[_JOB_RESULT_MAX] = { - [JOB_DONE] = "done", - [JOB_CANCELED] = "canceled", - [JOB_TIMEOUT] = "timeout", - [JOB_FAILED] = "failed", - [JOB_DEPENDENCY] = "dependency", - [JOB_SKIPPED] = "skipped", - [JOB_INVALID] = "invalid", - [JOB_ASSERT] = "assert", + [JOB_DONE] = "done", + [JOB_CANCELED] = "canceled", + [JOB_TIMEOUT] = "timeout", + [JOB_FAILED] = "failed", + [JOB_DEPENDENCY] = "dependency", + [JOB_SKIPPED] = "skipped", + [JOB_INVALID] = "invalid", + [JOB_ASSERT] = "assert", [JOB_UNSUPPORTED] = "unsupported", - [JOB_COLLECTED] = "collected", - [JOB_ONCE] = "once", + [JOB_COLLECTED] = "collected", + [JOB_ONCE] = "once", }; DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult); diff --git a/src/core/main.c b/src/core/main.c index 72d7c6b116..57d4f033dd 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -55,6 +55,7 @@ #include "machine-id-setup.h" #include "manager.h" #include "manager-dump.h" +#include "manager-serialize.h" #include "mkdir.h" #include "mount-setup.h" #include "os-util.h" diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c new file mode 100644 index 0000000000..60a35f48f3 --- /dev/null +++ b/src/core/manager-serialize.c @@ -0,0 +1,536 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "clean-ipc.h" +#include "dbus.h" +#include "fd-util.h" +#include "fileio.h" +#include "format-util.h" +#include "macro.h" +#include "manager-serialize.h" +#include "manager.h" +#include "parse-util.h" +#include "serialize.h" +#include "syslog-util.h" +#include "unit-serialize.h" +#include "user-util.h" + +int manager_open_serialization(Manager *m, FILE **ret_f) { + _cleanup_close_ int fd = -1; + FILE *f; + + assert(ret_f); + + fd = open_serialization_fd("systemd-state"); + if (fd < 0) + return fd; + + f = take_fdopen(&fd, "w+"); + if (!f) + return -errno; + + *ret_f = f; + return 0; +} + +static bool manager_timestamp_shall_serialize(ManagerTimestamp t) { + if (!in_initrd()) + return true; + + /* The following timestamps only apply to the host system, hence only serialize them there */ + return !IN_SET(t, + MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH, + MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH, + MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH, + MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH); +} + +static void manager_serialize_uid_refs_internal( + FILE *f, + Hashmap *uid_refs, + const char *field_name) { + + void *p, *k; + + assert(f); + assert(field_name); + + /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as + * the actual counter of it is better rebuild after a reload/reexec. */ + + HASHMAP_FOREACH_KEY(p, k, uid_refs) { + uint32_t c; + uid_t uid; + + uid = PTR_TO_UID(k); + c = PTR_TO_UINT32(p); + + if (!(c & DESTROY_IPC_FLAG)) + continue; + + (void) serialize_item_format(f, field_name, UID_FMT, uid); + } +} + +static void manager_serialize_uid_refs(Manager *m, FILE *f) { + manager_serialize_uid_refs_internal(f, m->uid_refs, "destroy-ipc-uid"); +} + +static void manager_serialize_gid_refs(Manager *m, FILE *f) { + manager_serialize_uid_refs_internal(f, m->gid_refs, "destroy-ipc-gid"); +} + +int manager_serialize( + Manager *m, + FILE *f, + FDSet *fds, + bool switching_root) { + + const char *t; + Unit *u; + int r; + + assert(m); + assert(f); + assert(fds); + + _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m); + + (void) serialize_item_format(f, "current-job-id", "%" PRIu32, m->current_job_id); + (void) serialize_item_format(f, "n-installed-jobs", "%u", m->n_installed_jobs); + (void) serialize_item_format(f, "n-failed-jobs", "%u", m->n_failed_jobs); + (void) serialize_bool(f, "taint-usr", m->taint_usr); + (void) serialize_bool(f, "ready-sent", m->ready_sent); + (void) serialize_bool(f, "taint-logged", m->taint_logged); + (void) serialize_bool(f, "service-watchdogs", m->service_watchdogs); + + /* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */ + (void) serialize_bool(f, "honor-device-enumeration", !switching_root); + + if (m->show_status_overridden != _SHOW_STATUS_INVALID) + (void) serialize_item(f, "show-status-overridden", + show_status_to_string(m->show_status_overridden)); + + if (m->log_level_overridden) + (void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level()); + if (m->log_target_overridden) + (void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target())); + + (void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]); + (void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]); + (void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]); + + for (ManagerTimestamp q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) { + _cleanup_free_ char *joined = NULL; + + if (!manager_timestamp_shall_serialize(q)) + continue; + + joined = strjoin(manager_timestamp_to_string(q), "-timestamp"); + if (!joined) + return log_oom(); + + (void) serialize_dual_timestamp(f, joined, m->timestamps + q); + } + + if (!switching_root) + (void) serialize_strv(f, "env", m->client_environment); + + if (m->notify_fd >= 0) { + r = serialize_fd(f, fds, "notify-fd", m->notify_fd); + if (r < 0) + return r; + + (void) serialize_item(f, "notify-socket", m->notify_socket); + } + + if (m->cgroups_agent_fd >= 0) { + r = serialize_fd(f, fds, "cgroups-agent-fd", m->cgroups_agent_fd); + if (r < 0) + return r; + } + + if (m->user_lookup_fds[0] >= 0) { + int copy0, copy1; + + copy0 = fdset_put_dup(fds, m->user_lookup_fds[0]); + if (copy0 < 0) + return log_error_errno(copy0, "Failed to add user lookup fd to serialization: %m"); + + copy1 = fdset_put_dup(fds, m->user_lookup_fds[1]); + if (copy1 < 0) + return log_error_errno(copy1, "Failed to add user lookup fd to serialization: %m"); + + (void) serialize_item_format(f, "user-lookup", "%i %i", copy0, copy1); + } + + bus_track_serialize(m->subscribed, f, "subscribed"); + + r = dynamic_user_serialize(m, f, fds); + if (r < 0) + return r; + + manager_serialize_uid_refs(m, f); + manager_serialize_gid_refs(m, f); + + r = exec_runtime_serialize(m, f, fds); + if (r < 0) + return r; + + (void) fputc('\n', f); + + HASHMAP_FOREACH_KEY(u, t, m->units) { + if (u->id != t) + continue; + + r = unit_serialize(u, f, fds, switching_root); + if (r < 0) + return r; + } + + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to flush serialization: %m"); + + r = bus_fdset_add_all(m, fds); + if (r < 0) + return log_error_errno(r, "Failed to add bus sockets to serialization: %m"); + + return 0; +} + +static int manager_deserialize_one_unit(Manager *m, const char *name, FILE *f, FDSet *fds) { + Unit *u; + int r; + + r = manager_load_unit(m, name, NULL, NULL, &u); + if (r < 0) { + if (r == -ENOMEM) + return r; + return log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", name); + } + + r = unit_deserialize(u, f, fds); + if (r < 0) { + if (r == -ENOMEM) + return r; + return log_notice_errno(r, "Failed to deserialize unit \"%s\", skipping: %m", name); + } + + return 0; +} + +static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) { + const char *unit_name; + int r; + + for (;;) { + _cleanup_free_ char *line = NULL; + /* Start marker */ + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read serialization line: %m"); + if (r == 0) + break; + + unit_name = strstrip(line); + + r = manager_deserialize_one_unit(m, unit_name, f, fds); + if (r == -ENOMEM) + return r; + if (r < 0) { + r = unit_deserialize_skip(f); + if (r < 0) + return r; + } + } + + return 0; +} + +static void manager_deserialize_uid_refs_one_internal( + Hashmap** uid_refs, + const char *value) { + + uid_t uid; + uint32_t c; + int r; + + assert(uid_refs); + assert(value); + + r = parse_uid(value, &uid); + if (r < 0 || uid == 0) { + log_debug("Unable to parse UID/GID reference serialization: " UID_FMT, uid); + return; + } + + if (hashmap_ensure_allocated(uid_refs, &trivial_hash_ops) < 0) { + log_oom(); + return; + } + + c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid))); + if (c & DESTROY_IPC_FLAG) + return; + + c |= DESTROY_IPC_FLAG; + + r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c)); + if (r < 0) { + log_debug_errno(r, "Failed to add UID/GID reference entry: %m"); + return; + } +} + +static void manager_deserialize_uid_refs_one(Manager *m, const char *value) { + manager_deserialize_uid_refs_one_internal(&m->uid_refs, value); +} + +static void manager_deserialize_gid_refs_one(Manager *m, const char *value) { + manager_deserialize_uid_refs_one_internal(&m->gid_refs, value); +} + +int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { + int r = 0; + + assert(m); + assert(f); + + if (DEBUG_LOGGING) { + if (fdset_isempty(fds)) + log_debug("No file descriptors passed"); + else { + int fd; + + FDSET_FOREACH(fd, fds) { + _cleanup_free_ char *fn = NULL; + + r = fd_get_path(fd, &fn); + if (r < 0) + log_debug_errno(r, "Received serialized fd %i → %m", fd); + else + log_debug("Received serialized fd %i → %s", fd, strna(fn)); + } + } + } + + log_debug("Deserializing state..."); + + /* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have + * increased it to non-zero, which is why we just increase it by one here and down again at the end of this + * call. */ + _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m); + + for (;;) { + _cleanup_free_ char *line = NULL; + const char *val, *l; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read serialization line: %m"); + if (r == 0) + break; + + l = strstrip(line); + if (isempty(l)) /* end marker */ + break; + + if ((val = startswith(l, "current-job-id="))) { + uint32_t id; + + if (safe_atou32(val, &id) < 0) + log_notice("Failed to parse current job id value '%s', ignoring.", val); + else + m->current_job_id = MAX(m->current_job_id, id); + + } else if ((val = startswith(l, "n-installed-jobs="))) { + uint32_t n; + + if (safe_atou32(val, &n) < 0) + log_notice("Failed to parse installed jobs counter '%s', ignoring.", val); + else + m->n_installed_jobs += n; + + } else if ((val = startswith(l, "n-failed-jobs="))) { + uint32_t n; + + if (safe_atou32(val, &n) < 0) + log_notice("Failed to parse failed jobs counter '%s', ignoring.", val); + else + m->n_failed_jobs += n; + + } else if ((val = startswith(l, "taint-usr="))) { + int b; + + b = parse_boolean(val); + if (b < 0) + log_notice("Failed to parse taint /usr flag '%s', ignoring.", val); + else + m->taint_usr = m->taint_usr || b; + + } 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', ignoring.", val); + else + m->ready_sent = m->ready_sent || b; + + } else if ((val = startswith(l, "taint-logged="))) { + int b; + + b = parse_boolean(val); + if (b < 0) + log_notice("Failed to parse taint-logged flag '%s', ignoring.", val); + else + m->taint_logged = m->taint_logged || b; + + } else if ((val = startswith(l, "service-watchdogs="))) { + int b; + + b = parse_boolean(val); + if (b < 0) + log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val); + else + m->service_watchdogs = b; + + } else if ((val = startswith(l, "honor-device-enumeration="))) { + int b; + + b = parse_boolean(val); + if (b < 0) + log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val); + else + m->honor_device_enumeration = b; + + } else if ((val = startswith(l, "show-status-overridden="))) { + ShowStatus s; + + s = show_status_from_string(val); + if (s < 0) + log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val); + else + manager_override_show_status(m, s, "deserialize"); + + } else if ((val = startswith(l, "log-level-override="))) { + int level; + + level = log_level_from_string(val); + if (level < 0) + log_notice("Failed to parse log-level-override value '%s', ignoring.", val); + else + manager_override_log_level(m, level); + + } else if ((val = startswith(l, "log-target-override="))) { + LogTarget target; + + target = log_target_from_string(val); + if (target < 0) + log_notice("Failed to parse log-target-override value '%s', ignoring.", val); + else + manager_override_log_target(m, target); + + } else if ((val = startswith(l, "runtime-watchdog-overridden="))) { + usec_t t; + + if (deserialize_usec(val, &t) < 0) + log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val); + else + manager_override_watchdog(m, WATCHDOG_RUNTIME, t); + + } else if ((val = startswith(l, "reboot-watchdog-overridden="))) { + usec_t t; + + if (deserialize_usec(val, &t) < 0) + log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val); + else + manager_override_watchdog(m, WATCHDOG_REBOOT, t); + + } else if ((val = startswith(l, "kexec-watchdog-overridden="))) { + usec_t t; + + if (deserialize_usec(val, &t) < 0) + log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val); + else + manager_override_watchdog(m, WATCHDOG_KEXEC, t); + + } else if (startswith(l, "env=")) { + r = deserialize_environment(l + 4, &m->client_environment); + if (r < 0) + log_notice_errno(r, "Failed to parse environment entry: \"%s\", ignoring: %m", l); + + } else if ((val = startswith(l, "notify-fd="))) { + int fd; + + if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_notice("Failed to parse notify fd, ignoring: \"%s\"", val); + else { + m->notify_event_source = sd_event_source_disable_unref(m->notify_event_source); + safe_close(m->notify_fd); + m->notify_fd = fdset_remove(fds, fd); + } + + } else if ((val = startswith(l, "notify-socket="))) { + r = free_and_strdup(&m->notify_socket, val); + if (r < 0) + return r; + + } else if ((val = startswith(l, "cgroups-agent-fd="))) { + int fd; + + if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_notice("Failed to parse cgroups agent fd, ignoring.: %s", val); + else { + m->cgroups_agent_event_source = sd_event_source_disable_unref(m->cgroups_agent_event_source); + safe_close(m->cgroups_agent_fd); + m->cgroups_agent_fd = fdset_remove(fds, fd); + } + + } else if ((val = startswith(l, "user-lookup="))) { + int fd0, fd1; + + if (sscanf(val, "%i %i", &fd0, &fd1) != 2 || fd0 < 0 || fd1 < 0 || fd0 == fd1 || !fdset_contains(fds, fd0) || !fdset_contains(fds, fd1)) + log_notice("Failed to parse user lookup fd, ignoring: %s", val); + else { + m->user_lookup_event_source = sd_event_source_disable_unref(m->user_lookup_event_source); + safe_close_pair(m->user_lookup_fds); + m->user_lookup_fds[0] = fdset_remove(fds, fd0); + m->user_lookup_fds[1] = fdset_remove(fds, fd1); + } + + } 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, "exec-runtime="))) + (void) exec_runtime_deserialize_one(m, val, fds); + else if ((val = startswith(l, "subscribed="))) { + + if (strv_extend(&m->deserialized_subscribed, val) < 0) + return -ENOMEM; + + } else { + ManagerTimestamp q; + + 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 */ + (void) deserialize_dual_timestamp(val, m->timestamps + q); + else if (!startswith(l, "kdbus-fd=")) /* ignore kdbus */ + log_notice("Unknown serialization item '%s', ignoring.", l); + } + } + + return manager_deserialize_units(m, f, fds); +} diff --git a/src/core/manager-serialize.h b/src/core/manager-serialize.h new file mode 100644 index 0000000000..c52261e378 --- /dev/null +++ b/src/core/manager-serialize.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <stdbool.h> + +#include "manager.h" +#include "fdset.h" + +#define DESTROY_IPC_FLAG (UINT32_C(1) << 31) + +int manager_open_serialization(Manager *m, FILE **ret_f); +int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root); +int manager_deserialize(Manager *m, FILE *f, FDSet *fds); diff --git a/src/core/manager.c b/src/core/manager.c index 18bdd83342..a3607ea44f 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -56,6 +56,7 @@ #include "macro.h" #include "manager.h" #include "manager-dump.h" +#include "manager-serialize.h" #include "memory-util.h" #include "mkdir.h" #include "parse-util.h" @@ -66,7 +67,6 @@ #include "rlimit-util.h" #include "rm-rf.h" #include "selinux-util.h" -#include "serialize.h" #include "signal-util.h" #include "socket-util.h" #include "special.h" @@ -82,7 +82,6 @@ #include "transaction.h" #include "umask-util.h" #include "unit-name.h" -#include "unit-serialize.h" #include "user-util.h" #include "virt.h" #include "watchdog.h" @@ -118,9 +117,19 @@ static int manager_run_generators(Manager *m); static void manager_vacuum(Manager *m); static usec_t manager_watch_jobs_next_time(Manager *m) { - return usec_add(now(CLOCK_MONOTONIC), - show_status_on(m->show_status) ? JOBS_IN_PROGRESS_WAIT_USEC : - JOBS_IN_PROGRESS_QUIET_WAIT_USEC); + usec_t timeout; + + if (MANAGER_IS_USER(m)) + /* Let the user manager without a timeout show status quickly, so the system manager can make + * use of it, if it wants to. */ + timeout = JOBS_IN_PROGRESS_WAIT_USEC * 2 / 3; + else if (show_status_on(m->show_status)) + /* When status is on, just use the usual timeout. */ + timeout = JOBS_IN_PROGRESS_WAIT_USEC; + else + timeout = JOBS_IN_PROGRESS_QUIET_WAIT_USEC; + + return usec_add(now(CLOCK_MONOTONIC), timeout); } static void manager_watch_jobs_in_progress(Manager *m) { @@ -200,7 +209,6 @@ static void manager_flip_auto_status(Manager *m, bool enable, const char *reason } static void manager_print_jobs_in_progress(Manager *m) { - _cleanup_free_ char *job_of_n = NULL; Job *j; unsigned counter = 0, print_nr; char cylon[6 + CYLON_BUFFER_EXTRA + 1]; @@ -230,26 +238,51 @@ static void manager_print_jobs_in_progress(Manager *m) { m->jobs_in_progress_iteration++; + char job_of_n[STRLEN("( of ) ") + DECIMAL_STR_MAX(unsigned)*2] = ""; if (m->n_running_jobs > 1) - if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0) - job_of_n = NULL; + xsprintf(job_of_n, "(%u of %u) ", counter, m->n_running_jobs); bool have_timeout = job_get_timeout(j, &x) > 0; /* We want to use enough information for the user to identify previous lines talking about the same * unit, but keep the message as short as possible. So if 'Starting foo.service' or 'Starting - * foo.service (Description)' were used, 'foo.service' is enough here. On the other hand, if we used + * foo.service - Description' were used, 'foo.service' is enough here. On the other hand, if we used * 'Starting Description' before, then we shall also use 'Description' here. So we pass NULL as the * second argument to unit_status_string(). */ const char *ident = unit_status_string(j->unit, NULL); - manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon, - "%sA %s job is running for %s (%s / %s)", - strempty(job_of_n), - job_type_to_string(j->type), - ident, - FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC), - have_timeout ? FORMAT_TIMESPAN(x - j->begin_usec, 1*USEC_PER_SEC) : "no limit"); + const char *time = FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC); + const char *limit = have_timeout ? FORMAT_TIMESPAN(x - j->begin_usec, 1*USEC_PER_SEC) : "no limit"; + + if (m->status_unit_format == STATUS_UNIT_FORMAT_DESCRIPTION) + /* When using 'Description', we effectively don't have enough space to show the nested status + * without ellipsization, so let's not even try. */ + manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon, + "%sA %s job is running for %s (%s / %s)", + job_of_n, + job_type_to_string(j->type), + ident, + time, limit); + else { + const char *status_text = unit_status_text(j->unit); + + manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon, + "%sJob %s/%s running (%s / %s)%s%s", + job_of_n, + ident, + job_type_to_string(j->type), + time, limit, + status_text ? ": " : "", + strempty(status_text)); + } + + sd_notifyf(false, + "STATUS=%sUser job %s/%s running (%s / %s)...", + job_of_n, + ident, + job_type_to_string(j->type), + time, limit); + m->status_ready = false; } static int have_ask_password(void) { @@ -621,9 +654,7 @@ static char** sanitize_environment(char **l) { NULL); /* Let's order the environment alphabetically, just to make it pretty */ - strv_sort(l); - - return l; + return strv_sort(l); } int manager_default_environment(Manager *m) { @@ -1686,11 +1717,11 @@ static void manager_ready(Manager *m) { m->honor_device_enumeration = true; } -static Manager* manager_reloading_start(Manager *m) { +Manager* manager_reloading_start(Manager *m) { m->n_reloading++; return m; } -static void manager_reloading_stopp(Manager **m) { +void manager_reloading_stopp(Manager **m) { if (*m) { assert((*m)->n_reloading > 0); (*m)->n_reloading--; @@ -2616,15 +2647,19 @@ turn_off: return 0; } -static void manager_start_target(Manager *m, const char *name, JobMode mode) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - int r; +static void manager_start_special(Manager *m, const char *name, JobMode mode) { + Job *job; - log_debug("Activating special unit %s", name); + if (manager_add_job_by_name_and_warn(m, JOB_START, name, mode, NULL, &job) < 0) + return; - r = manager_add_job_by_name(m, JOB_START, name, mode, NULL, &error, NULL); - if (r < 0) - log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r)); + const char *s = unit_status_string(job->unit, NULL); + + log_info("Activating special unit %s...", s); + + sd_notifyf(false, + "STATUS=Activating special unit %s...", s); + m->status_ready = false; } static void manager_handle_ctrl_alt_del(Manager *m) { @@ -2633,7 +2668,7 @@ static void manager_handle_ctrl_alt_del(Manager *m) { * unless it was disabled in system.conf */ if (ratelimit_below(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == EMERGENCY_ACTION_NONE) - manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY); + manager_start_special(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY); else emergency_action(m, m->cad_burst_action, EMERGENCY_ACTION_WARN, NULL, -1, "Ctrl-Alt-Del was pressed more than 7 times within 2s"); @@ -2697,21 +2732,20 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t if (MANAGER_IS_SYSTEM(m)) manager_handle_ctrl_alt_del(m); else - manager_start_target(m, SPECIAL_EXIT_TARGET, - JOB_REPLACE_IRREVERSIBLY); + manager_start_special(m, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY); break; case SIGWINCH: /* This is a nop on non-init */ if (MANAGER_IS_SYSTEM(m)) - manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE); + manager_start_special(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE); break; case SIGPWR: /* This is a nop on non-init */ if (MANAGER_IS_SYSTEM(m)) - manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE); + manager_start_special(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE); break; @@ -2723,10 +2757,8 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t if (MANAGER_IS_SYSTEM(m)) (void) bus_init_system(m); - } else { - log_info("Starting D-Bus service..."); - manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE); - } + } else + manager_start_special(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE); break; @@ -2777,8 +2809,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t if ((int) sfsi.ssi_signo >= SIGRTMIN+0 && (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) { int idx = (int) sfsi.ssi_signo - SIGRTMIN; - manager_start_target(m, target_table[idx].target, - target_table[idx].mode); + manager_start_special(m, target_table[idx].target, target_table[idx].mode); break; } @@ -3143,10 +3174,8 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) { return; } - if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) { - log_oom(); - return; - } + if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) + return (void) log_oom(); errno = 0; if (write(fd, message, n + 1) != n + 1) @@ -3154,242 +3183,6 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) { log_error_errno(errno, "Failed to write Plymouth message: %m"); } -int manager_open_serialization(Manager *m, FILE **_f) { - _cleanup_close_ int fd = -1; - FILE *f; - - assert(_f); - - fd = open_serialization_fd("systemd-state"); - if (fd < 0) - return fd; - - f = take_fdopen(&fd, "w+"); - if (!f) - return -errno; - - *_f = f; - return 0; -} - -static bool manager_timestamp_shall_serialize(ManagerTimestamp t) { - - if (!in_initrd()) - return true; - - /* The following timestamps only apply to the host system, hence only serialize them there */ - return !IN_SET(t, - MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH, - MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH, - MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH, - MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH); -} - -#define DESTROY_IPC_FLAG (UINT32_C(1) << 31) - -static void manager_serialize_uid_refs_internal( - FILE *f, - Hashmap *uid_refs, - const char *field_name) { - - void *p, *k; - - assert(f); - assert(field_name); - - /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as - * the actual counter of it is better rebuild after a reload/reexec. */ - - HASHMAP_FOREACH_KEY(p, k, uid_refs) { - uint32_t c; - uid_t uid; - - uid = PTR_TO_UID(k); - c = PTR_TO_UINT32(p); - - if (!(c & DESTROY_IPC_FLAG)) - continue; - - (void) serialize_item_format(f, field_name, UID_FMT, uid); - } -} - -static void manager_serialize_uid_refs(Manager *m, FILE *f) { - manager_serialize_uid_refs_internal(f, m->uid_refs, "destroy-ipc-uid"); -} - -static void manager_serialize_gid_refs(Manager *m, FILE *f) { - manager_serialize_uid_refs_internal(f, m->gid_refs, "destroy-ipc-gid"); -} - -int manager_serialize( - Manager *m, - FILE *f, - FDSet *fds, - bool switching_root) { - - const char *t; - Unit *u; - int r; - - assert(m); - assert(f); - assert(fds); - - _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m); - - (void) serialize_item_format(f, "current-job-id", "%" PRIu32, m->current_job_id); - (void) serialize_item_format(f, "n-installed-jobs", "%u", m->n_installed_jobs); - (void) serialize_item_format(f, "n-failed-jobs", "%u", m->n_failed_jobs); - (void) serialize_bool(f, "taint-usr", m->taint_usr); - (void) serialize_bool(f, "ready-sent", m->ready_sent); - (void) serialize_bool(f, "taint-logged", m->taint_logged); - (void) serialize_bool(f, "service-watchdogs", m->service_watchdogs); - - /* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */ - (void) serialize_bool(f, "honor-device-enumeration", !switching_root); - - if (m->show_status_overridden != _SHOW_STATUS_INVALID) - (void) serialize_item(f, "show-status-overridden", - show_status_to_string(m->show_status_overridden)); - - if (m->log_level_overridden) - (void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level()); - if (m->log_target_overridden) - (void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target())); - - (void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]); - (void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]); - (void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]); - - for (ManagerTimestamp q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) { - _cleanup_free_ char *joined = NULL; - - if (!manager_timestamp_shall_serialize(q)) - continue; - - joined = strjoin(manager_timestamp_to_string(q), "-timestamp"); - if (!joined) - return log_oom(); - - (void) serialize_dual_timestamp(f, joined, m->timestamps + q); - } - - if (!switching_root) - (void) serialize_strv(f, "env", m->client_environment); - - if (m->notify_fd >= 0) { - r = serialize_fd(f, fds, "notify-fd", m->notify_fd); - if (r < 0) - return r; - - (void) serialize_item(f, "notify-socket", m->notify_socket); - } - - if (m->cgroups_agent_fd >= 0) { - r = serialize_fd(f, fds, "cgroups-agent-fd", m->cgroups_agent_fd); - if (r < 0) - return r; - } - - if (m->user_lookup_fds[0] >= 0) { - int copy0, copy1; - - copy0 = fdset_put_dup(fds, m->user_lookup_fds[0]); - if (copy0 < 0) - return log_error_errno(copy0, "Failed to add user lookup fd to serialization: %m"); - - copy1 = fdset_put_dup(fds, m->user_lookup_fds[1]); - if (copy1 < 0) - return log_error_errno(copy1, "Failed to add user lookup fd to serialization: %m"); - - (void) serialize_item_format(f, "user-lookup", "%i %i", copy0, copy1); - } - - bus_track_serialize(m->subscribed, f, "subscribed"); - - r = dynamic_user_serialize(m, f, fds); - if (r < 0) - return r; - - manager_serialize_uid_refs(m, f); - manager_serialize_gid_refs(m, f); - - r = exec_runtime_serialize(m, f, fds); - if (r < 0) - return r; - - (void) fputc('\n', f); - - HASHMAP_FOREACH_KEY(u, t, m->units) { - if (u->id != t) - continue; - - r = unit_serialize(u, f, fds, switching_root); - if (r < 0) - return r; - } - - r = fflush_and_check(f); - if (r < 0) - return log_error_errno(r, "Failed to flush serialization: %m"); - - r = bus_fdset_add_all(m, fds); - if (r < 0) - return log_error_errno(r, "Failed to add bus sockets to serialization: %m"); - - return 0; -} - -static int manager_deserialize_one_unit(Manager *m, const char *name, FILE *f, FDSet *fds) { - Unit *u; - int r; - - r = manager_load_unit(m, name, NULL, NULL, &u); - if (r < 0) { - if (r == -ENOMEM) - return r; - return log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", name); - } - - r = unit_deserialize(u, f, fds); - if (r < 0) { - if (r == -ENOMEM) - return r; - return log_notice_errno(r, "Failed to deserialize unit \"%s\", skipping: %m", name); - } - - return 0; -} - -static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) { - const char *unit_name; - int r; - - for (;;) { - _cleanup_free_ char *line = NULL; - /* Start marker */ - r = read_line(f, LONG_LINE_MAX, &line); - if (r < 0) - return log_error_errno(r, "Failed to read serialization line: %m"); - if (r == 0) - break; - - unit_name = strstrip(line); - - r = manager_deserialize_one_unit(m, unit_name, f, fds); - if (r == -ENOMEM) - return r; - if (r < 0) { - r = unit_deserialize_skip(f); - if (r < 0) - return r; - } - } - - return 0; -} - usec_t manager_get_watchdog(Manager *m, WatchdogType t) { assert(m); @@ -3474,294 +3267,6 @@ void manager_retry_runtime_watchdog(Manager *m) { m->runtime_watchdog_running = true; } -static void manager_deserialize_uid_refs_one_internal( - Hashmap** uid_refs, - const char *value) { - - uid_t uid; - uint32_t c; - int r; - - assert(uid_refs); - assert(value); - - r = parse_uid(value, &uid); - if (r < 0 || uid == 0) { - log_debug("Unable to parse UID/GID reference serialization: " UID_FMT, uid); - return; - } - - if (hashmap_ensure_allocated(uid_refs, &trivial_hash_ops) < 0) { - log_oom(); - return; - } - - c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid))); - if (c & DESTROY_IPC_FLAG) - return; - - c |= DESTROY_IPC_FLAG; - - r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c)); - if (r < 0) { - log_debug_errno(r, "Failed to add UID/GID reference entry: %m"); - return; - } -} - -static void manager_deserialize_uid_refs_one(Manager *m, const char *value) { - manager_deserialize_uid_refs_one_internal(&m->uid_refs, value); -} - -static void manager_deserialize_gid_refs_one(Manager *m, const char *value) { - manager_deserialize_uid_refs_one_internal(&m->gid_refs, value); -} - -int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { - int r = 0; - - assert(m); - assert(f); - - if (DEBUG_LOGGING) { - if (fdset_isempty(fds)) - log_debug("No file descriptors passed"); - else { - int fd; - - FDSET_FOREACH(fd, fds) { - _cleanup_free_ char *fn = NULL; - - r = fd_get_path(fd, &fn); - if (r < 0) - log_debug_errno(r, "Received serialized fd %i → %m", fd); - else - log_debug("Received serialized fd %i → %s", fd, strna(fn)); - } - } - } - - log_debug("Deserializing state..."); - - /* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have - * increased it to non-zero, which is why we just increase it by one here and down again at the end of this - * call. */ - _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m); - - for (;;) { - _cleanup_free_ char *line = NULL; - const char *val, *l; - - r = read_line(f, LONG_LINE_MAX, &line); - if (r < 0) - return log_error_errno(r, "Failed to read serialization line: %m"); - if (r == 0) - break; - - l = strstrip(line); - if (isempty(l)) /* end marker */ - break; - - if ((val = startswith(l, "current-job-id="))) { - uint32_t id; - - if (safe_atou32(val, &id) < 0) - log_notice("Failed to parse current job id value '%s', ignoring.", val); - else - m->current_job_id = MAX(m->current_job_id, id); - - } else if ((val = startswith(l, "n-installed-jobs="))) { - uint32_t n; - - if (safe_atou32(val, &n) < 0) - log_notice("Failed to parse installed jobs counter '%s', ignoring.", val); - else - m->n_installed_jobs += n; - - } else if ((val = startswith(l, "n-failed-jobs="))) { - uint32_t n; - - if (safe_atou32(val, &n) < 0) - log_notice("Failed to parse failed jobs counter '%s', ignoring.", val); - else - m->n_failed_jobs += n; - - } else if ((val = startswith(l, "taint-usr="))) { - int b; - - b = parse_boolean(val); - if (b < 0) - log_notice("Failed to parse taint /usr flag '%s', ignoring.", val); - else - m->taint_usr = m->taint_usr || b; - - } 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', ignoring.", val); - else - m->ready_sent = m->ready_sent || b; - - } else if ((val = startswith(l, "taint-logged="))) { - int b; - - b = parse_boolean(val); - if (b < 0) - log_notice("Failed to parse taint-logged flag '%s', ignoring.", val); - else - m->taint_logged = m->taint_logged || b; - - } else if ((val = startswith(l, "service-watchdogs="))) { - int b; - - b = parse_boolean(val); - if (b < 0) - log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val); - else - m->service_watchdogs = b; - - } else if ((val = startswith(l, "honor-device-enumeration="))) { - int b; - - b = parse_boolean(val); - if (b < 0) - log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val); - else - m->honor_device_enumeration = b; - - } else if ((val = startswith(l, "show-status-overridden="))) { - ShowStatus s; - - s = show_status_from_string(val); - if (s < 0) - log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val); - else - manager_override_show_status(m, s, "deserialize"); - - } else if ((val = startswith(l, "log-level-override="))) { - int level; - - level = log_level_from_string(val); - if (level < 0) - log_notice("Failed to parse log-level-override value '%s', ignoring.", val); - else - manager_override_log_level(m, level); - - } else if ((val = startswith(l, "log-target-override="))) { - LogTarget target; - - target = log_target_from_string(val); - if (target < 0) - log_notice("Failed to parse log-target-override value '%s', ignoring.", val); - else - manager_override_log_target(m, target); - - } else if ((val = startswith(l, "runtime-watchdog-overridden="))) { - usec_t t; - - if (deserialize_usec(val, &t) < 0) - log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val); - else - manager_override_watchdog(m, WATCHDOG_RUNTIME, t); - - } else if ((val = startswith(l, "reboot-watchdog-overridden="))) { - usec_t t; - - if (deserialize_usec(val, &t) < 0) - log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val); - else - manager_override_watchdog(m, WATCHDOG_REBOOT, t); - - } else if ((val = startswith(l, "kexec-watchdog-overridden="))) { - usec_t t; - - if (deserialize_usec(val, &t) < 0) - log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val); - else - manager_override_watchdog(m, WATCHDOG_KEXEC, t); - - } else if (startswith(l, "env=")) { - r = deserialize_environment(l + 4, &m->client_environment); - if (r < 0) - log_notice_errno(r, "Failed to parse environment entry: \"%s\", ignoring: %m", l); - - } else if ((val = startswith(l, "notify-fd="))) { - int fd; - - if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) - log_notice("Failed to parse notify fd, ignoring: \"%s\"", val); - else { - m->notify_event_source = sd_event_source_disable_unref(m->notify_event_source); - safe_close(m->notify_fd); - m->notify_fd = fdset_remove(fds, fd); - } - - } else if ((val = startswith(l, "notify-socket="))) { - r = free_and_strdup(&m->notify_socket, val); - if (r < 0) - return r; - - } else if ((val = startswith(l, "cgroups-agent-fd="))) { - int fd; - - if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) - log_notice("Failed to parse cgroups agent fd, ignoring.: %s", val); - else { - m->cgroups_agent_event_source = sd_event_source_disable_unref(m->cgroups_agent_event_source); - safe_close(m->cgroups_agent_fd); - m->cgroups_agent_fd = fdset_remove(fds, fd); - } - - } else if ((val = startswith(l, "user-lookup="))) { - int fd0, fd1; - - if (sscanf(val, "%i %i", &fd0, &fd1) != 2 || fd0 < 0 || fd1 < 0 || fd0 == fd1 || !fdset_contains(fds, fd0) || !fdset_contains(fds, fd1)) - log_notice("Failed to parse user lookup fd, ignoring: %s", val); - else { - m->user_lookup_event_source = sd_event_source_disable_unref(m->user_lookup_event_source); - safe_close_pair(m->user_lookup_fds); - m->user_lookup_fds[0] = fdset_remove(fds, fd0); - m->user_lookup_fds[1] = fdset_remove(fds, fd1); - } - - } 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, "exec-runtime="))) - (void) exec_runtime_deserialize_one(m, val, fds); - else if ((val = startswith(l, "subscribed="))) { - - if (strv_extend(&m->deserialized_subscribed, val) < 0) - return -ENOMEM; - - } else { - ManagerTimestamp q; - - 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 */ - (void) deserialize_dual_timestamp(val, m->timestamps + q); - else if (!startswith(l, "kdbus-fd=")) /* ignore kdbus */ - log_notice("Unknown serialization item '%s', ignoring.", l); - } - } - - return manager_deserialize_units(m, f, fds); -} - int manager_reload(Manager *m) { _cleanup_(manager_reloading_stopp) Manager *reloading = NULL; _cleanup_fdset_free_ FDSet *fds = NULL; @@ -3974,28 +3479,32 @@ 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, - m->ready_sent ? "STATUS=Startup finished in %s." - : "READY=1\n" - "STATUS=Startup finished in %s.", - FORMAT_TIMESPAN(total_usec, USEC_PER_MSEC)); - m->ready_sent = true; - log_taint_string(m); } -static void manager_send_ready(Manager *m) { +static void user_manager_send_ready(Manager *m) { assert(m); /* We send READY=1 on reaching basic.target only when running in --user mode. */ if (!MANAGER_IS_USER(m) || m->ready_sent) return; - m->ready_sent = true; - sd_notifyf(false, "READY=1\n" "STATUS=Reached " SPECIAL_BASIC_TARGET "."); + m->ready_sent = true; + m->status_ready = false; +} + +static void manager_send_ready(Manager *m) { + if (m->ready_sent && m->status_ready) + /* Skip the notification if nothing changed. */ + return; + + sd_notifyf(false, + "%sSTATUS=Ready.", + m->ready_sent ? "READY=1\n" : ""); + m->ready_sent = m->status_ready = true; } static void manager_check_basic_target(Manager *m) { @@ -4012,7 +3521,7 @@ static void manager_check_basic_target(Manager *m) { return; /* For user managers, send out READY=1 as soon as we reach basic.target */ - manager_send_ready(m); + user_manager_send_ready(m); /* Log the taint string as soon as we reach basic.target */ log_taint_string(m); @@ -4043,6 +3552,11 @@ void manager_check_finished(Manager *m) { if (hashmap_buckets(m->jobs) > hashmap_size(m->units) / 10) m->jobs = hashmap_free(m->jobs); + manager_send_ready(m); + + if (MANAGER_IS_FINISHED(m)) + return; + manager_flip_auto_status(m, false, "boot finished"); /* Notify Type=idle units that we are done now */ @@ -4057,9 +3571,6 @@ void manager_check_finished(Manager *m) { /* This is no longer the first boot */ manager_set_first_boot(m, false); - if (MANAGER_IS_FINISHED(m)) - return; - dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_FINISH); manager_notify_finished(m); @@ -4929,33 +4440,33 @@ ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s) { static const char *const manager_state_table[_MANAGER_STATE_MAX] = { [MANAGER_INITIALIZING] = "initializing", - [MANAGER_STARTING] = "starting", - [MANAGER_RUNNING] = "running", - [MANAGER_DEGRADED] = "degraded", - [MANAGER_MAINTENANCE] = "maintenance", - [MANAGER_STOPPING] = "stopping", + [MANAGER_STARTING] = "starting", + [MANAGER_RUNNING] = "running", + [MANAGER_DEGRADED] = "degraded", + [MANAGER_MAINTENANCE] = "maintenance", + [MANAGER_STOPPING] = "stopping", }; 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", - [MANAGER_TIMESTAMP_INITRD_SECURITY_START] = "initrd-security-start", - [MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH] = "initrd-security-finish", - [MANAGER_TIMESTAMP_INITRD_GENERATORS_START] = "initrd-generators-start", + [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", + [MANAGER_TIMESTAMP_INITRD_SECURITY_START] = "initrd-security-start", + [MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH] = "initrd-security-finish", + [MANAGER_TIMESTAMP_INITRD_GENERATORS_START] = "initrd-generators-start", [MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH] = "initrd-generators-finish", - [MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START] = "initrd-units-load-start", + [MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START] = "initrd-units-load-start", [MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH] = "initrd-units-load-finish", }; @@ -4963,8 +4474,8 @@ DEFINE_STRING_TABLE_LOOKUP(manager_timestamp, ManagerTimestamp); static const char* const oom_policy_table[_OOM_POLICY_MAX] = { [OOM_CONTINUE] = "continue", - [OOM_STOP] = "stop", - [OOM_KILL] = "kill", + [OOM_STOP] = "stop", + [OOM_KILL] = "kill", }; DEFINE_STRING_TABLE_LOOKUP(oom_policy, OOMPolicy); diff --git a/src/core/manager.h b/src/core/manager.h index b3e7c68e6d..284ea42a9d 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -329,6 +329,9 @@ struct Manager { /* Have we already sent out the READY=1 notification? */ bool ready_sent; + /* Was the last status sent "STATUS=Ready."? */ + bool status_ready; + /* Have we already printed the taint line if necessary? */ bool taint_logged; @@ -500,12 +503,9 @@ int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit); int manager_loop(Manager *m); -int manager_open_serialization(Manager *m, FILE **_f); - -int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root); -int manager_deserialize(Manager *m, FILE *f, FDSet *fds); - int manager_reload(Manager *m); +Manager* manager_reloading_start(Manager *m); +void manager_reloading_stopp(Manager **m); void manager_reset_failed(Manager *m); diff --git a/src/core/meson.build b/src/core/meson.build index f0d2c6f642..1c364a53e2 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -87,6 +87,8 @@ libcore_sources = ''' locale-setup.h manager-dump.c manager-dump.h + manager-serialize.c + manager-serialize.h manager.c manager.h mount.c diff --git a/src/core/mount.c b/src/core/mount.c index fe0cb2b965..608ead5bc4 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -2139,7 +2139,7 @@ static int mount_can_clean(Unit *u, ExecCleanMask *ret) { } static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { - [MOUNT_EXEC_MOUNT] = "ExecMount", + [MOUNT_EXEC_MOUNT] = "ExecMount", [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", [MOUNT_EXEC_REMOUNT] = "ExecRemount", }; @@ -2147,14 +2147,14 @@ static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand); static const char* const mount_result_table[_MOUNT_RESULT_MAX] = { - [MOUNT_SUCCESS] = "success", - [MOUNT_FAILURE_RESOURCES] = "resources", - [MOUNT_FAILURE_TIMEOUT] = "timeout", - [MOUNT_FAILURE_EXIT_CODE] = "exit-code", - [MOUNT_FAILURE_SIGNAL] = "signal", - [MOUNT_FAILURE_CORE_DUMP] = "core-dump", + [MOUNT_SUCCESS] = "success", + [MOUNT_FAILURE_RESOURCES] = "resources", + [MOUNT_FAILURE_TIMEOUT] = "timeout", + [MOUNT_FAILURE_EXIT_CODE] = "exit-code", + [MOUNT_FAILURE_SIGNAL] = "signal", + [MOUNT_FAILURE_CORE_DUMP] = "core-dump", [MOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", - [MOUNT_FAILURE_PROTOCOL] = "protocol", + [MOUNT_FAILURE_PROTOCOL] = "protocol", }; DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult); diff --git a/src/core/path.c b/src/core/path.c index 87930f637f..800524a308 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -813,19 +813,19 @@ static void path_reset_failed(Unit *u) { } static const char* const path_type_table[_PATH_TYPE_MAX] = { - [PATH_EXISTS] = "PathExists", - [PATH_EXISTS_GLOB] = "PathExistsGlob", + [PATH_EXISTS] = "PathExists", + [PATH_EXISTS_GLOB] = "PathExistsGlob", [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty", - [PATH_CHANGED] = "PathChanged", - [PATH_MODIFIED] = "PathModified", + [PATH_CHANGED] = "PathChanged", + [PATH_MODIFIED] = "PathModified", }; DEFINE_STRING_TABLE_LOOKUP(path_type, PathType); static const char* const path_result_table[_PATH_RESULT_MAX] = { - [PATH_SUCCESS] = "success", - [PATH_FAILURE_RESOURCES] = "resources", - [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [PATH_SUCCESS] = "success", + [PATH_FAILURE_RESOURCES] = "resources", + [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit", }; diff --git a/src/core/scope.c b/src/core/scope.c index b7848a0a5d..1b60af22f3 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -632,9 +632,9 @@ static void scope_enumerate_perpetual(Manager *m) { } static const char* const scope_result_table[_SCOPE_RESULT_MAX] = { - [SCOPE_SUCCESS] = "success", + [SCOPE_SUCCESS] = "success", [SCOPE_FAILURE_RESOURCES] = "resources", - [SCOPE_FAILURE_TIMEOUT] = "timeout", + [SCOPE_FAILURE_TIMEOUT] = "timeout", }; DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult); diff --git a/src/core/service.c b/src/core/service.c index a015df83f4..f4a79dc2af 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -4379,6 +4379,14 @@ static int service_exit_status(Unit *u) { return s->main_exec_status.status; } +static const char* service_status_text(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + + return s->status_text; +} + static int service_clean(Unit *u, ExecCleanMask mask) { _cleanup_strv_free_ char **l = NULL; Service *s = SERVICE(u); @@ -4440,82 +4448,82 @@ static const char *service_finished_job(Unit *u, JobType t, JobResult result) { } static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { - [SERVICE_RESTART_NO] = "no", - [SERVICE_RESTART_ON_SUCCESS] = "on-success", - [SERVICE_RESTART_ON_FAILURE] = "on-failure", + [SERVICE_RESTART_NO] = "no", + [SERVICE_RESTART_ON_SUCCESS] = "on-success", + [SERVICE_RESTART_ON_FAILURE] = "on-failure", [SERVICE_RESTART_ON_ABNORMAL] = "on-abnormal", [SERVICE_RESTART_ON_WATCHDOG] = "on-watchdog", - [SERVICE_RESTART_ON_ABORT] = "on-abort", - [SERVICE_RESTART_ALWAYS] = "always", + [SERVICE_RESTART_ON_ABORT] = "on-abort", + [SERVICE_RESTART_ALWAYS] = "always", }; DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart); static const char* const service_type_table[_SERVICE_TYPE_MAX] = { - [SERVICE_SIMPLE] = "simple", + [SERVICE_SIMPLE] = "simple", [SERVICE_FORKING] = "forking", [SERVICE_ONESHOT] = "oneshot", - [SERVICE_DBUS] = "dbus", - [SERVICE_NOTIFY] = "notify", - [SERVICE_IDLE] = "idle", - [SERVICE_EXEC] = "exec", + [SERVICE_DBUS] = "dbus", + [SERVICE_NOTIFY] = "notify", + [SERVICE_IDLE] = "idle", + [SERVICE_EXEC] = "exec", }; DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType); static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = { - [SERVICE_EXEC_CONDITION] = "ExecCondition", - [SERVICE_EXEC_START_PRE] = "ExecStartPre", - [SERVICE_EXEC_START] = "ExecStart", + [SERVICE_EXEC_CONDITION] = "ExecCondition", + [SERVICE_EXEC_START_PRE] = "ExecStartPre", + [SERVICE_EXEC_START] = "ExecStart", [SERVICE_EXEC_START_POST] = "ExecStartPost", - [SERVICE_EXEC_RELOAD] = "ExecReload", - [SERVICE_EXEC_STOP] = "ExecStop", - [SERVICE_EXEC_STOP_POST] = "ExecStopPost", + [SERVICE_EXEC_RELOAD] = "ExecReload", + [SERVICE_EXEC_STOP] = "ExecStop", + [SERVICE_EXEC_STOP_POST] = "ExecStopPost", }; DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand); static const char* const service_exec_ex_command_table[_SERVICE_EXEC_COMMAND_MAX] = { - [SERVICE_EXEC_CONDITION] = "ExecConditionEx", - [SERVICE_EXEC_START_PRE] = "ExecStartPreEx", - [SERVICE_EXEC_START] = "ExecStartEx", + [SERVICE_EXEC_CONDITION] = "ExecConditionEx", + [SERVICE_EXEC_START_PRE] = "ExecStartPreEx", + [SERVICE_EXEC_START] = "ExecStartEx", [SERVICE_EXEC_START_POST] = "ExecStartPostEx", - [SERVICE_EXEC_RELOAD] = "ExecReloadEx", - [SERVICE_EXEC_STOP] = "ExecStopEx", - [SERVICE_EXEC_STOP_POST] = "ExecStopPostEx", + [SERVICE_EXEC_RELOAD] = "ExecReloadEx", + [SERVICE_EXEC_STOP] = "ExecStopEx", + [SERVICE_EXEC_STOP_POST] = "ExecStopPostEx", }; DEFINE_STRING_TABLE_LOOKUP(service_exec_ex_command, ServiceExecCommand); static const char* const notify_state_table[_NOTIFY_STATE_MAX] = { - [NOTIFY_UNKNOWN] = "unknown", - [NOTIFY_READY] = "ready", + [NOTIFY_UNKNOWN] = "unknown", + [NOTIFY_READY] = "ready", [NOTIFY_RELOADING] = "reloading", - [NOTIFY_STOPPING] = "stopping", + [NOTIFY_STOPPING] = "stopping", }; DEFINE_STRING_TABLE_LOOKUP(notify_state, NotifyState); static const char* const service_result_table[_SERVICE_RESULT_MAX] = { - [SERVICE_SUCCESS] = "success", - [SERVICE_FAILURE_RESOURCES] = "resources", - [SERVICE_FAILURE_PROTOCOL] = "protocol", - [SERVICE_FAILURE_TIMEOUT] = "timeout", - [SERVICE_FAILURE_EXIT_CODE] = "exit-code", - [SERVICE_FAILURE_SIGNAL] = "signal", - [SERVICE_FAILURE_CORE_DUMP] = "core-dump", - [SERVICE_FAILURE_WATCHDOG] = "watchdog", + [SERVICE_SUCCESS] = "success", + [SERVICE_FAILURE_RESOURCES] = "resources", + [SERVICE_FAILURE_PROTOCOL] = "protocol", + [SERVICE_FAILURE_TIMEOUT] = "timeout", + [SERVICE_FAILURE_EXIT_CODE] = "exit-code", + [SERVICE_FAILURE_SIGNAL] = "signal", + [SERVICE_FAILURE_CORE_DUMP] = "core-dump", + [SERVICE_FAILURE_WATCHDOG] = "watchdog", [SERVICE_FAILURE_START_LIMIT_HIT] = "start-limit-hit", - [SERVICE_FAILURE_OOM_KILL] = "oom-kill", - [SERVICE_SKIP_CONDITION] = "exec-condition", + [SERVICE_FAILURE_OOM_KILL] = "oom-kill", + [SERVICE_SKIP_CONDITION] = "exec-condition", }; DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult); static const char* const service_timeout_failure_mode_table[_SERVICE_TIMEOUT_FAILURE_MODE_MAX] = { [SERVICE_TIMEOUT_TERMINATE] = "terminate", - [SERVICE_TIMEOUT_ABORT] = "abort", - [SERVICE_TIMEOUT_KILL] = "kill", + [SERVICE_TIMEOUT_ABORT] = "abort", + [SERVICE_TIMEOUT_KILL] = "kill", }; DEFINE_STRING_TABLE_LOOKUP(service_timeout_failure_mode, ServiceTimeoutFailureMode); @@ -4590,6 +4598,7 @@ const UnitVTable service_vtable = { .get_timeout = service_get_timeout, .needs_console = service_needs_console, .exit_status = service_exit_status, + .status_text = service_status_text, .status_message_formats = { .finished_start_job = { diff --git a/src/core/socket.c b/src/core/socket.c index 0ae53e7336..8a2a688450 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -3425,24 +3425,24 @@ static int socket_can_clean(Unit *u, ExecCleanMask *ret) { } static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { - [SOCKET_EXEC_START_PRE] = "ExecStartPre", + [SOCKET_EXEC_START_PRE] = "ExecStartPre", [SOCKET_EXEC_START_CHOWN] = "ExecStartChown", - [SOCKET_EXEC_START_POST] = "ExecStartPost", - [SOCKET_EXEC_STOP_PRE] = "ExecStopPre", - [SOCKET_EXEC_STOP_POST] = "ExecStopPost" + [SOCKET_EXEC_START_POST] = "ExecStartPost", + [SOCKET_EXEC_STOP_PRE] = "ExecStopPre", + [SOCKET_EXEC_STOP_POST] = "ExecStopPost" }; DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand); static const char* const socket_result_table[_SOCKET_RESULT_MAX] = { - [SOCKET_SUCCESS] = "success", - [SOCKET_FAILURE_RESOURCES] = "resources", - [SOCKET_FAILURE_TIMEOUT] = "timeout", - [SOCKET_FAILURE_EXIT_CODE] = "exit-code", - [SOCKET_FAILURE_SIGNAL] = "signal", - [SOCKET_FAILURE_CORE_DUMP] = "core-dump", - [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit", - [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", + [SOCKET_SUCCESS] = "success", + [SOCKET_FAILURE_RESOURCES] = "resources", + [SOCKET_FAILURE_TIMEOUT] = "timeout", + [SOCKET_FAILURE_EXIT_CODE] = "exit-code", + [SOCKET_FAILURE_SIGNAL] = "signal", + [SOCKET_FAILURE_CORE_DUMP] = "core-dump", + [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit" }; @@ -3450,8 +3450,8 @@ DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult); static const char* const socket_timestamping_table[_SOCKET_TIMESTAMPING_MAX] = { [SOCKET_TIMESTAMPING_OFF] = "off", - [SOCKET_TIMESTAMPING_US] = "us", - [SOCKET_TIMESTAMPING_NS] = "ns", + [SOCKET_TIMESTAMPING_US] = "us", + [SOCKET_TIMESTAMPING_NS] = "ns", }; DEFINE_STRING_TABLE_LOOKUP(socket_timestamping, SocketTimestamping); diff --git a/src/core/swap.c b/src/core/swap.c index 81fb3bb2de..d7089f1c55 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1589,19 +1589,19 @@ static int swap_can_clean(Unit *u, ExecCleanMask *ret) { } static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { - [SWAP_EXEC_ACTIVATE] = "ExecActivate", + [SWAP_EXEC_ACTIVATE] = "ExecActivate", [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", }; DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand); static const char* const swap_result_table[_SWAP_RESULT_MAX] = { - [SWAP_SUCCESS] = "success", - [SWAP_FAILURE_RESOURCES] = "resources", - [SWAP_FAILURE_TIMEOUT] = "timeout", - [SWAP_FAILURE_EXIT_CODE] = "exit-code", - [SWAP_FAILURE_SIGNAL] = "signal", - [SWAP_FAILURE_CORE_DUMP] = "core-dump", + [SWAP_SUCCESS] = "success", + [SWAP_FAILURE_RESOURCES] = "resources", + [SWAP_FAILURE_TIMEOUT] = "timeout", + [SWAP_FAILURE_EXIT_CODE] = "exit-code", + [SWAP_FAILURE_SIGNAL] = "signal", + [SWAP_FAILURE_CORE_DUMP] = "core-dump", [SWAP_FAILURE_START_LIMIT_HIT] = "start-limit-hit", }; diff --git a/src/core/timer.c b/src/core/timer.c index 3b03f4672e..2c7f304cdd 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -891,19 +891,19 @@ static int timer_can_clean(Unit *u, ExecCleanMask *ret) { } static const char* const timer_base_table[_TIMER_BASE_MAX] = { - [TIMER_ACTIVE] = "OnActiveSec", - [TIMER_BOOT] = "OnBootSec", - [TIMER_STARTUP] = "OnStartupSec", - [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec", + [TIMER_ACTIVE] = "OnActiveSec", + [TIMER_BOOT] = "OnBootSec", + [TIMER_STARTUP] = "OnStartupSec", + [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec", [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec", - [TIMER_CALENDAR] = "OnCalendar" + [TIMER_CALENDAR] = "OnCalendar" }; DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase); static const char* const timer_result_table[_TIMER_RESULT_MAX] = { - [TIMER_SUCCESS] = "success", - [TIMER_FAILURE_RESOURCES] = "resources", + [TIMER_SUCCESS] = "success", + [TIMER_FAILURE_RESOURCES] = "resources", [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit", }; diff --git a/src/core/unit.h b/src/core/unit.h index 759104ffa7..48074d8ca5 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -631,6 +631,9 @@ typedef struct UnitVTable { * exit code of the "main" process of the service or similar. */ int (*exit_status)(Unit *u); + /* Return a copy of the status string pointer. */ + const char* (*status_text)(Unit *u); + /* Like the enumerate() callback further down, but only enumerates the perpetual units, i.e. all units that * unconditionally exist and are always active. The main reason to keep both enumeration functions separate is * philosophical: the state of perpetual units should be put in place by coldplug(), while the state of those @@ -744,6 +747,12 @@ static inline bool unit_is_extrinsic(Unit *u) { (UNIT_VTABLE(u)->is_extrinsic && UNIT_VTABLE(u)->is_extrinsic(u)); } +static inline const char* unit_status_text(Unit *u) { + if (u && UNIT_VTABLE(u)->status_text) + return UNIT_VTABLE(u)->status_text(u); + return NULL; +} + void unit_add_to_load_queue(Unit *u); void unit_add_to_dbus_queue(Unit *u); void unit_add_to_cleanup_queue(Unit *u); |