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