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