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
]);
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
);
124 for (ManagerTimestamp q
= 0; q
< _MANAGER_TIMESTAMP_MAX
; q
++) {
125 _cleanup_free_
char *joined
= NULL
;
127 if (!manager_timestamp_shall_serialize(q
))
130 joined
= strjoin(manager_timestamp_to_string(q
), "-timestamp");
134 (void) serialize_dual_timestamp(f
, joined
, m
->timestamps
+ q
);
138 (void) serialize_strv(f
, "env", m
->client_environment
);
140 if (m
->notify_fd
>= 0) {
141 r
= serialize_fd(f
, fds
, "notify-fd", m
->notify_fd
);
145 (void) serialize_item(f
, "notify-socket", m
->notify_socket
);
148 if (m
->cgroups_agent_fd
>= 0) {
149 r
= serialize_fd(f
, fds
, "cgroups-agent-fd", m
->cgroups_agent_fd
);
154 if (m
->user_lookup_fds
[0] >= 0) {
157 copy0
= fdset_put_dup(fds
, m
->user_lookup_fds
[0]);
159 return log_error_errno(copy0
, "Failed to add user lookup fd to serialization: %m");
161 copy1
= fdset_put_dup(fds
, m
->user_lookup_fds
[1]);
163 return log_error_errno(copy1
, "Failed to add user lookup fd to serialization: %m");
165 (void) serialize_item_format(f
, "user-lookup", "%i %i", copy0
, copy1
);
168 bus_track_serialize(m
->subscribed
, f
, "subscribed");
170 r
= dynamic_user_serialize(m
, f
, fds
);
174 manager_serialize_uid_refs(m
, f
);
175 manager_serialize_gid_refs(m
, f
);
177 r
= exec_runtime_serialize(m
, f
, fds
);
181 (void) fputc('\n', f
);
183 HASHMAP_FOREACH_KEY(u
, t
, m
->units
) {
187 r
= unit_serialize(u
, f
, fds
, switching_root
);
192 r
= fflush_and_check(f
);
194 return log_error_errno(r
, "Failed to flush serialization: %m");
196 r
= bus_fdset_add_all(m
, fds
);
198 return log_error_errno(r
, "Failed to add bus sockets to serialization: %m");
203 static int manager_deserialize_one_unit(Manager
*m
, const char *name
, FILE *f
, FDSet
*fds
) {
207 r
= manager_load_unit(m
, name
, NULL
, NULL
, &u
);
211 return log_notice_errno(r
, "Failed to load unit \"%s\", skipping deserialization: %m", name
);
214 r
= unit_deserialize(u
, f
, fds
);
218 return log_notice_errno(r
, "Failed to deserialize unit \"%s\", skipping: %m", name
);
224 static int manager_deserialize_units(Manager
*m
, FILE *f
, FDSet
*fds
) {
225 const char *unit_name
;
229 _cleanup_free_
char *line
= NULL
;
231 r
= read_line(f
, LONG_LINE_MAX
, &line
);
233 return log_error_errno(r
, "Failed to read serialization line: %m");
237 unit_name
= strstrip(line
);
239 r
= manager_deserialize_one_unit(m
, unit_name
, f
, fds
);
243 r
= unit_deserialize_skip(f
);
252 static void manager_deserialize_uid_refs_one_internal(
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
);
269 if (hashmap_ensure_allocated(uid_refs
, &trivial_hash_ops
) < 0) {
274 c
= PTR_TO_UINT32(hashmap_get(*uid_refs
, UID_TO_PTR(uid
)));
275 if (c
& DESTROY_IPC_FLAG
)
278 c
|= DESTROY_IPC_FLAG
;
280 r
= hashmap_replace(*uid_refs
, UID_TO_PTR(uid
), UINT32_TO_PTR(c
));
282 log_debug_errno(r
, "Failed to add UID/GID reference entry: %m");
287 static void manager_deserialize_uid_refs_one(Manager
*m
, const char *value
) {
288 manager_deserialize_uid_refs_one_internal(&m
->uid_refs
, value
);
291 static void manager_deserialize_gid_refs_one(Manager
*m
, const char *value
) {
292 manager_deserialize_uid_refs_one_internal(&m
->gid_refs
, value
);
295 int manager_deserialize(Manager
*m
, FILE *f
, FDSet
*fds
) {
302 if (fdset_isempty(fds
))
303 log_debug("No file descriptors passed");
307 FDSET_FOREACH(fd
, fds
) {
308 _cleanup_free_
char *fn
= NULL
;
310 r
= fd_get_path(fd
, &fn
);
312 log_debug_errno(r
, "Received serialized fd %i → %m", fd
);
314 log_debug("Received serialized fd %i → %s", fd
, strna(fn
));
319 log_debug("Deserializing state...");
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
324 _cleanup_(manager_reloading_stopp
) _unused_ Manager
*reloading
= manager_reloading_start(m
);
327 _cleanup_free_
char *line
= NULL
;
330 r
= read_line(f
, LONG_LINE_MAX
, &line
);
332 return log_error_errno(r
, "Failed to read serialization line: %m");
337 if (isempty(l
)) /* end marker */
340 if ((val
= startswith(l
, "current-job-id="))) {
343 if (safe_atou32(val
, &id
) < 0)
344 log_notice("Failed to parse current job id value '%s', ignoring.", val
);
346 m
->current_job_id
= MAX(m
->current_job_id
, id
);
348 } else if ((val
= startswith(l
, "n-installed-jobs="))) {
351 if (safe_atou32(val
, &n
) < 0)
352 log_notice("Failed to parse installed jobs counter '%s', ignoring.", val
);
354 m
->n_installed_jobs
+= n
;
356 } else if ((val
= startswith(l
, "n-failed-jobs="))) {
359 if (safe_atou32(val
, &n
) < 0)
360 log_notice("Failed to parse failed jobs counter '%s', ignoring.", val
);
362 m
->n_failed_jobs
+= n
;
364 } else if ((val
= startswith(l
, "taint-usr="))) {
367 b
= parse_boolean(val
);
369 log_notice("Failed to parse taint /usr flag '%s', ignoring.", val
);
371 m
->taint_usr
= m
->taint_usr
|| b
;
373 } else if ((val
= startswith(l
, "ready-sent="))) {
376 b
= parse_boolean(val
);
378 log_notice("Failed to parse ready-sent flag '%s', ignoring.", val
);
380 m
->ready_sent
= m
->ready_sent
|| b
;
382 } else if ((val
= startswith(l
, "taint-logged="))) {
385 b
= parse_boolean(val
);
387 log_notice("Failed to parse taint-logged flag '%s', ignoring.", val
);
389 m
->taint_logged
= m
->taint_logged
|| b
;
391 } else if ((val
= startswith(l
, "service-watchdogs="))) {
394 b
= parse_boolean(val
);
396 log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val
);
398 m
->service_watchdogs
= b
;
400 } else if ((val
= startswith(l
, "honor-device-enumeration="))) {
403 b
= parse_boolean(val
);
405 log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val
);
407 m
->honor_device_enumeration
= b
;
409 } else if ((val
= startswith(l
, "show-status-overridden="))) {
412 s
= show_status_from_string(val
);
414 log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val
);
416 manager_override_show_status(m
, s
, "deserialize");
418 } else if ((val
= startswith(l
, "log-level-override="))) {
421 level
= log_level_from_string(val
);
423 log_notice("Failed to parse log-level-override value '%s', ignoring.", val
);
425 manager_override_log_level(m
, level
);
427 } else if ((val
= startswith(l
, "log-target-override="))) {
430 target
= log_target_from_string(val
);
432 log_notice("Failed to parse log-target-override value '%s', ignoring.", val
);
434 manager_override_log_target(m
, target
);
436 } else if ((val
= startswith(l
, "runtime-watchdog-overridden="))) {
439 if (deserialize_usec(val
, &t
) < 0)
440 log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val
);
442 manager_override_watchdog(m
, WATCHDOG_RUNTIME
, t
);
444 } else if ((val
= startswith(l
, "reboot-watchdog-overridden="))) {
447 if (deserialize_usec(val
, &t
) < 0)
448 log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val
);
450 manager_override_watchdog(m
, WATCHDOG_REBOOT
, t
);
452 } else if ((val
= startswith(l
, "kexec-watchdog-overridden="))) {
455 if (deserialize_usec(val
, &t
) < 0)
456 log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val
);
458 manager_override_watchdog(m
, WATCHDOG_KEXEC
, t
);
460 } else if ((val
= startswith(l
, "pretimeout-watchdog-overridden="))) {
463 if (deserialize_usec(val
, &t
) < 0)
464 log_notice("Failed to parse pretimeout-watchdog-overridden value '%s', ignoring.", val
);
466 manager_override_watchdog(m
, WATCHDOG_PRETIMEOUT
, t
);
468 } else if ((val
= startswith(l
, "pretimeout-watchdog-governor-overridden="))) {
469 r
= free_and_strdup(&m
->watchdog_pretimeout_governor_overridden
, val
);
473 } else if (startswith(l
, "env=")) {
474 r
= deserialize_environment(l
+ 4, &m
->client_environment
);
476 log_notice_errno(r
, "Failed to parse environment entry: \"%s\", ignoring: %m", l
);
478 } else if ((val
= startswith(l
, "notify-fd="))) {
481 if (safe_atoi(val
, &fd
) < 0 || fd
< 0 || !fdset_contains(fds
, fd
))
482 log_notice("Failed to parse notify fd, ignoring: \"%s\"", val
);
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
);
489 } else if ((val
= startswith(l
, "notify-socket="))) {
490 r
= free_and_strdup(&m
->notify_socket
, val
);
494 } else if ((val
= startswith(l
, "cgroups-agent-fd="))) {
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
);
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
);
505 } else if ((val
= startswith(l
, "user-lookup="))) {
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
);
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
);
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="))) {
527 if (strv_extend(&m
->deserialized_subscribed
, val
) < 0)
533 for (q
= 0; q
< _MANAGER_TIMESTAMP_MAX
; q
++) {
534 val
= startswith(l
, manager_timestamp_to_string(q
));
538 val
= startswith(val
, "-timestamp=");
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
);
550 return manager_deserialize_units(m
, f
, fds
);