1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "bpf-socket-bind.h"
6 #include "fileio-label.h"
8 #include "format-util.h"
9 #include "parse-util.h"
10 #include "restrict-ifaces.h"
11 #include "serialize.h"
12 #include "string-table.h"
13 #include "unit-serialize.h"
14 #include "user-util.h"
16 static int serialize_cgroup_mask(FILE *f
, const char *key
, CGroupMask mask
) {
17 _cleanup_free_
char *s
= NULL
;
26 r
= cg_mask_to_string(mask
, &s
);
28 return log_error_errno(r
, "Failed to format cgroup mask: %m");
30 return serialize_item(f
, key
, s
);
33 /* Make sure out values fit in the bitfield. */
34 assert_cc(_UNIT_MARKER_MAX
<= sizeof(((Unit
){}).markers
) * 8);
36 static int serialize_markers(FILE *f
, unsigned markers
) {
43 for (UnitMarker m
= 0; m
< _UNIT_MARKER_MAX
; m
++)
44 if (FLAGS_SET(markers
, 1u << m
))
45 fputs(unit_marker_to_string(m
), f
);
50 static int deserialize_markers(Unit
*u
, const char *value
) {
55 for (const char *p
= value
;;) {
56 _cleanup_free_
char *word
= NULL
;
58 r
= extract_first_word(&p
, &word
, NULL
, 0);
62 UnitMarker m
= unit_marker_from_string(word
);
64 log_unit_debug_errno(u
, m
, "Unknown unit marker \"%s\", ignoring.", word
);
68 u
->markers
|= 1u << m
;
72 static const char *const ip_accounting_metric_field
[_CGROUP_IP_ACCOUNTING_METRIC_MAX
] = {
73 [CGROUP_IP_INGRESS_BYTES
] = "ip-accounting-ingress-bytes",
74 [CGROUP_IP_INGRESS_PACKETS
] = "ip-accounting-ingress-packets",
75 [CGROUP_IP_EGRESS_BYTES
] = "ip-accounting-egress-bytes",
76 [CGROUP_IP_EGRESS_PACKETS
] = "ip-accounting-egress-packets",
79 static const char *const io_accounting_metric_field_base
[_CGROUP_IO_ACCOUNTING_METRIC_MAX
] = {
80 [CGROUP_IO_READ_BYTES
] = "io-accounting-read-bytes-base",
81 [CGROUP_IO_WRITE_BYTES
] = "io-accounting-write-bytes-base",
82 [CGROUP_IO_READ_OPERATIONS
] = "io-accounting-read-operations-base",
83 [CGROUP_IO_WRITE_OPERATIONS
] = "io-accounting-write-operations-base",
86 static const char *const io_accounting_metric_field_last
[_CGROUP_IO_ACCOUNTING_METRIC_MAX
] = {
87 [CGROUP_IO_READ_BYTES
] = "io-accounting-read-bytes-last",
88 [CGROUP_IO_WRITE_BYTES
] = "io-accounting-write-bytes-last",
89 [CGROUP_IO_READ_OPERATIONS
] = "io-accounting-read-operations-last",
90 [CGROUP_IO_WRITE_OPERATIONS
] = "io-accounting-write-operations-last",
93 int unit_serialize(Unit
*u
, FILE *f
, FDSet
*fds
, bool switching_root
) {
100 if (switching_root
&& UNIT_VTABLE(u
)->exclude_from_switch_root_serialization
) {
101 /* In the new root, paths for mounts and automounts will be different, so it doesn't make
102 * much sense to serialize things. API file systems will be moved to the new root, but we
103 * don't have mount units for those. */
104 log_unit_debug(u
, "not serializing before switch-root");
112 assert(!!UNIT_VTABLE(u
)->serialize
== !!UNIT_VTABLE(u
)->deserialize_item
);
114 if (UNIT_VTABLE(u
)->serialize
) {
115 r
= UNIT_VTABLE(u
)->serialize(u
, f
, fds
);
120 (void) serialize_dual_timestamp(f
, "state-change-timestamp", &u
->state_change_timestamp
);
122 (void) serialize_dual_timestamp(f
, "inactive-exit-timestamp", &u
->inactive_exit_timestamp
);
123 (void) serialize_dual_timestamp(f
, "active-enter-timestamp", &u
->active_enter_timestamp
);
124 (void) serialize_dual_timestamp(f
, "active-exit-timestamp", &u
->active_exit_timestamp
);
125 (void) serialize_dual_timestamp(f
, "inactive-enter-timestamp", &u
->inactive_enter_timestamp
);
127 (void) serialize_dual_timestamp(f
, "condition-timestamp", &u
->condition_timestamp
);
128 (void) serialize_dual_timestamp(f
, "assert-timestamp", &u
->assert_timestamp
);
130 if (dual_timestamp_is_set(&u
->condition_timestamp
))
131 (void) serialize_bool(f
, "condition-result", u
->condition_result
);
133 if (dual_timestamp_is_set(&u
->assert_timestamp
))
134 (void) serialize_bool(f
, "assert-result", u
->assert_result
);
136 (void) serialize_bool(f
, "transient", u
->transient
);
137 (void) serialize_bool(f
, "in-audit", u
->in_audit
);
139 (void) serialize_bool(f
, "exported-invocation-id", u
->exported_invocation_id
);
140 (void) serialize_bool(f
, "exported-log-level-max", u
->exported_log_level_max
);
141 (void) serialize_bool(f
, "exported-log-extra-fields", u
->exported_log_extra_fields
);
142 (void) serialize_bool(f
, "exported-log-rate-limit-interval", u
->exported_log_ratelimit_interval
);
143 (void) serialize_bool(f
, "exported-log-rate-limit-burst", u
->exported_log_ratelimit_burst
);
145 (void) serialize_item_format(f
, "cpu-usage-base", "%" PRIu64
, u
->cpu_usage_base
);
146 if (u
->cpu_usage_last
!= NSEC_INFINITY
)
147 (void) serialize_item_format(f
, "cpu-usage-last", "%" PRIu64
, u
->cpu_usage_last
);
149 if (u
->managed_oom_kill_last
> 0)
150 (void) serialize_item_format(f
, "managed-oom-kill-last", "%" PRIu64
, u
->managed_oom_kill_last
);
152 if (u
->oom_kill_last
> 0)
153 (void) serialize_item_format(f
, "oom-kill-last", "%" PRIu64
, u
->oom_kill_last
);
155 for (CGroupIOAccountingMetric im
= 0; im
< _CGROUP_IO_ACCOUNTING_METRIC_MAX
; im
++) {
156 (void) serialize_item_format(f
, io_accounting_metric_field_base
[im
], "%" PRIu64
, u
->io_accounting_base
[im
]);
158 if (u
->io_accounting_last
[im
] != UINT64_MAX
)
159 (void) serialize_item_format(f
, io_accounting_metric_field_last
[im
], "%" PRIu64
, u
->io_accounting_last
[im
]);
163 (void) serialize_item(f
, "cgroup", u
->cgroup_path
);
165 (void) serialize_bool(f
, "cgroup-realized", u
->cgroup_realized
);
166 (void) serialize_cgroup_mask(f
, "cgroup-realized-mask", u
->cgroup_realized_mask
);
167 (void) serialize_cgroup_mask(f
, "cgroup-enabled-mask", u
->cgroup_enabled_mask
);
168 (void) serialize_cgroup_mask(f
, "cgroup-invalidated-mask", u
->cgroup_invalidated_mask
);
170 (void) bpf_serialize_socket_bind(u
, f
, fds
);
172 (void) bpf_program_serialize_attachment(f
, fds
, "ip-bpf-ingress-installed", u
->ip_bpf_ingress_installed
);
173 (void) bpf_program_serialize_attachment(f
, fds
, "ip-bpf-egress-installed", u
->ip_bpf_egress_installed
);
174 (void) bpf_program_serialize_attachment(f
, fds
, "bpf-device-control-installed", u
->bpf_device_control_installed
);
175 (void) bpf_program_serialize_attachment_set(f
, fds
, "ip-bpf-custom-ingress-installed", u
->ip_bpf_custom_ingress_installed
);
176 (void) bpf_program_serialize_attachment_set(f
, fds
, "ip-bpf-custom-egress-installed", u
->ip_bpf_custom_egress_installed
);
178 (void) serialize_restrict_network_interfaces(u
, f
, fds
);
180 if (uid_is_valid(u
->ref_uid
))
181 (void) serialize_item_format(f
, "ref-uid", UID_FMT
, u
->ref_uid
);
182 if (gid_is_valid(u
->ref_gid
))
183 (void) serialize_item_format(f
, "ref-gid", GID_FMT
, u
->ref_gid
);
185 if (!sd_id128_is_null(u
->invocation_id
))
186 (void) serialize_item_format(f
, "invocation-id", SD_ID128_FORMAT_STR
, SD_ID128_FORMAT_VAL(u
->invocation_id
));
188 (void) serialize_item_format(f
, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u
)));
189 (void) serialize_markers(f
, u
->markers
);
191 bus_track_serialize(u
->bus_track
, f
, "ref");
193 for (CGroupIPAccountingMetric m
= 0; m
< _CGROUP_IP_ACCOUNTING_METRIC_MAX
; m
++) {
196 r
= unit_get_ip_accounting(u
, m
, &v
);
198 (void) serialize_item_format(f
, ip_accounting_metric_field
[m
], "%" PRIu64
, v
);
201 if (!switching_root
) {
204 job_serialize(u
->job
, f
);
209 job_serialize(u
->nop_job
, f
);
218 static int unit_deserialize_job(Unit
*u
, FILE *f
) {
219 _cleanup_(job_freep
) Job
*j
= NULL
;
229 r
= job_deserialize(j
, f
);
233 r
= job_install_deserialized(j
);
241 #define MATCH_DESERIALIZE(key, l, v, parse_func, target) \
243 bool _deserialize_matched = streq(l, key); \
244 if (_deserialize_matched) { \
245 int _deserialize_r = parse_func(v); \
246 if (_deserialize_r < 0) \
247 log_unit_debug_errno(u, _deserialize_r, \
248 "Failed to parse \"%s=%s\", ignoring.", l, v); \
250 target = _deserialize_r; \
252 _deserialize_matched; \
255 #define MATCH_DESERIALIZE_IMMEDIATE(key, l, v, parse_func, target) \
257 bool _deserialize_matched = streq(l, key); \
258 if (_deserialize_matched) { \
259 int _deserialize_r = parse_func(v, &target); \
260 if (_deserialize_r < 0) \
261 log_unit_debug_errno(u, _deserialize_r, \
262 "Failed to parse \"%s=%s\", ignoring", l, v); \
264 _deserialize_matched; \
267 int unit_deserialize(Unit
*u
, FILE *f
, FDSet
*fds
) {
275 _cleanup_free_
char *line
= NULL
;
280 r
= read_line(f
, LONG_LINE_MAX
, &line
);
282 return log_error_errno(r
, "Failed to read serialization line: %m");
283 if (r
== 0) /* eof */
287 if (isempty(l
)) /* End marker */
298 if (streq(l
, "job")) {
300 /* New-style serialized job */
301 r
= unit_deserialize_job(u
, f
);
304 } else /* Legacy for pre-44 */
305 log_unit_warning(u
, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v
);
307 } else if (streq(l
, "state-change-timestamp")) {
308 (void) deserialize_dual_timestamp(v
, &u
->state_change_timestamp
);
310 } else if (streq(l
, "inactive-exit-timestamp")) {
311 (void) deserialize_dual_timestamp(v
, &u
->inactive_exit_timestamp
);
313 } else if (streq(l
, "active-enter-timestamp")) {
314 (void) deserialize_dual_timestamp(v
, &u
->active_enter_timestamp
);
316 } else if (streq(l
, "active-exit-timestamp")) {
317 (void) deserialize_dual_timestamp(v
, &u
->active_exit_timestamp
);
319 } else if (streq(l
, "inactive-enter-timestamp")) {
320 (void) deserialize_dual_timestamp(v
, &u
->inactive_enter_timestamp
);
322 } else if (streq(l
, "condition-timestamp")) {
323 (void) deserialize_dual_timestamp(v
, &u
->condition_timestamp
);
325 } else if (streq(l
, "assert-timestamp")) {
326 (void) deserialize_dual_timestamp(v
, &u
->assert_timestamp
);
329 } else if (MATCH_DESERIALIZE("condition-result", l
, v
, parse_boolean
, u
->condition_result
))
332 else if (MATCH_DESERIALIZE("assert-result", l
, v
, parse_boolean
, u
->assert_result
))
335 else if (MATCH_DESERIALIZE("transient", l
, v
, parse_boolean
, u
->transient
))
338 else if (MATCH_DESERIALIZE("in-audit", l
, v
, parse_boolean
, u
->in_audit
))
341 else if (MATCH_DESERIALIZE("exported-invocation-id", l
, v
, parse_boolean
, u
->exported_invocation_id
))
344 else if (MATCH_DESERIALIZE("exported-log-level-max", l
, v
, parse_boolean
, u
->exported_log_level_max
))
347 else if (MATCH_DESERIALIZE("exported-log-extra-fields", l
, v
, parse_boolean
, u
->exported_log_extra_fields
))
350 else if (MATCH_DESERIALIZE("exported-log-rate-limit-interval", l
, v
, parse_boolean
, u
->exported_log_ratelimit_interval
))
353 else if (MATCH_DESERIALIZE("exported-log-rate-limit-burst", l
, v
, parse_boolean
, u
->exported_log_ratelimit_burst
))
356 else if (MATCH_DESERIALIZE_IMMEDIATE("cpu-usage-base", l
, v
, safe_atou64
, u
->cpu_usage_base
) ||
357 MATCH_DESERIALIZE_IMMEDIATE("cpuacct-usage-base", l
, v
, safe_atou64
, u
->cpu_usage_base
))
360 else if (MATCH_DESERIALIZE_IMMEDIATE("cpu-usage-last", l
, v
, safe_atou64
, u
->cpu_usage_last
))
363 else if (MATCH_DESERIALIZE_IMMEDIATE("managed-oom-kill-last", l
, v
, safe_atou64
, u
->managed_oom_kill_last
))
366 else if (MATCH_DESERIALIZE_IMMEDIATE("oom-kill-last", l
, v
, safe_atou64
, u
->oom_kill_last
))
369 else if (streq(l
, "cgroup")) {
370 r
= unit_set_cgroup_path(u
, v
);
372 log_unit_debug_errno(u
, r
, "Failed to set cgroup path %s, ignoring: %m", v
);
374 (void) unit_watch_cgroup(u
);
375 (void) unit_watch_cgroup_memory(u
);
379 } else if (MATCH_DESERIALIZE("cgroup-realized", l
, v
, parse_boolean
, u
->cgroup_realized
))
382 else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-realized-mask", l
, v
, cg_mask_from_string
, u
->cgroup_realized_mask
))
385 else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-enabled-mask", l
, v
, cg_mask_from_string
, u
->cgroup_enabled_mask
))
388 else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-invalidated-mask", l
, v
, cg_mask_from_string
, u
->cgroup_invalidated_mask
))
391 else if (STR_IN_SET(l
, "ipv4-socket-bind-bpf-link-fd", "ipv6-socket-bind-bpf-link-fd")) {
394 if ((fd
= parse_fd(v
)) < 0 || !fdset_contains(fds
, fd
))
395 log_unit_debug(u
, "Failed to parse %s value: %s, ignoring.", l
, v
);
397 if (fdset_remove(fds
, fd
) < 0) {
398 log_unit_debug(u
, "Failed to remove %s value=%d from fdset", l
, fd
);
402 (void) bpf_socket_bind_add_initial_link_fd(u
, fd
);
406 } else if (streq(l
, "ip-bpf-ingress-installed")) {
407 (void) bpf_program_deserialize_attachment(v
, fds
, &u
->ip_bpf_ingress_installed
);
409 } else if (streq(l
, "ip-bpf-egress-installed")) {
410 (void) bpf_program_deserialize_attachment(v
, fds
, &u
->ip_bpf_egress_installed
);
412 } else if (streq(l
, "bpf-device-control-installed")) {
413 (void) bpf_program_deserialize_attachment(v
, fds
, &u
->bpf_device_control_installed
);
416 } else if (streq(l
, "ip-bpf-custom-ingress-installed")) {
417 (void) bpf_program_deserialize_attachment_set(v
, fds
, &u
->ip_bpf_custom_ingress_installed
);
419 } else if (streq(l
, "ip-bpf-custom-egress-installed")) {
420 (void) bpf_program_deserialize_attachment_set(v
, fds
, &u
->ip_bpf_custom_egress_installed
);
423 } else if (streq(l
, "restrict-ifaces-bpf-fd")) {
426 if ((fd
= parse_fd(v
)) < 0 || !fdset_contains(fds
, fd
)) {
427 log_unit_debug(u
, "Failed to parse restrict-ifaces-bpf-fd value: %s", v
);
430 if (fdset_remove(fds
, fd
) < 0) {
431 log_unit_debug(u
, "Failed to remove restrict-ifaces-bpf-fd %d from fdset", fd
);
435 (void) restrict_network_interfaces_add_initial_link_fd(u
, fd
);
438 } else if (streq(l
, "ref-uid")) {
441 r
= parse_uid(v
, &uid
);
443 log_unit_debug(u
, "Failed to parse \"%s=%s\", ignoring.", l
, v
);
445 unit_ref_uid_gid(u
, uid
, GID_INVALID
);
448 } else if (streq(l
, "ref-gid")) {
451 r
= parse_gid(v
, &gid
);
453 log_unit_debug(u
, "Failed to parse \"%s=%s\", ignoring.", l
, v
);
455 unit_ref_uid_gid(u
, UID_INVALID
, gid
);
458 } else if (streq(l
, "ref")) {
459 r
= strv_extend(&u
->deserialized_refs
, v
);
464 } else if (streq(l
, "invocation-id")) {
467 r
= sd_id128_from_string(v
, &id
);
469 log_unit_debug(u
, "Failed to parse \"%s=%s\", ignoring.", l
, v
);
471 r
= unit_set_invocation_id(u
, id
);
473 log_unit_warning_errno(u
, r
, "Failed to set invocation ID for unit: %m");
478 } else if (MATCH_DESERIALIZE("freezer-state", l
, v
, freezer_state_from_string
, u
->freezer_state
))
481 else if (streq(l
, "markers")) {
482 r
= deserialize_markers(u
, v
);
484 log_unit_debug_errno(u
, r
, "Failed to deserialize \"%s=%s\", ignoring: %m", l
, v
);
488 /* Check if this is an IP accounting metric serialization field */
489 m
= string_table_lookup(ip_accounting_metric_field
, ELEMENTSOF(ip_accounting_metric_field
), l
);
493 r
= safe_atou64(v
, &c
);
495 log_unit_debug(u
, "Failed to parse IP accounting value %s, ignoring.", v
);
497 u
->ip_accounting_extra
[m
] = c
;
501 m
= string_table_lookup(io_accounting_metric_field_base
, ELEMENTSOF(io_accounting_metric_field_base
), l
);
505 r
= safe_atou64(v
, &c
);
507 log_unit_debug(u
, "Failed to parse IO accounting base value %s, ignoring.", v
);
509 u
->io_accounting_base
[m
] = c
;
513 m
= string_table_lookup(io_accounting_metric_field_last
, ELEMENTSOF(io_accounting_metric_field_last
), l
);
517 r
= safe_atou64(v
, &c
);
519 log_unit_debug(u
, "Failed to parse IO accounting last value %s, ignoring.", v
);
521 u
->io_accounting_last
[m
] = c
;
525 r
= exec_shared_runtime_deserialize_compat(u
, l
, v
, fds
);
527 log_unit_warning(u
, "Failed to deserialize runtime parameter '%s', ignoring.", l
);
530 /* Returns positive if key was handled by the call */
533 if (UNIT_VTABLE(u
)->deserialize_item
) {
534 r
= UNIT_VTABLE(u
)->deserialize_item(u
, l
, v
, fds
);
536 log_unit_warning(u
, "Failed to deserialize unit parameter '%s', ignoring.", l
);
540 /* Versions before 228 did not carry a state change timestamp. In this case, take the current
541 * time. This is useful, so that timeouts based on this timestamp don't trigger too early, and is
542 * in-line with the logic from before 228 where the base for timeouts was not persistent across
545 if (!dual_timestamp_is_set(&u
->state_change_timestamp
))
546 dual_timestamp_get(&u
->state_change_timestamp
);
548 /* Let's make sure that everything that is deserialized also gets any potential new cgroup settings
549 * applied after we are done. For that we invalidate anything already realized, so that we can
550 * realize it again. */
551 if (u
->cgroup_realized
) {
552 unit_invalidate_cgroup(u
, _CGROUP_MASK_ALL
);
553 unit_invalidate_cgroup_bpf(u
);
559 int unit_deserialize_skip(FILE *f
) {
563 /* Skip serialized data for this unit. We don't know what it is. */
566 _cleanup_free_
char *line
= NULL
;
569 r
= read_line(f
, LONG_LINE_MAX
, &line
);
571 return log_error_errno(r
, "Failed to read serialization line: %m");
583 static void print_unit_dependency_mask(FILE *f
, const char *kind
, UnitDependencyMask mask
, bool *space
) {
585 UnitDependencyMask mask
;
588 { UNIT_DEPENDENCY_FILE
, "file" },
589 { UNIT_DEPENDENCY_IMPLICIT
, "implicit" },
590 { UNIT_DEPENDENCY_DEFAULT
, "default" },
591 { UNIT_DEPENDENCY_UDEV
, "udev" },
592 { UNIT_DEPENDENCY_PATH
, "path" },
593 { UNIT_DEPENDENCY_MOUNT_FILE
, "mount-file" },
594 { UNIT_DEPENDENCY_MOUNTINFO
, "mountinfo" },
595 { UNIT_DEPENDENCY_PROC_SWAP
, "proc-swap" },
596 { UNIT_DEPENDENCY_SLICE_PROPERTY
, "slice-property" },
603 for (size_t i
= 0; i
< ELEMENTSOF(table
); i
++) {
608 if (FLAGS_SET(mask
, table
[i
].mask
)) {
616 fputs(table
[i
].name
, f
);
618 mask
&= ~table
[i
].mask
;
625 void unit_dump(Unit
*u
, FILE *f
, const char *prefix
) {
629 _cleanup_set_free_ Set
*following_set
= NULL
;
634 assert(u
->type
>= 0);
636 prefix
= strempty(prefix
);
637 prefix2
= strjoina(prefix
, "\t");
643 SET_FOREACH(t
, u
->aliases
)
644 fprintf(f
, "%s\tAlias: %s\n", prefix
, t
);
647 "%s\tDescription: %s\n"
649 "%s\tUnit Load State: %s\n"
650 "%s\tUnit Active State: %s\n"
651 "%s\tState Change Timestamp: %s\n"
652 "%s\tInactive Exit Timestamp: %s\n"
653 "%s\tActive Enter Timestamp: %s\n"
654 "%s\tActive Exit Timestamp: %s\n"
655 "%s\tInactive Enter Timestamp: %s\n"
657 "%s\tNeed Daemon Reload: %s\n"
658 "%s\tTransient: %s\n"
659 "%s\tPerpetual: %s\n"
660 "%s\tGarbage Collection Mode: %s\n",
661 prefix
, unit_description(u
),
662 prefix
, strna(u
->instance
),
663 prefix
, unit_load_state_to_string(u
->load_state
),
664 prefix
, unit_active_state_to_string(unit_active_state(u
)),
665 prefix
, strna(FORMAT_TIMESTAMP(u
->state_change_timestamp
.realtime
)),
666 prefix
, strna(FORMAT_TIMESTAMP(u
->inactive_exit_timestamp
.realtime
)),
667 prefix
, strna(FORMAT_TIMESTAMP(u
->active_enter_timestamp
.realtime
)),
668 prefix
, strna(FORMAT_TIMESTAMP(u
->active_exit_timestamp
.realtime
)),
669 prefix
, strna(FORMAT_TIMESTAMP(u
->inactive_enter_timestamp
.realtime
)),
670 prefix
, yes_no(unit_may_gc(u
)),
671 prefix
, yes_no(unit_need_daemon_reload(u
)),
672 prefix
, yes_no(u
->transient
),
673 prefix
, yes_no(u
->perpetual
),
674 prefix
, collect_mode_to_string(u
->collect_mode
));
676 if (u
->markers
!= 0) {
677 fprintf(f
, "%s\tMarkers:", prefix
);
679 for (UnitMarker marker
= 0; marker
< _UNIT_MARKER_MAX
; marker
++)
680 if (FLAGS_SET(u
->markers
, 1u << marker
))
681 fprintf(f
, " %s", unit_marker_to_string(marker
));
685 if (UNIT_HAS_CGROUP_CONTEXT(u
)) {
689 "%s\tCGroup realized: %s\n",
690 prefix
, strna(unit_slice_name(u
)),
691 prefix
, strna(u
->cgroup_path
),
692 prefix
, yes_no(u
->cgroup_realized
));
694 if (u
->cgroup_realized_mask
!= 0) {
695 _cleanup_free_
char *s
= NULL
;
696 (void) cg_mask_to_string(u
->cgroup_realized_mask
, &s
);
697 fprintf(f
, "%s\tCGroup realized mask: %s\n", prefix
, strnull(s
));
700 if (u
->cgroup_enabled_mask
!= 0) {
701 _cleanup_free_
char *s
= NULL
;
702 (void) cg_mask_to_string(u
->cgroup_enabled_mask
, &s
);
703 fprintf(f
, "%s\tCGroup enabled mask: %s\n", prefix
, strnull(s
));
706 m
= unit_get_own_mask(u
);
708 _cleanup_free_
char *s
= NULL
;
709 (void) cg_mask_to_string(m
, &s
);
710 fprintf(f
, "%s\tCGroup own mask: %s\n", prefix
, strnull(s
));
713 m
= unit_get_members_mask(u
);
715 _cleanup_free_
char *s
= NULL
;
716 (void) cg_mask_to_string(m
, &s
);
717 fprintf(f
, "%s\tCGroup members mask: %s\n", prefix
, strnull(s
));
720 m
= unit_get_delegate_mask(u
);
722 _cleanup_free_
char *s
= NULL
;
723 (void) cg_mask_to_string(m
, &s
);
724 fprintf(f
, "%s\tCGroup delegate mask: %s\n", prefix
, strnull(s
));
728 if (!sd_id128_is_null(u
->invocation_id
))
729 fprintf(f
, "%s\tInvocation ID: " SD_ID128_FORMAT_STR
"\n",
730 prefix
, SD_ID128_FORMAT_VAL(u
->invocation_id
));
732 STRV_FOREACH(j
, u
->documentation
)
733 fprintf(f
, "%s\tDocumentation: %s\n", prefix
, *j
);
735 if (u
->access_selinux_context
)
736 fprintf(f
, "%s\tAccess SELinux Context: %s\n", prefix
, u
->access_selinux_context
);
738 following
= unit_following(u
);
740 fprintf(f
, "%s\tFollowing: %s\n", prefix
, following
->id
);
742 r
= unit_following_set(u
, &following_set
);
746 SET_FOREACH(other
, following_set
)
747 fprintf(f
, "%s\tFollowing Set Member: %s\n", prefix
, other
->id
);
750 if (u
->fragment_path
)
751 fprintf(f
, "%s\tFragment Path: %s\n", prefix
, u
->fragment_path
);
754 fprintf(f
, "%s\tSource Path: %s\n", prefix
, u
->source_path
);
756 STRV_FOREACH(j
, u
->dropin_paths
)
757 fprintf(f
, "%s\tDropIn Path: %s\n", prefix
, *j
);
759 if (u
->failure_action
!= EMERGENCY_ACTION_NONE
)
760 fprintf(f
, "%s\tFailure Action: %s\n", prefix
, emergency_action_to_string(u
->failure_action
));
761 if (u
->failure_action_exit_status
>= 0)
762 fprintf(f
, "%s\tFailure Action Exit Status: %i\n", prefix
, u
->failure_action_exit_status
);
763 if (u
->success_action
!= EMERGENCY_ACTION_NONE
)
764 fprintf(f
, "%s\tSuccess Action: %s\n", prefix
, emergency_action_to_string(u
->success_action
));
765 if (u
->success_action_exit_status
>= 0)
766 fprintf(f
, "%s\tSuccess Action Exit Status: %i\n", prefix
, u
->success_action_exit_status
);
768 if (u
->job_timeout
!= USEC_INFINITY
)
769 fprintf(f
, "%s\tJob Timeout: %s\n", prefix
, FORMAT_TIMESPAN(u
->job_timeout
, 0));
771 if (u
->job_timeout_action
!= EMERGENCY_ACTION_NONE
)
772 fprintf(f
, "%s\tJob Timeout Action: %s\n", prefix
, emergency_action_to_string(u
->job_timeout_action
));
774 if (u
->job_timeout_reboot_arg
)
775 fprintf(f
, "%s\tJob Timeout Reboot Argument: %s\n", prefix
, u
->job_timeout_reboot_arg
);
777 condition_dump_list(u
->conditions
, f
, prefix
, condition_type_to_string
);
778 condition_dump_list(u
->asserts
, f
, prefix
, assert_type_to_string
);
780 if (dual_timestamp_is_set(&u
->condition_timestamp
))
782 "%s\tCondition Timestamp: %s\n"
783 "%s\tCondition Result: %s\n",
784 prefix
, strna(FORMAT_TIMESTAMP(u
->condition_timestamp
.realtime
)),
785 prefix
, yes_no(u
->condition_result
));
787 if (dual_timestamp_is_set(&u
->assert_timestamp
))
789 "%s\tAssert Timestamp: %s\n"
790 "%s\tAssert Result: %s\n",
791 prefix
, strna(FORMAT_TIMESTAMP(u
->assert_timestamp
.realtime
)),
792 prefix
, yes_no(u
->assert_result
));
794 for (UnitDependency d
= 0; d
< _UNIT_DEPENDENCY_MAX
; d
++) {
795 UnitDependencyInfo di
;
798 HASHMAP_FOREACH_KEY(di
.data
, other
, unit_get_dependencies(u
, d
)) {
801 fprintf(f
, "%s\t%s: %s (", prefix
, unit_dependency_to_string(d
), other
->id
);
803 print_unit_dependency_mask(f
, "origin", di
.origin_mask
, &space
);
804 print_unit_dependency_mask(f
, "destination", di
.destination_mask
, &space
);
810 if (!hashmap_isempty(u
->requires_mounts_for
)) {
811 UnitDependencyInfo di
;
814 HASHMAP_FOREACH_KEY(di
.data
, path
, u
->requires_mounts_for
) {
817 fprintf(f
, "%s\tRequiresMountsFor: %s (", prefix
, path
);
819 print_unit_dependency_mask(f
, "origin", di
.origin_mask
, &space
);
820 print_unit_dependency_mask(f
, "destination", di
.destination_mask
, &space
);
826 if (u
->load_state
== UNIT_LOADED
) {
829 "%s\tStopWhenUnneeded: %s\n"
830 "%s\tRefuseManualStart: %s\n"
831 "%s\tRefuseManualStop: %s\n"
832 "%s\tDefaultDependencies: %s\n"
833 "%s\tOnSuccessJobMode: %s\n"
834 "%s\tOnFailureJobMode: %s\n"
835 "%s\tIgnoreOnIsolate: %s\n",
836 prefix
, yes_no(u
->stop_when_unneeded
),
837 prefix
, yes_no(u
->refuse_manual_start
),
838 prefix
, yes_no(u
->refuse_manual_stop
),
839 prefix
, yes_no(u
->default_dependencies
),
840 prefix
, job_mode_to_string(u
->on_success_job_mode
),
841 prefix
, job_mode_to_string(u
->on_failure_job_mode
),
842 prefix
, yes_no(u
->ignore_on_isolate
));
844 if (UNIT_VTABLE(u
)->dump
)
845 UNIT_VTABLE(u
)->dump(u
, f
, prefix2
);
847 } else if (u
->load_state
== UNIT_MERGED
)
849 "%s\tMerged into: %s\n",
850 prefix
, u
->merged_into
->id
);
851 else if (u
->load_state
== UNIT_ERROR
) {
852 errno
= abs(u
->load_error
);
853 fprintf(f
, "%s\tLoad Error Code: %m\n", prefix
);
856 for (const char *n
= sd_bus_track_first(u
->bus_track
); n
; n
= sd_bus_track_next(u
->bus_track
))
857 fprintf(f
, "%s\tBus Ref: %s\n", prefix
, n
);
860 job_dump(u
->job
, f
, prefix2
);
863 job_dump(u
->nop_job
, f
, prefix2
);