]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/unit-serialize.c
core: drop bitfields in VTable object
[thirdparty/systemd.git] / src / core / unit-serialize.c
CommitLineData
2d3b784d
ZJS
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include "bus-util.h"
4#include "dbus.h"
5#include "fileio-label.h"
6#include "fileio.h"
7#include "format-util.h"
8#include "parse-util.h"
9#include "serialize.h"
3d027d4d 10#include "socket-bind.h"
2d3b784d
ZJS
11#include "string-table.h"
12#include "unit-serialize.h"
13#include "user-util.h"
14
15static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) {
16 _cleanup_free_ char *s = NULL;
17 int r;
18
19 assert(f);
20 assert(key);
21
22 if (mask == 0)
23 return 0;
24
25 r = cg_mask_to_string(mask, &s);
26 if (r < 0)
27 return log_error_errno(r, "Failed to format cgroup mask: %m");
28
29 return serialize_item(f, key, s);
30}
31
ff68472a
ZJS
32/* Make sure out values fit in the bitfield. */
33assert_cc(_UNIT_MARKER_MAX <= sizeof(((Unit){}).markers) * 8);
34
35static int serialize_markers(FILE *f, unsigned markers) {
36 assert(f);
37
38 if (markers == 0)
39 return 0;
40
41 fputs("markers=", f);
42 for (UnitMarker m = 0; m < _UNIT_MARKER_MAX; m++)
43 if (FLAGS_SET(markers, 1u << m))
44 fputs(unit_marker_to_string(m), f);
45 fputc('\n', f);
46 return 0;
47}
48
49static int deserialize_markers(Unit *u, const char *value) {
50 assert(u);
51 assert(value);
52 int r;
53
54 for (const char *p = value;;) {
55 _cleanup_free_ char *word = NULL;
56
57 r = extract_first_word(&p, &word, NULL, 0);
58 if (r <= 0)
59 return r;
60
61 UnitMarker m = unit_marker_from_string(word);
62 if (m < 0) {
63 log_unit_debug_errno(u, m, "Unknown unit marker \"%s\", ignoring.", word);
64 continue;
65 }
66
67 u->markers |= 1u << m;
68 }
69}
70
2d3b784d
ZJS
71static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
72 [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes",
73 [CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets",
74 [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes",
75 [CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets",
76};
77
78static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
79 [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base",
80 [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base",
81 [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base",
82 [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base",
83};
84
85static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
86 [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last",
87 [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last",
88 [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last",
89 [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last",
90};
91
92int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
93 int r;
94
95 assert(u);
96 assert(f);
97 assert(fds);
98
99 if (unit_can_serialize(u)) {
100 r = UNIT_VTABLE(u)->serialize(u, f, fds);
101 if (r < 0)
102 return r;
103 }
104
105 (void) serialize_dual_timestamp(f, "state-change-timestamp", &u->state_change_timestamp);
106
107 (void) serialize_dual_timestamp(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
108 (void) serialize_dual_timestamp(f, "active-enter-timestamp", &u->active_enter_timestamp);
109 (void) serialize_dual_timestamp(f, "active-exit-timestamp", &u->active_exit_timestamp);
110 (void) serialize_dual_timestamp(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
111
112 (void) serialize_dual_timestamp(f, "condition-timestamp", &u->condition_timestamp);
113 (void) serialize_dual_timestamp(f, "assert-timestamp", &u->assert_timestamp);
114
115 if (dual_timestamp_is_set(&u->condition_timestamp))
116 (void) serialize_bool(f, "condition-result", u->condition_result);
117
118 if (dual_timestamp_is_set(&u->assert_timestamp))
119 (void) serialize_bool(f, "assert-result", u->assert_result);
120
121 (void) serialize_bool(f, "transient", u->transient);
122 (void) serialize_bool(f, "in-audit", u->in_audit);
123
124 (void) serialize_bool(f, "exported-invocation-id", u->exported_invocation_id);
125 (void) serialize_bool(f, "exported-log-level-max", u->exported_log_level_max);
126 (void) serialize_bool(f, "exported-log-extra-fields", u->exported_log_extra_fields);
127 (void) serialize_bool(f, "exported-log-rate-limit-interval", u->exported_log_ratelimit_interval);
128 (void) serialize_bool(f, "exported-log-rate-limit-burst", u->exported_log_ratelimit_burst);
129
130 (void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base);
131 if (u->cpu_usage_last != NSEC_INFINITY)
132 (void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last);
133
134 if (u->managed_oom_kill_last > 0)
135 (void) serialize_item_format(f, "managed-oom-kill-last", "%" PRIu64, u->managed_oom_kill_last);
136
137 if (u->oom_kill_last > 0)
138 (void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last);
139
140 for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) {
141 (void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]);
142
143 if (u->io_accounting_last[im] != UINT64_MAX)
144 (void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]);
145 }
146
147 if (u->cgroup_path)
148 (void) serialize_item(f, "cgroup", u->cgroup_path);
149
150 (void) serialize_bool(f, "cgroup-realized", u->cgroup_realized);
151 (void) serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask);
152 (void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask);
153 (void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask);
154
3d027d4d
JK
155 (void) serialize_socket_bind(u, f, fds);
156
2d3b784d
ZJS
157 if (uid_is_valid(u->ref_uid))
158 (void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid);
159 if (gid_is_valid(u->ref_gid))
160 (void) serialize_item_format(f, "ref-gid", GID_FMT, u->ref_gid);
161
162 if (!sd_id128_is_null(u->invocation_id))
163 (void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id));
164
165 (void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u)));
ff68472a 166 (void) serialize_markers(f, u->markers);
2d3b784d
ZJS
167
168 bus_track_serialize(u->bus_track, f, "ref");
169
170 for (CGroupIPAccountingMetric m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
171 uint64_t v;
172
173 r = unit_get_ip_accounting(u, m, &v);
174 if (r >= 0)
175 (void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v);
176 }
177
178 if (serialize_jobs) {
179 if (u->job) {
180 fputs("job\n", f);
181 job_serialize(u->job, f);
182 }
183
184 if (u->nop_job) {
185 fputs("job\n", f);
186 job_serialize(u->nop_job, f);
187 }
188 }
189
190 /* End marker */
191 fputc('\n', f);
192 return 0;
193}
194
195static int unit_deserialize_job(Unit *u, FILE *f) {
196 _cleanup_(job_freep) Job *j = NULL;
197 int r;
198
199 assert(u);
200 assert(f);
201
202 j = job_new_raw(u);
203 if (!j)
204 return log_oom();
205
206 r = job_deserialize(j, f);
207 if (r < 0)
208 return r;
209
210 r = job_install_deserialized(j);
211 if (r < 0)
212 return r;
213
214 TAKE_PTR(j);
215 return 0;
216}
217
9466ec13
ZJS
218#define MATCH_DESERIALIZE(key, l, v, parse_func, target) \
219 ({ \
220 bool _deserialize_matched = streq(l, key); \
221 if (_deserialize_matched) { \
222 int _deserialize_r = parse_func(v); \
223 if (_deserialize_r < 0) \
224 log_unit_debug_errno(u, _deserialize_r, \
225 "Failed to parse \"%s=%s\", ignoring.", l, v); \
226 else \
227 target = _deserialize_r; \
228 }; \
229 _deserialize_matched; \
230 })
231
232#define MATCH_DESERIALIZE_IMMEDIATE(key, l, v, parse_func, target) \
233 ({ \
234 bool _deserialize_matched = streq(l, key); \
235 if (_deserialize_matched) { \
236 int _deserialize_r = parse_func(v, &target); \
237 if (_deserialize_r < 0) \
238 log_unit_debug_errno(u, _deserialize_r, \
239 "Failed to parse \"%s=%s\", ignoring", l, v); \
240 }; \
241 _deserialize_matched; \
242 })
243
2d3b784d
ZJS
244int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
245 int r;
246
247 assert(u);
248 assert(f);
249 assert(fds);
250
251 for (;;) {
252 _cleanup_free_ char *line = NULL;
253 char *l, *v;
254 ssize_t m;
255 size_t k;
256
257 r = read_line(f, LONG_LINE_MAX, &line);
258 if (r < 0)
259 return log_error_errno(r, "Failed to read serialization line: %m");
260 if (r == 0) /* eof */
261 break;
262
263 l = strstrip(line);
264 if (isempty(l)) /* End marker */
265 break;
266
267 k = strcspn(l, "=");
268
269 if (l[k] == '=') {
270 l[k] = 0;
271 v = l+k+1;
272 } else
273 v = l+k;
274
275 if (streq(l, "job")) {
276 if (v[0] == '\0') {
277 /* New-style serialized job */
278 r = unit_deserialize_job(u, f);
279 if (r < 0)
280 return r;
281 } else /* Legacy for pre-44 */
282 log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
283 continue;
284 } else if (streq(l, "state-change-timestamp")) {
285 (void) deserialize_dual_timestamp(v, &u->state_change_timestamp);
286 continue;
287 } else if (streq(l, "inactive-exit-timestamp")) {
288 (void) deserialize_dual_timestamp(v, &u->inactive_exit_timestamp);
289 continue;
290 } else if (streq(l, "active-enter-timestamp")) {
291 (void) deserialize_dual_timestamp(v, &u->active_enter_timestamp);
292 continue;
293 } else if (streq(l, "active-exit-timestamp")) {
294 (void) deserialize_dual_timestamp(v, &u->active_exit_timestamp);
295 continue;
296 } else if (streq(l, "inactive-enter-timestamp")) {
297 (void) deserialize_dual_timestamp(v, &u->inactive_enter_timestamp);
298 continue;
299 } else if (streq(l, "condition-timestamp")) {
300 (void) deserialize_dual_timestamp(v, &u->condition_timestamp);
301 continue;
302 } else if (streq(l, "assert-timestamp")) {
303 (void) deserialize_dual_timestamp(v, &u->assert_timestamp);
304 continue;
2d3b784d 305
9466ec13 306 } else if (MATCH_DESERIALIZE("condition-result", l, v, parse_boolean, u->condition_result))
2d3b784d
ZJS
307 continue;
308
9466ec13 309 else if (MATCH_DESERIALIZE("assert-result", l, v, parse_boolean, u->assert_result))
2d3b784d
ZJS
310 continue;
311
9466ec13 312 else if (MATCH_DESERIALIZE("transient", l, v, parse_boolean, u->transient))
2d3b784d
ZJS
313 continue;
314
9466ec13 315 else if (MATCH_DESERIALIZE("in-audit", l, v, parse_boolean, u->in_audit))
2d3b784d
ZJS
316 continue;
317
9466ec13 318 else if (MATCH_DESERIALIZE("exported-invocation-id", l, v, parse_boolean, u->exported_invocation_id))
2d3b784d
ZJS
319 continue;
320
9466ec13 321 else if (MATCH_DESERIALIZE("exported-log-level-max", l, v, parse_boolean, u->exported_log_level_max))
2d3b784d
ZJS
322 continue;
323
9466ec13 324 else if (MATCH_DESERIALIZE("exported-log-extra-fields", l, v, parse_boolean, u->exported_log_extra_fields))
2d3b784d
ZJS
325 continue;
326
9466ec13 327 else if (MATCH_DESERIALIZE("exported-log-rate-limit-interval", l, v, parse_boolean, u->exported_log_ratelimit_interval))
2d3b784d
ZJS
328 continue;
329
9466ec13 330 else if (MATCH_DESERIALIZE("exported-log-rate-limit-burst", l, v, parse_boolean, u->exported_log_ratelimit_burst))
2d3b784d
ZJS
331 continue;
332
9466ec13
ZJS
333 else if (MATCH_DESERIALIZE_IMMEDIATE("cpu-usage-base", l, v, safe_atou64, u->cpu_usage_base) ||
334 MATCH_DESERIALIZE_IMMEDIATE("cpuacct-usage-base", l, v, safe_atou64, u->cpu_usage_base))
2d3b784d
ZJS
335 continue;
336
9466ec13 337 else if (MATCH_DESERIALIZE_IMMEDIATE("cpu-usage-last", l, v, safe_atou64, u->cpu_usage_last))
2d3b784d
ZJS
338 continue;
339
9466ec13 340 else if (MATCH_DESERIALIZE_IMMEDIATE("managed-oom-kill-last", l, v, safe_atou64, u->managed_oom_kill_last))
2d3b784d
ZJS
341 continue;
342
9466ec13 343 else if (MATCH_DESERIALIZE_IMMEDIATE("oom-kill-last", l, v, safe_atou64, u->oom_kill_last))
2d3b784d
ZJS
344 continue;
345
9466ec13 346 else if (streq(l, "cgroup")) {
2d3b784d
ZJS
347 r = unit_set_cgroup_path(u, v);
348 if (r < 0)
349 log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v);
350
351 (void) unit_watch_cgroup(u);
352 (void) unit_watch_cgroup_memory(u);
353
354 continue;
2d3b784d 355
9466ec13 356 } else if (MATCH_DESERIALIZE("cgroup-realized", l, v, parse_boolean, u->cgroup_realized))
2d3b784d
ZJS
357 continue;
358
9466ec13 359 else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-realized-mask", l, v, cg_mask_from_string, u->cgroup_realized_mask))
2d3b784d
ZJS
360 continue;
361
9466ec13 362 else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-enabled-mask", l, v, cg_mask_from_string, u->cgroup_enabled_mask))
2d3b784d
ZJS
363 continue;
364
9466ec13 365 else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-invalidated-mask", l, v, cg_mask_from_string, u->cgroup_invalidated_mask))
2d3b784d
ZJS
366 continue;
367
3d027d4d
JK
368 else if (STR_IN_SET(l, "ipv4-socket-bind-bpf-link-fd", "ipv6-socket-bind-bpf-link-fd")) {
369 int fd;
370
371 if (safe_atoi(v, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
372 log_unit_debug(u, "Failed to parse %s value: %s, ignoring.", l, v);
373 else {
374 if (fdset_remove(fds, fd) < 0) {
375 log_unit_debug(u, "Failed to remove %s value=%d from fdset", l, fd);
376
377 continue;
378 }
379
380 (void) socket_bind_add_initial_link_fd(u, fd);
381 }
382 continue;
383 }
384
9466ec13 385 else if (streq(l, "ref-uid")) {
2d3b784d
ZJS
386 uid_t uid;
387
388 r = parse_uid(v, &uid);
389 if (r < 0)
9466ec13 390 log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v);
2d3b784d
ZJS
391 else
392 unit_ref_uid_gid(u, uid, GID_INVALID);
2d3b784d
ZJS
393 continue;
394
395 } else if (streq(l, "ref-gid")) {
396 gid_t gid;
397
398 r = parse_gid(v, &gid);
399 if (r < 0)
9466ec13 400 log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v);
2d3b784d
ZJS
401 else
402 unit_ref_uid_gid(u, UID_INVALID, gid);
2d3b784d
ZJS
403 continue;
404
405 } else if (streq(l, "ref")) {
2d3b784d
ZJS
406 r = strv_extend(&u->deserialized_refs, v);
407 if (r < 0)
408 return log_oom();
2d3b784d 409 continue;
9466ec13 410
2d3b784d
ZJS
411 } else if (streq(l, "invocation-id")) {
412 sd_id128_t id;
413
414 r = sd_id128_from_string(v, &id);
415 if (r < 0)
9466ec13 416 log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v);
2d3b784d
ZJS
417 else {
418 r = unit_set_invocation_id(u, id);
419 if (r < 0)
420 log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m");
421 }
422
423 continue;
2d3b784d 424
9466ec13 425 } else if (MATCH_DESERIALIZE("freezer-state", l, v, freezer_state_from_string, u->freezer_state))
2d3b784d 426 continue;
2d3b784d 427
ff68472a
ZJS
428 else if (streq(l, "markers")) {
429 r = deserialize_markers(u, v);
430 if (r < 0)
431 log_unit_debug_errno(u, r, "Failed to deserialize \"%s=%s\", ignoring: %m", l, v);
432 continue;
433 }
434
2d3b784d
ZJS
435 /* Check if this is an IP accounting metric serialization field */
436 m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l);
437 if (m >= 0) {
438 uint64_t c;
439
440 r = safe_atou64(v, &c);
441 if (r < 0)
442 log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v);
443 else
444 u->ip_accounting_extra[m] = c;
445 continue;
446 }
447
448 m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l);
449 if (m >= 0) {
450 uint64_t c;
451
452 r = safe_atou64(v, &c);
453 if (r < 0)
454 log_unit_debug(u, "Failed to parse IO accounting base value %s, ignoring.", v);
455 else
456 u->io_accounting_base[m] = c;
457 continue;
458 }
459
460 m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l);
461 if (m >= 0) {
462 uint64_t c;
463
464 r = safe_atou64(v, &c);
465 if (r < 0)
466 log_unit_debug(u, "Failed to parse IO accounting last value %s, ignoring.", v);
467 else
468 u->io_accounting_last[m] = c;
469 continue;
470 }
471
472 if (unit_can_serialize(u)) {
473 r = exec_runtime_deserialize_compat(u, l, v, fds);
474 if (r < 0) {
475 log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
476 continue;
477 }
478
479 /* Returns positive if key was handled by the call */
480 if (r > 0)
481 continue;
482
483 r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
484 if (r < 0)
485 log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
486 }
487 }
488
489 /* Versions before 228 did not carry a state change timestamp. In this case, take the current
490 * time. This is useful, so that timeouts based on this timestamp don't trigger too early, and is
491 * in-line with the logic from before 228 where the base for timeouts was not persistent across
492 * reboots. */
493
494 if (!dual_timestamp_is_set(&u->state_change_timestamp))
495 dual_timestamp_get(&u->state_change_timestamp);
496
497 /* Let's make sure that everything that is deserialized also gets any potential new cgroup settings
498 * applied after we are done. For that we invalidate anything already realized, so that we can
499 * realize it again. */
500 unit_invalidate_cgroup(u, _CGROUP_MASK_ALL);
501 unit_invalidate_cgroup_bpf(u);
502
503 return 0;
504}
505
506int unit_deserialize_skip(FILE *f) {
507 int r;
508 assert(f);
509
510 /* Skip serialized data for this unit. We don't know what it is. */
511
512 for (;;) {
513 _cleanup_free_ char *line = NULL;
514 char *l;
515
516 r = read_line(f, LONG_LINE_MAX, &line);
517 if (r < 0)
518 return log_error_errno(r, "Failed to read serialization line: %m");
519 if (r == 0)
520 return 0;
521
522 l = strstrip(line);
523
524 /* End marker */
525 if (isempty(l))
526 return 1;
527 }
528}
529
530static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) {
531 const struct {
532 UnitDependencyMask mask;
533 const char *name;
534 } table[] = {
535 { UNIT_DEPENDENCY_FILE, "file" },
536 { UNIT_DEPENDENCY_IMPLICIT, "implicit" },
537 { UNIT_DEPENDENCY_DEFAULT, "default" },
538 { UNIT_DEPENDENCY_UDEV, "udev" },
539 { UNIT_DEPENDENCY_PATH, "path" },
540 { UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" },
541 { UNIT_DEPENDENCY_MOUNTINFO_DEFAULT, "mountinfo-default" },
542 { UNIT_DEPENDENCY_PROC_SWAP, "proc-swap" },
543 };
544
545 assert(f);
546 assert(kind);
547 assert(space);
548
549 for (size_t i = 0; i < ELEMENTSOF(table); i++) {
550
551 if (mask == 0)
552 break;
553
554 if (FLAGS_SET(mask, table[i].mask)) {
555 if (*space)
556 fputc(' ', f);
557 else
558 *space = true;
559
560 fputs(kind, f);
561 fputs("-", f);
562 fputs(table[i].name, f);
563
564 mask &= ~table[i].mask;
565 }
566 }
567
568 assert(mask == 0);
569}
570
571void unit_dump(Unit *u, FILE *f, const char *prefix) {
572 char *t, **j;
573 const char *prefix2;
574 char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX];
575 Unit *following;
576 _cleanup_set_free_ Set *following_set = NULL;
577 CGroupMask m;
578 int r;
579
580 assert(u);
581 assert(u->type >= 0);
582
583 prefix = strempty(prefix);
584 prefix2 = strjoina(prefix, "\t");
585
586 fprintf(f,
587 "%s-> Unit %s:\n",
588 prefix, u->id);
589
590 SET_FOREACH(t, u->aliases)
591 fprintf(f, "%s\tAlias: %s\n", prefix, t);
592
593 fprintf(f,
594 "%s\tDescription: %s\n"
595 "%s\tInstance: %s\n"
596 "%s\tUnit Load State: %s\n"
597 "%s\tUnit Active State: %s\n"
598 "%s\tState Change Timestamp: %s\n"
599 "%s\tInactive Exit Timestamp: %s\n"
600 "%s\tActive Enter Timestamp: %s\n"
601 "%s\tActive Exit Timestamp: %s\n"
602 "%s\tInactive Enter Timestamp: %s\n"
603 "%s\tMay GC: %s\n"
604 "%s\tNeed Daemon Reload: %s\n"
605 "%s\tTransient: %s\n"
606 "%s\tPerpetual: %s\n"
39628fed 607 "%s\tGarbage Collection Mode: %s\n",
2d3b784d
ZJS
608 prefix, unit_description(u),
609 prefix, strna(u->instance),
610 prefix, unit_load_state_to_string(u->load_state),
611 prefix, unit_active_state_to_string(unit_active_state(u)),
612 prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->state_change_timestamp.realtime)),
613 prefix, strna(format_timestamp(timestamp[1], sizeof(timestamp[1]), u->inactive_exit_timestamp.realtime)),
614 prefix, strna(format_timestamp(timestamp[2], sizeof(timestamp[2]), u->active_enter_timestamp.realtime)),
615 prefix, strna(format_timestamp(timestamp[3], sizeof(timestamp[3]), u->active_exit_timestamp.realtime)),
616 prefix, strna(format_timestamp(timestamp[4], sizeof(timestamp[4]), u->inactive_enter_timestamp.realtime)),
617 prefix, yes_no(unit_may_gc(u)),
618 prefix, yes_no(unit_need_daemon_reload(u)),
619 prefix, yes_no(u->transient),
620 prefix, yes_no(u->perpetual),
39628fed 621 prefix, collect_mode_to_string(u->collect_mode));
2d3b784d 622
ff68472a
ZJS
623 if (u->markers != 0) {
624 fprintf(f, "%s\tMarkers:", prefix);
625
626 for (UnitMarker marker = 0; marker < _UNIT_MARKER_MAX; marker++)
627 if (FLAGS_SET(u->markers, 1u << marker))
628 fprintf(f, " %s", unit_marker_to_string(marker));
629 fputs("\n", f);
630 }
631
39628fed
LP
632 if (UNIT_HAS_CGROUP_CONTEXT(u)) {
633 fprintf(f,
634 "%s\tSlice: %s\n"
635 "%s\tCGroup: %s\n"
636 "%s\tCGroup realized: %s\n",
637 prefix, strna(unit_slice_name(u)),
638 prefix, strna(u->cgroup_path),
639 prefix, yes_no(u->cgroup_realized));
640
641 if (u->cgroup_realized_mask != 0) {
642 _cleanup_free_ char *s = NULL;
643 (void) cg_mask_to_string(u->cgroup_realized_mask, &s);
644 fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s));
645 }
2d3b784d 646
39628fed
LP
647 if (u->cgroup_enabled_mask != 0) {
648 _cleanup_free_ char *s = NULL;
649 (void) cg_mask_to_string(u->cgroup_enabled_mask, &s);
650 fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s));
651 }
2d3b784d 652
39628fed
LP
653 m = unit_get_own_mask(u);
654 if (m != 0) {
655 _cleanup_free_ char *s = NULL;
656 (void) cg_mask_to_string(m, &s);
657 fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s));
658 }
2d3b784d 659
39628fed
LP
660 m = unit_get_members_mask(u);
661 if (m != 0) {
662 _cleanup_free_ char *s = NULL;
663 (void) cg_mask_to_string(m, &s);
664 fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s));
665 }
2d3b784d 666
39628fed
LP
667 m = unit_get_delegate_mask(u);
668 if (m != 0) {
669 _cleanup_free_ char *s = NULL;
670 (void) cg_mask_to_string(m, &s);
671 fprintf(f, "%s\tCGroup delegate mask: %s\n", prefix, strnull(s));
672 }
2d3b784d
ZJS
673 }
674
675 if (!sd_id128_is_null(u->invocation_id))
676 fprintf(f, "%s\tInvocation ID: " SD_ID128_FORMAT_STR "\n",
677 prefix, SD_ID128_FORMAT_VAL(u->invocation_id));
678
679 STRV_FOREACH(j, u->documentation)
680 fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);
681
682 following = unit_following(u);
683 if (following)
684 fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
685
686 r = unit_following_set(u, &following_set);
687 if (r >= 0) {
688 Unit *other;
689
690 SET_FOREACH(other, following_set)
691 fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id);
692 }
693
694 if (u->fragment_path)
695 fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
696
697 if (u->source_path)
698 fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);
699
700 STRV_FOREACH(j, u->dropin_paths)
701 fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
702
703 if (u->failure_action != EMERGENCY_ACTION_NONE)
704 fprintf(f, "%s\tFailure Action: %s\n", prefix, emergency_action_to_string(u->failure_action));
705 if (u->failure_action_exit_status >= 0)
706 fprintf(f, "%s\tFailure Action Exit Status: %i\n", prefix, u->failure_action_exit_status);
707 if (u->success_action != EMERGENCY_ACTION_NONE)
708 fprintf(f, "%s\tSuccess Action: %s\n", prefix, emergency_action_to_string(u->success_action));
709 if (u->success_action_exit_status >= 0)
710 fprintf(f, "%s\tSuccess Action Exit Status: %i\n", prefix, u->success_action_exit_status);
711
712 if (u->job_timeout != USEC_INFINITY)
713 fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
714
715 if (u->job_timeout_action != EMERGENCY_ACTION_NONE)
716 fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action));
717
718 if (u->job_timeout_reboot_arg)
719 fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
720
721 condition_dump_list(u->conditions, f, prefix, condition_type_to_string);
722 condition_dump_list(u->asserts, f, prefix, assert_type_to_string);
723
724 if (dual_timestamp_is_set(&u->condition_timestamp))
725 fprintf(f,
726 "%s\tCondition Timestamp: %s\n"
727 "%s\tCondition Result: %s\n",
728 prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->condition_timestamp.realtime)),
729 prefix, yes_no(u->condition_result));
730
731 if (dual_timestamp_is_set(&u->assert_timestamp))
732 fprintf(f,
733 "%s\tAssert Timestamp: %s\n"
734 "%s\tAssert Result: %s\n",
735 prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)),
736 prefix, yes_no(u->assert_result));
737
738 for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
739 UnitDependencyInfo di;
740 Unit *other;
741
15ed3c3a 742 HASHMAP_FOREACH_KEY(di.data, other, unit_get_dependencies(u, d)) {
2d3b784d
ZJS
743 bool space = false;
744
745 fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id);
746
747 print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
748 print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
749
750 fputs(")\n", f);
751 }
752 }
753
754 if (!hashmap_isempty(u->requires_mounts_for)) {
755 UnitDependencyInfo di;
756 const char *path;
757
758 HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) {
759 bool space = false;
760
761 fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path);
762
763 print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
764 print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
765
766 fputs(")\n", f);
767 }
768 }
769
770 if (u->load_state == UNIT_LOADED) {
771
772 fprintf(f,
773 "%s\tStopWhenUnneeded: %s\n"
774 "%s\tRefuseManualStart: %s\n"
775 "%s\tRefuseManualStop: %s\n"
776 "%s\tDefaultDependencies: %s\n"
294446dc 777 "%s\tOnSuccessJobMode: %s\n"
2d3b784d
ZJS
778 "%s\tOnFailureJobMode: %s\n"
779 "%s\tIgnoreOnIsolate: %s\n",
780 prefix, yes_no(u->stop_when_unneeded),
781 prefix, yes_no(u->refuse_manual_start),
782 prefix, yes_no(u->refuse_manual_stop),
783 prefix, yes_no(u->default_dependencies),
294446dc 784 prefix, job_mode_to_string(u->on_success_job_mode),
2d3b784d
ZJS
785 prefix, job_mode_to_string(u->on_failure_job_mode),
786 prefix, yes_no(u->ignore_on_isolate));
787
788 if (UNIT_VTABLE(u)->dump)
789 UNIT_VTABLE(u)->dump(u, f, prefix2);
790
791 } else if (u->load_state == UNIT_MERGED)
792 fprintf(f,
793 "%s\tMerged into: %s\n",
794 prefix, u->merged_into->id);
795 else if (u->load_state == UNIT_ERROR)
796 fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror_safe(u->load_error));
797
798 for (const char *n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track))
799 fprintf(f, "%s\tBus Ref: %s\n", prefix, n);
800
801 if (u->job)
802 job_dump(u->job, f, prefix2);
803
804 if (u->nop_job)
805 job_dump(u->nop_job, f, prefix2);
806}