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 if (m
->show_status_overridden
!= _SHOW_STATUS_INVALID
)
107 (void) serialize_item(f
, "show-status-overridden",
108 show_status_to_string(m
->show_status_overridden
));
110 if (m
->log_level_overridden
)
111 (void) serialize_item_format(f
, "log-level-override", "%i", log_get_max_level());
112 if (m
->log_target_overridden
)
113 (void) serialize_item(f
, "log-target-override", log_target_to_string(log_get_target()));
115 (void) serialize_usec(f
, "runtime-watchdog-overridden", m
->watchdog_overridden
[WATCHDOG_RUNTIME
]);
116 (void) serialize_usec(f
, "reboot-watchdog-overridden", m
->watchdog_overridden
[WATCHDOG_REBOOT
]);
117 (void) serialize_usec(f
, "kexec-watchdog-overridden", m
->watchdog_overridden
[WATCHDOG_KEXEC
]);
118 (void) serialize_usec(f
, "pretimeout-watchdog-overridden", m
->watchdog_overridden
[WATCHDOG_PRETIMEOUT
]);
119 (void) serialize_item(f
, "pretimeout-watchdog-governor-overridden", m
->watchdog_pretimeout_governor_overridden
);
121 for (ManagerTimestamp q
= 0; q
< _MANAGER_TIMESTAMP_MAX
; q
++) {
122 _cleanup_free_
char *joined
= NULL
;
124 if (!manager_timestamp_shall_serialize(q
))
127 joined
= strjoin(manager_timestamp_to_string(q
), "-timestamp");
131 (void) serialize_dual_timestamp(f
, joined
, m
->timestamps
+ q
);
135 (void) serialize_strv(f
, "env", m
->client_environment
);
137 if (m
->notify_fd
>= 0) {
138 r
= serialize_fd(f
, fds
, "notify-fd", m
->notify_fd
);
142 (void) serialize_item(f
, "notify-socket", m
->notify_socket
);
145 if (m
->cgroups_agent_fd
>= 0) {
146 r
= serialize_fd(f
, fds
, "cgroups-agent-fd", m
->cgroups_agent_fd
);
151 if (m
->user_lookup_fds
[0] >= 0) {
154 copy0
= fdset_put_dup(fds
, m
->user_lookup_fds
[0]);
156 return log_error_errno(copy0
, "Failed to add user lookup fd to serialization: %m");
158 copy1
= fdset_put_dup(fds
, m
->user_lookup_fds
[1]);
160 return log_error_errno(copy1
, "Failed to add user lookup fd to serialization: %m");
162 (void) serialize_item_format(f
, "user-lookup", "%i %i", copy0
, copy1
);
165 bus_track_serialize(m
->subscribed
, f
, "subscribed");
167 r
= dynamic_user_serialize(m
, f
, fds
);
171 manager_serialize_uid_refs(m
, f
);
172 manager_serialize_gid_refs(m
, f
);
174 r
= exec_runtime_serialize(m
, f
, fds
);
178 (void) fputc('\n', f
);
180 HASHMAP_FOREACH_KEY(u
, t
, m
->units
) {
184 r
= unit_serialize(u
, f
, fds
, switching_root
);
189 r
= fflush_and_check(f
);
191 return log_error_errno(r
, "Failed to flush serialization: %m");
193 r
= bus_fdset_add_all(m
, fds
);
195 return log_error_errno(r
, "Failed to add bus sockets to serialization: %m");
200 static int manager_deserialize_one_unit(Manager
*m
, const char *name
, FILE *f
, FDSet
*fds
) {
204 r
= manager_load_unit(m
, name
, NULL
, NULL
, &u
);
208 return log_notice_errno(r
, "Failed to load unit \"%s\", skipping deserialization: %m", name
);
211 r
= unit_deserialize(u
, f
, fds
);
215 return log_notice_errno(r
, "Failed to deserialize unit \"%s\", skipping: %m", name
);
221 static int manager_deserialize_units(Manager
*m
, FILE *f
, FDSet
*fds
) {
222 const char *unit_name
;
226 _cleanup_free_
char *line
= NULL
;
228 r
= read_line(f
, LONG_LINE_MAX
, &line
);
230 return log_error_errno(r
, "Failed to read serialization line: %m");
234 unit_name
= strstrip(line
);
236 r
= manager_deserialize_one_unit(m
, unit_name
, f
, fds
);
240 r
= unit_deserialize_skip(f
);
249 static void manager_deserialize_uid_refs_one_internal(
260 r
= parse_uid(value
, &uid
);
261 if (r
< 0 || uid
== 0) {
262 log_debug("Unable to parse UID/GID reference serialization: " UID_FMT
, uid
);
266 if (hashmap_ensure_allocated(uid_refs
, &trivial_hash_ops
) < 0) {
271 c
= PTR_TO_UINT32(hashmap_get(*uid_refs
, UID_TO_PTR(uid
)));
272 if (c
& DESTROY_IPC_FLAG
)
275 c
|= DESTROY_IPC_FLAG
;
277 r
= hashmap_replace(*uid_refs
, UID_TO_PTR(uid
), UINT32_TO_PTR(c
));
279 log_debug_errno(r
, "Failed to add UID/GID reference entry: %m");
284 static void manager_deserialize_uid_refs_one(Manager
*m
, const char *value
) {
285 manager_deserialize_uid_refs_one_internal(&m
->uid_refs
, value
);
288 static void manager_deserialize_gid_refs_one(Manager
*m
, const char *value
) {
289 manager_deserialize_uid_refs_one_internal(&m
->gid_refs
, value
);
292 int manager_deserialize(Manager
*m
, FILE *f
, FDSet
*fds
) {
299 if (fdset_isempty(fds
))
300 log_debug("No file descriptors passed");
304 FDSET_FOREACH(fd
, fds
) {
305 _cleanup_free_
char *fn
= NULL
;
307 r
= fd_get_path(fd
, &fn
);
309 log_debug_errno(r
, "Received serialized fd %i %s %m",
310 fd
, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
));
312 log_debug("Received serialized fd %i %s %s",
313 fd
, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
), strna(fn
));
318 log_debug("Deserializing state...");
320 /* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have
321 * increased it to non-zero, which is why we just increase it by one here and down again at the end of this
323 _cleanup_(manager_reloading_stopp
) _unused_ Manager
*reloading
= manager_reloading_start(m
);
326 _cleanup_free_
char *line
= NULL
;
329 r
= read_line(f
, LONG_LINE_MAX
, &line
);
331 return log_error_errno(r
, "Failed to read serialization line: %m");
336 if (isempty(l
)) /* end marker */
339 if ((val
= startswith(l
, "current-job-id="))) {
342 if (safe_atou32(val
, &id
) < 0)
343 log_notice("Failed to parse current job id value '%s', ignoring.", val
);
345 m
->current_job_id
= MAX(m
->current_job_id
, id
);
347 } else if ((val
= startswith(l
, "n-installed-jobs="))) {
350 if (safe_atou32(val
, &n
) < 0)
351 log_notice("Failed to parse installed jobs counter '%s', ignoring.", val
);
353 m
->n_installed_jobs
+= n
;
355 } else if ((val
= startswith(l
, "n-failed-jobs="))) {
358 if (safe_atou32(val
, &n
) < 0)
359 log_notice("Failed to parse failed jobs counter '%s', ignoring.", val
);
361 m
->n_failed_jobs
+= n
;
363 } else if ((val
= startswith(l
, "taint-usr="))) {
366 b
= parse_boolean(val
);
368 log_notice("Failed to parse taint /usr flag '%s', ignoring.", val
);
370 m
->taint_usr
= m
->taint_usr
|| b
;
372 } else if ((val
= startswith(l
, "ready-sent="))) {
375 b
= parse_boolean(val
);
377 log_notice("Failed to parse ready-sent flag '%s', ignoring.", val
);
379 m
->ready_sent
= m
->ready_sent
|| b
;
381 } else if ((val
= startswith(l
, "taint-logged="))) {
384 b
= parse_boolean(val
);
386 log_notice("Failed to parse taint-logged flag '%s', ignoring.", val
);
388 m
->taint_logged
= m
->taint_logged
|| b
;
390 } else if ((val
= startswith(l
, "service-watchdogs="))) {
393 b
= parse_boolean(val
);
395 log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val
);
397 m
->service_watchdogs
= b
;
399 } else if ((val
= startswith(l
, "show-status-overridden="))) {
402 s
= show_status_from_string(val
);
404 log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val
);
406 manager_override_show_status(m
, s
, "deserialize");
408 } else if ((val
= startswith(l
, "log-level-override="))) {
411 level
= log_level_from_string(val
);
413 log_notice("Failed to parse log-level-override value '%s', ignoring.", val
);
415 manager_override_log_level(m
, level
);
417 } else if ((val
= startswith(l
, "log-target-override="))) {
420 target
= log_target_from_string(val
);
422 log_notice("Failed to parse log-target-override value '%s', ignoring.", val
);
424 manager_override_log_target(m
, target
);
426 } else if ((val
= startswith(l
, "runtime-watchdog-overridden="))) {
429 if (deserialize_usec(val
, &t
) < 0)
430 log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val
);
432 manager_override_watchdog(m
, WATCHDOG_RUNTIME
, t
);
434 } else if ((val
= startswith(l
, "reboot-watchdog-overridden="))) {
437 if (deserialize_usec(val
, &t
) < 0)
438 log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val
);
440 manager_override_watchdog(m
, WATCHDOG_REBOOT
, t
);
442 } else if ((val
= startswith(l
, "kexec-watchdog-overridden="))) {
445 if (deserialize_usec(val
, &t
) < 0)
446 log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val
);
448 manager_override_watchdog(m
, WATCHDOG_KEXEC
, t
);
450 } else if ((val
= startswith(l
, "pretimeout-watchdog-overridden="))) {
453 if (deserialize_usec(val
, &t
) < 0)
454 log_notice("Failed to parse pretimeout-watchdog-overridden value '%s', ignoring.", val
);
456 manager_override_watchdog(m
, WATCHDOG_PRETIMEOUT
, t
);
458 } else if ((val
= startswith(l
, "pretimeout-watchdog-governor-overridden="))) {
459 r
= free_and_strdup(&m
->watchdog_pretimeout_governor_overridden
, val
);
463 } else if (startswith(l
, "env=")) {
464 r
= deserialize_environment(l
+ 4, &m
->client_environment
);
466 log_notice_errno(r
, "Failed to parse environment entry: \"%s\", ignoring: %m", l
);
468 } else if ((val
= startswith(l
, "notify-fd="))) {
471 if (safe_atoi(val
, &fd
) < 0 || fd
< 0 || !fdset_contains(fds
, fd
))
472 log_notice("Failed to parse notify fd, ignoring: \"%s\"", val
);
474 m
->notify_event_source
= sd_event_source_disable_unref(m
->notify_event_source
);
475 safe_close(m
->notify_fd
);
476 m
->notify_fd
= fdset_remove(fds
, fd
);
479 } else if ((val
= startswith(l
, "notify-socket="))) {
480 r
= free_and_strdup(&m
->notify_socket
, val
);
484 } else if ((val
= startswith(l
, "cgroups-agent-fd="))) {
487 if (safe_atoi(val
, &fd
) < 0 || fd
< 0 || !fdset_contains(fds
, fd
))
488 log_notice("Failed to parse cgroups agent fd, ignoring.: %s", val
);
490 m
->cgroups_agent_event_source
= sd_event_source_disable_unref(m
->cgroups_agent_event_source
);
491 safe_close(m
->cgroups_agent_fd
);
492 m
->cgroups_agent_fd
= fdset_remove(fds
, fd
);
495 } else if ((val
= startswith(l
, "user-lookup="))) {
498 if (sscanf(val
, "%i %i", &fd0
, &fd1
) != 2 || fd0
< 0 || fd1
< 0 || fd0
== fd1
|| !fdset_contains(fds
, fd0
) || !fdset_contains(fds
, fd1
))
499 log_notice("Failed to parse user lookup fd, ignoring: %s", val
);
501 m
->user_lookup_event_source
= sd_event_source_disable_unref(m
->user_lookup_event_source
);
502 safe_close_pair(m
->user_lookup_fds
);
503 m
->user_lookup_fds
[0] = fdset_remove(fds
, fd0
);
504 m
->user_lookup_fds
[1] = fdset_remove(fds
, fd1
);
507 } else if ((val
= startswith(l
, "dynamic-user=")))
508 dynamic_user_deserialize_one(m
, val
, fds
);
509 else if ((val
= startswith(l
, "destroy-ipc-uid=")))
510 manager_deserialize_uid_refs_one(m
, val
);
511 else if ((val
= startswith(l
, "destroy-ipc-gid=")))
512 manager_deserialize_gid_refs_one(m
, val
);
513 else if ((val
= startswith(l
, "exec-runtime=")))
514 (void) exec_runtime_deserialize_one(m
, val
, fds
);
515 else if ((val
= startswith(l
, "subscribed="))) {
517 if (strv_extend(&m
->deserialized_subscribed
, val
) < 0)
523 for (q
= 0; q
< _MANAGER_TIMESTAMP_MAX
; q
++) {
524 val
= startswith(l
, manager_timestamp_to_string(q
));
528 val
= startswith(val
, "-timestamp=");
533 if (q
< _MANAGER_TIMESTAMP_MAX
) /* found it */
534 (void) deserialize_dual_timestamp(val
, m
->timestamps
+ q
);
535 else if (!STARTSWITH_SET(l
, "kdbus-fd=", "honor-device-enumeration=")) /* ignore deprecated values */
536 log_notice("Unknown serialization item '%s', ignoring.", l
);
540 return manager_deserialize_units(m
, f
, fds
);