mirror of
https://github.com/systemd/systemd.git
synced 2024-10-30 23:21:22 +03:00
Merge pull request #20123 from keszybz/extended-job-status
Nested job status for systemd+user service managers
This commit is contained in:
commit
cac38a9803
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
536
src/core/manager-serialize.c
Normal file
536
src/core/manager-serialize.c
Normal file
@ -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);
|
||||
}
|
13
src/core/manager-serialize.h
Normal file
13
src/core/manager-serialize.h
Normal file
@ -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);
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
};
|
||||
|
||||
|
@ -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",
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user