1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "format-util.h"
9 #include "manager-serialize.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"
17 int manager_open_serialization(Manager
*m
, FILE **ret_f
) {
18 _cleanup_close_
int fd
= -1;
23 fd
= open_serialization_fd("systemd-state");
27 f
= take_fdopen(&fd
, "w+");
35 static bool manager_timestamp_shall_serialize(ManagerTimestamp t
) {
39 /* The following timestamps only apply to the host system, hence only serialize them there */
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
);
47 static void manager_serialize_uid_refs_internal(
50 const char *field_name
) {
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. */
60 HASHMAP_FOREACH_KEY(p
, k
, uid_refs
) {
67 if (!(c
& DESTROY_IPC_FLAG
))
70 (void) serialize_item_format(f
, field_name
, UID_FMT
, uid
);
74 static void manager_serialize_uid_refs(Manager
*m
, FILE *f
) {
75 manager_serialize_uid_refs_internal(f
, m
->uid_refs
, "destroy-ipc-uid");
78 static void manager_serialize_gid_refs(Manager
*m
, FILE *f
) {
79 manager_serialize_uid_refs_internal(f
, m
->gid_refs
, "destroy-ipc-gid");
82 int manager_serialize(
86 bool switching_root
) {
96 _cleanup_(manager_reloading_stopp
) _unused_ Manager
*reloading
= manager_reloading_start(m
);
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
);
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
);
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
));
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()));
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
]);
122 for (ManagerTimestamp q
= 0; q
< _MANAGER_TIMESTAMP_MAX
; q
++) {
123 _cleanup_free_
char *joined
= NULL
;
125 if (!manager_timestamp_shall_serialize(q
))
128 joined
= strjoin(manager_timestamp_to_string(q
), "-timestamp");
132 (void) serialize_dual_timestamp(f
, joined
, m
->timestamps
+ q
);
136 (void) serialize_strv(f
, "env", m
->client_environment
);
138 if (m
->notify_fd
>= 0) {
139 r
= serialize_fd(f
, fds
, "notify-fd", m
->notify_fd
);
143 (void) serialize_item(f
, "notify-socket", m
->notify_socket
);
146 if (m
->cgroups_agent_fd
>= 0) {
147 r
= serialize_fd(f
, fds
, "cgroups-agent-fd", m
->cgroups_agent_fd
);
152 if (m
->user_lookup_fds
[0] >= 0) {
155 copy0
= fdset_put_dup(fds
, m
->user_lookup_fds
[0]);
157 return log_error_errno(copy0
, "Failed to add user lookup fd to serialization: %m");
159 copy1
= fdset_put_dup(fds
, m
->user_lookup_fds
[1]);
161 return log_error_errno(copy1
, "Failed to add user lookup fd to serialization: %m");
163 (void) serialize_item_format(f
, "user-lookup", "%i %i", copy0
, copy1
);
166 bus_track_serialize(m
->subscribed
, f
, "subscribed");
168 r
= dynamic_user_serialize(m
, f
, fds
);
172 manager_serialize_uid_refs(m
, f
);
173 manager_serialize_gid_refs(m
, f
);
175 r
= exec_runtime_serialize(m
, f
, fds
);
179 (void) fputc('\n', f
);
181 HASHMAP_FOREACH_KEY(u
, t
, m
->units
) {
185 r
= unit_serialize(u
, f
, fds
, switching_root
);
190 r
= fflush_and_check(f
);
192 return log_error_errno(r
, "Failed to flush serialization: %m");
194 r
= bus_fdset_add_all(m
, fds
);
196 return log_error_errno(r
, "Failed to add bus sockets to serialization: %m");
201 static int manager_deserialize_one_unit(Manager
*m
, const char *name
, FILE *f
, FDSet
*fds
) {
205 r
= manager_load_unit(m
, name
, NULL
, NULL
, &u
);
209 return log_notice_errno(r
, "Failed to load unit \"%s\", skipping deserialization: %m", name
);
212 r
= unit_deserialize(u
, f
, fds
);
216 return log_notice_errno(r
, "Failed to deserialize unit \"%s\", skipping: %m", name
);
222 static int manager_deserialize_units(Manager
*m
, FILE *f
, FDSet
*fds
) {
223 const char *unit_name
;
227 _cleanup_free_
char *line
= NULL
;
229 r
= read_line(f
, LONG_LINE_MAX
, &line
);
231 return log_error_errno(r
, "Failed to read serialization line: %m");
235 unit_name
= strstrip(line
);
237 r
= manager_deserialize_one_unit(m
, unit_name
, f
, fds
);
241 r
= unit_deserialize_skip(f
);
250 static void manager_deserialize_uid_refs_one_internal(
261 r
= parse_uid(value
, &uid
);
262 if (r
< 0 || uid
== 0) {
263 log_debug("Unable to parse UID/GID reference serialization: " UID_FMT
, uid
);
267 if (hashmap_ensure_allocated(uid_refs
, &trivial_hash_ops
) < 0) {
272 c
= PTR_TO_UINT32(hashmap_get(*uid_refs
, UID_TO_PTR(uid
)));
273 if (c
& DESTROY_IPC_FLAG
)
276 c
|= DESTROY_IPC_FLAG
;
278 r
= hashmap_replace(*uid_refs
, UID_TO_PTR(uid
), UINT32_TO_PTR(c
));
280 log_debug_errno(r
, "Failed to add UID/GID reference entry: %m");
285 static void manager_deserialize_uid_refs_one(Manager
*m
, const char *value
) {
286 manager_deserialize_uid_refs_one_internal(&m
->uid_refs
, value
);
289 static void manager_deserialize_gid_refs_one(Manager
*m
, const char *value
) {
290 manager_deserialize_uid_refs_one_internal(&m
->gid_refs
, value
);
293 int manager_deserialize(Manager
*m
, FILE *f
, FDSet
*fds
) {
300 if (fdset_isempty(fds
))
301 log_debug("No file descriptors passed");
305 FDSET_FOREACH(fd
, fds
) {
306 _cleanup_free_
char *fn
= NULL
;
308 r
= fd_get_path(fd
, &fn
);
310 log_debug_errno(r
, "Received serialized fd %i → %m", fd
);
312 log_debug("Received serialized fd %i → %s", fd
, strna(fn
));
317 log_debug("Deserializing state...");
319 /* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have
320 * increased it to non-zero, which is why we just increase it by one here and down again at the end of this
322 _cleanup_(manager_reloading_stopp
) _unused_ Manager
*reloading
= manager_reloading_start(m
);
325 _cleanup_free_
char *line
= NULL
;
328 r
= read_line(f
, LONG_LINE_MAX
, &line
);
330 return log_error_errno(r
, "Failed to read serialization line: %m");
335 if (isempty(l
)) /* end marker */
338 if ((val
= startswith(l
, "current-job-id="))) {
341 if (safe_atou32(val
, &id
) < 0)
342 log_notice("Failed to parse current job id value '%s', ignoring.", val
);
344 m
->current_job_id
= MAX(m
->current_job_id
, id
);
346 } else if ((val
= startswith(l
, "n-installed-jobs="))) {
349 if (safe_atou32(val
, &n
) < 0)
350 log_notice("Failed to parse installed jobs counter '%s', ignoring.", val
);
352 m
->n_installed_jobs
+= n
;
354 } else if ((val
= startswith(l
, "n-failed-jobs="))) {
357 if (safe_atou32(val
, &n
) < 0)
358 log_notice("Failed to parse failed jobs counter '%s', ignoring.", val
);
360 m
->n_failed_jobs
+= n
;
362 } else if ((val
= startswith(l
, "taint-usr="))) {
365 b
= parse_boolean(val
);
367 log_notice("Failed to parse taint /usr flag '%s', ignoring.", val
);
369 m
->taint_usr
= m
->taint_usr
|| b
;
371 } else if ((val
= startswith(l
, "ready-sent="))) {
374 b
= parse_boolean(val
);
376 log_notice("Failed to parse ready-sent flag '%s', ignoring.", val
);
378 m
->ready_sent
= m
->ready_sent
|| b
;
380 } else if ((val
= startswith(l
, "taint-logged="))) {
383 b
= parse_boolean(val
);
385 log_notice("Failed to parse taint-logged flag '%s', ignoring.", val
);
387 m
->taint_logged
= m
->taint_logged
|| b
;
389 } else if ((val
= startswith(l
, "service-watchdogs="))) {
392 b
= parse_boolean(val
);
394 log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val
);
396 m
->service_watchdogs
= b
;
398 } else if ((val
= startswith(l
, "honor-device-enumeration="))) {
401 b
= parse_boolean(val
);
403 log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val
);
405 m
->honor_device_enumeration
= b
;
407 } else if ((val
= startswith(l
, "show-status-overridden="))) {
410 s
= show_status_from_string(val
);
412 log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val
);
414 manager_override_show_status(m
, s
, "deserialize");
416 } else if ((val
= startswith(l
, "log-level-override="))) {
419 level
= log_level_from_string(val
);
421 log_notice("Failed to parse log-level-override value '%s', ignoring.", val
);
423 manager_override_log_level(m
, level
);
425 } else if ((val
= startswith(l
, "log-target-override="))) {
428 target
= log_target_from_string(val
);
430 log_notice("Failed to parse log-target-override value '%s', ignoring.", val
);
432 manager_override_log_target(m
, target
);
434 } else if ((val
= startswith(l
, "runtime-watchdog-overridden="))) {
437 if (deserialize_usec(val
, &t
) < 0)
438 log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val
);
440 manager_override_watchdog(m
, WATCHDOG_RUNTIME
, t
);
442 } else if ((val
= startswith(l
, "reboot-watchdog-overridden="))) {
445 if (deserialize_usec(val
, &t
) < 0)
446 log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val
);
448 manager_override_watchdog(m
, WATCHDOG_REBOOT
, t
);
450 } else if ((val
= startswith(l
, "kexec-watchdog-overridden="))) {
453 if (deserialize_usec(val
, &t
) < 0)
454 log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val
);
456 manager_override_watchdog(m
, WATCHDOG_KEXEC
, t
);
458 } else if (startswith(l
, "env=")) {
459 r
= deserialize_environment(l
+ 4, &m
->client_environment
);
461 log_notice_errno(r
, "Failed to parse environment entry: \"%s\", ignoring: %m", l
);
463 } else if ((val
= startswith(l
, "notify-fd="))) {
466 if (safe_atoi(val
, &fd
) < 0 || fd
< 0 || !fdset_contains(fds
, fd
))
467 log_notice("Failed to parse notify fd, ignoring: \"%s\"", val
);
469 m
->notify_event_source
= sd_event_source_disable_unref(m
->notify_event_source
);
470 safe_close(m
->notify_fd
);
471 m
->notify_fd
= fdset_remove(fds
, fd
);
474 } else if ((val
= startswith(l
, "notify-socket="))) {
475 r
= free_and_strdup(&m
->notify_socket
, val
);
479 } else if ((val
= startswith(l
, "cgroups-agent-fd="))) {
482 if (safe_atoi(val
, &fd
) < 0 || fd
< 0 || !fdset_contains(fds
, fd
))
483 log_notice("Failed to parse cgroups agent fd, ignoring.: %s", val
);
485 m
->cgroups_agent_event_source
= sd_event_source_disable_unref(m
->cgroups_agent_event_source
);
486 safe_close(m
->cgroups_agent_fd
);
487 m
->cgroups_agent_fd
= fdset_remove(fds
, fd
);
490 } else if ((val
= startswith(l
, "user-lookup="))) {
493 if (sscanf(val
, "%i %i", &fd0
, &fd1
) != 2 || fd0
< 0 || fd1
< 0 || fd0
== fd1
|| !fdset_contains(fds
, fd0
) || !fdset_contains(fds
, fd1
))
494 log_notice("Failed to parse user lookup fd, ignoring: %s", val
);
496 m
->user_lookup_event_source
= sd_event_source_disable_unref(m
->user_lookup_event_source
);
497 safe_close_pair(m
->user_lookup_fds
);
498 m
->user_lookup_fds
[0] = fdset_remove(fds
, fd0
);
499 m
->user_lookup_fds
[1] = fdset_remove(fds
, fd1
);
502 } else if ((val
= startswith(l
, "dynamic-user=")))
503 dynamic_user_deserialize_one(m
, val
, fds
);
504 else if ((val
= startswith(l
, "destroy-ipc-uid=")))
505 manager_deserialize_uid_refs_one(m
, val
);
506 else if ((val
= startswith(l
, "destroy-ipc-gid=")))
507 manager_deserialize_gid_refs_one(m
, val
);
508 else if ((val
= startswith(l
, "exec-runtime=")))
509 (void) exec_runtime_deserialize_one(m
, val
, fds
);
510 else if ((val
= startswith(l
, "subscribed="))) {
512 if (strv_extend(&m
->deserialized_subscribed
, val
) < 0)
518 for (q
= 0; q
< _MANAGER_TIMESTAMP_MAX
; q
++) {
519 val
= startswith(l
, manager_timestamp_to_string(q
));
523 val
= startswith(val
, "-timestamp=");
528 if (q
< _MANAGER_TIMESTAMP_MAX
) /* found it */
529 (void) deserialize_dual_timestamp(val
, m
->timestamps
+ q
);
530 else if (!startswith(l
, "kdbus-fd=")) /* ignore kdbus */
531 log_notice("Unknown serialization item '%s', ignoring.", l
);
535 return manager_deserialize_units(m
, f
, fds
);