]> git.ipfire.org Git - thirdparty/systemd.git/blame - manager.c
manager: fix GC logic
[thirdparty/systemd.git] / manager.c
CommitLineData
60918275
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60918275
LP
22#include <assert.h>
23#include <errno.h>
87d1515d 24#include <string.h>
9152c765
LP
25#include <sys/epoll.h>
26#include <signal.h>
27#include <sys/signalfd.h>
28#include <sys/wait.h>
29#include <unistd.h>
e537352b 30#include <utmpx.h>
9152c765 31#include <sys/poll.h>
e1414003
LP
32#include <sys/reboot.h>
33#include <sys/ioctl.h>
34#include <linux/kd.h>
8e274523 35#include <libcgroup.h>
80876c20
LP
36#include <termios.h>
37#include <fcntl.h>
a16e1123
LP
38#include <sys/types.h>
39#include <sys/stat.h>
60918275
LP
40
41#include "manager.h"
42#include "hashmap.h"
43#include "macro.h"
44#include "strv.h"
16354eff 45#include "log.h"
2a987ee8 46#include "util.h"
ea430986 47#include "ratelimit.h"
8e274523
LP
48#include "cgroup.h"
49#include "mount-setup.h"
e537352b 50#include "utmp-wtmp.h"
9e2f7c11 51#include "unit-name.h"
4139c1b2
LP
52#include "dbus-unit.h"
53#include "dbus-job.h"
60918275 54
701cc384
LP
55/* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
56#define GC_QUEUE_ENTRIES_MAX 16
57
58/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
59#define GC_QUEUE_USEC_MAX (5*USEC_PER_SEC)
60
80876c20
LP
61static int enable_special_signals(Manager *m) {
62 char fd;
63
64 assert(m);
65
66 /* Enable that we get SIGINT on control-alt-del */
67 if (reboot(RB_DISABLE_CAD) < 0)
68 log_warning("Failed to enable ctrl-alt-del handling: %m");
69
70 if ((fd = open_terminal("/dev/tty0", O_RDWR)) < 0)
71 log_warning("Failed to open /dev/tty0: %m");
72 else {
73 /* Enable that we get SIGWINCH on kbrequest */
74 if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
75 log_warning("Failed to enable kbrequest handling: %s", strerror(errno));
76
77 close_nointr_nofail(fd);
78 }
79
80 return 0;
81}
82
ce578209 83static int manager_setup_signals(Manager *m) {
9152c765
LP
84 sigset_t mask;
85 struct epoll_event ev;
57c0c30e 86 struct sigaction sa;
60918275 87
ce578209
LP
88 assert(m);
89
57c0c30e
LP
90 /* We are not interested in SIGSTOP and friends. */
91 zero(sa);
92 sa.sa_handler = SIG_DFL;
93 sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
94 assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
95
ce578209
LP
96 assert_se(sigemptyset(&mask) == 0);
97 assert_se(sigaddset(&mask, SIGCHLD) == 0);
ce578209
LP
98 assert_se(sigaddset(&mask, SIGTERM) == 0);
99 assert_se(sigaddset(&mask, SIGHUP) == 0);
100 assert_se(sigaddset(&mask, SIGUSR1) == 0);
101 assert_se(sigaddset(&mask, SIGUSR2) == 0);
57ee42ce
LP
102 assert_se(sigaddset(&mask, SIGINT) == 0); /* Kernel sends us this on control-alt-del */
103 assert_se(sigaddset(&mask, SIGWINCH) == 0); /* Kernel sends us this on kbrequest (alt-arrowup) */
104 assert_se(sigaddset(&mask, SIGPWR) == 0); /* Some kernel drivers and upsd send us this on power failure */
ce578209
LP
105 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
106
ef734fd6 107 m->signal_watch.type = WATCH_SIGNAL;
ce578209
LP
108 if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0)
109 return -errno;
110
111 zero(ev);
112 ev.events = EPOLLIN;
113 ev.data.ptr = &m->signal_watch;
114
115 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
116 return -errno;
117
80876c20
LP
118 if (m->running_as == MANAGER_INIT)
119 return enable_special_signals(m);
e1414003 120
ce578209
LP
121 return 0;
122}
123
036643a2
LP
124static char** session_dirs(void) {
125 const char *home, *e;
126 char *config_home = NULL, *data_home = NULL;
127 char **config_dirs = NULL, **data_dirs = NULL;
128 char **r = NULL, **t;
129
130 /* Implement the mechanisms defined in
131 *
132 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
133 *
134 * We look in both the config and the data dirs because we
135 * want to encourage that distributors ship their unit files
136 * as data, and allow overriding as configuration.
137 */
138
139 home = getenv("HOME");
140
141 if ((e = getenv("XDG_CONFIG_HOME"))) {
142 if (asprintf(&config_home, "%s/systemd/session", e) < 0)
143 goto fail;
144
145 } else if (home) {
146 if (asprintf(&config_home, "%s/.config/systemd/session", home) < 0)
147 goto fail;
148 }
149
150 if ((e = getenv("XDG_CONFIG_DIRS")))
151 config_dirs = strv_split(e, ":");
152 else
153 config_dirs = strv_new("/etc/xdg", NULL);
154
155 if (!config_dirs)
156 goto fail;
157
158 if ((e = getenv("XDG_DATA_HOME"))) {
159 if (asprintf(&data_home, "%s/systemd/session", e) < 0)
160 goto fail;
161
162 } else if (home) {
163 if (asprintf(&data_home, "%s/.local/share/systemd/session", home) < 0)
164 goto fail;
165 }
166
167 if ((e = getenv("XDG_DATA_DIRS")))
168 data_dirs = strv_split(e, ":");
169 else
170 data_dirs = strv_new("/usr/local/share", "/usr/share", NULL);
171
172 if (!data_dirs)
173 goto fail;
174
175 /* Now merge everything we found. */
176 if (config_home) {
177 if (!(t = strv_append(r, config_home)))
178 goto fail;
179 strv_free(r);
180 r = t;
181 }
182
183 if (!(t = strv_merge_concat(r, config_dirs, "/systemd/session")))
184 goto finish;
185 strv_free(r);
186 r = t;
187
188 if (!(t = strv_append(r, SESSION_CONFIG_UNIT_PATH)))
189 goto fail;
190 strv_free(r);
191 r = t;
192
193 if (data_home) {
194 if (!(t = strv_append(r, data_home)))
195 goto fail;
196 strv_free(r);
197 r = t;
198 }
199
200 if (!(t = strv_merge_concat(r, data_dirs, "/systemd/session")))
201 goto fail;
202 strv_free(r);
203 r = t;
204
205 if (!(t = strv_append(r, SESSION_DATA_UNIT_PATH)))
206 goto fail;
207 strv_free(r);
208 r = t;
209
210 if (!strv_path_make_absolute_cwd(r))
211 goto fail;
212
213finish:
214 free(config_home);
215 strv_free(config_dirs);
216 free(data_home);
217 strv_free(data_dirs);
218
219 return r;
220
221fail:
222 strv_free(r);
223 r = NULL;
224 goto finish;
225}
226
227static int manager_find_paths(Manager *m) {
228 const char *e;
229 char *t;
23a177ef 230
036643a2
LP
231 assert(m);
232
233 /* First priority is whatever has been passed to us via env
234 * vars */
235 if ((e = getenv("SYSTEMD_UNIT_PATH")))
236 if (!(m->unit_path = split_path_and_make_absolute(e)))
237 return -ENOMEM;
238
239 if (strv_isempty(m->unit_path)) {
240
241 /* Nothing is set, so let's figure something out. */
242 strv_free(m->unit_path);
243
244 if (m->running_as == MANAGER_SESSION) {
245 if (!(m->unit_path = session_dirs()))
246 return -ENOMEM;
247 } else
248 if (!(m->unit_path = strv_new(
249 SYSTEM_CONFIG_UNIT_PATH, /* /etc/systemd/system/ */
250 SYSTEM_DATA_UNIT_PATH, /* /lib/systemd/system/ */
251 NULL)))
252 return -ENOMEM;
253 }
254
e1414003 255 if (m->running_as == MANAGER_INIT) {
036643a2
LP
256 /* /etc/init.d/ compativility does not matter to users */
257
258 if ((e = getenv("SYSTEMD_SYSVINIT_PATH")))
259 if (!(m->sysvinit_path = split_path_and_make_absolute(e)))
260 return -ENOMEM;
261
262 if (strv_isempty(m->sysvinit_path)) {
263 strv_free(m->sysvinit_path);
264
265 if (!(m->sysvinit_path = strv_new(
266 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
267 NULL)))
268 return -ENOMEM;
269 }
0571e011
LP
270
271 if ((e = getenv("SYSTEMD_SYSVRCND_PATH")))
272 if (!(m->sysvrcnd_path = split_path_and_make_absolute(e)))
273 return -ENOMEM;
274
275 if (strv_isempty(m->sysvrcnd_path)) {
276 strv_free(m->sysvrcnd_path);
277
278 if (!(m->sysvrcnd_path = strv_new(
279 SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
280 NULL)))
281 return -ENOMEM;
282 }
036643a2
LP
283 }
284
285 strv_uniq(m->unit_path);
286 strv_uniq(m->sysvinit_path);
0571e011 287 strv_uniq(m->sysvrcnd_path);
036643a2
LP
288
289 assert(!strv_isempty(m->unit_path));
290 if (!(t = strv_join(m->unit_path, "\n\t")))
291 return -ENOMEM;
292 log_debug("Looking for unit files in:\n\t%s", t);
293 free(t);
294
295 if (!strv_isempty(m->sysvinit_path)) {
296
297 if (!(t = strv_join(m->sysvinit_path, "\n\t")))
298 return -ENOMEM;
299
300 log_debug("Looking for SysV init scripts in:\n\t%s", t);
301 free(t);
302 } else
303 log_debug("Ignoring SysV init scripts.");
304
0571e011
LP
305 if (!strv_isempty(m->sysvrcnd_path)) {
306
307 if (!(t = strv_join(m->sysvrcnd_path, "\n\t")))
308 return -ENOMEM;
309
310 log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
311 free(t);
312 } else
313 log_debug("Ignoring SysV rcN.d links.");
314
036643a2
LP
315 return 0;
316}
317
80876c20 318int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) {
ce578209 319 Manager *m;
8e274523
LP
320 int r = -ENOMEM;
321
322 assert(_m);
a5dab5ce
LP
323 assert(running_as >= 0);
324 assert(running_as < _MANAGER_RUNNING_AS_MAX);
ce578209 325
60918275 326 if (!(m = new0(Manager, 1)))
8e274523 327 return -ENOMEM;
60918275 328
e537352b
LP
329 m->boot_timestamp = now(CLOCK_REALTIME);
330
a5dab5ce 331 m->running_as = running_as;
80876c20 332 m->confirm_spawn = confirm_spawn;
05e343b7 333 m->name_data_slot = -1;
a16e1123 334 m->exit_code = _MANAGER_EXIT_CODE_INVALID;
80876c20 335
8d567588 336 m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1;
ea430986 337 m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
9152c765 338
87f0e418 339 if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
60918275
LP
340 goto fail;
341
342 if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
343 goto fail;
344
e5b5ae50 345 if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
60918275
LP
346 goto fail;
347
9152c765
LP
348 if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
349 goto fail;
350
8e274523
LP
351 if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
352 goto fail;
353
05e343b7
LP
354 if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
355 goto fail;
356
9152c765
LP
357 if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
358 goto fail;
359
8e274523 360 if ((r = manager_find_paths(m)) < 0)
e1414003
LP
361 goto fail;
362
8e274523
LP
363 if ((r = manager_setup_signals(m)) < 0)
364 goto fail;
365
8e274523 366 if ((r = manager_setup_cgroup(m)) < 0)
9152c765
LP
367 goto fail;
368
f278026d
LP
369 /* Try to connect to the busses, if possible. */
370 if ((r = bus_init_system(m)) < 0 ||
371 (r = bus_init_api(m)) < 0)
ea430986
LP
372 goto fail;
373
8e274523
LP
374 *_m = m;
375 return 0;
60918275
LP
376
377fail:
378 manager_free(m);
8e274523 379 return r;
60918275
LP
380}
381
23a177ef
LP
382static unsigned manager_dispatch_cleanup_queue(Manager *m) {
383 Meta *meta;
384 unsigned n = 0;
385
386 assert(m);
387
388 while ((meta = m->cleanup_queue)) {
389 assert(meta->in_cleanup_queue);
390
391 unit_free(UNIT(meta));
392 n++;
393 }
394
395 return n;
396}
397
701cc384
LP
398static void unit_gc_sweep(Unit *u, int gc_marker) {
399 Iterator i;
400 Unit *other;
401
402 assert(u);
403
404 if (u->meta.gc_marker == gc_marker ||
405 u->meta.gc_marker == -gc_marker)
406 return;
407
c9c0cadb 408 if (u->meta.in_cleanup_queue)
701cc384
LP
409 goto bad;
410
411 if (unit_check_gc(u))
412 goto good;
413
414 SET_FOREACH(other, u->meta.dependencies[UNIT_REFERENCED_BY], i) {
415 unit_gc_sweep(other, gc_marker);
416
417 if (other->meta.gc_marker == gc_marker)
418 goto good;
419 }
420
421bad:
422 /* So there is no reason to keep this unit around, hence let's get rid of it */
423 u->meta.gc_marker = -gc_marker;
424 return;
425
426good:
427 u->meta.gc_marker = gc_marker;
428}
429
430static unsigned manager_dispatch_gc_queue(Manager *m) {
431 Meta *meta;
432 unsigned n = 0;
433 int gc_marker;
434
435 assert(m);
436
437 if ((m->n_in_gc_queue < GC_QUEUE_ENTRIES_MAX) &&
438 (m->gc_queue_timestamp <= 0 ||
439 (m->gc_queue_timestamp + GC_QUEUE_USEC_MAX) > now(CLOCK_MONOTONIC)))
440 return 0;
441
442 log_debug("Running GC...");
443
c9c0cadb
LP
444 gc_marker = ++m->gc_marker;
445
446 if (m->gc_marker < 0)
447 m->gc_marker = 1;
701cc384
LP
448
449 while ((meta = m->gc_queue)) {
450 assert(meta->in_gc_queue);
451
452 LIST_REMOVE(Meta, gc_queue, m->gc_queue, meta);
453 meta->in_gc_queue = false;
454
455 n++;
456
457 unit_gc_sweep(UNIT(meta), gc_marker);
458
459 if (meta->gc_marker == -gc_marker) {
460 log_debug("Collecting %s", meta->id);
461 unit_add_to_cleanup_queue(UNIT(meta));
462 }
463 }
464
465 m->n_in_gc_queue = 0;
466 m->gc_queue_timestamp = 0;
467
468 return n;
469}
470
a16e1123 471static void manager_clear_jobs_and_units(Manager *m) {
e5b5ae50 472 Job *j;
a16e1123 473 Unit *u;
60918275
LP
474
475 assert(m);
476
87f0e418 477 while ((j = hashmap_first(m->transaction_jobs)))
e5b5ae50
LP
478 job_free(j);
479
87f0e418
LP
480 while ((u = hashmap_first(m->units)))
481 unit_free(u);
a16e1123
LP
482}
483
484void manager_free(Manager *m) {
485 UnitType c;
87f0e418 486
a16e1123
LP
487 assert(m);
488
489 manager_clear_jobs_and_units(m);
23a177ef 490
7824bbeb
LP
491 for (c = 0; c < _UNIT_TYPE_MAX; c++)
492 if (unit_vtable[c]->shutdown)
493 unit_vtable[c]->shutdown(m);
494
a16e1123
LP
495 /* If we reexecute ourselves, we keep the root cgroup
496 * around */
497 manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
8e274523 498
f278026d
LP
499 bus_done_api(m);
500 bus_done_system(m);
ea430986 501
87f0e418 502 hashmap_free(m->units);
60918275 503 hashmap_free(m->jobs);
e5b5ae50 504 hashmap_free(m->transaction_jobs);
9152c765 505 hashmap_free(m->watch_pids);
05e343b7 506 hashmap_free(m->watch_bus);
9152c765
LP
507
508 if (m->epoll_fd >= 0)
a16e1123 509 close_nointr_nofail(m->epoll_fd);
acbb0225 510 if (m->signal_watch.fd >= 0)
a16e1123 511 close_nointr_nofail(m->signal_watch.fd);
60918275 512
036643a2
LP
513 strv_free(m->unit_path);
514 strv_free(m->sysvinit_path);
0571e011 515 strv_free(m->sysvrcnd_path);
036643a2 516
8e274523
LP
517 free(m->cgroup_controller);
518 free(m->cgroup_hierarchy);
519
8e274523
LP
520 hashmap_free(m->cgroup_bondings);
521
60918275
LP
522 free(m);
523}
524
a16e1123
LP
525int manager_enumerate(Manager *m) {
526 int r = 0, q;
f50e0a01 527 UnitType c;
f50e0a01
LP
528
529 assert(m);
530
a16e1123
LP
531 /* Let's ask every type to load all units from disk/kernel
532 * that it might know */
f50e0a01
LP
533 for (c = 0; c < _UNIT_TYPE_MAX; c++)
534 if (unit_vtable[c]->enumerate)
a16e1123
LP
535 if ((q = unit_vtable[c]->enumerate(m)) < 0)
536 r = q;
f50e0a01
LP
537
538 manager_dispatch_load_queue(m);
a16e1123
LP
539 return r;
540}
541
542int manager_coldplug(Manager *m) {
543 int r = 0, q;
544 Iterator i;
545 Unit *u;
546 char *k;
547
548 assert(m);
f50e0a01
LP
549
550 /* Then, let's set up their initial state. */
551 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
552
553 /* ignore aliases */
9e2f7c11 554 if (u->meta.id != k)
f50e0a01
LP
555 continue;
556
557 if (UNIT_VTABLE(u)->coldplug)
a16e1123
LP
558 if ((q = UNIT_VTABLE(u)->coldplug(u)) < 0)
559 r = q;
f50e0a01
LP
560 }
561
a16e1123
LP
562 return r;
563}
564
565int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
566 int r, q;
567
568 assert(m);
569
570 /* First, enumerate what we can from all config files */
571 r = manager_enumerate(m);
572
573 /* Second, deserialize if there is something to deserialize */
574 if (serialization)
575 if ((q = manager_deserialize(m, serialization, fds)) < 0)
576 r = q;
577
578 /* Third, fire things up! */
579 if ((q = manager_coldplug(m)) < 0)
580 r = q;
581
e537352b
LP
582 /* Now that the initial devices are available, let's see if we
583 * can write the utmp file */
584 manager_write_utmp_reboot(m);
585
a16e1123 586 return r;
f50e0a01
LP
587}
588
23a177ef 589static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) {
302d0040
LP
590 assert(m);
591 assert(j);
592
1ffba6fe
LP
593 /* Deletes one job from the transaction */
594
23a177ef 595 manager_transaction_unlink_job(m, j, delete_dependencies);
302d0040 596
ac1135be 597 if (!j->installed)
302d0040
LP
598 job_free(j);
599}
600
87f0e418 601static void transaction_delete_unit(Manager *m, Unit *u) {
1ffba6fe
LP
602 Job *j;
603
87f0e418 604 /* Deletes all jobs associated with a certain unit from the
1ffba6fe
LP
605 * transaction */
606
87f0e418 607 while ((j = hashmap_get(m->transaction_jobs, u)))
23a177ef 608 transaction_delete_job(m, j, true);
1ffba6fe
LP
609}
610
f04fa1d5
LP
611static void transaction_clean_dependencies(Manager *m) {
612 Iterator i;
613 Job *j;
614
615 assert(m);
616
617 /* Drops all dependencies of all installed jobs */
618
619 HASHMAP_FOREACH(j, m->jobs, i) {
620 while (j->subject_list)
621 job_dependency_free(j->subject_list);
622 while (j->object_list)
623 job_dependency_free(j->object_list);
624 }
625
626 assert(!m->transaction_anchor);
627}
628
11dd41ce
LP
629static void transaction_abort(Manager *m) {
630 Job *j;
631
632 assert(m);
11dd41ce 633
e5b5ae50 634 while ((j = hashmap_first(m->transaction_jobs)))
ac1135be 635 if (j->installed)
23a177ef 636 transaction_delete_job(m, j, true);
e5b5ae50
LP
637 else
638 job_free(j);
639
640 assert(hashmap_isempty(m->transaction_jobs));
f04fa1d5
LP
641
642 transaction_clean_dependencies(m);
e5b5ae50
LP
643}
644
645static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsigned generation) {
646 JobDependency *l;
647
648 assert(m);
649
87f0e418 650 /* A recursive sweep through the graph that marks all units
1ffba6fe
LP
651 * that matter to the anchor job, i.e. are directly or
652 * indirectly a dependency of the anchor job via paths that
653 * are fully marked as mattering. */
654
44d8db9e
LP
655 if (j)
656 l = j->subject_list;
657 else
658 l = m->transaction_anchor;
659
660 LIST_FOREACH(subject, l, l) {
e5b5ae50
LP
661
662 /* This link does not matter */
663 if (!l->matters)
664 continue;
665
87f0e418 666 /* This unit has already been marked */
e5b5ae50
LP
667 if (l->object->generation == generation)
668 continue;
669
670 l->object->matters_to_anchor = true;
671 l->object->generation = generation;
672
673 transaction_find_jobs_that_matter_to_anchor(m, l->object, generation);
674 }
675}
676
7fad411c 677static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, JobType t) {
e5b5ae50
LP
678 JobDependency *l, *last;
679
680 assert(j);
681 assert(other);
87f0e418 682 assert(j->unit == other->unit);
ac1135be 683 assert(!j->installed);
e5b5ae50 684
1ffba6fe
LP
685 /* Merges 'other' into 'j' and then deletes j. */
686
e5b5ae50
LP
687 j->type = t;
688 j->state = JOB_WAITING;
9e2f7c11 689 j->override = j->override || other->override;
e5b5ae50
LP
690
691 j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
692
693 /* Patch us in as new owner of the JobDependency objects */
694 last = NULL;
44d8db9e 695 LIST_FOREACH(subject, l, other->subject_list) {
e5b5ae50
LP
696 assert(l->subject == other);
697 l->subject = j;
698 last = l;
699 }
700
701 /* Merge both lists */
702 if (last) {
703 last->subject_next = j->subject_list;
704 if (j->subject_list)
705 j->subject_list->subject_prev = last;
706 j->subject_list = other->subject_list;
707 }
708
709 /* Patch us in as new owner of the JobDependency objects */
710 last = NULL;
44d8db9e 711 LIST_FOREACH(object, l, other->object_list) {
e5b5ae50
LP
712 assert(l->object == other);
713 l->object = j;
714 last = l;
715 }
716
717 /* Merge both lists */
718 if (last) {
719 last->object_next = j->object_list;
720 if (j->object_list)
721 j->object_list->object_prev = last;
722 j->object_list = other->object_list;
723 }
724
e5b5ae50
LP
725 /* Kill the other job */
726 other->subject_list = NULL;
727 other->object_list = NULL;
23a177ef 728 transaction_delete_job(m, other, true);
e5b5ae50
LP
729}
730
5cb5a6ff 731static int delete_one_unmergeable_job(Manager *m, Job *j) {
1ffba6fe
LP
732 Job *k;
733
734 assert(j);
735
736 /* Tries to delete one item in the linked list
737 * j->transaction_next->transaction_next->... that conflicts
738 * whith another one, in an attempt to make an inconsistent
739 * transaction work. */
740
741 /* We rely here on the fact that if a merged with b does not
742 * merge with c, either a or b merge with c neither */
034c6ed7
LP
743 LIST_FOREACH(transaction, j, j)
744 LIST_FOREACH(transaction, k, j->transaction_next) {
1ffba6fe
LP
745 Job *d;
746
747 /* Is this one mergeable? Then skip it */
5cb5a6ff 748 if (job_type_is_mergeable(j->type, k->type))
1ffba6fe
LP
749 continue;
750
751 /* Ok, we found two that conflict, let's see if we can
752 * drop one of them */
753 if (!j->matters_to_anchor)
754 d = j;
755 else if (!k->matters_to_anchor)
756 d = k;
757 else
758 return -ENOEXEC;
759
760 /* Ok, we can drop one, so let's do so. */
9e2f7c11 761 log_debug("Trying to fix job merging by deleting job %s/%s", d->unit->meta.id, job_type_to_string(d->type));
23a177ef 762 transaction_delete_job(m, d, true);
1ffba6fe
LP
763 return 0;
764 }
765
766 return -EINVAL;
767}
768
e5b5ae50 769static int transaction_merge_jobs(Manager *m) {
11dd41ce 770 Job *j;
034c6ed7 771 Iterator i;
e5b5ae50
LP
772 int r;
773
774 assert(m);
775
1ffba6fe
LP
776 /* First step, check whether any of the jobs for one specific
777 * task conflict. If so, try to drop one of them. */
034c6ed7 778 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1ffba6fe
LP
779 JobType t;
780 Job *k;
781
782 t = j->type;
034c6ed7 783 LIST_FOREACH(transaction, k, j->transaction_next) {
1ffba6fe
LP
784 if ((r = job_type_merge(&t, k->type)) >= 0)
785 continue;
786
787 /* OK, we could not merge all jobs for this
788 * action. Let's see if we can get rid of one
789 * of them */
790
5cb5a6ff 791 if ((r = delete_one_unmergeable_job(m, j)) >= 0)
1ffba6fe
LP
792 /* Ok, we managed to drop one, now
793 * let's ask our callers to call us
794 * again after garbage collecting */
795 return -EAGAIN;
796
797 /* We couldn't merge anything. Failure */
798 return r;
799 }
800 }
801
802 /* Second step, merge the jobs. */
034c6ed7 803 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e5b5ae50
LP
804 JobType t = j->type;
805 Job *k;
806
e094e853 807 /* Merge all transactions */
034c6ed7 808 LIST_FOREACH(transaction, k, j->transaction_next)
1ffba6fe 809 assert_se(job_type_merge(&t, k->type) == 0);
e5b5ae50 810
5cb5a6ff 811 /* If an active job is mergeable, merge it too */
87f0e418
LP
812 if (j->unit->meta.job)
813 job_type_merge(&t, j->unit->meta.job->type); /* Might fail. Which is OK */
e094e853 814
e5b5ae50 815 while ((k = j->transaction_next)) {
ac1135be 816 if (j->installed) {
7fad411c 817 transaction_merge_and_delete_job(m, k, j, t);
e5b5ae50
LP
818 j = k;
819 } else
7fad411c 820 transaction_merge_and_delete_job(m, j, k, t);
e5b5ae50
LP
821 }
822
823 assert(!j->transaction_next);
824 assert(!j->transaction_prev);
825 }
826
7fad411c 827 return 0;
e5b5ae50
LP
828}
829
23a177ef
LP
830static void transaction_drop_redundant(Manager *m) {
831 bool again;
832
833 assert(m);
834
835 /* Goes through the transaction and removes all jobs that are
836 * a noop */
837
838 do {
839 Job *j;
840 Iterator i;
841
842 again = false;
843
844 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
845 bool changes_something = false;
846 Job *k;
847
848 LIST_FOREACH(transaction, k, j) {
849
850 if (!job_is_anchor(k) &&
851 job_type_is_redundant(k->type, unit_active_state(k->unit)))
852 continue;
853
854 changes_something = true;
855 break;
856 }
857
858 if (changes_something)
859 continue;
860
9e2f7c11 861 log_debug("Found redundant job %s/%s, dropping.", j->unit->meta.id, job_type_to_string(j->type));
23a177ef
LP
862 transaction_delete_job(m, j, false);
863 again = true;
864 break;
865 }
866
867 } while (again);
868}
869
87f0e418
LP
870static bool unit_matters_to_anchor(Unit *u, Job *j) {
871 assert(u);
1ffba6fe
LP
872 assert(!j->transaction_prev);
873
87f0e418 874 /* Checks whether at least one of the jobs for this unit
1ffba6fe
LP
875 * matters to the anchor. */
876
034c6ed7 877 LIST_FOREACH(transaction, j, j)
1ffba6fe
LP
878 if (j->matters_to_anchor)
879 return true;
880
881 return false;
882}
883
e5b5ae50 884static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned generation) {
034c6ed7 885 Iterator i;
87f0e418 886 Unit *u;
11dd41ce 887 int r;
e5b5ae50
LP
888
889 assert(m);
890 assert(j);
1ffba6fe
LP
891 assert(!j->transaction_prev);
892
893 /* Does a recursive sweep through the ordering graph, looking
894 * for a cycle. If we find cycle we try to break it. */
e5b5ae50 895
7fad411c 896 /* Did we find a cycle? */
e5b5ae50
LP
897 if (j->marker && j->generation == generation) {
898 Job *k;
899
900 /* So, we already have been here. We have a
1ffba6fe
LP
901 * cycle. Let's try to break it. We go backwards in
902 * our path and try to find a suitable job to
903 * remove. We use the marker to find our way back,
904 * since smart how we are we stored our way back in
905 * there. */
e5b5ae50 906
9e2f7c11 907 log_debug("Found ordering cycle on %s/%s", j->unit->meta.id, job_type_to_string(j->type));
9f04bd52 908
e5b5ae50 909 for (k = from; k; k = (k->generation == generation ? k->marker : NULL)) {
1ffba6fe 910
9e2f7c11 911 log_debug("Walked on cycle path to %s/%s", k->unit->meta.id, job_type_to_string(k->type));
9f04bd52 912
ac1135be 913 if (!k->installed &&
87f0e418 914 !unit_matters_to_anchor(k->unit, k)) {
1ffba6fe
LP
915 /* Ok, we can drop this one, so let's
916 * do so. */
9e2f7c11 917 log_debug("Breaking order cycle by deleting job %s/%s", k->unit->meta.id, job_type_to_string(k->type));
87f0e418 918 transaction_delete_unit(m, k->unit);
e5b5ae50
LP
919 return -EAGAIN;
920 }
921
922 /* Check if this in fact was the beginning of
7fad411c 923 * the cycle */
e5b5ae50
LP
924 if (k == j)
925 break;
926 }
927
9f04bd52
LP
928 log_debug("Unable to break cycle");
929
1ffba6fe 930 return -ENOEXEC;
e5b5ae50
LP
931 }
932
1ffba6fe
LP
933 /* Make the marker point to where we come from, so that we can
934 * find our way backwards if we want to break a cycle */
e5b5ae50
LP
935 j->marker = from;
936 j->generation = generation;
937
1ffba6fe 938 /* We assume that the the dependencies are bidirectional, and
87f0e418
LP
939 * hence can ignore UNIT_AFTER */
940 SET_FOREACH(u, j->unit->meta.dependencies[UNIT_BEFORE], i) {
e5b5ae50
LP
941 Job *o;
942
87f0e418
LP
943 /* Is there a job for this unit? */
944 if (!(o = hashmap_get(m->transaction_jobs, u)))
1ffba6fe
LP
945
946 /* Ok, there is no job for this in the
947 * transaction, but maybe there is already one
948 * running? */
87f0e418 949 if (!(o = u->meta.job))
e5b5ae50
LP
950 continue;
951
952 if ((r = transaction_verify_order_one(m, o, j, generation)) < 0)
953 return r;
954 }
955
9f04bd52
LP
956 /* Ok, let's backtrack, and remember that this entry is not on
957 * our path anymore. */
958 j->marker = NULL;
959
e5b5ae50
LP
960 return 0;
961}
962
963static int transaction_verify_order(Manager *m, unsigned *generation) {
1ffba6fe
LP
964 Job *j;
965 int r;
034c6ed7 966 Iterator i;
1ffba6fe 967
e5b5ae50
LP
968 assert(m);
969 assert(generation);
970
1ffba6fe
LP
971 /* Check if the ordering graph is cyclic. If it is, try to fix
972 * that up by dropping one of the jobs. */
e5b5ae50 973
034c6ed7 974 HASHMAP_FOREACH(j, m->transaction_jobs, i)
1ffba6fe
LP
975 if ((r = transaction_verify_order_one(m, j, NULL, (*generation)++)) < 0)
976 return r;
e5b5ae50
LP
977
978 return 0;
979}
980
981static void transaction_collect_garbage(Manager *m) {
982 bool again;
983
984 assert(m);
985
1ffba6fe
LP
986 /* Drop jobs that are not required by any other job */
987
e5b5ae50 988 do {
034c6ed7 989 Iterator i;
e5b5ae50
LP
990 Job *j;
991
992 again = false;
993
034c6ed7 994 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e5b5ae50
LP
995 if (j->object_list)
996 continue;
997
9e2f7c11 998 log_debug("Garbage collecting job %s/%s", j->unit->meta.id, job_type_to_string(j->type));
23a177ef 999 transaction_delete_job(m, j, true);
e5b5ae50
LP
1000 again = true;
1001 break;
1002 }
1003
1004 } while (again);
1005}
1006
1007static int transaction_is_destructive(Manager *m, JobMode mode) {
034c6ed7 1008 Iterator i;
e5b5ae50 1009 Job *j;
11dd41ce
LP
1010
1011 assert(m);
11dd41ce 1012
e5b5ae50
LP
1013 /* Checks whether applying this transaction means that
1014 * existing jobs would be replaced */
11dd41ce 1015
034c6ed7 1016 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e094e853
LP
1017
1018 /* Assume merged */
1019 assert(!j->transaction_prev);
1020 assert(!j->transaction_next);
1021
87f0e418
LP
1022 if (j->unit->meta.job &&
1023 j->unit->meta.job != j &&
1024 !job_type_is_superset(j->type, j->unit->meta.job->type))
e5b5ae50 1025 return -EEXIST;
e094e853 1026 }
11dd41ce 1027
e5b5ae50
LP
1028 return 0;
1029}
1030
e094e853
LP
1031static void transaction_minimize_impact(Manager *m) {
1032 bool again;
1033 assert(m);
1034
1035 /* Drops all unnecessary jobs that reverse already active jobs
1036 * or that stop a running service. */
1037
1038 do {
1039 Job *j;
034c6ed7 1040 Iterator i;
e094e853
LP
1041
1042 again = false;
1043
034c6ed7
LP
1044 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1045 LIST_FOREACH(transaction, j, j) {
c20cae32 1046 bool stops_running_service, changes_existing_job;
e094e853
LP
1047
1048 /* If it matters, we shouldn't drop it */
1049 if (j->matters_to_anchor)
1050 continue;
1051
1052 /* Would this stop a running service?
1053 * Would this change an existing job?
1054 * If so, let's drop this entry */
c20cae32
LP
1055
1056 stops_running_service =
1057 j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
1058
1059 changes_existing_job =
1060 j->unit->meta.job && job_type_is_conflicting(j->type, j->unit->meta.job->state);
1061
1062 if (!stops_running_service && !changes_existing_job)
e094e853
LP
1063 continue;
1064
c20cae32 1065 if (stops_running_service)
9e2f7c11 1066 log_debug("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type));
c20cae32
LP
1067
1068 if (changes_existing_job)
9e2f7c11 1069 log_debug("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type));
c20cae32 1070
e094e853 1071 /* Ok, let's get rid of this */
9e2f7c11 1072 log_debug("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type));
c20cae32 1073
23a177ef 1074 transaction_delete_job(m, j, true);
e094e853
LP
1075 again = true;
1076 break;
1077 }
1078
1079 if (again)
1080 break;
1081 }
1082
1083 } while (again);
1084}
1085
e5b5ae50 1086static int transaction_apply(Manager *m, JobMode mode) {
034c6ed7 1087 Iterator i;
e5b5ae50
LP
1088 Job *j;
1089 int r;
1090
1ffba6fe
LP
1091 /* Moves the transaction jobs to the set of active jobs */
1092
034c6ed7 1093 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e094e853
LP
1094 /* Assume merged */
1095 assert(!j->transaction_prev);
1096 assert(!j->transaction_next);
1097
ac1135be 1098 if (j->installed)
e5b5ae50
LP
1099 continue;
1100
1101 if ((r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j)) < 0)
11dd41ce
LP
1102 goto rollback;
1103 }
1104
e5b5ae50 1105 while ((j = hashmap_steal_first(m->transaction_jobs))) {
ac1135be 1106 if (j->installed)
e5b5ae50
LP
1107 continue;
1108
87f0e418
LP
1109 if (j->unit->meta.job)
1110 job_free(j->unit->meta.job);
11dd41ce 1111
87f0e418 1112 j->unit->meta.job = j;
ac1135be 1113 j->installed = true;
11dd41ce 1114
e5b5ae50
LP
1115 /* We're fully installed. Now let's free data we don't
1116 * need anymore. */
1117
1118 assert(!j->transaction_next);
1119 assert(!j->transaction_prev);
1120
c1e1601e
LP
1121 job_add_to_run_queue(j);
1122 job_add_to_dbus_queue(j);
01184e04
LP
1123 }
1124
1125 /* As last step, kill all remaining job dependencies. */
f04fa1d5 1126 transaction_clean_dependencies(m);
1ffba6fe 1127
11dd41ce
LP
1128 return 0;
1129
1130rollback:
1131
034c6ed7 1132 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
ac1135be 1133 if (j->installed)
e5b5ae50
LP
1134 continue;
1135
1136 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
1137 }
1138
1139 return r;
1140}
1141
e5b5ae50
LP
1142static int transaction_activate(Manager *m, JobMode mode) {
1143 int r;
1144 unsigned generation = 1;
1145
1146 assert(m);
1147
1148 /* This applies the changes recorded in transaction_jobs to
1149 * the actual list of jobs, if possible. */
1150
1151 /* First step: figure out which jobs matter */
1152 transaction_find_jobs_that_matter_to_anchor(m, NULL, generation++);
1153
e094e853
LP
1154 /* Second step: Try not to stop any running services if
1155 * we don't have to. Don't try to reverse running
1156 * jobs if we don't have to. */
1157 transaction_minimize_impact(m);
1158
23a177ef
LP
1159 /* Third step: Drop redundant jobs */
1160 transaction_drop_redundant(m);
1161
1ffba6fe 1162 for (;;) {
23a177ef 1163 /* Fourth step: Let's remove unneeded jobs that might
1ffba6fe
LP
1164 * be lurking. */
1165 transaction_collect_garbage(m);
e5b5ae50 1166
23a177ef 1167 /* Fifth step: verify order makes sense and correct
1ffba6fe
LP
1168 * cycles if necessary and possible */
1169 if ((r = transaction_verify_order(m, &generation)) >= 0)
1170 break;
e5b5ae50 1171
9f04bd52
LP
1172 if (r != -EAGAIN) {
1173 log_debug("Requested transaction contains an unfixable cyclic ordering dependency: %s", strerror(-r));
1ffba6fe 1174 goto rollback;
9f04bd52 1175 }
e5b5ae50 1176
1ffba6fe
LP
1177 /* Let's see if the resulting transaction ordering
1178 * graph is still cyclic... */
1179 }
1180
1181 for (;;) {
23a177ef 1182 /* Sixth step: let's drop unmergeable entries if
1ffba6fe
LP
1183 * necessary and possible, merge entries we can
1184 * merge */
1185 if ((r = transaction_merge_jobs(m)) >= 0)
1186 break;
1187
9f04bd52
LP
1188 if (r != -EAGAIN) {
1189 log_debug("Requested transaction contains unmergable jobs: %s", strerror(-r));
1ffba6fe 1190 goto rollback;
9f04bd52 1191 }
1ffba6fe 1192
23a177ef 1193 /* Seventh step: an entry got dropped, let's garbage
1ffba6fe
LP
1194 * collect its dependencies. */
1195 transaction_collect_garbage(m);
1196
1197 /* Let's see if the resulting transaction still has
5cb5a6ff 1198 * unmergeable entries ... */
1ffba6fe
LP
1199 }
1200
23a177ef
LP
1201 /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
1202 transaction_drop_redundant(m);
1203
1204 /* Ninth step: check whether we can actually apply this */
e5b5ae50 1205 if (mode == JOB_FAIL)
9f04bd52
LP
1206 if ((r = transaction_is_destructive(m, mode)) < 0) {
1207 log_debug("Requested transaction contradicts existing jobs: %s", strerror(-r));
e5b5ae50 1208 goto rollback;
9f04bd52 1209 }
e5b5ae50 1210
23a177ef 1211 /* Tenth step: apply changes */
9f04bd52
LP
1212 if ((r = transaction_apply(m, mode)) < 0) {
1213 log_debug("Failed to apply transaction: %s", strerror(-r));
e5b5ae50 1214 goto rollback;
9f04bd52 1215 }
e5b5ae50
LP
1216
1217 assert(hashmap_isempty(m->transaction_jobs));
1218 assert(!m->transaction_anchor);
1219
1220 return 0;
11dd41ce 1221
e5b5ae50 1222rollback:
11dd41ce
LP
1223 transaction_abort(m);
1224 return r;
1225}
1226
9e2f7c11 1227static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool override, bool *is_new) {
e5b5ae50 1228 Job *j, *f;
60918275
LP
1229 int r;
1230
1231 assert(m);
87f0e418 1232 assert(unit);
60918275 1233
e5b5ae50
LP
1234 /* Looks for an axisting prospective job and returns that. If
1235 * it doesn't exist it is created and added to the prospective
1236 * jobs list. */
60918275 1237
87f0e418 1238 f = hashmap_get(m->transaction_jobs, unit);
60918275 1239
034c6ed7 1240 LIST_FOREACH(transaction, j, f) {
87f0e418 1241 assert(j->unit == unit);
60918275 1242
e5b5ae50
LP
1243 if (j->type == type) {
1244 if (is_new)
1245 *is_new = false;
1246 return j;
1247 }
1248 }
60918275 1249
87f0e418
LP
1250 if (unit->meta.job && unit->meta.job->type == type)
1251 j = unit->meta.job;
1252 else if (!(j = job_new(m, type, unit)))
e5b5ae50 1253 return NULL;
60918275 1254
e5b5ae50
LP
1255 j->generation = 0;
1256 j->marker = NULL;
1257 j->matters_to_anchor = false;
9e2f7c11 1258 j->override = override;
60918275 1259
034c6ed7
LP
1260 LIST_PREPEND(Job, transaction, f, j);
1261
87f0e418 1262 if ((r = hashmap_replace(m->transaction_jobs, unit, f)) < 0) {
034c6ed7
LP
1263 job_free(j);
1264 return NULL;
1265 }
1266
e5b5ae50
LP
1267 if (is_new)
1268 *is_new = true;
60918275 1269
9e2f7c11 1270 log_debug("Added job %s/%s to transaction.", unit->meta.id, job_type_to_string(type));
23a177ef 1271
e5b5ae50
LP
1272 return j;
1273}
11dd41ce 1274
23a177ef 1275void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies) {
e5b5ae50
LP
1276 assert(m);
1277 assert(j);
11dd41ce 1278
e5b5ae50
LP
1279 if (j->transaction_prev)
1280 j->transaction_prev->transaction_next = j->transaction_next;
1281 else if (j->transaction_next)
87f0e418 1282 hashmap_replace(m->transaction_jobs, j->unit, j->transaction_next);
e5b5ae50 1283 else
87f0e418 1284 hashmap_remove_value(m->transaction_jobs, j->unit, j);
e5b5ae50
LP
1285
1286 if (j->transaction_next)
1287 j->transaction_next->transaction_prev = j->transaction_prev;
1288
1289 j->transaction_prev = j->transaction_next = NULL;
1290
1291 while (j->subject_list)
1292 job_dependency_free(j->subject_list);
1e198baf
LP
1293
1294 while (j->object_list) {
1295 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
1296
e5b5ae50 1297 job_dependency_free(j->object_list);
1e198baf 1298
23a177ef 1299 if (other && delete_dependencies) {
5cb5a6ff 1300 log_debug("Deleting job %s/%s as dependency of job %s/%s",
9e2f7c11
LP
1301 other->unit->meta.id, job_type_to_string(other->type),
1302 j->unit->meta.id, job_type_to_string(j->type));
23a177ef 1303 transaction_delete_job(m, other, delete_dependencies);
1e198baf
LP
1304 }
1305 }
e5b5ae50
LP
1306}
1307
9e2f7c11
LP
1308static int transaction_add_job_and_dependencies(
1309 Manager *m,
1310 JobType type,
1311 Unit *unit,
1312 Job *by,
1313 bool matters,
1314 bool override,
1315 Job **_ret) {
e5b5ae50 1316 Job *ret;
034c6ed7 1317 Iterator i;
87f0e418 1318 Unit *dep;
e5b5ae50
LP
1319 int r;
1320 bool is_new;
1321
1322 assert(m);
1323 assert(type < _JOB_TYPE_MAX);
87f0e418 1324 assert(unit);
e5b5ae50 1325
87f0e418 1326 if (unit->meta.load_state != UNIT_LOADED)
21b293e8
LP
1327 return -EINVAL;
1328
87f0e418 1329 if (!unit_job_is_applicable(unit, type))
cd2dbd7d
LP
1330 return -EBADR;
1331
e5b5ae50 1332 /* First add the job. */
9e2f7c11 1333 if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new)))
e5b5ae50
LP
1334 return -ENOMEM;
1335
1336 /* Then, add a link to the job. */
1337 if (!job_dependency_new(by, ret, matters))
1338 return -ENOMEM;
1339
1340 if (is_new) {
1341 /* Finally, recursively add in all dependencies. */
1342 if (type == JOB_START || type == JOB_RELOAD_OR_START) {
87f0e418 1343 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i)
9e2f7c11 1344 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
e5b5ae50 1345 goto fail;
9e2f7c11
LP
1346
1347 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
1348 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, NULL)) < 0 && r != -EBADR)
1349 log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
1350
87f0e418 1351 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i)
9e2f7c11
LP
1352 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, NULL)) < 0)
1353 log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
1354
87f0e418 1355 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i)
9e2f7c11 1356 if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
e5b5ae50 1357 goto fail;
9e2f7c11
LP
1358
1359 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
1360 if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, NULL)) < 0 && r != -EBADR)
1361 log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
1362
87f0e418 1363 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i)
9e2f7c11 1364 if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
e5b5ae50
LP
1365 goto fail;
1366
1367 } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
1368
87f0e418 1369 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i)
9e2f7c11 1370 if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
e5b5ae50
LP
1371 goto fail;
1372 }
1373
1374 /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */
1375 }
60918275 1376
c0dafa48
LP
1377 if (_ret)
1378 *_ret = ret;
1379
60918275
LP
1380 return 0;
1381
1382fail:
e5b5ae50
LP
1383 return r;
1384}
1385
9e2f7c11 1386int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, Job **_ret) {
e5b5ae50
LP
1387 int r;
1388 Job *ret;
1389
1390 assert(m);
1391 assert(type < _JOB_TYPE_MAX);
87f0e418 1392 assert(unit);
e5b5ae50 1393 assert(mode < _JOB_MODE_MAX);
60918275 1394
9e2f7c11 1395 log_debug("Trying to enqueue job %s/%s", unit->meta.id, job_type_to_string(type));
9f04bd52 1396
9e2f7c11 1397 if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, &ret)) < 0) {
11dd41ce 1398 transaction_abort(m);
e5b5ae50
LP
1399 return r;
1400 }
11dd41ce 1401
e5b5ae50
LP
1402 if ((r = transaction_activate(m, mode)) < 0)
1403 return r;
1404
9e2f7c11 1405 log_debug("Enqueued job %s/%s as %u", unit->meta.id, job_type_to_string(type), (unsigned) ret->id);
f50e0a01 1406
e5b5ae50
LP
1407 if (_ret)
1408 *_ret = ret;
60918275 1409
e5b5ae50
LP
1410 return 0;
1411}
60918275 1412
9e2f7c11 1413int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, Job **_ret) {
28247076
LP
1414 Unit *unit;
1415 int r;
1416
1417 assert(m);
1418 assert(type < _JOB_TYPE_MAX);
1419 assert(name);
1420 assert(mode < _JOB_MODE_MAX);
1421
9e2f7c11 1422 if ((r = manager_load_unit(m, name, NULL, &unit)) < 0)
28247076
LP
1423 return r;
1424
9e2f7c11 1425 return manager_add_job(m, type, unit, mode, override, _ret);
28247076
LP
1426}
1427
60918275
LP
1428Job *manager_get_job(Manager *m, uint32_t id) {
1429 assert(m);
1430
1431 return hashmap_get(m->jobs, UINT32_TO_PTR(id));
1432}
1433
87f0e418 1434Unit *manager_get_unit(Manager *m, const char *name) {
60918275
LP
1435 assert(m);
1436 assert(name);
1437
87f0e418 1438 return hashmap_get(m->units, name);
60918275
LP
1439}
1440
c1e1601e 1441unsigned manager_dispatch_load_queue(Manager *m) {
60918275 1442 Meta *meta;
c1e1601e 1443 unsigned n = 0;
60918275
LP
1444
1445 assert(m);
1446
223dabab
LP
1447 /* Make sure we are not run recursively */
1448 if (m->dispatching_load_queue)
c1e1601e 1449 return 0;
223dabab
LP
1450
1451 m->dispatching_load_queue = true;
1452
87f0e418 1453 /* Dispatches the load queue. Takes a unit from the queue and
60918275
LP
1454 * tries to load its data until the queue is empty */
1455
1456 while ((meta = m->load_queue)) {
034c6ed7
LP
1457 assert(meta->in_load_queue);
1458
87f0e418 1459 unit_load(UNIT(meta));
c1e1601e 1460 n++;
60918275
LP
1461 }
1462
223dabab 1463 m->dispatching_load_queue = false;
c1e1601e 1464 return n;
60918275
LP
1465}
1466
9e2f7c11 1467int manager_load_unit(Manager *m, const char *name, const char *path, Unit **_ret) {
87f0e418 1468 Unit *ret;
60918275
LP
1469 int r;
1470
1471 assert(m);
9e2f7c11 1472 assert(name || path);
60918275 1473
223dabab 1474 /* This will load the service information files, but not actually
0301abf4
LP
1475 * start any services or anything. */
1476
9e2f7c11
LP
1477 if (path && !is_path(path))
1478 return -EINVAL;
1479
1480 if (!name)
1481 name = file_name_from_path(path);
1482
1483 if (!unit_name_is_valid(name))
1484 return -EINVAL;
60918275 1485
87f0e418 1486 if ((ret = manager_get_unit(m, name))) {
034c6ed7
LP
1487 *_ret = ret;
1488 return 0;
1489 }
60918275 1490
87f0e418 1491 if (!(ret = unit_new(m)))
60918275
LP
1492 return -ENOMEM;
1493
9e2f7c11 1494 if (path)
6be1e7d5 1495 if (!(ret->meta.fragment_path = strdup(path))) {
0301abf4
LP
1496 unit_free(ret);
1497 return -ENOMEM;
1498 }
0301abf4 1499
87f0e418
LP
1500 if ((r = unit_add_name(ret, name)) < 0) {
1501 unit_free(ret);
1ffba6fe 1502 return r;
60918275
LP
1503 }
1504
87f0e418 1505 unit_add_to_load_queue(ret);
c1e1601e
LP
1506 unit_add_to_dbus_queue(ret);
1507
f50e0a01 1508 manager_dispatch_load_queue(m);
60918275 1509
9e2f7c11
LP
1510 if (_ret)
1511 *_ret = unit_follow_merge(ret);
1512
60918275
LP
1513 return 0;
1514}
a66d02c3 1515
cea8e32e 1516void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
034c6ed7 1517 Iterator i;
a66d02c3
LP
1518 Job *j;
1519
1520 assert(s);
1521 assert(f);
1522
034c6ed7 1523 HASHMAP_FOREACH(j, s->jobs, i)
cea8e32e 1524 job_dump(j, f, prefix);
a66d02c3
LP
1525}
1526
87f0e418 1527void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
034c6ed7 1528 Iterator i;
87f0e418 1529 Unit *u;
11dd41ce 1530 const char *t;
a66d02c3
LP
1531
1532 assert(s);
1533 assert(f);
1534
87f0e418 1535 HASHMAP_FOREACH_KEY(u, t, s->units, i)
9e2f7c11 1536 if (u->meta.id == t)
87f0e418 1537 unit_dump(u, f, prefix);
a66d02c3 1538}
7fad411c
LP
1539
1540void manager_clear_jobs(Manager *m) {
1541 Job *j;
1542
1543 assert(m);
1544
1545 transaction_abort(m);
1546
1547 while ((j = hashmap_first(m->jobs)))
1548 job_free(j);
1549}
83c60c9f 1550
c1e1601e 1551unsigned manager_dispatch_run_queue(Manager *m) {
83c60c9f 1552 Job *j;
c1e1601e 1553 unsigned n = 0;
83c60c9f 1554
034c6ed7 1555 if (m->dispatching_run_queue)
c1e1601e 1556 return 0;
034c6ed7
LP
1557
1558 m->dispatching_run_queue = true;
9152c765 1559
034c6ed7 1560 while ((j = m->run_queue)) {
ac1135be 1561 assert(j->installed);
034c6ed7
LP
1562 assert(j->in_run_queue);
1563
1564 job_run_and_invalidate(j);
c1e1601e 1565 n++;
9152c765 1566 }
034c6ed7
LP
1567
1568 m->dispatching_run_queue = false;
c1e1601e
LP
1569 return n;
1570}
1571
1572unsigned manager_dispatch_dbus_queue(Manager *m) {
1573 Job *j;
1574 Meta *meta;
1575 unsigned n = 0;
1576
1577 assert(m);
1578
1579 if (m->dispatching_dbus_queue)
1580 return 0;
1581
1582 m->dispatching_dbus_queue = true;
1583
1584 while ((meta = m->dbus_unit_queue)) {
23a177ef 1585 assert(meta->in_dbus_queue);
c1e1601e 1586
23a177ef 1587 bus_unit_send_change_signal(UNIT(meta));
c1e1601e
LP
1588 n++;
1589 }
1590
1591 while ((j = m->dbus_job_queue)) {
1592 assert(j->in_dbus_queue);
1593
1594 bus_job_send_change_signal(j);
1595 n++;
1596 }
1597
1598 m->dispatching_dbus_queue = false;
1599 return n;
9152c765
LP
1600}
1601
034c6ed7 1602static int manager_dispatch_sigchld(Manager *m) {
9152c765
LP
1603 assert(m);
1604
1605 for (;;) {
1606 siginfo_t si;
87f0e418 1607 Unit *u;
9152c765
LP
1608
1609 zero(si);
4112df16
LP
1610
1611 /* First we call waitd() for a PID and do not reap the
1612 * zombie. That way we can still access /proc/$PID for
1613 * it while it is a zombie. */
1614 if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) {
acbb0225
LP
1615
1616 if (errno == ECHILD)
1617 break;
1618
4112df16
LP
1619 if (errno == EINTR)
1620 continue;
1621
9152c765 1622 return -errno;
acbb0225 1623 }
9152c765 1624
4112df16 1625 if (si.si_pid <= 0)
9152c765
LP
1626 break;
1627
15d5d9d9 1628 if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) {
4112df16
LP
1629 char *name = NULL;
1630
1631 get_process_name(si.si_pid, &name);
1632 log_debug("Got SIGCHLD for process %llu (%s)", (unsigned long long) si.si_pid, strna(name));
1633 free(name);
1634 }
1635
1636 /* And now, we actually reap the zombie. */
1637 if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
1638 if (errno == EINTR)
1639 continue;
1640
1641 return -errno;
1642 }
1643
034c6ed7
LP
1644 if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED)
1645 continue;
1646
4112df16
LP
1647 log_debug("Child %llu died (code=%s, status=%i/%s)",
1648 (long long unsigned) si.si_pid,
1649 sigchld_code_to_string(si.si_code),
1650 si.si_status,
1651 strna(si.si_code == CLD_EXITED ? exit_status_to_string(si.si_status) : strsignal(si.si_status)));
acbb0225 1652
87f0e418 1653 if (!(u = hashmap_remove(m->watch_pids, UINT32_TO_PTR(si.si_pid))))
9152c765
LP
1654 continue;
1655
9e2f7c11 1656 log_debug("Child %llu belongs to %s", (long long unsigned) si.si_pid, u->meta.id);
6c1a0478 1657
87f0e418 1658 UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
9152c765
LP
1659 }
1660
1661 return 0;
1662}
1663
28247076
LP
1664static void manager_start_target(Manager *m, const char *name) {
1665 int r;
1666
1667 if ((r = manager_add_job_by_name(m, JOB_START, name, JOB_REPLACE, true, NULL)) < 0)
1668 log_error("Failed to enqueue %s job: %s", name, strerror(-r));
1669}
1670
a16e1123 1671static int manager_process_signal_fd(Manager *m) {
9152c765
LP
1672 ssize_t n;
1673 struct signalfd_siginfo sfsi;
1674 bool sigchld = false;
1675
1676 assert(m);
1677
1678 for (;;) {
acbb0225 1679 if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
9152c765
LP
1680
1681 if (n >= 0)
1682 return -EIO;
1683
1684 if (errno == EAGAIN)
acbb0225 1685 break;
9152c765
LP
1686
1687 return -errno;
1688 }
1689
b9cd2ec1
LP
1690 switch (sfsi.ssi_signo) {
1691
4112df16 1692 case SIGCHLD:
9152c765 1693 sigchld = true;
b9cd2ec1
LP
1694 break;
1695
1696 case SIGINT:
6632c602 1697 case SIGTERM:
84e9af1e 1698
28247076
LP
1699 if (m->running_as == MANAGER_INIT) {
1700 manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET);
84e9af1e
LP
1701 break;
1702 }
1703
a16e1123 1704 m->exit_code = MANAGER_EXIT;
28247076 1705 return 0;
84e9af1e 1706
28247076 1707 case SIGWINCH:
84e9af1e 1708
28247076
LP
1709 if (m->running_as == MANAGER_INIT)
1710 manager_start_target(m, SPECIAL_KBREQUEST_TARGET);
84e9af1e 1711
28247076
LP
1712 /* This is a nop on non-init */
1713 break;
84e9af1e 1714
28247076
LP
1715 case SIGPWR:
1716 if (m->running_as == MANAGER_INIT)
1717 manager_start_target(m, SPECIAL_SIGPWR_TARGET);
84e9af1e 1718
28247076 1719 /* This is a nop on non-init */
84e9af1e 1720 break;
6632c602 1721
0398f3da 1722 case SIGUSR1:
0398f3da 1723 manager_dump_units(m, stdout, "\t");
0398f3da 1724 manager_dump_jobs(m, stdout, "\t");
0398f3da
LP
1725 break;
1726
57ee42ce
LP
1727 case SIGUSR2: {
1728 Unit *u;
1729
1730 u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
1731
1732 if (!u || UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
1733 log_info("Trying to reconnect to bus...");
1734 bus_init_system(m);
1735 bus_init_api(m);
1736 }
1737
1738 if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) {
1739 log_info("Loading D-Bus service...");
1740 manager_start_target(m, SPECIAL_DBUS_SERVICE);
1741 }
1742
1743 break;
1744 }
1745
a16e1123
LP
1746 case SIGHUP:
1747 m->exit_code = MANAGER_RELOAD;
1748 break;
1749
6632c602
LP
1750 default:
1751 log_info("Got unhandled signal <%s>.", strsignal(sfsi.ssi_signo));
b9cd2ec1 1752 }
9152c765
LP
1753 }
1754
1755 if (sigchld)
034c6ed7
LP
1756 return manager_dispatch_sigchld(m);
1757
1758 return 0;
1759}
1760
a16e1123 1761static int process_event(Manager *m, struct epoll_event *ev) {
034c6ed7 1762 int r;
acbb0225 1763 Watch *w;
034c6ed7
LP
1764
1765 assert(m);
1766 assert(ev);
1767
acbb0225 1768 assert(w = ev->data.ptr);
034c6ed7 1769
acbb0225 1770 switch (w->type) {
034c6ed7 1771
ef734fd6 1772 case WATCH_SIGNAL:
034c6ed7 1773
acbb0225 1774 /* An incoming signal? */
f94ea366 1775 if (ev->events != EPOLLIN)
acbb0225 1776 return -EINVAL;
034c6ed7 1777
a16e1123 1778 if ((r = manager_process_signal_fd(m)) < 0)
acbb0225 1779 return r;
034c6ed7 1780
acbb0225 1781 break;
034c6ed7 1782
acbb0225 1783 case WATCH_FD:
034c6ed7 1784
acbb0225 1785 /* Some fd event, to be dispatched to the units */
ea430986 1786 UNIT_VTABLE(w->data.unit)->fd_event(w->data.unit, w->fd, ev->events, w);
acbb0225 1787 break;
034c6ed7 1788
acbb0225
LP
1789 case WATCH_TIMER: {
1790 uint64_t v;
1791 ssize_t k;
034c6ed7 1792
acbb0225 1793 /* Some timer event, to be dispatched to the units */
be888ebb 1794 if ((k = read(w->fd, &v, sizeof(v))) != sizeof(v)) {
034c6ed7 1795
acbb0225
LP
1796 if (k < 0 && (errno == EINTR || errno == EAGAIN))
1797 break;
034c6ed7 1798
acbb0225 1799 return k < 0 ? -errno : -EIO;
034c6ed7
LP
1800 }
1801
ea430986 1802 UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w);
acbb0225
LP
1803 break;
1804 }
1805
ef734fd6
LP
1806 case WATCH_MOUNT:
1807 /* Some mount table change, intended for the mount subsystem */
1808 mount_fd_event(m, ev->events);
1809 break;
1810
f94ea366
LP
1811 case WATCH_UDEV:
1812 /* Some notification from udev, intended for the device subsystem */
1813 device_fd_event(m, ev->events);
1814 break;
1815
ea430986
LP
1816 case WATCH_DBUS_WATCH:
1817 bus_watch_event(m, w, ev->events);
1818 break;
1819
1820 case WATCH_DBUS_TIMEOUT:
1821 bus_timeout_event(m, w, ev->events);
1822 break;
1823
acbb0225
LP
1824 default:
1825 assert_not_reached("Unknown epoll event type.");
034c6ed7 1826 }
9152c765
LP
1827
1828 return 0;
1829}
1830
1831int manager_loop(Manager *m) {
1832 int r;
9152c765 1833
ea430986
LP
1834 RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 1000);
1835
9152c765 1836 assert(m);
a16e1123 1837 m->exit_code = MANAGER_RUNNING;
9152c765 1838
a16e1123 1839 while (m->exit_code == MANAGER_RUNNING) {
957ca890
LP
1840 struct epoll_event event;
1841 int n;
9152c765 1842
ea430986
LP
1843 if (!ratelimit_test(&rl)) {
1844 /* Yay, something is going seriously wrong, pause a little */
1845 log_warning("Looping too fast. Throttling execution a little.");
1846 sleep(1);
1847 }
1848
23a177ef
LP
1849 if (manager_dispatch_cleanup_queue(m) > 0)
1850 continue;
1851
701cc384
LP
1852 if (manager_dispatch_gc_queue(m) > 0)
1853 continue;
1854
c1e1601e
LP
1855 if (manager_dispatch_load_queue(m) > 0)
1856 continue;
034c6ed7 1857
c1e1601e
LP
1858 if (manager_dispatch_run_queue(m) > 0)
1859 continue;
1860
1861 if (bus_dispatch(m) > 0)
1862 continue;
1863
1864 if (manager_dispatch_dbus_queue(m) > 0)
ea430986 1865 continue;
ea430986 1866
957ca890 1867 if ((n = epoll_wait(m->epoll_fd, &event, 1, -1)) < 0) {
9152c765
LP
1868
1869 if (errno == -EINTR)
1870 continue;
1871
1872 return -errno;
1873 }
1874
957ca890 1875 assert(n == 1);
b9cd2ec1 1876
a16e1123 1877 if ((r = process_event(m, &event)) < 0)
957ca890 1878 return r;
a16e1123 1879 }
957ca890 1880
a16e1123 1881 return m->exit_code;
83c60c9f 1882}
ea430986
LP
1883
1884int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u) {
1885 char *n;
1886 Unit *u;
1887
1888 assert(m);
1889 assert(s);
1890 assert(_u);
1891
1892 if (!startswith(s, "/org/freedesktop/systemd1/unit/"))
1893 return -EINVAL;
1894
1895 if (!(n = bus_path_unescape(s+31)))
1896 return -ENOMEM;
1897
1898 u = manager_get_unit(m, n);
1899 free(n);
1900
1901 if (!u)
1902 return -ENOENT;
1903
1904 *_u = u;
1905
1906 return 0;
1907}
86fbf370
LP
1908
1909int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
1910 Job *j;
1911 unsigned id;
1912 int r;
1913
1914 assert(m);
1915 assert(s);
1916 assert(_j);
1917
1918 if (!startswith(s, "/org/freedesktop/systemd1/job/"))
1919 return -EINVAL;
1920
1921 if ((r = safe_atou(s + 30, &id)) < 0)
1922 return r;
1923
1924 if (!(j = manager_get_job(m, id)))
1925 return -ENOENT;
1926
1927 *_j = j;
1928
1929 return 0;
1930}
dfcd764e 1931
e537352b
LP
1932static bool manager_utmp_good(Manager *m) {
1933 int r;
1934
1935 assert(m);
1936
1937 if ((r = mount_path_is_mounted(m, _PATH_UTMPX)) <= 0) {
1938
1939 if (r < 0)
1940 log_warning("Failed to determine whether " _PATH_UTMPX " is mounted: %s", strerror(-r));
1941
1942 return false;
1943 }
1944
1945 return true;
1946}
1947
1948void manager_write_utmp_reboot(Manager *m) {
1949 int r;
1950
1951 assert(m);
1952
1953 if (m->utmp_reboot_written)
1954 return;
1955
1956 if (m->running_as != MANAGER_INIT)
1957 return;
1958
1959 if (!manager_utmp_good(m))
1960 return;
1961
1962 if ((r = utmp_put_reboot(m->boot_timestamp)) < 0) {
1963
1964 if (r != -ENOENT && r != -EROFS)
1965 log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
1966
1967 return;
1968 }
1969
1970 m->utmp_reboot_written = true;
1971}
1972
1973void manager_write_utmp_runlevel(Manager *m, Unit *u) {
1974 int runlevel, r;
1975
1976 assert(m);
1977 assert(u);
1978
1979 if (u->meta.type != UNIT_TARGET)
1980 return;
1981
1982 if (m->running_as != MANAGER_INIT)
1983 return;
1984
1985 if (!manager_utmp_good(m))
1986 return;
1987
1988 if ((runlevel = target_get_runlevel(TARGET(u))) <= 0)
1989 return;
1990
1991 if ((r = utmp_put_runlevel(0, runlevel, 0)) < 0) {
1992
1993 if (r != -ENOENT && r != -EROFS)
1994 log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
1995 }
1996}
1997
05e343b7
LP
1998void manager_dispatch_bus_name_owner_changed(
1999 Manager *m,
2000 const char *name,
2001 const char* old_owner,
2002 const char *new_owner) {
2003
2004 Unit *u;
2005
2006 assert(m);
2007 assert(name);
2008
2009 if (!(u = hashmap_get(m->watch_bus, name)))
2010 return;
2011
2012 UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
2013}
2014
2015void manager_dispatch_bus_query_pid_done(
2016 Manager *m,
2017 const char *name,
2018 pid_t pid) {
2019
2020 Unit *u;
2021
2022 assert(m);
2023 assert(name);
2024 assert(pid >= 1);
2025
2026 if (!(u = hashmap_get(m->watch_bus, name)))
2027 return;
2028
2029 UNIT_VTABLE(u)->bus_query_pid_done(u, name, pid);
2030}
2031
a16e1123
LP
2032int manager_open_serialization(FILE **_f) {
2033 char *path;
2034 mode_t saved_umask;
2035 int fd;
2036 FILE *f;
2037
2038 assert(_f);
2039
2040 if (asprintf(&path, "/dev/shm/systemd-%u.dump-XXXXXX", (unsigned) getpid()) < 0)
2041 return -ENOMEM;
2042
2043 saved_umask = umask(0077);
2044 fd = mkostemp(path, O_RDWR|O_CLOEXEC);
2045 umask(saved_umask);
2046
2047 if (fd < 0) {
2048 free(path);
2049 return -errno;
2050 }
2051
2052 unlink(path);
2053
2054 log_debug("Serializing state to %s", path);
2055 free(path);
2056
2057 if (!(f = fdopen(fd, "w+")) < 0)
2058 return -errno;
2059
2060 *_f = f;
2061
2062 return 0;
2063}
2064
2065int manager_serialize(Manager *m, FILE *f, FDSet *fds) {
2066 Iterator i;
2067 Unit *u;
2068 const char *t;
2069 int r;
2070
2071 assert(m);
2072 assert(f);
2073 assert(fds);
2074
2075 HASHMAP_FOREACH_KEY(u, t, m->units, i) {
2076 if (u->meta.id != t)
2077 continue;
2078
2079 if (!unit_can_serialize(u))
2080 continue;
2081
2082 /* Start marker */
2083 fputs(u->meta.id, f);
2084 fputc('\n', f);
2085
2086 if ((r = unit_serialize(u, f, fds)) < 0)
2087 return r;
2088 }
2089
2090 if (ferror(f))
2091 return -EIO;
2092
2093 return 0;
2094}
2095
2096int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
2097 int r = 0;
2098
2099 assert(m);
2100 assert(f);
2101
2102 log_debug("Deserializing state...");
2103
2104 for (;;) {
2105 Unit *u;
2106 char name[UNIT_NAME_MAX+2];
2107
2108 /* Start marker */
2109 if (!fgets(name, sizeof(name), f)) {
2110 if (feof(f))
2111 break;
2112
2113 return -errno;
2114 }
2115
2116 char_array_0(name);
2117
2118 if ((r = manager_load_unit(m, strstrip(name), NULL, &u)) < 0)
2119 return r;
2120
2121 if ((r = unit_deserialize(u, f, fds)) < 0)
2122 return r;
2123 }
2124
2125 if (ferror(f))
2126 return -EIO;
2127
2128 return 0;
2129}
2130
2131int manager_reload(Manager *m) {
2132 int r, q;
2133 FILE *f;
2134 FDSet *fds;
2135
2136 assert(m);
2137
2138 if ((r = manager_open_serialization(&f)) < 0)
2139 return r;
2140
2141 if (!(fds = fdset_new())) {
2142 r = -ENOMEM;
2143 goto finish;
2144 }
2145
2146 if ((r = manager_serialize(m, f, fds)) < 0)
2147 goto finish;
2148
2149 if (fseeko(f, 0, SEEK_SET) < 0) {
2150 r = -errno;
2151 goto finish;
2152 }
2153
2154 /* From here on there is no way back. */
2155 manager_clear_jobs_and_units(m);
2156
2157 /* First, enumerate what we can from all config files */
2158 if ((q = manager_enumerate(m)) < 0)
2159 r = q;
2160
2161 /* Second, deserialize our stored data */
2162 if ((q = manager_deserialize(m, f, fds)) < 0)
2163 r = q;
2164
2165 fclose(f);
2166 f = NULL;
2167
2168 /* Third, fire things up! */
2169 if ((q = manager_coldplug(m)) < 0)
2170 r = q;
2171
2172finish:
2173 if (f)
2174 fclose(f);
2175
2176 if (fds)
2177 fdset_free(fds);
2178
2179 return r;
2180}
2181
dfcd764e
LP
2182static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
2183 [MANAGER_INIT] = "init",
2184 [MANAGER_SYSTEM] = "system",
036643a2 2185 [MANAGER_SESSION] = "session"
dfcd764e
LP
2186};
2187
2188DEFINE_STRING_TABLE_LOOKUP(manager_running_as, ManagerRunningAs);