core: split out a few funcs into unit-serialize.[ch]
Just a straightforward move and resulting include file adjustments.
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include "path-util.h"
|
||||
#include "strv.h"
|
||||
#include "unit-name.h"
|
||||
#include "unit-serialize.h"
|
||||
|
||||
static int prepare_filename(const char *filename, char **ret) {
|
||||
int r;
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@
|
||||
#include "terminal-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "umask-util.h"
|
||||
#include "unit.h"
|
||||
#include "unit-serialize.h"
|
||||
#include "user-util.h"
|
||||
#include "utmp-wtmp.h"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "install.h"
|
||||
#include "load-fragment.h"
|
||||
#include "string-util.h"
|
||||
#include "unit.h"
|
||||
#include "unit-serialize.h"
|
||||
#include "utf8.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
#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"
|
||||
|
||||
@@ -115,6 +115,8 @@ libcore_sources = '''
|
||||
transaction.h
|
||||
unit-printf.c
|
||||
unit-printf.h
|
||||
unit-serialize.c
|
||||
unit-serialize.h
|
||||
unit.c
|
||||
unit.h
|
||||
'''.split()
|
||||
|
||||
@@ -0,0 +1,810 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "bus-util.h"
|
||||
#include "dbus.h"
|
||||
#include "fileio-label.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "serialize.h"
|
||||
#include "string-table.h"
|
||||
#include "unit-serialize.h"
|
||||
#include "user-util.h"
|
||||
|
||||
static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
assert(key);
|
||||
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
|
||||
r = cg_mask_to_string(mask, &s);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format cgroup mask: %m");
|
||||
|
||||
return serialize_item(f, key, s);
|
||||
}
|
||||
|
||||
static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes",
|
||||
[CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets",
|
||||
[CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes",
|
||||
[CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets",
|
||||
};
|
||||
|
||||
static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base",
|
||||
[CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base",
|
||||
};
|
||||
|
||||
static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last",
|
||||
[CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last",
|
||||
};
|
||||
|
||||
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
assert(fds);
|
||||
|
||||
if (unit_can_serialize(u)) {
|
||||
r = UNIT_VTABLE(u)->serialize(u, f, fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
(void) serialize_dual_timestamp(f, "state-change-timestamp", &u->state_change_timestamp);
|
||||
|
||||
(void) serialize_dual_timestamp(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "active-enter-timestamp", &u->active_enter_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "active-exit-timestamp", &u->active_exit_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
|
||||
|
||||
(void) serialize_dual_timestamp(f, "condition-timestamp", &u->condition_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "assert-timestamp", &u->assert_timestamp);
|
||||
|
||||
if (dual_timestamp_is_set(&u->condition_timestamp))
|
||||
(void) serialize_bool(f, "condition-result", u->condition_result);
|
||||
|
||||
if (dual_timestamp_is_set(&u->assert_timestamp))
|
||||
(void) serialize_bool(f, "assert-result", u->assert_result);
|
||||
|
||||
(void) serialize_bool(f, "transient", u->transient);
|
||||
(void) serialize_bool(f, "in-audit", u->in_audit);
|
||||
|
||||
(void) serialize_bool(f, "exported-invocation-id", u->exported_invocation_id);
|
||||
(void) serialize_bool(f, "exported-log-level-max", u->exported_log_level_max);
|
||||
(void) serialize_bool(f, "exported-log-extra-fields", u->exported_log_extra_fields);
|
||||
(void) serialize_bool(f, "exported-log-rate-limit-interval", u->exported_log_ratelimit_interval);
|
||||
(void) serialize_bool(f, "exported-log-rate-limit-burst", u->exported_log_ratelimit_burst);
|
||||
|
||||
(void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base);
|
||||
if (u->cpu_usage_last != NSEC_INFINITY)
|
||||
(void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last);
|
||||
|
||||
if (u->managed_oom_kill_last > 0)
|
||||
(void) serialize_item_format(f, "managed-oom-kill-last", "%" PRIu64, u->managed_oom_kill_last);
|
||||
|
||||
if (u->oom_kill_last > 0)
|
||||
(void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last);
|
||||
|
||||
for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) {
|
||||
(void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]);
|
||||
|
||||
if (u->io_accounting_last[im] != UINT64_MAX)
|
||||
(void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]);
|
||||
}
|
||||
|
||||
if (u->cgroup_path)
|
||||
(void) serialize_item(f, "cgroup", u->cgroup_path);
|
||||
|
||||
(void) serialize_bool(f, "cgroup-realized", u->cgroup_realized);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask);
|
||||
|
||||
if (uid_is_valid(u->ref_uid))
|
||||
(void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid);
|
||||
if (gid_is_valid(u->ref_gid))
|
||||
(void) serialize_item_format(f, "ref-gid", GID_FMT, u->ref_gid);
|
||||
|
||||
if (!sd_id128_is_null(u->invocation_id))
|
||||
(void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id));
|
||||
|
||||
(void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u)));
|
||||
|
||||
bus_track_serialize(u->bus_track, f, "ref");
|
||||
|
||||
for (CGroupIPAccountingMetric m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
|
||||
uint64_t v;
|
||||
|
||||
r = unit_get_ip_accounting(u, m, &v);
|
||||
if (r >= 0)
|
||||
(void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v);
|
||||
}
|
||||
|
||||
if (serialize_jobs) {
|
||||
if (u->job) {
|
||||
fputs("job\n", f);
|
||||
job_serialize(u->job, f);
|
||||
}
|
||||
|
||||
if (u->nop_job) {
|
||||
fputs("job\n", f);
|
||||
job_serialize(u->nop_job, f);
|
||||
}
|
||||
}
|
||||
|
||||
/* End marker */
|
||||
fputc('\n', f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unit_deserialize_job(Unit *u, FILE *f) {
|
||||
_cleanup_(job_freep) Job *j = NULL;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
|
||||
j = job_new_raw(u);
|
||||
if (!j)
|
||||
return log_oom();
|
||||
|
||||
r = job_deserialize(j, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = job_install_deserialized(j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(j);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
assert(fds);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
char *l, *v;
|
||||
ssize_t m;
|
||||
size_t k;
|
||||
|
||||
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) /* eof */
|
||||
break;
|
||||
|
||||
l = strstrip(line);
|
||||
if (isempty(l)) /* End marker */
|
||||
break;
|
||||
|
||||
k = strcspn(l, "=");
|
||||
|
||||
if (l[k] == '=') {
|
||||
l[k] = 0;
|
||||
v = l+k+1;
|
||||
} else
|
||||
v = l+k;
|
||||
|
||||
if (streq(l, "job")) {
|
||||
if (v[0] == '\0') {
|
||||
/* New-style serialized job */
|
||||
r = unit_deserialize_job(u, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else /* Legacy for pre-44 */
|
||||
log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
|
||||
continue;
|
||||
} else if (streq(l, "state-change-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->state_change_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "inactive-exit-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->inactive_exit_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "active-enter-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->active_enter_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "active-exit-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->active_exit_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "inactive-enter-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->inactive_enter_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "condition-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->condition_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "assert-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->assert_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "condition-result")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse condition result value %s, ignoring.", v);
|
||||
else
|
||||
u->condition_result = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "assert-result")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse assert result value %s, ignoring.", v);
|
||||
else
|
||||
u->assert_result = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "transient")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse transient bool %s, ignoring.", v);
|
||||
else
|
||||
u->transient = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "in-audit")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse in-audit bool %s, ignoring.", v);
|
||||
else
|
||||
u->in_audit = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-invocation-id")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported invocation ID bool %s, ignoring.", v);
|
||||
else
|
||||
u->exported_invocation_id = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-level-max")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log level max bool %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_level_max = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-extra-fields")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log extra fields bool %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_extra_fields = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-rate-limit-interval")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log rate limit interval %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_ratelimit_interval = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-rate-limit-burst")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log rate limit burst %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_ratelimit_burst = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (STR_IN_SET(l, "cpu-usage-base", "cpuacct-usage-base")) {
|
||||
|
||||
r = safe_atou64(v, &u->cpu_usage_base);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse CPU usage base %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cpu-usage-last")) {
|
||||
|
||||
r = safe_atou64(v, &u->cpu_usage_last);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to read CPU usage last %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "managed-oom-kill-last")) {
|
||||
|
||||
r = safe_atou64(v, &u->managed_oom_kill_last);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to read managed OOM kill last %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "oom-kill-last")) {
|
||||
|
||||
r = safe_atou64(v, &u->oom_kill_last);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to read OOM kill last %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup")) {
|
||||
|
||||
r = unit_set_cgroup_path(u, v);
|
||||
if (r < 0)
|
||||
log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v);
|
||||
|
||||
(void) unit_watch_cgroup(u);
|
||||
(void) unit_watch_cgroup_memory(u);
|
||||
|
||||
continue;
|
||||
} else if (streq(l, "cgroup-realized")) {
|
||||
int b;
|
||||
|
||||
b = parse_boolean(v);
|
||||
if (b < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-realized bool %s, ignoring.", v);
|
||||
else
|
||||
u->cgroup_realized = b;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup-realized-mask")) {
|
||||
|
||||
r = cg_mask_from_string(v, &u->cgroup_realized_mask);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-realized-mask %s, ignoring.", v);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup-enabled-mask")) {
|
||||
|
||||
r = cg_mask_from_string(v, &u->cgroup_enabled_mask);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-enabled-mask %s, ignoring.", v);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup-invalidated-mask")) {
|
||||
|
||||
r = cg_mask_from_string(v, &u->cgroup_invalidated_mask);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-invalidated-mask %s, ignoring.", v);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref-uid")) {
|
||||
uid_t uid;
|
||||
|
||||
r = parse_uid(v, &uid);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse referenced UID %s, ignoring.", v);
|
||||
else
|
||||
unit_ref_uid_gid(u, uid, GID_INVALID);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref-gid")) {
|
||||
gid_t gid;
|
||||
|
||||
r = parse_gid(v, &gid);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse referenced GID %s, ignoring.", v);
|
||||
else
|
||||
unit_ref_uid_gid(u, UID_INVALID, gid);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref")) {
|
||||
|
||||
r = strv_extend(&u->deserialized_refs, v);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
continue;
|
||||
} else if (streq(l, "invocation-id")) {
|
||||
sd_id128_t id;
|
||||
|
||||
r = sd_id128_from_string(v, &id);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse invocation id %s, ignoring.", v);
|
||||
else {
|
||||
r = unit_set_invocation_id(u, id);
|
||||
if (r < 0)
|
||||
log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m");
|
||||
}
|
||||
|
||||
continue;
|
||||
} else if (streq(l, "freezer-state")) {
|
||||
FreezerState s;
|
||||
|
||||
s = freezer_state_from_string(v);
|
||||
if (s < 0)
|
||||
log_unit_debug(u, "Failed to deserialize freezer-state '%s', ignoring.", v);
|
||||
else
|
||||
u->freezer_state = s;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if this is an IP accounting metric serialization field */
|
||||
m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v);
|
||||
else
|
||||
u->ip_accounting_extra[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IO accounting base value %s, ignoring.", v);
|
||||
else
|
||||
u->io_accounting_base[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IO accounting last value %s, ignoring.", v);
|
||||
else
|
||||
u->io_accounting_last[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unit_can_serialize(u)) {
|
||||
r = exec_runtime_deserialize_compat(u, l, v, fds);
|
||||
if (r < 0) {
|
||||
log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Returns positive if key was handled by the call */
|
||||
if (r > 0)
|
||||
continue;
|
||||
|
||||
r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
|
||||
if (r < 0)
|
||||
log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Versions before 228 did not carry a state change timestamp. In this case, take the current
|
||||
* time. This is useful, so that timeouts based on this timestamp don't trigger too early, and is
|
||||
* in-line with the logic from before 228 where the base for timeouts was not persistent across
|
||||
* reboots. */
|
||||
|
||||
if (!dual_timestamp_is_set(&u->state_change_timestamp))
|
||||
dual_timestamp_get(&u->state_change_timestamp);
|
||||
|
||||
/* Let's make sure that everything that is deserialized also gets any potential new cgroup settings
|
||||
* applied after we are done. For that we invalidate anything already realized, so that we can
|
||||
* realize it again. */
|
||||
unit_invalidate_cgroup(u, _CGROUP_MASK_ALL);
|
||||
unit_invalidate_cgroup_bpf(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_deserialize_skip(FILE *f) {
|
||||
int r;
|
||||
assert(f);
|
||||
|
||||
/* Skip serialized data for this unit. We don't know what it is. */
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
char *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)
|
||||
return 0;
|
||||
|
||||
l = strstrip(line);
|
||||
|
||||
/* End marker */
|
||||
if (isempty(l))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) {
|
||||
const struct {
|
||||
UnitDependencyMask mask;
|
||||
const char *name;
|
||||
} table[] = {
|
||||
{ UNIT_DEPENDENCY_FILE, "file" },
|
||||
{ UNIT_DEPENDENCY_IMPLICIT, "implicit" },
|
||||
{ UNIT_DEPENDENCY_DEFAULT, "default" },
|
||||
{ UNIT_DEPENDENCY_UDEV, "udev" },
|
||||
{ UNIT_DEPENDENCY_PATH, "path" },
|
||||
{ UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" },
|
||||
{ UNIT_DEPENDENCY_MOUNTINFO_DEFAULT, "mountinfo-default" },
|
||||
{ UNIT_DEPENDENCY_PROC_SWAP, "proc-swap" },
|
||||
};
|
||||
|
||||
assert(f);
|
||||
assert(kind);
|
||||
assert(space);
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
|
||||
|
||||
if (mask == 0)
|
||||
break;
|
||||
|
||||
if (FLAGS_SET(mask, table[i].mask)) {
|
||||
if (*space)
|
||||
fputc(' ', f);
|
||||
else
|
||||
*space = true;
|
||||
|
||||
fputs(kind, f);
|
||||
fputs("-", f);
|
||||
fputs(table[i].name, f);
|
||||
|
||||
mask &= ~table[i].mask;
|
||||
}
|
||||
}
|
||||
|
||||
assert(mask == 0);
|
||||
}
|
||||
|
||||
void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
char *t, **j;
|
||||
const char *prefix2;
|
||||
char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX];
|
||||
Unit *following;
|
||||
_cleanup_set_free_ Set *following_set = NULL;
|
||||
CGroupMask m;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(u->type >= 0);
|
||||
|
||||
prefix = strempty(prefix);
|
||||
prefix2 = strjoina(prefix, "\t");
|
||||
|
||||
fprintf(f,
|
||||
"%s-> Unit %s:\n",
|
||||
prefix, u->id);
|
||||
|
||||
SET_FOREACH(t, u->aliases)
|
||||
fprintf(f, "%s\tAlias: %s\n", prefix, t);
|
||||
|
||||
fprintf(f,
|
||||
"%s\tDescription: %s\n"
|
||||
"%s\tInstance: %s\n"
|
||||
"%s\tUnit Load State: %s\n"
|
||||
"%s\tUnit Active State: %s\n"
|
||||
"%s\tState Change Timestamp: %s\n"
|
||||
"%s\tInactive Exit Timestamp: %s\n"
|
||||
"%s\tActive Enter Timestamp: %s\n"
|
||||
"%s\tActive Exit Timestamp: %s\n"
|
||||
"%s\tInactive Enter Timestamp: %s\n"
|
||||
"%s\tMay GC: %s\n"
|
||||
"%s\tNeed Daemon Reload: %s\n"
|
||||
"%s\tTransient: %s\n"
|
||||
"%s\tPerpetual: %s\n"
|
||||
"%s\tGarbage Collection Mode: %s\n"
|
||||
"%s\tSlice: %s\n"
|
||||
"%s\tCGroup: %s\n"
|
||||
"%s\tCGroup realized: %s\n",
|
||||
prefix, unit_description(u),
|
||||
prefix, strna(u->instance),
|
||||
prefix, unit_load_state_to_string(u->load_state),
|
||||
prefix, unit_active_state_to_string(unit_active_state(u)),
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->state_change_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[1], sizeof(timestamp[1]), u->inactive_exit_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[2], sizeof(timestamp[2]), u->active_enter_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[3], sizeof(timestamp[3]), u->active_exit_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[4], sizeof(timestamp[4]), u->inactive_enter_timestamp.realtime)),
|
||||
prefix, yes_no(unit_may_gc(u)),
|
||||
prefix, yes_no(unit_need_daemon_reload(u)),
|
||||
prefix, yes_no(u->transient),
|
||||
prefix, yes_no(u->perpetual),
|
||||
prefix, collect_mode_to_string(u->collect_mode),
|
||||
prefix, strna(unit_slice_name(u)),
|
||||
prefix, strna(u->cgroup_path),
|
||||
prefix, yes_no(u->cgroup_realized));
|
||||
|
||||
if (u->cgroup_realized_mask != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(u->cgroup_realized_mask, &s);
|
||||
fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
if (u->cgroup_enabled_mask != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(u->cgroup_enabled_mask, &s);
|
||||
fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_own_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_members_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_delegate_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup delegate mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
if (!sd_id128_is_null(u->invocation_id))
|
||||
fprintf(f, "%s\tInvocation ID: " SD_ID128_FORMAT_STR "\n",
|
||||
prefix, SD_ID128_FORMAT_VAL(u->invocation_id));
|
||||
|
||||
STRV_FOREACH(j, u->documentation)
|
||||
fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);
|
||||
|
||||
following = unit_following(u);
|
||||
if (following)
|
||||
fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
|
||||
|
||||
r = unit_following_set(u, &following_set);
|
||||
if (r >= 0) {
|
||||
Unit *other;
|
||||
|
||||
SET_FOREACH(other, following_set)
|
||||
fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id);
|
||||
}
|
||||
|
||||
if (u->fragment_path)
|
||||
fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
|
||||
|
||||
if (u->source_path)
|
||||
fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);
|
||||
|
||||
STRV_FOREACH(j, u->dropin_paths)
|
||||
fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
|
||||
|
||||
if (u->failure_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tFailure Action: %s\n", prefix, emergency_action_to_string(u->failure_action));
|
||||
if (u->failure_action_exit_status >= 0)
|
||||
fprintf(f, "%s\tFailure Action Exit Status: %i\n", prefix, u->failure_action_exit_status);
|
||||
if (u->success_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tSuccess Action: %s\n", prefix, emergency_action_to_string(u->success_action));
|
||||
if (u->success_action_exit_status >= 0)
|
||||
fprintf(f, "%s\tSuccess Action Exit Status: %i\n", prefix, u->success_action_exit_status);
|
||||
|
||||
if (u->job_timeout != USEC_INFINITY)
|
||||
fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
|
||||
|
||||
if (u->job_timeout_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action));
|
||||
|
||||
if (u->job_timeout_reboot_arg)
|
||||
fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
|
||||
|
||||
condition_dump_list(u->conditions, f, prefix, condition_type_to_string);
|
||||
condition_dump_list(u->asserts, f, prefix, assert_type_to_string);
|
||||
|
||||
if (dual_timestamp_is_set(&u->condition_timestamp))
|
||||
fprintf(f,
|
||||
"%s\tCondition Timestamp: %s\n"
|
||||
"%s\tCondition Result: %s\n",
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->condition_timestamp.realtime)),
|
||||
prefix, yes_no(u->condition_result));
|
||||
|
||||
if (dual_timestamp_is_set(&u->assert_timestamp))
|
||||
fprintf(f,
|
||||
"%s\tAssert Timestamp: %s\n"
|
||||
"%s\tAssert Result: %s\n",
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)),
|
||||
prefix, yes_no(u->assert_result));
|
||||
|
||||
for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
|
||||
UnitDependencyInfo di;
|
||||
Unit *other;
|
||||
|
||||
HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d]) {
|
||||
bool space = false;
|
||||
|
||||
fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id);
|
||||
|
||||
print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
|
||||
print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
|
||||
|
||||
fputs(")\n", f);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hashmap_isempty(u->requires_mounts_for)) {
|
||||
UnitDependencyInfo di;
|
||||
const char *path;
|
||||
|
||||
HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) {
|
||||
bool space = false;
|
||||
|
||||
fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path);
|
||||
|
||||
print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
|
||||
print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
|
||||
|
||||
fputs(")\n", f);
|
||||
}
|
||||
}
|
||||
|
||||
if (u->load_state == UNIT_LOADED) {
|
||||
|
||||
fprintf(f,
|
||||
"%s\tStopWhenUnneeded: %s\n"
|
||||
"%s\tRefuseManualStart: %s\n"
|
||||
"%s\tRefuseManualStop: %s\n"
|
||||
"%s\tDefaultDependencies: %s\n"
|
||||
"%s\tOnFailureJobMode: %s\n"
|
||||
"%s\tIgnoreOnIsolate: %s\n",
|
||||
prefix, yes_no(u->stop_when_unneeded),
|
||||
prefix, yes_no(u->refuse_manual_start),
|
||||
prefix, yes_no(u->refuse_manual_stop),
|
||||
prefix, yes_no(u->default_dependencies),
|
||||
prefix, job_mode_to_string(u->on_failure_job_mode),
|
||||
prefix, yes_no(u->ignore_on_isolate));
|
||||
|
||||
if (UNIT_VTABLE(u)->dump)
|
||||
UNIT_VTABLE(u)->dump(u, f, prefix2);
|
||||
|
||||
} else if (u->load_state == UNIT_MERGED)
|
||||
fprintf(f,
|
||||
"%s\tMerged into: %s\n",
|
||||
prefix, u->merged_into->id);
|
||||
else if (u->load_state == UNIT_ERROR)
|
||||
fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror_safe(u->load_error));
|
||||
|
||||
for (const char *n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track))
|
||||
fprintf(f, "%s\tBus Ref: %s\n", prefix, n);
|
||||
|
||||
if (u->job)
|
||||
job_dump(u->job, f, prefix2);
|
||||
|
||||
if (u->nop_job)
|
||||
job_dump(u->nop_job, f, prefix2);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "unit.h"
|
||||
#include "fdset.h"
|
||||
|
||||
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
|
||||
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
|
||||
int unit_deserialize_skip(FILE *f);
|
||||
|
||||
void unit_dump(Unit *u, FILE *f, const char *prefix);
|
||||
+2
-799
@@ -26,8 +26,8 @@
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "id128-util.h"
|
||||
#include "io-util.h"
|
||||
#include "install.h"
|
||||
#include "io-util.h"
|
||||
#include "label.h"
|
||||
#include "load-dropin.h"
|
||||
#include "load-fragment.h"
|
||||
@@ -35,11 +35,9 @@
|
||||
#include "macro.h"
|
||||
#include "missing_audit.h"
|
||||
#include "mkdir.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "serialize.h"
|
||||
#include "set.h"
|
||||
#include "signal-util.h"
|
||||
#include "sparse-endian.h"
|
||||
@@ -1166,269 +1164,6 @@ const char *unit_status_string(Unit *u) {
|
||||
return unit_description(u);
|
||||
}
|
||||
|
||||
static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) {
|
||||
const struct {
|
||||
UnitDependencyMask mask;
|
||||
const char *name;
|
||||
} table[] = {
|
||||
{ UNIT_DEPENDENCY_FILE, "file" },
|
||||
{ UNIT_DEPENDENCY_IMPLICIT, "implicit" },
|
||||
{ UNIT_DEPENDENCY_DEFAULT, "default" },
|
||||
{ UNIT_DEPENDENCY_UDEV, "udev" },
|
||||
{ UNIT_DEPENDENCY_PATH, "path" },
|
||||
{ UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" },
|
||||
{ UNIT_DEPENDENCY_MOUNTINFO_DEFAULT, "mountinfo-default" },
|
||||
{ UNIT_DEPENDENCY_PROC_SWAP, "proc-swap" },
|
||||
};
|
||||
|
||||
assert(f);
|
||||
assert(kind);
|
||||
assert(space);
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
|
||||
|
||||
if (mask == 0)
|
||||
break;
|
||||
|
||||
if (FLAGS_SET(mask, table[i].mask)) {
|
||||
if (*space)
|
||||
fputc(' ', f);
|
||||
else
|
||||
*space = true;
|
||||
|
||||
fputs(kind, f);
|
||||
fputs("-", f);
|
||||
fputs(table[i].name, f);
|
||||
|
||||
mask &= ~table[i].mask;
|
||||
}
|
||||
}
|
||||
|
||||
assert(mask == 0);
|
||||
}
|
||||
|
||||
void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
char *t, **j;
|
||||
const char *prefix2;
|
||||
char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX];
|
||||
Unit *following;
|
||||
_cleanup_set_free_ Set *following_set = NULL;
|
||||
CGroupMask m;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(u->type >= 0);
|
||||
|
||||
prefix = strempty(prefix);
|
||||
prefix2 = strjoina(prefix, "\t");
|
||||
|
||||
fprintf(f,
|
||||
"%s-> Unit %s:\n",
|
||||
prefix, u->id);
|
||||
|
||||
SET_FOREACH(t, u->aliases)
|
||||
fprintf(f, "%s\tAlias: %s\n", prefix, t);
|
||||
|
||||
fprintf(f,
|
||||
"%s\tDescription: %s\n"
|
||||
"%s\tInstance: %s\n"
|
||||
"%s\tUnit Load State: %s\n"
|
||||
"%s\tUnit Active State: %s\n"
|
||||
"%s\tState Change Timestamp: %s\n"
|
||||
"%s\tInactive Exit Timestamp: %s\n"
|
||||
"%s\tActive Enter Timestamp: %s\n"
|
||||
"%s\tActive Exit Timestamp: %s\n"
|
||||
"%s\tInactive Enter Timestamp: %s\n"
|
||||
"%s\tMay GC: %s\n"
|
||||
"%s\tNeed Daemon Reload: %s\n"
|
||||
"%s\tTransient: %s\n"
|
||||
"%s\tPerpetual: %s\n"
|
||||
"%s\tGarbage Collection Mode: %s\n"
|
||||
"%s\tSlice: %s\n"
|
||||
"%s\tCGroup: %s\n"
|
||||
"%s\tCGroup realized: %s\n",
|
||||
prefix, unit_description(u),
|
||||
prefix, strna(u->instance),
|
||||
prefix, unit_load_state_to_string(u->load_state),
|
||||
prefix, unit_active_state_to_string(unit_active_state(u)),
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->state_change_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[1], sizeof(timestamp[1]), u->inactive_exit_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[2], sizeof(timestamp[2]), u->active_enter_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[3], sizeof(timestamp[3]), u->active_exit_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[4], sizeof(timestamp[4]), u->inactive_enter_timestamp.realtime)),
|
||||
prefix, yes_no(unit_may_gc(u)),
|
||||
prefix, yes_no(unit_need_daemon_reload(u)),
|
||||
prefix, yes_no(u->transient),
|
||||
prefix, yes_no(u->perpetual),
|
||||
prefix, collect_mode_to_string(u->collect_mode),
|
||||
prefix, strna(unit_slice_name(u)),
|
||||
prefix, strna(u->cgroup_path),
|
||||
prefix, yes_no(u->cgroup_realized));
|
||||
|
||||
if (u->cgroup_realized_mask != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(u->cgroup_realized_mask, &s);
|
||||
fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
if (u->cgroup_enabled_mask != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(u->cgroup_enabled_mask, &s);
|
||||
fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_own_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_members_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_delegate_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup delegate mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
if (!sd_id128_is_null(u->invocation_id))
|
||||
fprintf(f, "%s\tInvocation ID: " SD_ID128_FORMAT_STR "\n",
|
||||
prefix, SD_ID128_FORMAT_VAL(u->invocation_id));
|
||||
|
||||
STRV_FOREACH(j, u->documentation)
|
||||
fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);
|
||||
|
||||
following = unit_following(u);
|
||||
if (following)
|
||||
fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
|
||||
|
||||
r = unit_following_set(u, &following_set);
|
||||
if (r >= 0) {
|
||||
Unit *other;
|
||||
|
||||
SET_FOREACH(other, following_set)
|
||||
fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id);
|
||||
}
|
||||
|
||||
if (u->fragment_path)
|
||||
fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
|
||||
|
||||
if (u->source_path)
|
||||
fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);
|
||||
|
||||
STRV_FOREACH(j, u->dropin_paths)
|
||||
fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
|
||||
|
||||
if (u->failure_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tFailure Action: %s\n", prefix, emergency_action_to_string(u->failure_action));
|
||||
if (u->failure_action_exit_status >= 0)
|
||||
fprintf(f, "%s\tFailure Action Exit Status: %i\n", prefix, u->failure_action_exit_status);
|
||||
if (u->success_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tSuccess Action: %s\n", prefix, emergency_action_to_string(u->success_action));
|
||||
if (u->success_action_exit_status >= 0)
|
||||
fprintf(f, "%s\tSuccess Action Exit Status: %i\n", prefix, u->success_action_exit_status);
|
||||
|
||||
if (u->job_timeout != USEC_INFINITY)
|
||||
fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
|
||||
|
||||
if (u->job_timeout_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action));
|
||||
|
||||
if (u->job_timeout_reboot_arg)
|
||||
fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
|
||||
|
||||
condition_dump_list(u->conditions, f, prefix, condition_type_to_string);
|
||||
condition_dump_list(u->asserts, f, prefix, assert_type_to_string);
|
||||
|
||||
if (dual_timestamp_is_set(&u->condition_timestamp))
|
||||
fprintf(f,
|
||||
"%s\tCondition Timestamp: %s\n"
|
||||
"%s\tCondition Result: %s\n",
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->condition_timestamp.realtime)),
|
||||
prefix, yes_no(u->condition_result));
|
||||
|
||||
if (dual_timestamp_is_set(&u->assert_timestamp))
|
||||
fprintf(f,
|
||||
"%s\tAssert Timestamp: %s\n"
|
||||
"%s\tAssert Result: %s\n",
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)),
|
||||
prefix, yes_no(u->assert_result));
|
||||
|
||||
for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
|
||||
UnitDependencyInfo di;
|
||||
Unit *other;
|
||||
|
||||
HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d]) {
|
||||
bool space = false;
|
||||
|
||||
fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id);
|
||||
|
||||
print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
|
||||
print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
|
||||
|
||||
fputs(")\n", f);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hashmap_isempty(u->requires_mounts_for)) {
|
||||
UnitDependencyInfo di;
|
||||
const char *path;
|
||||
|
||||
HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) {
|
||||
bool space = false;
|
||||
|
||||
fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path);
|
||||
|
||||
print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
|
||||
print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
|
||||
|
||||
fputs(")\n", f);
|
||||
}
|
||||
}
|
||||
|
||||
if (u->load_state == UNIT_LOADED) {
|
||||
|
||||
fprintf(f,
|
||||
"%s\tStopWhenUnneeded: %s\n"
|
||||
"%s\tRefuseManualStart: %s\n"
|
||||
"%s\tRefuseManualStop: %s\n"
|
||||
"%s\tDefaultDependencies: %s\n"
|
||||
"%s\tOnFailureJobMode: %s\n"
|
||||
"%s\tIgnoreOnIsolate: %s\n",
|
||||
prefix, yes_no(u->stop_when_unneeded),
|
||||
prefix, yes_no(u->refuse_manual_start),
|
||||
prefix, yes_no(u->refuse_manual_stop),
|
||||
prefix, yes_no(u->default_dependencies),
|
||||
prefix, job_mode_to_string(u->on_failure_job_mode),
|
||||
prefix, yes_no(u->ignore_on_isolate));
|
||||
|
||||
if (UNIT_VTABLE(u)->dump)
|
||||
UNIT_VTABLE(u)->dump(u, f, prefix2);
|
||||
|
||||
} else if (u->load_state == UNIT_MERGED)
|
||||
fprintf(f,
|
||||
"%s\tMerged into: %s\n",
|
||||
prefix, u->merged_into->id);
|
||||
else if (u->load_state == UNIT_ERROR)
|
||||
fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror_safe(u->load_error));
|
||||
|
||||
for (const char *n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track))
|
||||
fprintf(f, "%s\tBus Ref: %s\n", prefix, n);
|
||||
|
||||
if (u->job)
|
||||
job_dump(u->job, f, prefix2);
|
||||
|
||||
if (u->nop_job)
|
||||
job_dump(u->nop_job, f, prefix2);
|
||||
}
|
||||
|
||||
/* Common implementation for multiple backends */
|
||||
int unit_load_fragment_and_dropin(Unit *u, bool fragment_required) {
|
||||
int r;
|
||||
@@ -3241,7 +2976,7 @@ char *unit_dbus_path_invocation_id(Unit *u) {
|
||||
return unit_dbus_path_from_name(u->invocation_id_string);
|
||||
}
|
||||
|
||||
static int unit_set_invocation_id(Unit *u, sd_id128_t id) {
|
||||
int unit_set_invocation_id(Unit *u, sd_id128_t id) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
@@ -3526,538 +3261,6 @@ bool unit_can_serialize(Unit *u) {
|
||||
return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item;
|
||||
}
|
||||
|
||||
static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
assert(key);
|
||||
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
|
||||
r = cg_mask_to_string(mask, &s);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format cgroup mask: %m");
|
||||
|
||||
return serialize_item(f, key, s);
|
||||
}
|
||||
|
||||
static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes",
|
||||
[CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets",
|
||||
[CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes",
|
||||
[CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets",
|
||||
};
|
||||
|
||||
static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base",
|
||||
[CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base",
|
||||
};
|
||||
|
||||
static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last",
|
||||
[CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last",
|
||||
};
|
||||
|
||||
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
assert(fds);
|
||||
|
||||
if (unit_can_serialize(u)) {
|
||||
r = UNIT_VTABLE(u)->serialize(u, f, fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
(void) serialize_dual_timestamp(f, "state-change-timestamp", &u->state_change_timestamp);
|
||||
|
||||
(void) serialize_dual_timestamp(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "active-enter-timestamp", &u->active_enter_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "active-exit-timestamp", &u->active_exit_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
|
||||
|
||||
(void) serialize_dual_timestamp(f, "condition-timestamp", &u->condition_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "assert-timestamp", &u->assert_timestamp);
|
||||
|
||||
if (dual_timestamp_is_set(&u->condition_timestamp))
|
||||
(void) serialize_bool(f, "condition-result", u->condition_result);
|
||||
|
||||
if (dual_timestamp_is_set(&u->assert_timestamp))
|
||||
(void) serialize_bool(f, "assert-result", u->assert_result);
|
||||
|
||||
(void) serialize_bool(f, "transient", u->transient);
|
||||
(void) serialize_bool(f, "in-audit", u->in_audit);
|
||||
|
||||
(void) serialize_bool(f, "exported-invocation-id", u->exported_invocation_id);
|
||||
(void) serialize_bool(f, "exported-log-level-max", u->exported_log_level_max);
|
||||
(void) serialize_bool(f, "exported-log-extra-fields", u->exported_log_extra_fields);
|
||||
(void) serialize_bool(f, "exported-log-rate-limit-interval", u->exported_log_ratelimit_interval);
|
||||
(void) serialize_bool(f, "exported-log-rate-limit-burst", u->exported_log_ratelimit_burst);
|
||||
|
||||
(void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base);
|
||||
if (u->cpu_usage_last != NSEC_INFINITY)
|
||||
(void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last);
|
||||
|
||||
if (u->managed_oom_kill_last > 0)
|
||||
(void) serialize_item_format(f, "managed-oom-kill-last", "%" PRIu64, u->managed_oom_kill_last);
|
||||
|
||||
if (u->oom_kill_last > 0)
|
||||
(void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last);
|
||||
|
||||
for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) {
|
||||
(void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]);
|
||||
|
||||
if (u->io_accounting_last[im] != UINT64_MAX)
|
||||
(void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]);
|
||||
}
|
||||
|
||||
if (u->cgroup_path)
|
||||
(void) serialize_item(f, "cgroup", u->cgroup_path);
|
||||
|
||||
(void) serialize_bool(f, "cgroup-realized", u->cgroup_realized);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask);
|
||||
|
||||
if (uid_is_valid(u->ref_uid))
|
||||
(void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid);
|
||||
if (gid_is_valid(u->ref_gid))
|
||||
(void) serialize_item_format(f, "ref-gid", GID_FMT, u->ref_gid);
|
||||
|
||||
if (!sd_id128_is_null(u->invocation_id))
|
||||
(void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id));
|
||||
|
||||
(void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u)));
|
||||
|
||||
bus_track_serialize(u->bus_track, f, "ref");
|
||||
|
||||
for (CGroupIPAccountingMetric m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
|
||||
uint64_t v;
|
||||
|
||||
r = unit_get_ip_accounting(u, m, &v);
|
||||
if (r >= 0)
|
||||
(void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v);
|
||||
}
|
||||
|
||||
if (serialize_jobs) {
|
||||
if (u->job) {
|
||||
fputs("job\n", f);
|
||||
job_serialize(u->job, f);
|
||||
}
|
||||
|
||||
if (u->nop_job) {
|
||||
fputs("job\n", f);
|
||||
job_serialize(u->nop_job, f);
|
||||
}
|
||||
}
|
||||
|
||||
/* End marker */
|
||||
fputc('\n', f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unit_deserialize_job(Unit *u, FILE *f) {
|
||||
_cleanup_(job_freep) Job *j = NULL;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
|
||||
j = job_new_raw(u);
|
||||
if (!j)
|
||||
return log_oom();
|
||||
|
||||
r = job_deserialize(j, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = job_install_deserialized(j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(j);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
assert(fds);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
char *l, *v;
|
||||
ssize_t m;
|
||||
size_t k;
|
||||
|
||||
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) /* eof */
|
||||
break;
|
||||
|
||||
l = strstrip(line);
|
||||
if (isempty(l)) /* End marker */
|
||||
break;
|
||||
|
||||
k = strcspn(l, "=");
|
||||
|
||||
if (l[k] == '=') {
|
||||
l[k] = 0;
|
||||
v = l+k+1;
|
||||
} else
|
||||
v = l+k;
|
||||
|
||||
if (streq(l, "job")) {
|
||||
if (v[0] == '\0') {
|
||||
/* New-style serialized job */
|
||||
r = unit_deserialize_job(u, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else /* Legacy for pre-44 */
|
||||
log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
|
||||
continue;
|
||||
} else if (streq(l, "state-change-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->state_change_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "inactive-exit-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->inactive_exit_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "active-enter-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->active_enter_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "active-exit-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->active_exit_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "inactive-enter-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->inactive_enter_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "condition-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->condition_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "assert-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->assert_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "condition-result")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse condition result value %s, ignoring.", v);
|
||||
else
|
||||
u->condition_result = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "assert-result")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse assert result value %s, ignoring.", v);
|
||||
else
|
||||
u->assert_result = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "transient")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse transient bool %s, ignoring.", v);
|
||||
else
|
||||
u->transient = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "in-audit")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse in-audit bool %s, ignoring.", v);
|
||||
else
|
||||
u->in_audit = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-invocation-id")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported invocation ID bool %s, ignoring.", v);
|
||||
else
|
||||
u->exported_invocation_id = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-level-max")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log level max bool %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_level_max = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-extra-fields")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log extra fields bool %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_extra_fields = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-rate-limit-interval")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log rate limit interval %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_ratelimit_interval = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-rate-limit-burst")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log rate limit burst %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_ratelimit_burst = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (STR_IN_SET(l, "cpu-usage-base", "cpuacct-usage-base")) {
|
||||
|
||||
r = safe_atou64(v, &u->cpu_usage_base);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse CPU usage base %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cpu-usage-last")) {
|
||||
|
||||
r = safe_atou64(v, &u->cpu_usage_last);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to read CPU usage last %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "managed-oom-kill-last")) {
|
||||
|
||||
r = safe_atou64(v, &u->managed_oom_kill_last);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to read managed OOM kill last %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "oom-kill-last")) {
|
||||
|
||||
r = safe_atou64(v, &u->oom_kill_last);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to read OOM kill last %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup")) {
|
||||
|
||||
r = unit_set_cgroup_path(u, v);
|
||||
if (r < 0)
|
||||
log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v);
|
||||
|
||||
(void) unit_watch_cgroup(u);
|
||||
(void) unit_watch_cgroup_memory(u);
|
||||
|
||||
continue;
|
||||
} else if (streq(l, "cgroup-realized")) {
|
||||
int b;
|
||||
|
||||
b = parse_boolean(v);
|
||||
if (b < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-realized bool %s, ignoring.", v);
|
||||
else
|
||||
u->cgroup_realized = b;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup-realized-mask")) {
|
||||
|
||||
r = cg_mask_from_string(v, &u->cgroup_realized_mask);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-realized-mask %s, ignoring.", v);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup-enabled-mask")) {
|
||||
|
||||
r = cg_mask_from_string(v, &u->cgroup_enabled_mask);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-enabled-mask %s, ignoring.", v);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup-invalidated-mask")) {
|
||||
|
||||
r = cg_mask_from_string(v, &u->cgroup_invalidated_mask);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-invalidated-mask %s, ignoring.", v);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref-uid")) {
|
||||
uid_t uid;
|
||||
|
||||
r = parse_uid(v, &uid);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse referenced UID %s, ignoring.", v);
|
||||
else
|
||||
unit_ref_uid_gid(u, uid, GID_INVALID);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref-gid")) {
|
||||
gid_t gid;
|
||||
|
||||
r = parse_gid(v, &gid);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse referenced GID %s, ignoring.", v);
|
||||
else
|
||||
unit_ref_uid_gid(u, UID_INVALID, gid);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref")) {
|
||||
|
||||
r = strv_extend(&u->deserialized_refs, v);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
continue;
|
||||
} else if (streq(l, "invocation-id")) {
|
||||
sd_id128_t id;
|
||||
|
||||
r = sd_id128_from_string(v, &id);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse invocation id %s, ignoring.", v);
|
||||
else {
|
||||
r = unit_set_invocation_id(u, id);
|
||||
if (r < 0)
|
||||
log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m");
|
||||
}
|
||||
|
||||
continue;
|
||||
} else if (streq(l, "freezer-state")) {
|
||||
FreezerState s;
|
||||
|
||||
s = freezer_state_from_string(v);
|
||||
if (s < 0)
|
||||
log_unit_debug(u, "Failed to deserialize freezer-state '%s', ignoring.", v);
|
||||
else
|
||||
u->freezer_state = s;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if this is an IP accounting metric serialization field */
|
||||
m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v);
|
||||
else
|
||||
u->ip_accounting_extra[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IO accounting base value %s, ignoring.", v);
|
||||
else
|
||||
u->io_accounting_base[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IO accounting last value %s, ignoring.", v);
|
||||
else
|
||||
u->io_accounting_last[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unit_can_serialize(u)) {
|
||||
r = exec_runtime_deserialize_compat(u, l, v, fds);
|
||||
if (r < 0) {
|
||||
log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Returns positive if key was handled by the call */
|
||||
if (r > 0)
|
||||
continue;
|
||||
|
||||
r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
|
||||
if (r < 0)
|
||||
log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Versions before 228 did not carry a state change timestamp. In this case, take the current time. This is
|
||||
* useful, so that timeouts based on this timestamp don't trigger too early, and is in-line with the logic from
|
||||
* before 228 where the base for timeouts was not persistent across reboots. */
|
||||
|
||||
if (!dual_timestamp_is_set(&u->state_change_timestamp))
|
||||
dual_timestamp_get(&u->state_change_timestamp);
|
||||
|
||||
/* Let's make sure that everything that is deserialized also gets any potential new cgroup settings applied
|
||||
* after we are done. For that we invalidate anything already realized, so that we can realize it again. */
|
||||
unit_invalidate_cgroup(u, _CGROUP_MASK_ALL);
|
||||
unit_invalidate_cgroup_bpf(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_deserialize_skip(FILE *f) {
|
||||
int r;
|
||||
assert(f);
|
||||
|
||||
/* Skip serialized data for this unit. We don't know what it is. */
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
char *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)
|
||||
return 0;
|
||||
|
||||
l = strstrip(line);
|
||||
|
||||
/* End marker */
|
||||
if (isempty(l))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int unit_add_node_dependency(Unit *u, const char *what, UnitDependency dep, UnitDependencyMask mask) {
|
||||
_cleanup_free_ char *e = NULL;
|
||||
|
||||
+3
-6
@@ -5,6 +5,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "bpf-program.h"
|
||||
#include "condition.h"
|
||||
#include "emergency-action.h"
|
||||
@@ -721,8 +723,6 @@ int unit_freezer_state_kernel(Unit *u, FreezerState *ret);
|
||||
|
||||
const char* unit_sub_state_to_string(Unit *u);
|
||||
|
||||
void unit_dump(Unit *u, FILE *f, const char *prefix);
|
||||
|
||||
bool unit_can_reload(Unit *u) _pure_;
|
||||
bool unit_can_start(Unit *u) _pure_;
|
||||
bool unit_can_stop(Unit *u) _pure_;
|
||||
@@ -764,10 +764,6 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
|
||||
|
||||
bool unit_can_serialize(Unit *u) _pure_;
|
||||
|
||||
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
|
||||
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
|
||||
int unit_deserialize_skip(FILE *f);
|
||||
|
||||
int unit_add_node_dependency(Unit *u, const char *what, UnitDependency d, UnitDependencyMask mask);
|
||||
int unit_add_blockdev_dependency(Unit *u, const char *what, UnitDependencyMask mask);
|
||||
|
||||
@@ -847,6 +843,7 @@ void unit_unref_uid_gid(Unit *u, bool destroy_now);
|
||||
|
||||
void unit_notify_user_lookup(Unit *u, uid_t uid, gid_t gid);
|
||||
|
||||
int unit_set_invocation_id(Unit *u, sd_id128_t id);
|
||||
int unit_acquire_invocation_id(Unit *u);
|
||||
|
||||
bool unit_shall_confirm_spawn(Unit *u);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "rm-rf.h"
|
||||
#include "service.h"
|
||||
#include "tests.h"
|
||||
#include "unit.h"
|
||||
#include "unit-serialize.h"
|
||||
#include "virt.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
Reference in New Issue
Block a user