summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Boccassi <luca.boccassi@microsoft.com>2021-07-21 11:39:10 +0100
committerGitHub <noreply@github.com>2021-07-21 11:39:10 +0100
commitcac38a98033e72bb54fe23576c5418edd92e5a75 (patch)
tree296764d370dae4dc44ed2c458b524f51239d53d9
parent654eaa403070d3c897454a5190603fda4071c3ff (diff)
parent3889fc6fc347f0e12070f7b873d065508c8df816 (diff)
downloadsystemd-cac38a98033e72bb54fe23576c5418edd92e5a75.tar.gz
Merge pull request #20123 from keszybz/extended-job-status
Nested job status for systemd+user service managers
-rw-r--r--src/core/automount.c8
-rw-r--r--src/core/job.c50
-rw-r--r--src/core/main.c1
-rw-r--r--src/core/manager-serialize.c536
-rw-r--r--src/core/manager-serialize.h13
-rw-r--r--src/core/manager.c719
-rw-r--r--src/core/manager.h10
-rw-r--r--src/core/meson.build2
-rw-r--r--src/core/mount.c16
-rw-r--r--src/core/path.c14
-rw-r--r--src/core/scope.c4
-rw-r--r--src/core/service.c83
-rw-r--r--src/core/socket.c28
-rw-r--r--src/core/swap.c14
-rw-r--r--src/core/timer.c14
-rw-r--r--src/core/unit.h9
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);