]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/manager-serialize.c
Merge pull request #22605 from yuwata/test-journal-send-fd-leaks
[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 "dbus.h"
5 #include "fd-util.h"
6 #include "fileio.h"
7 #include "format-util.h"
8 #include "macro.h"
9 #include "manager-serialize.h"
10 #include "manager.h"
11 #include "parse-util.h"
12 #include "serialize.h"
13 #include "syslog-util.h"
14 #include "unit-serialize.h"
15 #include "user-util.h"
16
17 int manager_open_serialization(Manager *m, FILE **ret_f) {
18 _cleanup_close_ int fd = -1;
19 FILE *f;
20
21 assert(ret_f);
22
23 fd = open_serialization_fd("systemd-state");
24 if (fd < 0)
25 return fd;
26
27 f = take_fdopen(&fd, "w+");
28 if (!f)
29 return -errno;
30
31 *ret_f = f;
32 return 0;
33 }
34
35 static bool manager_timestamp_shall_serialize(ManagerTimestamp t) {
36 if (!in_initrd())
37 return true;
38
39 /* The following timestamps only apply to the host system, hence only serialize them there */
40 return !IN_SET(t,
41 MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH,
42 MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH,
43 MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH,
44 MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
45 }
46
47 static void manager_serialize_uid_refs_internal(
48 FILE *f,
49 Hashmap *uid_refs,
50 const char *field_name) {
51
52 void *p, *k;
53
54 assert(f);
55 assert(field_name);
56
57 /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as
58 * the actual counter of it is better rebuild after a reload/reexec. */
59
60 HASHMAP_FOREACH_KEY(p, k, uid_refs) {
61 uint32_t c;
62 uid_t uid;
63
64 uid = PTR_TO_UID(k);
65 c = PTR_TO_UINT32(p);
66
67 if (!(c & DESTROY_IPC_FLAG))
68 continue;
69
70 (void) serialize_item_format(f, field_name, UID_FMT, uid);
71 }
72 }
73
74 static void manager_serialize_uid_refs(Manager *m, FILE *f) {
75 manager_serialize_uid_refs_internal(f, m->uid_refs, "destroy-ipc-uid");
76 }
77
78 static void manager_serialize_gid_refs(Manager *m, FILE *f) {
79 manager_serialize_uid_refs_internal(f, m->gid_refs, "destroy-ipc-gid");
80 }
81
82 int manager_serialize(
83 Manager *m,
84 FILE *f,
85 FDSet *fds,
86 bool switching_root) {
87
88 const char *t;
89 Unit *u;
90 int r;
91
92 assert(m);
93 assert(f);
94 assert(fds);
95
96 _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
97
98 (void) serialize_item_format(f, "current-job-id", "%" PRIu32, m->current_job_id);
99 (void) serialize_item_format(f, "n-installed-jobs", "%u", m->n_installed_jobs);
100 (void) serialize_item_format(f, "n-failed-jobs", "%u", m->n_failed_jobs);
101 (void) serialize_bool(f, "taint-usr", m->taint_usr);
102 (void) serialize_bool(f, "ready-sent", m->ready_sent);
103 (void) serialize_bool(f, "taint-logged", m->taint_logged);
104 (void) serialize_bool(f, "service-watchdogs", m->service_watchdogs);
105
106 /* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */
107 (void) serialize_bool(f, "honor-device-enumeration", !switching_root);
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 bus_track_serialize(m->subscribed, f, "subscribed");
169
170 r = dynamic_user_serialize(m, f, fds);
171 if (r < 0)
172 return r;
173
174 manager_serialize_uid_refs(m, f);
175 manager_serialize_gid_refs(m, f);
176
177 r = exec_runtime_serialize(m, f, fds);
178 if (r < 0)
179 return r;
180
181 (void) fputc('\n', f);
182
183 HASHMAP_FOREACH_KEY(u, t, m->units) {
184 if (u->id != t)
185 continue;
186
187 r = unit_serialize(u, f, fds, switching_root);
188 if (r < 0)
189 return r;
190 }
191
192 r = fflush_and_check(f);
193 if (r < 0)
194 return log_error_errno(r, "Failed to flush serialization: %m");
195
196 r = bus_fdset_add_all(m, fds);
197 if (r < 0)
198 return log_error_errno(r, "Failed to add bus sockets to serialization: %m");
199
200 return 0;
201 }
202
203 static int manager_deserialize_one_unit(Manager *m, const char *name, FILE *f, FDSet *fds) {
204 Unit *u;
205 int r;
206
207 r = manager_load_unit(m, name, NULL, NULL, &u);
208 if (r < 0) {
209 if (r == -ENOMEM)
210 return r;
211 return log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", name);
212 }
213
214 r = unit_deserialize(u, f, fds);
215 if (r < 0) {
216 if (r == -ENOMEM)
217 return r;
218 return log_notice_errno(r, "Failed to deserialize unit \"%s\", skipping: %m", name);
219 }
220
221 return 0;
222 }
223
224 static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) {
225 const char *unit_name;
226 int r;
227
228 for (;;) {
229 _cleanup_free_ char *line = NULL;
230 /* Start marker */
231 r = read_line(f, LONG_LINE_MAX, &line);
232 if (r < 0)
233 return log_error_errno(r, "Failed to read serialization line: %m");
234 if (r == 0)
235 break;
236
237 unit_name = strstrip(line);
238
239 r = manager_deserialize_one_unit(m, unit_name, f, fds);
240 if (r == -ENOMEM)
241 return r;
242 if (r < 0) {
243 r = unit_deserialize_skip(f);
244 if (r < 0)
245 return r;
246 }
247 }
248
249 return 0;
250 }
251
252 static void manager_deserialize_uid_refs_one_internal(
253 Hashmap** uid_refs,
254 const char *value) {
255
256 uid_t uid;
257 uint32_t c;
258 int r;
259
260 assert(uid_refs);
261 assert(value);
262
263 r = parse_uid(value, &uid);
264 if (r < 0 || uid == 0) {
265 log_debug("Unable to parse UID/GID reference serialization: " UID_FMT, uid);
266 return;
267 }
268
269 if (hashmap_ensure_allocated(uid_refs, &trivial_hash_ops) < 0) {
270 log_oom();
271 return;
272 }
273
274 c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
275 if (c & DESTROY_IPC_FLAG)
276 return;
277
278 c |= DESTROY_IPC_FLAG;
279
280 r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
281 if (r < 0) {
282 log_debug_errno(r, "Failed to add UID/GID reference entry: %m");
283 return;
284 }
285 }
286
287 static void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
288 manager_deserialize_uid_refs_one_internal(&m->uid_refs, value);
289 }
290
291 static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
292 manager_deserialize_uid_refs_one_internal(&m->gid_refs, value);
293 }
294
295 int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
296 int r = 0;
297
298 assert(m);
299 assert(f);
300
301 if (DEBUG_LOGGING) {
302 if (fdset_isempty(fds))
303 log_debug("No file descriptors passed");
304 else {
305 int fd;
306
307 FDSET_FOREACH(fd, fds) {
308 _cleanup_free_ char *fn = NULL;
309
310 r = fd_get_path(fd, &fn);
311 if (r < 0)
312 log_debug_errno(r, "Received serialized fd %i → %m", fd);
313 else
314 log_debug("Received serialized fd %i → %s", fd, strna(fn));
315 }
316 }
317 }
318
319 log_debug("Deserializing state...");
320
321 /* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have
322 * increased it to non-zero, which is why we just increase it by one here and down again at the end of this
323 * call. */
324 _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
325
326 for (;;) {
327 _cleanup_free_ char *line = NULL;
328 const char *val, *l;
329
330 r = read_line(f, LONG_LINE_MAX, &line);
331 if (r < 0)
332 return log_error_errno(r, "Failed to read serialization line: %m");
333 if (r == 0)
334 break;
335
336 l = strstrip(line);
337 if (isempty(l)) /* end marker */
338 break;
339
340 if ((val = startswith(l, "current-job-id="))) {
341 uint32_t id;
342
343 if (safe_atou32(val, &id) < 0)
344 log_notice("Failed to parse current job id value '%s', ignoring.", val);
345 else
346 m->current_job_id = MAX(m->current_job_id, id);
347
348 } else if ((val = startswith(l, "n-installed-jobs="))) {
349 uint32_t n;
350
351 if (safe_atou32(val, &n) < 0)
352 log_notice("Failed to parse installed jobs counter '%s', ignoring.", val);
353 else
354 m->n_installed_jobs += n;
355
356 } else if ((val = startswith(l, "n-failed-jobs="))) {
357 uint32_t n;
358
359 if (safe_atou32(val, &n) < 0)
360 log_notice("Failed to parse failed jobs counter '%s', ignoring.", val);
361 else
362 m->n_failed_jobs += n;
363
364 } else if ((val = startswith(l, "taint-usr="))) {
365 int b;
366
367 b = parse_boolean(val);
368 if (b < 0)
369 log_notice("Failed to parse taint /usr flag '%s', ignoring.", val);
370 else
371 m->taint_usr = m->taint_usr || b;
372
373 } else if ((val = startswith(l, "ready-sent="))) {
374 int b;
375
376 b = parse_boolean(val);
377 if (b < 0)
378 log_notice("Failed to parse ready-sent flag '%s', ignoring.", val);
379 else
380 m->ready_sent = m->ready_sent || b;
381
382 } else if ((val = startswith(l, "taint-logged="))) {
383 int b;
384
385 b = parse_boolean(val);
386 if (b < 0)
387 log_notice("Failed to parse taint-logged flag '%s', ignoring.", val);
388 else
389 m->taint_logged = m->taint_logged || b;
390
391 } else if ((val = startswith(l, "service-watchdogs="))) {
392 int b;
393
394 b = parse_boolean(val);
395 if (b < 0)
396 log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val);
397 else
398 m->service_watchdogs = b;
399
400 } else if ((val = startswith(l, "honor-device-enumeration="))) {
401 int b;
402
403 b = parse_boolean(val);
404 if (b < 0)
405 log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val);
406 else
407 m->honor_device_enumeration = b;
408
409 } else if ((val = startswith(l, "show-status-overridden="))) {
410 ShowStatus s;
411
412 s = show_status_from_string(val);
413 if (s < 0)
414 log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val);
415 else
416 manager_override_show_status(m, s, "deserialize");
417
418 } else if ((val = startswith(l, "log-level-override="))) {
419 int level;
420
421 level = log_level_from_string(val);
422 if (level < 0)
423 log_notice("Failed to parse log-level-override value '%s', ignoring.", val);
424 else
425 manager_override_log_level(m, level);
426
427 } else if ((val = startswith(l, "log-target-override="))) {
428 LogTarget target;
429
430 target = log_target_from_string(val);
431 if (target < 0)
432 log_notice("Failed to parse log-target-override value '%s', ignoring.", val);
433 else
434 manager_override_log_target(m, target);
435
436 } else if ((val = startswith(l, "runtime-watchdog-overridden="))) {
437 usec_t t;
438
439 if (deserialize_usec(val, &t) < 0)
440 log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
441 else
442 manager_override_watchdog(m, WATCHDOG_RUNTIME, t);
443
444 } else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
445 usec_t t;
446
447 if (deserialize_usec(val, &t) < 0)
448 log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
449 else
450 manager_override_watchdog(m, WATCHDOG_REBOOT, t);
451
452 } else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
453 usec_t t;
454
455 if (deserialize_usec(val, &t) < 0)
456 log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
457 else
458 manager_override_watchdog(m, WATCHDOG_KEXEC, t);
459
460 } else if ((val = startswith(l, "pretimeout-watchdog-overridden="))) {
461 usec_t t;
462
463 if (deserialize_usec(val, &t) < 0)
464 log_notice("Failed to parse pretimeout-watchdog-overridden value '%s', ignoring.", val);
465 else
466 manager_override_watchdog(m, WATCHDOG_PRETIMEOUT, t);
467
468 } else if ((val = startswith(l, "pretimeout-watchdog-governor-overridden="))) {
469 r = free_and_strdup(&m->watchdog_pretimeout_governor_overridden, val);
470 if (r < 0)
471 return r;
472
473 } else if (startswith(l, "env=")) {
474 r = deserialize_environment(l + 4, &m->client_environment);
475 if (r < 0)
476 log_notice_errno(r, "Failed to parse environment entry: \"%s\", ignoring: %m", l);
477
478 } else if ((val = startswith(l, "notify-fd="))) {
479 int fd;
480
481 if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
482 log_notice("Failed to parse notify fd, ignoring: \"%s\"", val);
483 else {
484 m->notify_event_source = sd_event_source_disable_unref(m->notify_event_source);
485 safe_close(m->notify_fd);
486 m->notify_fd = fdset_remove(fds, fd);
487 }
488
489 } else if ((val = startswith(l, "notify-socket="))) {
490 r = free_and_strdup(&m->notify_socket, val);
491 if (r < 0)
492 return r;
493
494 } else if ((val = startswith(l, "cgroups-agent-fd="))) {
495 int fd;
496
497 if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
498 log_notice("Failed to parse cgroups agent fd, ignoring.: %s", val);
499 else {
500 m->cgroups_agent_event_source = sd_event_source_disable_unref(m->cgroups_agent_event_source);
501 safe_close(m->cgroups_agent_fd);
502 m->cgroups_agent_fd = fdset_remove(fds, fd);
503 }
504
505 } else if ((val = startswith(l, "user-lookup="))) {
506 int fd0, fd1;
507
508 if (sscanf(val, "%i %i", &fd0, &fd1) != 2 || fd0 < 0 || fd1 < 0 || fd0 == fd1 || !fdset_contains(fds, fd0) || !fdset_contains(fds, fd1))
509 log_notice("Failed to parse user lookup fd, ignoring: %s", val);
510 else {
511 m->user_lookup_event_source = sd_event_source_disable_unref(m->user_lookup_event_source);
512 safe_close_pair(m->user_lookup_fds);
513 m->user_lookup_fds[0] = fdset_remove(fds, fd0);
514 m->user_lookup_fds[1] = fdset_remove(fds, fd1);
515 }
516
517 } else if ((val = startswith(l, "dynamic-user=")))
518 dynamic_user_deserialize_one(m, val, fds);
519 else if ((val = startswith(l, "destroy-ipc-uid=")))
520 manager_deserialize_uid_refs_one(m, val);
521 else if ((val = startswith(l, "destroy-ipc-gid=")))
522 manager_deserialize_gid_refs_one(m, val);
523 else if ((val = startswith(l, "exec-runtime=")))
524 (void) exec_runtime_deserialize_one(m, val, fds);
525 else if ((val = startswith(l, "subscribed="))) {
526
527 if (strv_extend(&m->deserialized_subscribed, val) < 0)
528 return -ENOMEM;
529
530 } else {
531 ManagerTimestamp q;
532
533 for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
534 val = startswith(l, manager_timestamp_to_string(q));
535 if (!val)
536 continue;
537
538 val = startswith(val, "-timestamp=");
539 if (val)
540 break;
541 }
542
543 if (q < _MANAGER_TIMESTAMP_MAX) /* found it */
544 (void) deserialize_dual_timestamp(val, m->timestamps + q);
545 else if (!startswith(l, "kdbus-fd=")) /* ignore kdbus */
546 log_notice("Unknown serialization item '%s', ignoring.", l);
547 }
548 }
549
550 return manager_deserialize_units(m, f, fds);
551 }