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 
manager_open_serialization(Manager * m,FILE ** ret_f)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 
manager_timestamp_shall_serialize(ManagerTimestamp t)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 
manager_serialize_uid_refs_internal(FILE * f,Hashmap * uid_refs,const char * field_name)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 
manager_serialize_uid_refs(Manager * m,FILE * f)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 
manager_serialize_gid_refs(Manager * m,FILE * f)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 
manager_serialize(Manager * m,FILE * f,FDSet * fds,bool switching_root)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 
manager_deserialize_one_unit(Manager * m,const char * name,FILE * f,FDSet * fds)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 
manager_deserialize_units(Manager * m,FILE * f,FDSet * fds)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 
manager_deserialize_uid_refs_one_internal(Hashmap ** uid_refs,const char * value)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 
manager_deserialize_uid_refs_one(Manager * m,const char * value)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 
manager_deserialize_gid_refs_one(Manager * m,const char * 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);
293 }
294 
manager_deserialize(Manager * m,FILE * f,FDSet * fds)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 }
552