From a01ba4b2b8deeb31c65f8ed525ebab51972919bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 2 Jul 2021 15:53:38 +0200 Subject: [PATCH 1/7] core: split out manager-serialize.[ch] The file is super long, so let's split this out one subject to a new file. --- src/core/main.c | 1 + src/core/manager-serialize.c | 536 +++++++++++++++++++++++++++++++++++ src/core/manager-serialize.h | 13 + src/core/manager.c | 531 +--------------------------------- src/core/manager.h | 7 +- src/core/meson.build | 2 + 6 files changed, 557 insertions(+), 533 deletions(-) create mode 100644 src/core/manager-serialize.c create mode 100644 src/core/manager-serialize.h diff --git a/src/core/main.c b/src/core/main.c index 72d7c6b1165..57d4f033dd4 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 00000000000..60a35f48f3e --- /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 00000000000..c52261e3784 --- /dev/null +++ b/src/core/manager-serialize.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#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 18bdd833425..72f1e109d79 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" @@ -1686,11 +1685,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--; @@ -3154,242 +3153,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 +3237,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; diff --git a/src/core/manager.h b/src/core/manager.h index b3e7c68e6dd..6b1ed48bebf 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -500,12 +500,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 f0d2c6f6423..1c364a53e2d 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 From 305757d80819873c8918c6ea229f96fc10b77696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 2 Jul 2021 16:48:56 +0200 Subject: [PATCH 2/7] core: modernize asprintf error handling The man page says asprintf() pointer is "undefined" on error, but the only meaningful interpretation is that it's either NULL or points to something that should be freed with free(). --- src/core/manager.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/core/manager.c b/src/core/manager.c index 72f1e109d79..594be370c65 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -230,8 +230,7 @@ static void manager_print_jobs_in_progress(Manager *m) { m->jobs_in_progress_iteration++; if (m->n_running_jobs > 1) - if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0) - job_of_n = NULL; + (void) asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs); bool have_timeout = job_get_timeout(j, &x) > 0; @@ -620,9 +619,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) { @@ -3142,10 +3139,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) From 48d83e33682654fd01ffc43e5c6ae999e53c8e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 2 Jul 2021 16:59:23 +0200 Subject: [PATCH 3/7] core: align string tables --- src/core/automount.c | 8 ++--- src/core/job.c | 50 +++++++++++++++--------------- src/core/manager.c | 46 +++++++++++++-------------- src/core/mount.c | 16 +++++----- src/core/path.c | 14 ++++----- src/core/scope.c | 4 +-- src/core/service.c | 74 ++++++++++++++++++++++---------------------- src/core/socket.c | 28 ++++++++--------- src/core/swap.c | 14 ++++----- src/core/timer.c | 14 ++++----- 10 files changed, 134 insertions(+), 134 deletions(-) diff --git a/src/core/automount.c b/src/core/automount.c index 68e794ac2e2..30226b9bde6 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 eb6728ad879..a526e5e4ee6 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/manager.c b/src/core/manager.c index 594be370c65..2e47cd50768 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -4399,33 +4399,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", }; @@ -4433,8 +4433,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/mount.c b/src/core/mount.c index fe0cb2b9657..608ead5bc43 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 87930f637f2..800524a3089 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 b7848a0a5d5..1b60af22f3a 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 a015df83f40..1f38a254768 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -4440,82 +4440,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); diff --git a/src/core/socket.c b/src/core/socket.c index 0ae53e73366..8a2a6884509 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 81fb3bb2de7..d7089f1c55c 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 3b03f4672ed..2c7f304cdd2 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", }; From 5e1669ff26198a916c4fe1532448b8bf908b2eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 2 Jul 2021 17:00:00 +0200 Subject: [PATCH 4/7] core: add helper to retrieve service.status_text --- src/core/service.c | 9 +++++++++ src/core/unit.h | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/core/service.c b/src/core/service.c index 1f38a254768..f4a79dc2af5 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); @@ -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/unit.h b/src/core/unit.h index 759104ffa79..48074d8ca5b 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); From 5f968096288ebdd9c3da3ddc309e1ad430884e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 2 Jul 2021 18:22:03 +0200 Subject: [PATCH 5/7] manager: always log when starting a "special unit" This is the initiatation of the machine shutdown/reboot/etc, so it's useful to log about this. We log about the steps that we take, but so far we didn't really log why we started the sequence (except at debug level). The function is renamed, because we also use it for dbus.service, not just targets. --- src/core/manager.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/core/manager.c b/src/core/manager.c index 2e47cd50768..e269e870210 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2612,15 +2612,15 @@ 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); } static void manager_handle_ctrl_alt_del(Manager *m) { @@ -2629,7 +2629,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"); @@ -2693,21 +2693,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; @@ -2719,10 +2718,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; @@ -2773,8 +2770,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; } From 6d9326595592f98e8126eacb4176acd8c3516d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 5 Jul 2021 12:25:23 +0200 Subject: [PATCH 6/7] manager: rework sending of STATUS= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We would send READY=1,STATUS="Startup finished in …" once after finishing boot. This changes the message to just "Ready.". The time used to reach readiness is not part of the ongoing status — it's just a bit of debug information that it useful in some scenarious, but completely uninteresting most of the time. Also, when we start sending status about other things in subsequent patches, we can't really go back to showing "Startup finished in …" later on. So let's just show "Ready." whenever we're in the steady state. In manager_check_finished(), more steps are skipped if MANAGER_IS_FINISHED(). Those steps are idempotent, but no need to waste cycles trying to do them more than once. We'll now also check whether to send the status message whenever the job queue runs empty. If we already sent the exact same message already, we'll not send again. --- src/core/manager.c | 34 ++++++++++++++++++++-------------- src/core/manager.h | 3 +++ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/core/manager.c b/src/core/manager.c index e269e870210..efa0efcb0c7 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -3440,28 +3440,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) { @@ -3478,7 +3482,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); @@ -3509,6 +3513,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 */ @@ -3523,9 +3532,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); diff --git a/src/core/manager.h b/src/core/manager.h index 6b1ed48bebf..284ea42a9dd 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; From 3889fc6fc347f0e12070f7b873d065508c8df816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 2 Jul 2021 18:28:11 +0200 Subject: [PATCH 7/7] manager: print status text of the service when waiting for a job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This does two semi-independent but interleaved things: firstly, the manager now prints the status text (if available) of a service when we have a job running for that service and it is slow. Because it's hard to fit enough info on the line, we only do this if the output mode uses unit names. The format of the line "… job is running for …" is changed to be shorter. This way we can somewhat reasonably fit two status messages on one line. Secondly, the manager now sends more information using sd_notify. This mostly matters for in case of the user manager. In particular, we notify when starting one of the special units. Without this, when the system manager would display a line about waiting for the user manager, it would show status like "Ready.", which is confusing. Now it'll either show something like "Started special unit shutdown.target", or the line about waiting for a user job. Also, the timeouts for the user manager are lowered: the user manager usually (always?) has status disabled, so we would wait for 25 seconds before showing job progress. Normally we don't expect to have any jobs that take more than a second. So let's start the progress output fairly quickly, like we would if status showing was enabled. This obviously makes the output in the system manager about the user manager more useful. The timeouts are "desynchronized" by a fraction so if there are multiple jobs running, we'll cycle through showing all combinations. Example output: Stopping user@1000.service... [ OK ] Stopped dracut-shutdown.service. [ OK ] Stopped systemd-logind.service. [ OK ] Stopped systemd-logind.service - User Login Management. [* ] Job user@1000.service/stop running (2s / 2min): (1 of 2) User job slowstop.service/stop running (1s / 1min 30s)... [*** ] Job user@1000.service/stop running (3s / 2min): (2 of 2) User job slowstop2.service/stop running (2s / 1min 30s)... [ ***] Job user@1000.service/stop running (4s / 2min): (1 of 2) User job slowstop.service/stop running (4s / 1min 30s)... [ *] Job user@1000.service/stop running (5s / 2min): (1 of 2) User job slowstop.service/stop running (5s / 1min 30s)... [ ***] Job user@1000.service/stop running (6s / 2min): (2 of 2) User job slowstop2.service/stop running (6s / 1min 30s)... [*** ] Job user@1000.service/stop running (8s / 2min): (1 of 2) User job slowstop.service/stop running (7s / 1min 30s)... [*** ] Job user@1000.service/stop running (10s / 2min): (2 of 2) User job slowstop2.service/stop running (9s / 1min 30s)... [ *** ] Job user@1000.service/stop running (11s / 2min): (1 of 2) User job slowstop.service/stop running (10s / 1min 30s)... [ *] Job user@1000.service/stop running (12s / 2min): (2 of 2) User job slowstop2.service/stop running (12s / 1min 30s)... [ ***] Job user@1000.service/stop running (13s / 2min): (1 of 2) User job slowstop.service/stop running (13s / 1min 30s)... [*** ] Job user@1000.service/stop running (15s / 2min): (2 of 2) User job slowstop2.service/stop running (14s / 1min 30s)... [* ] Job user@1000.service/stop running (15s / 2min): (2 of 2) User job slowstop2.service/stop running (14s / 1min 30s)... [*** ] Job user@1000.service/stop running (16s / 2min): User job slowstop.service/stop running (16s / 1min 30s)... [ ***] Job user@1000.service/stop running (18s / 2min): User job slowstop.service/stop running (17s / 1min 30s)... [ *] Job user@1000.service/stop running (19s / 2min): User job slowstop.service/stop running (18s / 1min 30s)... [ ***] Job user@1000.service/stop running (20s / 2min): User job slowstop.service/stop running (19s / 1min 30s)... [* ] Job user@1000.service/stop running (22s / 2min): User job slowstop.service/stop running (22s / 1min 30s)... [** ] Job user@1000.service/stop running (30s / 2min): User job slowstop.service/stop running (29s / 1min 30s)... [ ***] Job user@1000.service/stop running (32s / 2min): User job slowstop.service/stop running (31s / 1min 30s)... [ *] Job user@1000.service/stop running (33s / 2min): User job slowstop.service/stop running (32s / 1min 30s)... [ ***] Job user@1000.service/stop running (34s / 2min): User job slowstop.service/stop running (33s / 1min 30s)... [** ] Job user@1000.service/stop running (37s / 2min): User job slowstop.service/stop running (36s / 1min 30s)... [ *** ] Job user@1000.service/stop running (41s / 2min): User job slowstop.service/stop running (41s / 1min 30s)... [ OK ] Stopped user@1000.service - User Manager for UID 1000. Stopping user-runtime-dir@1000.service - User Runtime Directory /run/user/1000... [ OK ] Unmounted run-user-1000.mount - /run/user/1000. [ OK ] Stopped user-runtime-dir@1000.service - User Runtime Directory /run/user/1000. If the output width is lower than approximately 100 columns, the output stops being very useful. No idea what to do about that. --- src/core/manager.c | 65 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/src/core/manager.c b/src/core/manager.c index efa0efcb0c7..a3607ea44f6 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -117,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) { @@ -199,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]; @@ -229,25 +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) - (void) asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs); + 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) { @@ -2621,6 +2656,10 @@ static void manager_start_special(Manager *m, const char *name, JobMode mode) { 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) {