]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/manager-serialize.c
core: fix typo
[thirdparty/systemd.git] / src / core / manager-serialize.c
CommitLineData
a01ba4b2
ZJS
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include "clean-ipc.h"
008798e9 4#include "core-varlink.h"
a01ba4b2
ZJS
5#include "dbus.h"
6#include "fd-util.h"
7#include "fileio.h"
8#include "format-util.h"
baa6a42d 9#include "initrd-util.h"
a01ba4b2
ZJS
10#include "macro.h"
11#include "manager-serialize.h"
12#include "manager.h"
13#include "parse-util.h"
14#include "serialize.h"
15#include "syslog-util.h"
16#include "unit-serialize.h"
17#include "user-util.h"
008798e9 18#include "varlink-internal.h"
a01ba4b2
ZJS
19
20int manager_open_serialization(Manager *m, FILE **ret_f) {
254d1313 21 _cleanup_close_ int fd = -EBADF;
a01ba4b2
ZJS
22 FILE *f;
23
24 assert(ret_f);
25
26 fd = open_serialization_fd("systemd-state");
27 if (fd < 0)
28 return fd;
29
30 f = take_fdopen(&fd, "w+");
31 if (!f)
32 return -errno;
33
34 *ret_f = f;
35 return 0;
36}
37
38static bool manager_timestamp_shall_serialize(ManagerTimestamp t) {
39 if (!in_initrd())
40 return true;
41
42 /* The following timestamps only apply to the host system, hence only serialize them there */
43 return !IN_SET(t,
44 MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH,
45 MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH,
46 MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH,
47 MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
48}
49
50static void manager_serialize_uid_refs_internal(
51 FILE *f,
52 Hashmap *uid_refs,
53 const char *field_name) {
54
55 void *p, *k;
56
57 assert(f);
58 assert(field_name);
59
60 /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as
61 * the actual counter of it is better rebuild after a reload/reexec. */
62
63 HASHMAP_FOREACH_KEY(p, k, uid_refs) {
64 uint32_t c;
65 uid_t uid;
66
67 uid = PTR_TO_UID(k);
68 c = PTR_TO_UINT32(p);
69
70 if (!(c & DESTROY_IPC_FLAG))
71 continue;
72
73 (void) serialize_item_format(f, field_name, UID_FMT, uid);
74 }
75}
76
77static void manager_serialize_uid_refs(Manager *m, FILE *f) {
78 manager_serialize_uid_refs_internal(f, m->uid_refs, "destroy-ipc-uid");
79}
80
81static void manager_serialize_gid_refs(Manager *m, FILE *f) {
82 manager_serialize_uid_refs_internal(f, m->gid_refs, "destroy-ipc-gid");
83}
84
85int manager_serialize(
86 Manager *m,
87 FILE *f,
88 FDSet *fds,
89 bool switching_root) {
90
91 const char *t;
92 Unit *u;
93 int r;
94
95 assert(m);
96 assert(f);
97 assert(fds);
98
99 _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
100
101 (void) serialize_item_format(f, "current-job-id", "%" PRIu32, m->current_job_id);
102 (void) serialize_item_format(f, "n-installed-jobs", "%u", m->n_installed_jobs);
103 (void) serialize_item_format(f, "n-failed-jobs", "%u", m->n_failed_jobs);
a01ba4b2
ZJS
104 (void) serialize_bool(f, "ready-sent", m->ready_sent);
105 (void) serialize_bool(f, "taint-logged", m->taint_logged);
106 (void) serialize_bool(f, "service-watchdogs", m->service_watchdogs);
107
a01ba4b2
ZJS
108 if (m->show_status_overridden != _SHOW_STATUS_INVALID)
109 (void) serialize_item(f, "show-status-overridden",
110 show_status_to_string(m->show_status_overridden));
111
112 if (m->log_level_overridden)
113 (void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level());
114 if (m->log_target_overridden)
115 (void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target()));
116
117 (void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]);
118 (void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]);
119 (void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]);
5717062e 120 (void) serialize_usec(f, "pretimeout-watchdog-overridden", m->watchdog_overridden[WATCHDOG_PRETIMEOUT]);
aff3a9e1 121 (void) serialize_item(f, "pretimeout-watchdog-governor-overridden", m->watchdog_pretimeout_governor_overridden);
a01ba4b2
ZJS
122
123 for (ManagerTimestamp q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
124 _cleanup_free_ char *joined = NULL;
125
126 if (!manager_timestamp_shall_serialize(q))
127 continue;
128
129 joined = strjoin(manager_timestamp_to_string(q), "-timestamp");
130 if (!joined)
131 return log_oom();
132
133 (void) serialize_dual_timestamp(f, joined, m->timestamps + q);
134 }
135
136 if (!switching_root)
137 (void) serialize_strv(f, "env", m->client_environment);
138
139 if (m->notify_fd >= 0) {
140 r = serialize_fd(f, fds, "notify-fd", m->notify_fd);
141 if (r < 0)
142 return r;
143
144 (void) serialize_item(f, "notify-socket", m->notify_socket);
145 }
146
147 if (m->cgroups_agent_fd >= 0) {
148 r = serialize_fd(f, fds, "cgroups-agent-fd", m->cgroups_agent_fd);
149 if (r < 0)
150 return r;
151 }
152
153 if (m->user_lookup_fds[0] >= 0) {
154 int copy0, copy1;
155
156 copy0 = fdset_put_dup(fds, m->user_lookup_fds[0]);
157 if (copy0 < 0)
158 return log_error_errno(copy0, "Failed to add user lookup fd to serialization: %m");
159
160 copy1 = fdset_put_dup(fds, m->user_lookup_fds[1]);
161 if (copy1 < 0)
162 return log_error_errno(copy1, "Failed to add user lookup fd to serialization: %m");
163
164 (void) serialize_item_format(f, "user-lookup", "%i %i", copy0, copy1);
165 }
166
d9365956
LB
167 (void) serialize_item_format(f,
168 "dump-ratelimit",
169 USEC_FMT " " USEC_FMT " %u %u",
170 m->dump_ratelimit.begin,
171 m->dump_ratelimit.interval,
172 m->dump_ratelimit.num,
173 m->dump_ratelimit.burst);
174
a01ba4b2
ZJS
175 bus_track_serialize(m->subscribed, f, "subscribed");
176
177 r = dynamic_user_serialize(m, f, fds);
178 if (r < 0)
179 return r;
180
181 manager_serialize_uid_refs(m, f);
182 manager_serialize_gid_refs(m, f);
183
e76506b7 184 r = exec_shared_runtime_serialize(m, f, fds);
a01ba4b2
ZJS
185 if (r < 0)
186 return r;
187
008798e9
AZ
188 r = varlink_server_serialize(m->varlink_server, f, fds);
189 if (r < 0)
190 return r;
191
a01ba4b2
ZJS
192 (void) fputc('\n', f);
193
194 HASHMAP_FOREACH_KEY(u, t, m->units) {
195 if (u->id != t)
196 continue;
197
198 r = unit_serialize(u, f, fds, switching_root);
199 if (r < 0)
200 return r;
201 }
202
203 r = fflush_and_check(f);
204 if (r < 0)
205 return log_error_errno(r, "Failed to flush serialization: %m");
206
207 r = bus_fdset_add_all(m, fds);
208 if (r < 0)
209 return log_error_errno(r, "Failed to add bus sockets to serialization: %m");
210
211 return 0;
212}
213
214static int manager_deserialize_one_unit(Manager *m, const char *name, FILE *f, FDSet *fds) {
215 Unit *u;
216 int r;
217
218 r = manager_load_unit(m, name, NULL, NULL, &u);
219 if (r < 0) {
220 if (r == -ENOMEM)
221 return r;
222 return log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", name);
223 }
224
225 r = unit_deserialize(u, f, fds);
226 if (r < 0) {
227 if (r == -ENOMEM)
228 return r;
229 return log_notice_errno(r, "Failed to deserialize unit \"%s\", skipping: %m", name);
230 }
231
232 return 0;
233}
234
235static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) {
236 const char *unit_name;
237 int r;
238
239 for (;;) {
240 _cleanup_free_ char *line = NULL;
241 /* Start marker */
242 r = read_line(f, LONG_LINE_MAX, &line);
243 if (r < 0)
244 return log_error_errno(r, "Failed to read serialization line: %m");
245 if (r == 0)
246 break;
247
248 unit_name = strstrip(line);
249
250 r = manager_deserialize_one_unit(m, unit_name, f, fds);
251 if (r == -ENOMEM)
252 return r;
253 if (r < 0) {
254 r = unit_deserialize_skip(f);
255 if (r < 0)
256 return r;
257 }
258 }
259
260 return 0;
261}
262
263static void manager_deserialize_uid_refs_one_internal(
264 Hashmap** uid_refs,
265 const char *value) {
266
267 uid_t uid;
268 uint32_t c;
269 int r;
270
271 assert(uid_refs);
272 assert(value);
273
274 r = parse_uid(value, &uid);
275 if (r < 0 || uid == 0) {
6cb105b8 276 log_debug("Unable to parse UID/GID reference serialization: %s", value);
a01ba4b2
ZJS
277 return;
278 }
279
280 if (hashmap_ensure_allocated(uid_refs, &trivial_hash_ops) < 0) {
281 log_oom();
282 return;
283 }
284
285 c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
286 if (c & DESTROY_IPC_FLAG)
287 return;
288
289 c |= DESTROY_IPC_FLAG;
290
291 r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
292 if (r < 0) {
293 log_debug_errno(r, "Failed to add UID/GID reference entry: %m");
294 return;
295 }
296}
297
298static void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
299 manager_deserialize_uid_refs_one_internal(&m->uid_refs, value);
300}
301
302static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
303 manager_deserialize_uid_refs_one_internal(&m->gid_refs, value);
304}
305
306int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
008798e9 307 bool deserialize_varlink_sockets = false;
a01ba4b2
ZJS
308 int r = 0;
309
310 assert(m);
311 assert(f);
312
313 if (DEBUG_LOGGING) {
314 if (fdset_isempty(fds))
315 log_debug("No file descriptors passed");
316 else {
317 int fd;
318
319 FDSET_FOREACH(fd, fds) {
320 _cleanup_free_ char *fn = NULL;
321
322 r = fd_get_path(fd, &fn);
323 if (r < 0)
e2341b6b
DT
324 log_debug_errno(r, "Received serialized fd %i %s %m",
325 fd, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT));
a01ba4b2 326 else
e2341b6b
DT
327 log_debug("Received serialized fd %i %s %s",
328 fd, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), strna(fn));
a01ba4b2
ZJS
329 }
330 }
331 }
332
333 log_debug("Deserializing state...");
334
335 /* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have
336 * increased it to non-zero, which is why we just increase it by one here and down again at the end of this
337 * call. */
338 _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
339
340 for (;;) {
0df7d525
LP
341 _cleanup_free_ char *l = NULL;
342 const char *val;
a01ba4b2 343
0df7d525 344 r = deserialize_read_line(f, &l);
a01ba4b2 345 if (r < 0)
0df7d525
LP
346 return r;
347 if (r == 0) /* eof or end marker */
a01ba4b2
ZJS
348 break;
349
350 if ((val = startswith(l, "current-job-id="))) {
351 uint32_t id;
352
353 if (safe_atou32(val, &id) < 0)
354 log_notice("Failed to parse current job id value '%s', ignoring.", val);
355 else
356 m->current_job_id = MAX(m->current_job_id, id);
357
358 } else if ((val = startswith(l, "n-installed-jobs="))) {
359 uint32_t n;
360
361 if (safe_atou32(val, &n) < 0)
362 log_notice("Failed to parse installed jobs counter '%s', ignoring.", val);
363 else
364 m->n_installed_jobs += n;
365
366 } else if ((val = startswith(l, "n-failed-jobs="))) {
367 uint32_t n;
368
369 if (safe_atou32(val, &n) < 0)
370 log_notice("Failed to parse failed jobs counter '%s', ignoring.", val);
371 else
372 m->n_failed_jobs += n;
373
a01ba4b2
ZJS
374 } else if ((val = startswith(l, "ready-sent="))) {
375 int b;
376
377 b = parse_boolean(val);
378 if (b < 0)
379 log_notice("Failed to parse ready-sent flag '%s', ignoring.", val);
380 else
381 m->ready_sent = m->ready_sent || b;
382
383 } else if ((val = startswith(l, "taint-logged="))) {
384 int b;
385
386 b = parse_boolean(val);
387 if (b < 0)
388 log_notice("Failed to parse taint-logged flag '%s', ignoring.", val);
389 else
390 m->taint_logged = m->taint_logged || b;
391
392 } else if ((val = startswith(l, "service-watchdogs="))) {
393 int b;
394
395 b = parse_boolean(val);
396 if (b < 0)
397 log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val);
398 else
399 m->service_watchdogs = b;
400
a01ba4b2
ZJS
401 } else if ((val = startswith(l, "show-status-overridden="))) {
402 ShowStatus s;
403
404 s = show_status_from_string(val);
405 if (s < 0)
406 log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val);
407 else
408 manager_override_show_status(m, s, "deserialize");
409
410 } else if ((val = startswith(l, "log-level-override="))) {
411 int level;
412
413 level = log_level_from_string(val);
414 if (level < 0)
415 log_notice("Failed to parse log-level-override value '%s', ignoring.", val);
416 else
417 manager_override_log_level(m, level);
418
419 } else if ((val = startswith(l, "log-target-override="))) {
420 LogTarget target;
421
422 target = log_target_from_string(val);
423 if (target < 0)
424 log_notice("Failed to parse log-target-override value '%s', ignoring.", val);
425 else
426 manager_override_log_target(m, target);
427
428 } else if ((val = startswith(l, "runtime-watchdog-overridden="))) {
429 usec_t t;
430
431 if (deserialize_usec(val, &t) < 0)
432 log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
433 else
434 manager_override_watchdog(m, WATCHDOG_RUNTIME, t);
435
436 } else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
437 usec_t t;
438
439 if (deserialize_usec(val, &t) < 0)
440 log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
441 else
442 manager_override_watchdog(m, WATCHDOG_REBOOT, t);
443
444 } else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
445 usec_t t;
446
447 if (deserialize_usec(val, &t) < 0)
448 log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
449 else
450 manager_override_watchdog(m, WATCHDOG_KEXEC, t);
451
5717062e
CK
452 } else if ((val = startswith(l, "pretimeout-watchdog-overridden="))) {
453 usec_t t;
454
455 if (deserialize_usec(val, &t) < 0)
456 log_notice("Failed to parse pretimeout-watchdog-overridden value '%s', ignoring.", val);
457 else
458 manager_override_watchdog(m, WATCHDOG_PRETIMEOUT, t);
459
aff3a9e1
LB
460 } else if ((val = startswith(l, "pretimeout-watchdog-governor-overridden="))) {
461 r = free_and_strdup(&m->watchdog_pretimeout_governor_overridden, val);
462 if (r < 0)
463 return r;
464
a01ba4b2
ZJS
465 } else if (startswith(l, "env=")) {
466 r = deserialize_environment(l + 4, &m->client_environment);
467 if (r < 0)
468 log_notice_errno(r, "Failed to parse environment entry: \"%s\", ignoring: %m", l);
469
470 } else if ((val = startswith(l, "notify-fd="))) {
471 int fd;
472
e652663a 473 if ((fd = parse_fd(val)) < 0 || !fdset_contains(fds, fd))
a01ba4b2
ZJS
474 log_notice("Failed to parse notify fd, ignoring: \"%s\"", val);
475 else {
476 m->notify_event_source = sd_event_source_disable_unref(m->notify_event_source);
477 safe_close(m->notify_fd);
478 m->notify_fd = fdset_remove(fds, fd);
479 }
480
481 } else if ((val = startswith(l, "notify-socket="))) {
482 r = free_and_strdup(&m->notify_socket, val);
483 if (r < 0)
484 return r;
485
486 } else if ((val = startswith(l, "cgroups-agent-fd="))) {
487 int fd;
488
e652663a 489 if ((fd = parse_fd(val)) < 0 || !fdset_contains(fds, fd))
a01ba4b2
ZJS
490 log_notice("Failed to parse cgroups agent fd, ignoring.: %s", val);
491 else {
492 m->cgroups_agent_event_source = sd_event_source_disable_unref(m->cgroups_agent_event_source);
493 safe_close(m->cgroups_agent_fd);
494 m->cgroups_agent_fd = fdset_remove(fds, fd);
495 }
496
497 } else if ((val = startswith(l, "user-lookup="))) {
498 int fd0, fd1;
499
500 if (sscanf(val, "%i %i", &fd0, &fd1) != 2 || fd0 < 0 || fd1 < 0 || fd0 == fd1 || !fdset_contains(fds, fd0) || !fdset_contains(fds, fd1))
501 log_notice("Failed to parse user lookup fd, ignoring: %s", val);
502 else {
503 m->user_lookup_event_source = sd_event_source_disable_unref(m->user_lookup_event_source);
504 safe_close_pair(m->user_lookup_fds);
505 m->user_lookup_fds[0] = fdset_remove(fds, fd0);
506 m->user_lookup_fds[1] = fdset_remove(fds, fd1);
507 }
508
509 } else if ((val = startswith(l, "dynamic-user=")))
510 dynamic_user_deserialize_one(m, val, fds);
511 else if ((val = startswith(l, "destroy-ipc-uid=")))
512 manager_deserialize_uid_refs_one(m, val);
513 else if ((val = startswith(l, "destroy-ipc-gid=")))
514 manager_deserialize_gid_refs_one(m, val);
515 else if ((val = startswith(l, "exec-runtime=")))
e76506b7 516 (void) exec_shared_runtime_deserialize_one(m, val, fds);
a01ba4b2
ZJS
517 else if ((val = startswith(l, "subscribed="))) {
518
519 if (strv_extend(&m->deserialized_subscribed, val) < 0)
520 return -ENOMEM;
008798e9
AZ
521 } else if ((val = startswith(l, "varlink-server-socket-address="))) {
522 if (!m->varlink_server && MANAGER_IS_SYSTEM(m)) {
523 _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
524
525 r = manager_setup_varlink_server(m, &s);
526 if (r < 0) {
527 log_warning_errno(r, "Failed to setup varlink server, ignoring: %m");
528 continue;
529 }
530
531 r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
532 if (r < 0) {
533 log_warning_errno(r, "Failed to attach varlink connection to event loop, ignoring: %m");
534 continue;
535 }
536
537 m->varlink_server = TAKE_PTR(s);
538 deserialize_varlink_sockets = true;
539 }
a01ba4b2 540
8c35a977 541 /* To avoid unnecessary deserialization (i.e. during reload vs. reexec) we only deserialize
008798e9
AZ
542 * the FDs if we had to create a new m->varlink_server. The deserialize_varlink_sockets flag
543 * is initialized outside of the loop, is flipped after the VarlinkServer is setup, and
544 * remains set until all serialized contents are handled. */
545 if (deserialize_varlink_sockets)
546 (void) varlink_server_deserialize_one(m->varlink_server, val, fds);
d9365956
LB
547 } else if ((val = startswith(l, "dump-ratelimit="))) {
548 usec_t begin, interval;
549 unsigned num, burst;
550
551 if (sscanf(val, USEC_FMT " " USEC_FMT " %u %u", &begin, &interval, &num, &burst) != 4)
552 log_notice("Failed to parse dump ratelimit, ignoring: %s", val);
553 else {
554 /* If we changed the values across versions, flush the counter */
555 if (interval != m->dump_ratelimit.interval || burst != m->dump_ratelimit.burst)
556 m->dump_ratelimit.num = 0;
557 else
558 m->dump_ratelimit.num = num;
559 m->dump_ratelimit.begin = begin;
560 }
561
a01ba4b2
ZJS
562 } else {
563 ManagerTimestamp q;
564
565 for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
566 val = startswith(l, manager_timestamp_to_string(q));
567 if (!val)
568 continue;
569
570 val = startswith(val, "-timestamp=");
571 if (val)
572 break;
573 }
574
575 if (q < _MANAGER_TIMESTAMP_MAX) /* found it */
576 (void) deserialize_dual_timestamp(val, m->timestamps + q);
7870de03 577 else if (!STARTSWITH_SET(l, "kdbus-fd=", "honor-device-enumeration=")) /* ignore deprecated values */
a01ba4b2
ZJS
578 log_notice("Unknown serialization item '%s', ignoring.", l);
579 }
580 }
581
582 return manager_deserialize_units(m, f, fds);
583}