1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "core-varlink.h"
8 #include "format-util.h"
9 #include "initrd-util.h"
11 #include "manager-serialize.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"
20 int manager_open_serialization(Manager
*m
, FILE **ret_f
) {
21 _cleanup_close_
int fd
= -EBADF
;
26 fd
= open_serialization_fd("systemd-state");
30 f
= take_fdopen(&fd
, "w+");
38 static bool manager_timestamp_shall_serialize(ManagerTimestamp t
) {
42 /* The following timestamps only apply to the host system, hence only serialize them there */
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
);
50 static void manager_serialize_uid_refs_internal(
53 const char *field_name
) {
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. */
63 HASHMAP_FOREACH_KEY(p
, k
, uid_refs
) {
70 if (!(c
& DESTROY_IPC_FLAG
))
73 (void) serialize_item_format(f
, field_name
, UID_FMT
, uid
);
77 static void manager_serialize_uid_refs(Manager
*m
, FILE *f
) {
78 manager_serialize_uid_refs_internal(f
, m
->uid_refs
, "destroy-ipc-uid");
81 static void manager_serialize_gid_refs(Manager
*m
, FILE *f
) {
82 manager_serialize_uid_refs_internal(f
, m
->gid_refs
, "destroy-ipc-gid");
85 int manager_serialize(
89 bool switching_root
) {
99 _cleanup_(manager_reloading_stopp
) _unused_ Manager
*reloading
= manager_reloading_start(m
);
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
);
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_shared_runtime_serialize(m
, f
, fds
);
181 r
= varlink_server_serialize(m
->varlink_server
, f
, fds
);
185 (void) fputc('\n', f
);
187 HASHMAP_FOREACH_KEY(u
, t
, m
->units
) {
191 r
= unit_serialize(u
, f
, fds
, switching_root
);
196 r
= fflush_and_check(f
);
198 return log_error_errno(r
, "Failed to flush serialization: %m");
200 r
= bus_fdset_add_all(m
, fds
);
202 return log_error_errno(r
, "Failed to add bus sockets to serialization: %m");
207 static int manager_deserialize_one_unit(Manager
*m
, const char *name
, FILE *f
, FDSet
*fds
) {
211 r
= manager_load_unit(m
, name
, NULL
, NULL
, &u
);
215 return log_notice_errno(r
, "Failed to load unit \"%s\", skipping deserialization: %m", name
);
218 r
= unit_deserialize(u
, f
, fds
);
222 return log_notice_errno(r
, "Failed to deserialize unit \"%s\", skipping: %m", name
);
228 static int manager_deserialize_units(Manager
*m
, FILE *f
, FDSet
*fds
) {
229 const char *unit_name
;
233 _cleanup_free_
char *line
= NULL
;
235 r
= read_line(f
, LONG_LINE_MAX
, &line
);
237 return log_error_errno(r
, "Failed to read serialization line: %m");
241 unit_name
= strstrip(line
);
243 r
= manager_deserialize_one_unit(m
, unit_name
, f
, fds
);
247 r
= unit_deserialize_skip(f
);
256 static void manager_deserialize_uid_refs_one_internal(
267 r
= parse_uid(value
, &uid
);
268 if (r
< 0 || uid
== 0) {
269 log_debug("Unable to parse UID/GID reference serialization: " UID_FMT
, uid
);
273 if (hashmap_ensure_allocated(uid_refs
, &trivial_hash_ops
) < 0) {
278 c
= PTR_TO_UINT32(hashmap_get(*uid_refs
, UID_TO_PTR(uid
)));
279 if (c
& DESTROY_IPC_FLAG
)
282 c
|= DESTROY_IPC_FLAG
;
284 r
= hashmap_replace(*uid_refs
, UID_TO_PTR(uid
), UINT32_TO_PTR(c
));
286 log_debug_errno(r
, "Failed to add UID/GID reference entry: %m");
291 static void manager_deserialize_uid_refs_one(Manager
*m
, const char *value
) {
292 manager_deserialize_uid_refs_one_internal(&m
->uid_refs
, value
);
295 static void manager_deserialize_gid_refs_one(Manager
*m
, const char *value
) {
296 manager_deserialize_uid_refs_one_internal(&m
->gid_refs
, value
);
299 int manager_deserialize(Manager
*m
, FILE *f
, FDSet
*fds
) {
300 bool deserialize_varlink_sockets
= false;
307 if (fdset_isempty(fds
))
308 log_debug("No file descriptors passed");
312 FDSET_FOREACH(fd
, fds
) {
313 _cleanup_free_
char *fn
= NULL
;
315 r
= fd_get_path(fd
, &fn
);
317 log_debug_errno(r
, "Received serialized fd %i %s %m",
318 fd
, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
));
320 log_debug("Received serialized fd %i %s %s",
321 fd
, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
), strna(fn
));
326 log_debug("Deserializing state...");
328 /* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have
329 * increased it to non-zero, which is why we just increase it by one here and down again at the end of this
331 _cleanup_(manager_reloading_stopp
) _unused_ Manager
*reloading
= manager_reloading_start(m
);
334 _cleanup_free_
char *line
= NULL
;
337 r
= read_line(f
, LONG_LINE_MAX
, &line
);
339 return log_error_errno(r
, "Failed to read serialization line: %m");
344 if (isempty(l
)) /* end marker */
347 if ((val
= startswith(l
, "current-job-id="))) {
350 if (safe_atou32(val
, &id
) < 0)
351 log_notice("Failed to parse current job id value '%s', ignoring.", val
);
353 m
->current_job_id
= MAX(m
->current_job_id
, id
);
355 } else if ((val
= startswith(l
, "n-installed-jobs="))) {
358 if (safe_atou32(val
, &n
) < 0)
359 log_notice("Failed to parse installed jobs counter '%s', ignoring.", val
);
361 m
->n_installed_jobs
+= n
;
363 } else if ((val
= startswith(l
, "n-failed-jobs="))) {
366 if (safe_atou32(val
, &n
) < 0)
367 log_notice("Failed to parse failed jobs counter '%s', ignoring.", val
);
369 m
->n_failed_jobs
+= n
;
371 } else if ((val
= startswith(l
, "taint-usr="))) {
374 b
= parse_boolean(val
);
376 log_notice("Failed to parse taint /usr flag '%s', ignoring.", val
);
378 m
->taint_usr
= m
->taint_usr
|| b
;
380 } else if ((val
= startswith(l
, "ready-sent="))) {
383 b
= parse_boolean(val
);
385 log_notice("Failed to parse ready-sent flag '%s', ignoring.", val
);
387 m
->ready_sent
= m
->ready_sent
|| b
;
389 } else if ((val
= startswith(l
, "taint-logged="))) {
392 b
= parse_boolean(val
);
394 log_notice("Failed to parse taint-logged flag '%s', ignoring.", val
);
396 m
->taint_logged
= m
->taint_logged
|| b
;
398 } else if ((val
= startswith(l
, "service-watchdogs="))) {
401 b
= parse_boolean(val
);
403 log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val
);
405 m
->service_watchdogs
= 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 ((val
= startswith(l
, "pretimeout-watchdog-overridden="))) {
461 if (deserialize_usec(val
, &t
) < 0)
462 log_notice("Failed to parse pretimeout-watchdog-overridden value '%s', ignoring.", val
);
464 manager_override_watchdog(m
, WATCHDOG_PRETIMEOUT
, t
);
466 } else if ((val
= startswith(l
, "pretimeout-watchdog-governor-overridden="))) {
467 r
= free_and_strdup(&m
->watchdog_pretimeout_governor_overridden
, val
);
471 } else if (startswith(l
, "env=")) {
472 r
= deserialize_environment(l
+ 4, &m
->client_environment
);
474 log_notice_errno(r
, "Failed to parse environment entry: \"%s\", ignoring: %m", l
);
476 } else if ((val
= startswith(l
, "notify-fd="))) {
479 if (safe_atoi(val
, &fd
) < 0 || fd
< 0 || !fdset_contains(fds
, fd
))
480 log_notice("Failed to parse notify fd, ignoring: \"%s\"", val
);
482 m
->notify_event_source
= sd_event_source_disable_unref(m
->notify_event_source
);
483 safe_close(m
->notify_fd
);
484 m
->notify_fd
= fdset_remove(fds
, fd
);
487 } else if ((val
= startswith(l
, "notify-socket="))) {
488 r
= free_and_strdup(&m
->notify_socket
, val
);
492 } else if ((val
= startswith(l
, "cgroups-agent-fd="))) {
495 if (safe_atoi(val
, &fd
) < 0 || fd
< 0 || !fdset_contains(fds
, fd
))
496 log_notice("Failed to parse cgroups agent fd, ignoring.: %s", val
);
498 m
->cgroups_agent_event_source
= sd_event_source_disable_unref(m
->cgroups_agent_event_source
);
499 safe_close(m
->cgroups_agent_fd
);
500 m
->cgroups_agent_fd
= fdset_remove(fds
, fd
);
503 } else if ((val
= startswith(l
, "user-lookup="))) {
506 if (sscanf(val
, "%i %i", &fd0
, &fd1
) != 2 || fd0
< 0 || fd1
< 0 || fd0
== fd1
|| !fdset_contains(fds
, fd0
) || !fdset_contains(fds
, fd1
))
507 log_notice("Failed to parse user lookup fd, ignoring: %s", val
);
509 m
->user_lookup_event_source
= sd_event_source_disable_unref(m
->user_lookup_event_source
);
510 safe_close_pair(m
->user_lookup_fds
);
511 m
->user_lookup_fds
[0] = fdset_remove(fds
, fd0
);
512 m
->user_lookup_fds
[1] = fdset_remove(fds
, fd1
);
515 } else if ((val
= startswith(l
, "dynamic-user=")))
516 dynamic_user_deserialize_one(m
, val
, fds
);
517 else if ((val
= startswith(l
, "destroy-ipc-uid=")))
518 manager_deserialize_uid_refs_one(m
, val
);
519 else if ((val
= startswith(l
, "destroy-ipc-gid=")))
520 manager_deserialize_gid_refs_one(m
, val
);
521 else if ((val
= startswith(l
, "exec-runtime=")))
522 (void) exec_shared_runtime_deserialize_one(m
, val
, fds
);
523 else if ((val
= startswith(l
, "subscribed="))) {
525 if (strv_extend(&m
->deserialized_subscribed
, val
) < 0)
527 } else if ((val
= startswith(l
, "varlink-server-socket-address="))) {
528 if (!m
->varlink_server
&& MANAGER_IS_SYSTEM(m
)) {
529 _cleanup_(varlink_server_unrefp
) VarlinkServer
*s
= NULL
;
531 r
= manager_setup_varlink_server(m
, &s
);
533 log_warning_errno(r
, "Failed to setup varlink server, ignoring: %m");
537 r
= varlink_server_attach_event(s
, m
->event
, SD_EVENT_PRIORITY_NORMAL
);
539 log_warning_errno(r
, "Failed to attach varlink connection to event loop, ignoring: %m");
543 m
->varlink_server
= TAKE_PTR(s
);
544 deserialize_varlink_sockets
= true;
547 /* To void unnecessary deserialization (i.e. during reload vs. reexec) we only deserialize
548 * the FDs if we had to create a new m->varlink_server. The deserialize_varlink_sockets flag
549 * is initialized outside of the loop, is flipped after the VarlinkServer is setup, and
550 * remains set until all serialized contents are handled. */
551 if (deserialize_varlink_sockets
)
552 (void) varlink_server_deserialize_one(m
->varlink_server
, val
, fds
);
556 for (q
= 0; q
< _MANAGER_TIMESTAMP_MAX
; q
++) {
557 val
= startswith(l
, manager_timestamp_to_string(q
));
561 val
= startswith(val
, "-timestamp=");
566 if (q
< _MANAGER_TIMESTAMP_MAX
) /* found it */
567 (void) deserialize_dual_timestamp(val
, m
->timestamps
+ q
);
568 else if (!STARTSWITH_SET(l
, "kdbus-fd=", "honor-device-enumeration=")) /* ignore deprecated values */
569 log_notice("Unknown serialization item '%s', ignoring.", l
);
573 return manager_deserialize_units(m
, f
, fds
);