]> git.ipfire.org Git - people/ms/systemd.git/blame - manager.c
cgroup: add cgroupsification
[people/ms/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>
30#include <sys/poll.h>
e1414003
LP
31#include <sys/reboot.h>
32#include <sys/ioctl.h>
33#include <linux/kd.h>
8e274523 34#include <libcgroup.h>
60918275
LP
35
36#include "manager.h"
37#include "hashmap.h"
38#include "macro.h"
39#include "strv.h"
16354eff 40#include "log.h"
2a987ee8 41#include "util.h"
ea430986 42#include "ratelimit.h"
8e274523
LP
43#include "cgroup.h"
44#include "mount-setup.h"
60918275 45
ce578209 46static int manager_setup_signals(Manager *m) {
9152c765
LP
47 sigset_t mask;
48 struct epoll_event ev;
60918275 49
ce578209
LP
50 assert(m);
51
52 assert_se(reset_all_signal_handlers() == 0);
53
54 assert_se(sigemptyset(&mask) == 0);
55 assert_se(sigaddset(&mask, SIGCHLD) == 0);
56 assert_se(sigaddset(&mask, SIGINT) == 0); /* Kernel sends us this on control-alt-del */
57 assert_se(sigaddset(&mask, SIGWINCH) == 0); /* Kernel sends us this on kbrequest (alt-arrowup) */
58 assert_se(sigaddset(&mask, SIGTERM) == 0);
59 assert_se(sigaddset(&mask, SIGHUP) == 0);
60 assert_se(sigaddset(&mask, SIGUSR1) == 0);
61 assert_se(sigaddset(&mask, SIGUSR2) == 0);
62 assert_se(sigaddset(&mask, SIGPIPE) == 0);
e1414003
LP
63 assert_se(sigaddset(&mask, SIGPWR) == 0);
64 assert_se(sigaddset(&mask, SIGTTIN) == 0);
ce578209
LP
65 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
66
ef734fd6 67 m->signal_watch.type = WATCH_SIGNAL;
ce578209
LP
68 if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0)
69 return -errno;
70
71 zero(ev);
72 ev.events = EPOLLIN;
73 ev.data.ptr = &m->signal_watch;
74
75 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
76 return -errno;
77
e1414003
LP
78 if (m->running_as == MANAGER_INIT) {
79 /* Enable that we get SIGINT on control-alt-del */
80 if (reboot(RB_DISABLE_CAD) < 0)
81 log_warning("Failed to enable ctrl-alt-del handling: %s", strerror(errno));
82
83 /* Enable that we get SIGWINCH on kbrequest */
84 if (ioctl(0, KDSIGACCEPT, SIGWINCH) < 0)
85 log_warning("Failed to enable kbrequest handling: %s", strerror(errno));
86 }
87
ce578209
LP
88 return 0;
89}
90
036643a2
LP
91static char** session_dirs(void) {
92 const char *home, *e;
93 char *config_home = NULL, *data_home = NULL;
94 char **config_dirs = NULL, **data_dirs = NULL;
95 char **r = NULL, **t;
96
97 /* Implement the mechanisms defined in
98 *
99 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
100 *
101 * We look in both the config and the data dirs because we
102 * want to encourage that distributors ship their unit files
103 * as data, and allow overriding as configuration.
104 */
105
106 home = getenv("HOME");
107
108 if ((e = getenv("XDG_CONFIG_HOME"))) {
109 if (asprintf(&config_home, "%s/systemd/session", e) < 0)
110 goto fail;
111
112 } else if (home) {
113 if (asprintf(&config_home, "%s/.config/systemd/session", home) < 0)
114 goto fail;
115 }
116
117 if ((e = getenv("XDG_CONFIG_DIRS")))
118 config_dirs = strv_split(e, ":");
119 else
120 config_dirs = strv_new("/etc/xdg", NULL);
121
122 if (!config_dirs)
123 goto fail;
124
125 if ((e = getenv("XDG_DATA_HOME"))) {
126 if (asprintf(&data_home, "%s/systemd/session", e) < 0)
127 goto fail;
128
129 } else if (home) {
130 if (asprintf(&data_home, "%s/.local/share/systemd/session", home) < 0)
131 goto fail;
132 }
133
134 if ((e = getenv("XDG_DATA_DIRS")))
135 data_dirs = strv_split(e, ":");
136 else
137 data_dirs = strv_new("/usr/local/share", "/usr/share", NULL);
138
139 if (!data_dirs)
140 goto fail;
141
142 /* Now merge everything we found. */
143 if (config_home) {
144 if (!(t = strv_append(r, config_home)))
145 goto fail;
146 strv_free(r);
147 r = t;
148 }
149
150 if (!(t = strv_merge_concat(r, config_dirs, "/systemd/session")))
151 goto finish;
152 strv_free(r);
153 r = t;
154
155 if (!(t = strv_append(r, SESSION_CONFIG_UNIT_PATH)))
156 goto fail;
157 strv_free(r);
158 r = t;
159
160 if (data_home) {
161 if (!(t = strv_append(r, data_home)))
162 goto fail;
163 strv_free(r);
164 r = t;
165 }
166
167 if (!(t = strv_merge_concat(r, data_dirs, "/systemd/session")))
168 goto fail;
169 strv_free(r);
170 r = t;
171
172 if (!(t = strv_append(r, SESSION_DATA_UNIT_PATH)))
173 goto fail;
174 strv_free(r);
175 r = t;
176
177 if (!strv_path_make_absolute_cwd(r))
178 goto fail;
179
180finish:
181 free(config_home);
182 strv_free(config_dirs);
183 free(data_home);
184 strv_free(data_dirs);
185
186 return r;
187
188fail:
189 strv_free(r);
190 r = NULL;
191 goto finish;
192}
193
194static int manager_find_paths(Manager *m) {
195 const char *e;
196 char *t;
197 assert(m);
198
199 /* First priority is whatever has been passed to us via env
200 * vars */
201 if ((e = getenv("SYSTEMD_UNIT_PATH")))
202 if (!(m->unit_path = split_path_and_make_absolute(e)))
203 return -ENOMEM;
204
205 if (strv_isempty(m->unit_path)) {
206
207 /* Nothing is set, so let's figure something out. */
208 strv_free(m->unit_path);
209
210 if (m->running_as == MANAGER_SESSION) {
211 if (!(m->unit_path = session_dirs()))
212 return -ENOMEM;
213 } else
214 if (!(m->unit_path = strv_new(
215 SYSTEM_CONFIG_UNIT_PATH, /* /etc/systemd/system/ */
216 SYSTEM_DATA_UNIT_PATH, /* /lib/systemd/system/ */
217 NULL)))
218 return -ENOMEM;
219 }
220
e1414003 221 if (m->running_as == MANAGER_INIT) {
036643a2
LP
222 /* /etc/init.d/ compativility does not matter to users */
223
224 if ((e = getenv("SYSTEMD_SYSVINIT_PATH")))
225 if (!(m->sysvinit_path = split_path_and_make_absolute(e)))
226 return -ENOMEM;
227
228 if (strv_isempty(m->sysvinit_path)) {
229 strv_free(m->sysvinit_path);
230
231 if (!(m->sysvinit_path = strv_new(
232 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
233 NULL)))
234 return -ENOMEM;
235 }
236 }
237
238 strv_uniq(m->unit_path);
239 strv_uniq(m->sysvinit_path);
240
241 assert(!strv_isempty(m->unit_path));
242 if (!(t = strv_join(m->unit_path, "\n\t")))
243 return -ENOMEM;
244 log_debug("Looking for unit files in:\n\t%s", t);
245 free(t);
246
247 if (!strv_isempty(m->sysvinit_path)) {
248
249 if (!(t = strv_join(m->sysvinit_path, "\n\t")))
250 return -ENOMEM;
251
252 log_debug("Looking for SysV init scripts in:\n\t%s", t);
253 free(t);
254 } else
255 log_debug("Ignoring SysV init scripts.");
256
257 return 0;
258}
259
8e274523 260int manager_new(Manager **_m) {
ce578209 261 Manager *m;
8e274523
LP
262 int r = -ENOMEM;
263
264 assert(_m);
ce578209 265
60918275 266 if (!(m = new0(Manager, 1)))
8e274523 267 return -ENOMEM;
60918275 268
f94ea366 269 m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = -1;
ea430986 270 m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
9152c765 271
87f0e418 272 if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
60918275
LP
273 goto fail;
274
275 if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
276 goto fail;
277
e5b5ae50 278 if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
60918275
LP
279 goto fail;
280
9152c765
LP
281 if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
282 goto fail;
283
8e274523
LP
284 if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
285 goto fail;
286
9152c765
LP
287 if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
288 goto fail;
289
e1414003
LP
290 if (getpid() == 1)
291 m->running_as = MANAGER_INIT;
292 else if (getuid() == 0)
293 m->running_as = MANAGER_SYSTEM;
294 else
295 m->running_as = MANAGER_SESSION;
296
297 log_debug("systemd running in %s mode.", manager_running_as_to_string(m->running_as));
298
8e274523 299 if ((r = manager_find_paths(m)) < 0)
e1414003
LP
300 goto fail;
301
302 if (chdir("/") < 0)
303 log_warning("Failed to chdir to /: %s", strerror(errno));
304
305 /* Become a session leader if we aren't one yet. */
306 setsid();
307
8e274523
LP
308 if ((r = manager_setup_signals(m)) < 0)
309 goto fail;
310
311 if ((r = mount_setup()) < 0)
312 goto fail;
313
314 if ((r = manager_setup_cgroup(m)) < 0)
9152c765
LP
315 goto fail;
316
ea430986 317 /* FIXME: this should be called only when the D-Bus bus daemon is running */
8e274523 318 if ((r = bus_init(m)) < 0)
ea430986
LP
319 goto fail;
320
8e274523
LP
321 *_m = m;
322 return 0;
60918275
LP
323
324fail:
325 manager_free(m);
8e274523 326 return r;
60918275
LP
327}
328
329void manager_free(Manager *m) {
7824bbeb 330 UnitType c;
87f0e418 331 Unit *u;
e5b5ae50 332 Job *j;
60918275
LP
333
334 assert(m);
335
87f0e418 336 while ((j = hashmap_first(m->transaction_jobs)))
e5b5ae50
LP
337 job_free(j);
338
87f0e418
LP
339 while ((u = hashmap_first(m->units)))
340 unit_free(u);
341
7824bbeb
LP
342 for (c = 0; c < _UNIT_TYPE_MAX; c++)
343 if (unit_vtable[c]->shutdown)
344 unit_vtable[c]->shutdown(m);
345
8e274523
LP
346 manager_shutdown_cgroup(m);
347
ea430986
LP
348 bus_done(m);
349
87f0e418 350 hashmap_free(m->units);
60918275 351 hashmap_free(m->jobs);
e5b5ae50 352 hashmap_free(m->transaction_jobs);
9152c765
LP
353 hashmap_free(m->watch_pids);
354
355 if (m->epoll_fd >= 0)
356 close_nointr(m->epoll_fd);
acbb0225
LP
357 if (m->signal_watch.fd >= 0)
358 close_nointr(m->signal_watch.fd);
60918275 359
036643a2
LP
360 strv_free(m->unit_path);
361 strv_free(m->sysvinit_path);
362
8e274523
LP
363 free(m->cgroup_controller);
364 free(m->cgroup_hierarchy);
365
366 assert(hashmap_isempty(m->cgroup_bondings));
367 hashmap_free(m->cgroup_bondings);
368
60918275
LP
369 free(m);
370}
371
f50e0a01
LP
372int manager_coldplug(Manager *m) {
373 int r;
374 UnitType c;
375 Iterator i;
376 Unit *u;
377 char *k;
378
379 assert(m);
380
381 /* First, let's ask every type to load all units from
382 * disk/kernel that it might know */
383 for (c = 0; c < _UNIT_TYPE_MAX; c++)
384 if (unit_vtable[c]->enumerate)
385 if ((r = unit_vtable[c]->enumerate(m)) < 0)
386 return r;
387
388 manager_dispatch_load_queue(m);
389
390 /* Then, let's set up their initial state. */
391 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
392
393 /* ignore aliases */
394 if (unit_id(u) != k)
395 continue;
396
397 if (UNIT_VTABLE(u)->coldplug)
398 if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0)
399 return r;
400 }
401
402 return 0;
403}
404
302d0040
LP
405static void transaction_delete_job(Manager *m, Job *j) {
406 assert(m);
407 assert(j);
408
1ffba6fe
LP
409 /* Deletes one job from the transaction */
410
302d0040
LP
411 manager_transaction_unlink_job(m, j);
412
ac1135be 413 if (!j->installed)
302d0040
LP
414 job_free(j);
415}
416
87f0e418 417static void transaction_delete_unit(Manager *m, Unit *u) {
1ffba6fe
LP
418 Job *j;
419
87f0e418 420 /* Deletes all jobs associated with a certain unit from the
1ffba6fe
LP
421 * transaction */
422
87f0e418 423 while ((j = hashmap_get(m->transaction_jobs, u)))
1ffba6fe
LP
424 transaction_delete_job(m, j);
425}
426
f04fa1d5
LP
427static void transaction_clean_dependencies(Manager *m) {
428 Iterator i;
429 Job *j;
430
431 assert(m);
432
433 /* Drops all dependencies of all installed jobs */
434
435 HASHMAP_FOREACH(j, m->jobs, i) {
436 while (j->subject_list)
437 job_dependency_free(j->subject_list);
438 while (j->object_list)
439 job_dependency_free(j->object_list);
440 }
441
442 assert(!m->transaction_anchor);
443}
444
11dd41ce
LP
445static void transaction_abort(Manager *m) {
446 Job *j;
447
448 assert(m);
11dd41ce 449
e5b5ae50 450 while ((j = hashmap_first(m->transaction_jobs)))
ac1135be 451 if (j->installed)
302d0040 452 transaction_delete_job(m, j);
e5b5ae50
LP
453 else
454 job_free(j);
455
456 assert(hashmap_isempty(m->transaction_jobs));
f04fa1d5
LP
457
458 transaction_clean_dependencies(m);
e5b5ae50
LP
459}
460
461static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsigned generation) {
462 JobDependency *l;
463
464 assert(m);
465
87f0e418 466 /* A recursive sweep through the graph that marks all units
1ffba6fe
LP
467 * that matter to the anchor job, i.e. are directly or
468 * indirectly a dependency of the anchor job via paths that
469 * are fully marked as mattering. */
470
44d8db9e
LP
471 if (j)
472 l = j->subject_list;
473 else
474 l = m->transaction_anchor;
475
476 LIST_FOREACH(subject, l, l) {
e5b5ae50
LP
477
478 /* This link does not matter */
479 if (!l->matters)
480 continue;
481
87f0e418 482 /* This unit has already been marked */
e5b5ae50
LP
483 if (l->object->generation == generation)
484 continue;
485
486 l->object->matters_to_anchor = true;
487 l->object->generation = generation;
488
489 transaction_find_jobs_that_matter_to_anchor(m, l->object, generation);
490 }
491}
492
7fad411c 493static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, JobType t) {
e5b5ae50
LP
494 JobDependency *l, *last;
495
496 assert(j);
497 assert(other);
87f0e418 498 assert(j->unit == other->unit);
ac1135be 499 assert(!j->installed);
e5b5ae50 500
1ffba6fe
LP
501 /* Merges 'other' into 'j' and then deletes j. */
502
e5b5ae50
LP
503 j->type = t;
504 j->state = JOB_WAITING;
5cb5a6ff 505 j->forced = j->forced || other->forced;
e5b5ae50
LP
506
507 j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
508
509 /* Patch us in as new owner of the JobDependency objects */
510 last = NULL;
44d8db9e 511 LIST_FOREACH(subject, l, other->subject_list) {
e5b5ae50
LP
512 assert(l->subject == other);
513 l->subject = j;
514 last = l;
515 }
516
517 /* Merge both lists */
518 if (last) {
519 last->subject_next = j->subject_list;
520 if (j->subject_list)
521 j->subject_list->subject_prev = last;
522 j->subject_list = other->subject_list;
523 }
524
525 /* Patch us in as new owner of the JobDependency objects */
526 last = NULL;
44d8db9e 527 LIST_FOREACH(object, l, other->object_list) {
e5b5ae50
LP
528 assert(l->object == other);
529 l->object = j;
530 last = l;
531 }
532
533 /* Merge both lists */
534 if (last) {
535 last->object_next = j->object_list;
536 if (j->object_list)
537 j->object_list->object_prev = last;
538 j->object_list = other->object_list;
539 }
540
e5b5ae50
LP
541 /* Kill the other job */
542 other->subject_list = NULL;
543 other->object_list = NULL;
302d0040 544 transaction_delete_job(m, other);
e5b5ae50
LP
545}
546
5cb5a6ff 547static int delete_one_unmergeable_job(Manager *m, Job *j) {
1ffba6fe
LP
548 Job *k;
549
550 assert(j);
551
552 /* Tries to delete one item in the linked list
553 * j->transaction_next->transaction_next->... that conflicts
554 * whith another one, in an attempt to make an inconsistent
555 * transaction work. */
556
557 /* We rely here on the fact that if a merged with b does not
558 * merge with c, either a or b merge with c neither */
034c6ed7
LP
559 LIST_FOREACH(transaction, j, j)
560 LIST_FOREACH(transaction, k, j->transaction_next) {
1ffba6fe
LP
561 Job *d;
562
563 /* Is this one mergeable? Then skip it */
5cb5a6ff 564 if (job_type_is_mergeable(j->type, k->type))
1ffba6fe
LP
565 continue;
566
567 /* Ok, we found two that conflict, let's see if we can
568 * drop one of them */
569 if (!j->matters_to_anchor)
570 d = j;
571 else if (!k->matters_to_anchor)
572 d = k;
573 else
574 return -ENOEXEC;
575
576 /* Ok, we can drop one, so let's do so. */
87f0e418 577 log_debug("Try to fix job merging by deleting job %s/%s", unit_id(d->unit), job_type_to_string(d->type));
1ffba6fe
LP
578 transaction_delete_job(m, d);
579 return 0;
580 }
581
582 return -EINVAL;
583}
584
e5b5ae50 585static int transaction_merge_jobs(Manager *m) {
11dd41ce 586 Job *j;
034c6ed7 587 Iterator i;
e5b5ae50
LP
588 int r;
589
590 assert(m);
591
1ffba6fe
LP
592 /* First step, check whether any of the jobs for one specific
593 * task conflict. If so, try to drop one of them. */
034c6ed7 594 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1ffba6fe
LP
595 JobType t;
596 Job *k;
597
598 t = j->type;
034c6ed7 599 LIST_FOREACH(transaction, k, j->transaction_next) {
1ffba6fe
LP
600 if ((r = job_type_merge(&t, k->type)) >= 0)
601 continue;
602
603 /* OK, we could not merge all jobs for this
604 * action. Let's see if we can get rid of one
605 * of them */
606
5cb5a6ff 607 if ((r = delete_one_unmergeable_job(m, j)) >= 0)
1ffba6fe
LP
608 /* Ok, we managed to drop one, now
609 * let's ask our callers to call us
610 * again after garbage collecting */
611 return -EAGAIN;
612
613 /* We couldn't merge anything. Failure */
614 return r;
615 }
616 }
617
618 /* Second step, merge the jobs. */
034c6ed7 619 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e5b5ae50
LP
620 JobType t = j->type;
621 Job *k;
622
e094e853 623 /* Merge all transactions */
034c6ed7 624 LIST_FOREACH(transaction, k, j->transaction_next)
1ffba6fe 625 assert_se(job_type_merge(&t, k->type) == 0);
e5b5ae50 626
5cb5a6ff 627 /* If an active job is mergeable, merge it too */
87f0e418
LP
628 if (j->unit->meta.job)
629 job_type_merge(&t, j->unit->meta.job->type); /* Might fail. Which is OK */
e094e853 630
e5b5ae50 631 while ((k = j->transaction_next)) {
ac1135be 632 if (j->installed) {
7fad411c 633 transaction_merge_and_delete_job(m, k, j, t);
e5b5ae50
LP
634 j = k;
635 } else
7fad411c 636 transaction_merge_and_delete_job(m, j, k, t);
e5b5ae50
LP
637 }
638
639 assert(!j->transaction_next);
640 assert(!j->transaction_prev);
641 }
642
7fad411c 643 return 0;
e5b5ae50
LP
644}
645
87f0e418
LP
646static bool unit_matters_to_anchor(Unit *u, Job *j) {
647 assert(u);
1ffba6fe
LP
648 assert(!j->transaction_prev);
649
87f0e418 650 /* Checks whether at least one of the jobs for this unit
1ffba6fe
LP
651 * matters to the anchor. */
652
034c6ed7 653 LIST_FOREACH(transaction, j, j)
1ffba6fe
LP
654 if (j->matters_to_anchor)
655 return true;
656
657 return false;
658}
659
e5b5ae50 660static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned generation) {
034c6ed7 661 Iterator i;
87f0e418 662 Unit *u;
11dd41ce 663 int r;
e5b5ae50
LP
664
665 assert(m);
666 assert(j);
1ffba6fe
LP
667 assert(!j->transaction_prev);
668
669 /* Does a recursive sweep through the ordering graph, looking
670 * for a cycle. If we find cycle we try to break it. */
e5b5ae50 671
7fad411c 672 /* Did we find a cycle? */
e5b5ae50
LP
673 if (j->marker && j->generation == generation) {
674 Job *k;
675
676 /* So, we already have been here. We have a
1ffba6fe
LP
677 * cycle. Let's try to break it. We go backwards in
678 * our path and try to find a suitable job to
679 * remove. We use the marker to find our way back,
680 * since smart how we are we stored our way back in
681 * there. */
e5b5ae50 682
9f04bd52
LP
683 log_debug("Found cycle on %s/%s", unit_id(j->unit), job_type_to_string(j->type));
684
e5b5ae50 685 for (k = from; k; k = (k->generation == generation ? k->marker : NULL)) {
1ffba6fe 686
9f04bd52
LP
687 log_debug("Walked on cycle path to %s/%s", unit_id(j->unit), job_type_to_string(j->type));
688
ac1135be 689 if (!k->installed &&
87f0e418 690 !unit_matters_to_anchor(k->unit, k)) {
1ffba6fe
LP
691 /* Ok, we can drop this one, so let's
692 * do so. */
87f0e418
LP
693 log_debug("Breaking order cycle by deleting job %s/%s", unit_id(k->unit), job_type_to_string(k->type));
694 transaction_delete_unit(m, k->unit);
e5b5ae50
LP
695 return -EAGAIN;
696 }
697
698 /* Check if this in fact was the beginning of
7fad411c 699 * the cycle */
e5b5ae50
LP
700 if (k == j)
701 break;
702 }
703
9f04bd52
LP
704 log_debug("Unable to break cycle");
705
1ffba6fe 706 return -ENOEXEC;
e5b5ae50
LP
707 }
708
1ffba6fe
LP
709 /* Make the marker point to where we come from, so that we can
710 * find our way backwards if we want to break a cycle */
e5b5ae50
LP
711 j->marker = from;
712 j->generation = generation;
713
1ffba6fe 714 /* We assume that the the dependencies are bidirectional, and
87f0e418
LP
715 * hence can ignore UNIT_AFTER */
716 SET_FOREACH(u, j->unit->meta.dependencies[UNIT_BEFORE], i) {
e5b5ae50
LP
717 Job *o;
718
87f0e418
LP
719 /* Is there a job for this unit? */
720 if (!(o = hashmap_get(m->transaction_jobs, u)))
1ffba6fe
LP
721
722 /* Ok, there is no job for this in the
723 * transaction, but maybe there is already one
724 * running? */
87f0e418 725 if (!(o = u->meta.job))
e5b5ae50
LP
726 continue;
727
728 if ((r = transaction_verify_order_one(m, o, j, generation)) < 0)
729 return r;
730 }
731
9f04bd52
LP
732 /* Ok, let's backtrack, and remember that this entry is not on
733 * our path anymore. */
734 j->marker = NULL;
735
e5b5ae50
LP
736 return 0;
737}
738
739static int transaction_verify_order(Manager *m, unsigned *generation) {
1ffba6fe
LP
740 Job *j;
741 int r;
034c6ed7 742 Iterator i;
1ffba6fe 743
e5b5ae50
LP
744 assert(m);
745 assert(generation);
746
1ffba6fe
LP
747 /* Check if the ordering graph is cyclic. If it is, try to fix
748 * that up by dropping one of the jobs. */
e5b5ae50 749
034c6ed7 750 HASHMAP_FOREACH(j, m->transaction_jobs, i)
1ffba6fe
LP
751 if ((r = transaction_verify_order_one(m, j, NULL, (*generation)++)) < 0)
752 return r;
e5b5ae50
LP
753
754 return 0;
755}
756
757static void transaction_collect_garbage(Manager *m) {
758 bool again;
759
760 assert(m);
761
1ffba6fe
LP
762 /* Drop jobs that are not required by any other job */
763
e5b5ae50 764 do {
034c6ed7 765 Iterator i;
e5b5ae50
LP
766 Job *j;
767
768 again = false;
769
034c6ed7 770 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e5b5ae50
LP
771 if (j->object_list)
772 continue;
773
87f0e418 774 log_debug("Garbage collecting job %s/%s", unit_id(j->unit), job_type_to_string(j->type));
302d0040 775 transaction_delete_job(m, j);
e5b5ae50
LP
776 again = true;
777 break;
778 }
779
780 } while (again);
781}
782
783static int transaction_is_destructive(Manager *m, JobMode mode) {
034c6ed7 784 Iterator i;
e5b5ae50 785 Job *j;
11dd41ce
LP
786
787 assert(m);
11dd41ce 788
e5b5ae50
LP
789 /* Checks whether applying this transaction means that
790 * existing jobs would be replaced */
11dd41ce 791
034c6ed7 792 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e094e853
LP
793
794 /* Assume merged */
795 assert(!j->transaction_prev);
796 assert(!j->transaction_next);
797
87f0e418
LP
798 if (j->unit->meta.job &&
799 j->unit->meta.job != j &&
800 !job_type_is_superset(j->type, j->unit->meta.job->type))
e5b5ae50 801 return -EEXIST;
e094e853 802 }
11dd41ce 803
e5b5ae50
LP
804 return 0;
805}
806
e094e853
LP
807static void transaction_minimize_impact(Manager *m) {
808 bool again;
809 assert(m);
810
811 /* Drops all unnecessary jobs that reverse already active jobs
812 * or that stop a running service. */
813
814 do {
815 Job *j;
034c6ed7 816 Iterator i;
e094e853
LP
817
818 again = false;
819
034c6ed7
LP
820 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
821 LIST_FOREACH(transaction, j, j) {
c20cae32 822 bool stops_running_service, changes_existing_job;
e094e853
LP
823
824 /* If it matters, we shouldn't drop it */
825 if (j->matters_to_anchor)
826 continue;
827
828 /* Would this stop a running service?
829 * Would this change an existing job?
830 * If so, let's drop this entry */
c20cae32
LP
831
832 stops_running_service =
833 j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
834
835 changes_existing_job =
836 j->unit->meta.job && job_type_is_conflicting(j->type, j->unit->meta.job->state);
837
838 if (!stops_running_service && !changes_existing_job)
e094e853
LP
839 continue;
840
c20cae32
LP
841 if (stops_running_service)
842 log_debug("%s/%s would stop a running service.", unit_id(j->unit), job_type_to_string(j->type));
843
844 if (changes_existing_job)
845 log_debug("%s/%s would change existing job.", unit_id(j->unit), job_type_to_string(j->type));
846
e094e853 847 /* Ok, let's get rid of this */
c20cae32
LP
848 log_debug("Deleting %s/%s to minimize impact.", unit_id(j->unit), job_type_to_string(j->type));
849
e094e853
LP
850 transaction_delete_job(m, j);
851 again = true;
852 break;
853 }
854
855 if (again)
856 break;
857 }
858
859 } while (again);
860}
861
e5b5ae50 862static int transaction_apply(Manager *m, JobMode mode) {
034c6ed7 863 Iterator i;
e5b5ae50
LP
864 Job *j;
865 int r;
866
1ffba6fe
LP
867 /* Moves the transaction jobs to the set of active jobs */
868
034c6ed7 869 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e094e853
LP
870 /* Assume merged */
871 assert(!j->transaction_prev);
872 assert(!j->transaction_next);
873
ac1135be 874 if (j->installed)
e5b5ae50
LP
875 continue;
876
877 if ((r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j)) < 0)
11dd41ce
LP
878 goto rollback;
879 }
880
e5b5ae50 881 while ((j = hashmap_steal_first(m->transaction_jobs))) {
ac1135be 882 if (j->installed)
e5b5ae50
LP
883 continue;
884
87f0e418
LP
885 if (j->unit->meta.job)
886 job_free(j->unit->meta.job);
11dd41ce 887
87f0e418 888 j->unit->meta.job = j;
ac1135be 889 j->installed = true;
11dd41ce 890
e5b5ae50
LP
891 /* We're fully installed. Now let's free data we don't
892 * need anymore. */
893
894 assert(!j->transaction_next);
895 assert(!j->transaction_prev);
896
c1e1601e
LP
897 job_add_to_run_queue(j);
898 job_add_to_dbus_queue(j);
01184e04
LP
899 }
900
901 /* As last step, kill all remaining job dependencies. */
f04fa1d5 902 transaction_clean_dependencies(m);
1ffba6fe 903
11dd41ce
LP
904 return 0;
905
906rollback:
907
034c6ed7 908 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
ac1135be 909 if (j->installed)
e5b5ae50
LP
910 continue;
911
912 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
913 }
914
915 return r;
916}
917
e5b5ae50
LP
918static int transaction_activate(Manager *m, JobMode mode) {
919 int r;
920 unsigned generation = 1;
921
922 assert(m);
923
924 /* This applies the changes recorded in transaction_jobs to
925 * the actual list of jobs, if possible. */
926
927 /* First step: figure out which jobs matter */
928 transaction_find_jobs_that_matter_to_anchor(m, NULL, generation++);
929
e094e853
LP
930 /* Second step: Try not to stop any running services if
931 * we don't have to. Don't try to reverse running
932 * jobs if we don't have to. */
933 transaction_minimize_impact(m);
934
1ffba6fe 935 for (;;) {
e094e853 936 /* Third step: Let's remove unneeded jobs that might
1ffba6fe
LP
937 * be lurking. */
938 transaction_collect_garbage(m);
e5b5ae50 939
e094e853 940 /* Fourth step: verify order makes sense and correct
1ffba6fe
LP
941 * cycles if necessary and possible */
942 if ((r = transaction_verify_order(m, &generation)) >= 0)
943 break;
e5b5ae50 944
9f04bd52
LP
945 if (r != -EAGAIN) {
946 log_debug("Requested transaction contains an unfixable cyclic ordering dependency: %s", strerror(-r));
1ffba6fe 947 goto rollback;
9f04bd52 948 }
e5b5ae50 949
1ffba6fe
LP
950 /* Let's see if the resulting transaction ordering
951 * graph is still cyclic... */
952 }
953
954 for (;;) {
5cb5a6ff 955 /* Fifth step: let's drop unmergeable entries if
1ffba6fe
LP
956 * necessary and possible, merge entries we can
957 * merge */
958 if ((r = transaction_merge_jobs(m)) >= 0)
959 break;
960
9f04bd52
LP
961 if (r != -EAGAIN) {
962 log_debug("Requested transaction contains unmergable jobs: %s", strerror(-r));
1ffba6fe 963 goto rollback;
9f04bd52 964 }
1ffba6fe 965
e094e853 966 /* Sixth step: an entry got dropped, let's garbage
1ffba6fe
LP
967 * collect its dependencies. */
968 transaction_collect_garbage(m);
969
970 /* Let's see if the resulting transaction still has
5cb5a6ff 971 * unmergeable entries ... */
1ffba6fe
LP
972 }
973
e094e853 974 /* Seventh step: check whether we can actually apply this */
e5b5ae50 975 if (mode == JOB_FAIL)
9f04bd52
LP
976 if ((r = transaction_is_destructive(m, mode)) < 0) {
977 log_debug("Requested transaction contradicts existing jobs: %s", strerror(-r));
e5b5ae50 978 goto rollback;
9f04bd52 979 }
e5b5ae50 980
e094e853 981 /* Eights step: apply changes */
9f04bd52
LP
982 if ((r = transaction_apply(m, mode)) < 0) {
983 log_debug("Failed to apply transaction: %s", strerror(-r));
e5b5ae50 984 goto rollback;
9f04bd52 985 }
e5b5ae50
LP
986
987 assert(hashmap_isempty(m->transaction_jobs));
988 assert(!m->transaction_anchor);
989
990 return 0;
11dd41ce 991
e5b5ae50 992rollback:
11dd41ce
LP
993 transaction_abort(m);
994 return r;
995}
996
87f0e418 997static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool force, bool *is_new) {
e5b5ae50 998 Job *j, *f;
60918275
LP
999 int r;
1000
1001 assert(m);
87f0e418 1002 assert(unit);
60918275 1003
e5b5ae50
LP
1004 /* Looks for an axisting prospective job and returns that. If
1005 * it doesn't exist it is created and added to the prospective
1006 * jobs list. */
60918275 1007
87f0e418 1008 f = hashmap_get(m->transaction_jobs, unit);
60918275 1009
034c6ed7 1010 LIST_FOREACH(transaction, j, f) {
87f0e418 1011 assert(j->unit == unit);
60918275 1012
e5b5ae50
LP
1013 if (j->type == type) {
1014 if (is_new)
1015 *is_new = false;
1016 return j;
1017 }
1018 }
60918275 1019
87f0e418
LP
1020 if (unit->meta.job && unit->meta.job->type == type)
1021 j = unit->meta.job;
1022 else if (!(j = job_new(m, type, unit)))
e5b5ae50 1023 return NULL;
60918275 1024
e5b5ae50
LP
1025 j->generation = 0;
1026 j->marker = NULL;
1027 j->matters_to_anchor = false;
5cb5a6ff 1028 j->forced = force;
60918275 1029
034c6ed7
LP
1030 LIST_PREPEND(Job, transaction, f, j);
1031
87f0e418 1032 if ((r = hashmap_replace(m->transaction_jobs, unit, f)) < 0) {
034c6ed7
LP
1033 job_free(j);
1034 return NULL;
1035 }
1036
e5b5ae50
LP
1037 if (is_new)
1038 *is_new = true;
60918275 1039
e5b5ae50
LP
1040 return j;
1041}
11dd41ce 1042
302d0040 1043void manager_transaction_unlink_job(Manager *m, Job *j) {
e5b5ae50
LP
1044 assert(m);
1045 assert(j);
11dd41ce 1046
e5b5ae50
LP
1047 if (j->transaction_prev)
1048 j->transaction_prev->transaction_next = j->transaction_next;
1049 else if (j->transaction_next)
87f0e418 1050 hashmap_replace(m->transaction_jobs, j->unit, j->transaction_next);
e5b5ae50 1051 else
87f0e418 1052 hashmap_remove_value(m->transaction_jobs, j->unit, j);
e5b5ae50
LP
1053
1054 if (j->transaction_next)
1055 j->transaction_next->transaction_prev = j->transaction_prev;
1056
1057 j->transaction_prev = j->transaction_next = NULL;
1058
1059 while (j->subject_list)
1060 job_dependency_free(j->subject_list);
1e198baf
LP
1061
1062 while (j->object_list) {
1063 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
1064
e5b5ae50 1065 job_dependency_free(j->object_list);
1e198baf
LP
1066
1067 if (other) {
5cb5a6ff 1068 log_debug("Deleting job %s/%s as dependency of job %s/%s",
87f0e418
LP
1069 unit_id(other->unit), job_type_to_string(other->type),
1070 unit_id(j->unit), job_type_to_string(j->type));
302d0040 1071 transaction_delete_job(m, other);
1e198baf
LP
1072 }
1073 }
e5b5ae50
LP
1074}
1075
87f0e418 1076static int transaction_add_job_and_dependencies(Manager *m, JobType type, Unit *unit, Job *by, bool matters, bool force, Job **_ret) {
e5b5ae50 1077 Job *ret;
034c6ed7 1078 Iterator i;
87f0e418 1079 Unit *dep;
e5b5ae50
LP
1080 int r;
1081 bool is_new;
1082
1083 assert(m);
1084 assert(type < _JOB_TYPE_MAX);
87f0e418 1085 assert(unit);
e5b5ae50 1086
87f0e418 1087 if (unit->meta.load_state != UNIT_LOADED)
21b293e8
LP
1088 return -EINVAL;
1089
87f0e418 1090 if (!unit_job_is_applicable(unit, type))
cd2dbd7d
LP
1091 return -EBADR;
1092
e5b5ae50 1093 /* First add the job. */
87f0e418 1094 if (!(ret = transaction_add_one_job(m, type, unit, force, &is_new)))
e5b5ae50
LP
1095 return -ENOMEM;
1096
1097 /* Then, add a link to the job. */
1098 if (!job_dependency_new(by, ret, matters))
1099 return -ENOMEM;
1100
1101 if (is_new) {
1102 /* Finally, recursively add in all dependencies. */
1103 if (type == JOB_START || type == JOB_RELOAD_OR_START) {
87f0e418 1104 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i)
542563ba 1105 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
e5b5ae50 1106 goto fail;
87f0e418 1107 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_SOFT_REQUIRES], i)
542563ba 1108 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !force, force, NULL)) < 0 && r != -EBADR)
e5b5ae50 1109 goto fail;
87f0e418 1110 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i)
542563ba 1111 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, force, NULL)) < 0 && r != -EBADR)
e5b5ae50 1112 goto fail;
87f0e418 1113 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i)
542563ba 1114 if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
e5b5ae50 1115 goto fail;
87f0e418 1116 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_SOFT_REQUISITE], i)
542563ba 1117 if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !force, force, NULL)) < 0 && r != -EBADR)
e5b5ae50 1118 goto fail;
87f0e418 1119 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i)
542563ba 1120 if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
e5b5ae50
LP
1121 goto fail;
1122
1123 } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
1124
87f0e418 1125 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i)
542563ba 1126 if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
e5b5ae50
LP
1127 goto fail;
1128 }
1129
1130 /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */
1131 }
60918275 1132
c0dafa48
LP
1133 if (_ret)
1134 *_ret = ret;
1135
60918275
LP
1136 return 0;
1137
1138fail:
e5b5ae50
LP
1139 return r;
1140}
1141
87f0e418 1142int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, Job **_ret) {
e5b5ae50
LP
1143 int r;
1144 Job *ret;
1145
1146 assert(m);
1147 assert(type < _JOB_TYPE_MAX);
87f0e418 1148 assert(unit);
e5b5ae50 1149 assert(mode < _JOB_MODE_MAX);
60918275 1150
9f04bd52
LP
1151 log_debug("Trying to enqueue job %s/%s", unit_id(unit), job_type_to_string(type));
1152
c0dafa48 1153 if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, force, &ret)) < 0) {
11dd41ce 1154 transaction_abort(m);
e5b5ae50
LP
1155 return r;
1156 }
11dd41ce 1157
e5b5ae50
LP
1158 if ((r = transaction_activate(m, mode)) < 0)
1159 return r;
1160
c0dafa48 1161 log_debug("Enqueued job %s/%s as %u", unit_id(unit), job_type_to_string(type), (unsigned) ret->id);
f50e0a01 1162
e5b5ae50
LP
1163 if (_ret)
1164 *_ret = ret;
60918275 1165
e5b5ae50
LP
1166 return 0;
1167}
60918275
LP
1168
1169Job *manager_get_job(Manager *m, uint32_t id) {
1170 assert(m);
1171
1172 return hashmap_get(m->jobs, UINT32_TO_PTR(id));
1173}
1174
87f0e418 1175Unit *manager_get_unit(Manager *m, const char *name) {
60918275
LP
1176 assert(m);
1177 assert(name);
1178
87f0e418 1179 return hashmap_get(m->units, name);
60918275
LP
1180}
1181
c1e1601e 1182unsigned manager_dispatch_load_queue(Manager *m) {
60918275 1183 Meta *meta;
c1e1601e 1184 unsigned n = 0;
60918275
LP
1185
1186 assert(m);
1187
223dabab
LP
1188 /* Make sure we are not run recursively */
1189 if (m->dispatching_load_queue)
c1e1601e 1190 return 0;
223dabab
LP
1191
1192 m->dispatching_load_queue = true;
1193
87f0e418 1194 /* Dispatches the load queue. Takes a unit from the queue and
60918275
LP
1195 * tries to load its data until the queue is empty */
1196
1197 while ((meta = m->load_queue)) {
034c6ed7
LP
1198 assert(meta->in_load_queue);
1199
87f0e418 1200 unit_load(UNIT(meta));
c1e1601e 1201 n++;
60918275
LP
1202 }
1203
223dabab 1204 m->dispatching_load_queue = false;
c1e1601e 1205 return n;
60918275
LP
1206}
1207
0301abf4 1208int manager_load_unit(Manager *m, const char *path, Unit **_ret) {
87f0e418 1209 Unit *ret;
60918275 1210 int r;
0301abf4 1211 const char *name;
60918275
LP
1212
1213 assert(m);
0301abf4 1214 assert(path);
60918275 1215 assert(_ret);
60918275 1216
223dabab 1217 /* This will load the service information files, but not actually
0301abf4
LP
1218 * start any services or anything. */
1219
1220 name = file_name_from_path(path);
60918275 1221
87f0e418 1222 if ((ret = manager_get_unit(m, name))) {
034c6ed7
LP
1223 *_ret = ret;
1224 return 0;
1225 }
60918275 1226
87f0e418 1227 if (!(ret = unit_new(m)))
60918275
LP
1228 return -ENOMEM;
1229
0301abf4 1230 if (is_path(path)) {
6be1e7d5 1231 if (!(ret->meta.fragment_path = strdup(path))) {
0301abf4
LP
1232 unit_free(ret);
1233 return -ENOMEM;
1234 }
1235 }
1236
87f0e418
LP
1237 if ((r = unit_add_name(ret, name)) < 0) {
1238 unit_free(ret);
1ffba6fe 1239 return r;
60918275
LP
1240 }
1241
87f0e418 1242 unit_add_to_load_queue(ret);
c1e1601e
LP
1243 unit_add_to_dbus_queue(ret);
1244
f50e0a01 1245 manager_dispatch_load_queue(m);
60918275 1246
60918275
LP
1247 *_ret = ret;
1248 return 0;
1249}
a66d02c3 1250
cea8e32e 1251void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
034c6ed7 1252 Iterator i;
a66d02c3
LP
1253 Job *j;
1254
1255 assert(s);
1256 assert(f);
1257
034c6ed7 1258 HASHMAP_FOREACH(j, s->jobs, i)
cea8e32e 1259 job_dump(j, f, prefix);
a66d02c3
LP
1260}
1261
87f0e418 1262void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
034c6ed7 1263 Iterator i;
87f0e418 1264 Unit *u;
11dd41ce 1265 const char *t;
a66d02c3
LP
1266
1267 assert(s);
1268 assert(f);
1269
87f0e418
LP
1270 HASHMAP_FOREACH_KEY(u, t, s->units, i)
1271 if (unit_id(u) == t)
1272 unit_dump(u, f, prefix);
a66d02c3 1273}
7fad411c
LP
1274
1275void manager_clear_jobs(Manager *m) {
1276 Job *j;
1277
1278 assert(m);
1279
1280 transaction_abort(m);
1281
1282 while ((j = hashmap_first(m->jobs)))
1283 job_free(j);
1284}
83c60c9f 1285
c1e1601e 1286unsigned manager_dispatch_run_queue(Manager *m) {
83c60c9f 1287 Job *j;
c1e1601e 1288 unsigned n = 0;
83c60c9f 1289
034c6ed7 1290 if (m->dispatching_run_queue)
c1e1601e 1291 return 0;
034c6ed7
LP
1292
1293 m->dispatching_run_queue = true;
9152c765 1294
034c6ed7 1295 while ((j = m->run_queue)) {
ac1135be 1296 assert(j->installed);
034c6ed7
LP
1297 assert(j->in_run_queue);
1298
1299 job_run_and_invalidate(j);
c1e1601e 1300 n++;
9152c765 1301 }
034c6ed7
LP
1302
1303 m->dispatching_run_queue = false;
c1e1601e
LP
1304 return n;
1305}
1306
1307unsigned manager_dispatch_dbus_queue(Manager *m) {
1308 Job *j;
1309 Meta *meta;
1310 unsigned n = 0;
1311
1312 assert(m);
1313
1314 if (m->dispatching_dbus_queue)
1315 return 0;
1316
1317 m->dispatching_dbus_queue = true;
1318
1319 while ((meta = m->dbus_unit_queue)) {
1320 Unit *u = (Unit*) meta;
1321 assert(u->meta.in_dbus_queue);
1322
1323 bus_unit_send_change_signal(u);
1324 n++;
1325 }
1326
1327 while ((j = m->dbus_job_queue)) {
1328 assert(j->in_dbus_queue);
1329
1330 bus_job_send_change_signal(j);
1331 n++;
1332 }
1333
1334 m->dispatching_dbus_queue = false;
1335 return n;
9152c765
LP
1336}
1337
034c6ed7 1338static int manager_dispatch_sigchld(Manager *m) {
9152c765
LP
1339 assert(m);
1340
acbb0225
LP
1341 log_debug("dispatching SIGCHLD");
1342
9152c765
LP
1343 for (;;) {
1344 siginfo_t si;
87f0e418 1345 Unit *u;
9152c765
LP
1346
1347 zero(si);
acbb0225
LP
1348 if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG) < 0) {
1349
1350 if (errno == ECHILD)
1351 break;
1352
9152c765 1353 return -errno;
acbb0225 1354 }
9152c765
LP
1355
1356 if (si.si_pid == 0)
1357 break;
1358
034c6ed7
LP
1359 if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED)
1360 continue;
1361
94f04347 1362 log_debug("child %llu died (code=%s, status=%i)", (long long unsigned) si.si_pid, sigchld_code_to_string(si.si_code), si.si_status);
acbb0225 1363
87f0e418 1364 if (!(u = hashmap_remove(m->watch_pids, UINT32_TO_PTR(si.si_pid))))
9152c765
LP
1365 continue;
1366
87f0e418 1367 UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
9152c765
LP
1368 }
1369
1370 return 0;
1371}
1372
b9cd2ec1 1373static int manager_process_signal_fd(Manager *m, bool *quit) {
9152c765
LP
1374 ssize_t n;
1375 struct signalfd_siginfo sfsi;
1376 bool sigchld = false;
1377
1378 assert(m);
1379
1380 for (;;) {
acbb0225 1381 if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
9152c765
LP
1382
1383 if (n >= 0)
1384 return -EIO;
1385
1386 if (errno == EAGAIN)
acbb0225 1387 break;
9152c765
LP
1388
1389 return -errno;
1390 }
1391
b9cd2ec1
LP
1392 switch (sfsi.ssi_signo) {
1393
1394 case SIGCHLD:
9152c765 1395 sigchld = true;
b9cd2ec1
LP
1396 break;
1397
1398 case SIGINT:
6632c602 1399 case SIGTERM:
84e9af1e
LP
1400
1401 if (m->running_as != MANAGER_INIT) {
1402 *quit = true;
1403 return 0;
1404
1405 } else {
1406 Unit *target;
1407 int r;
1408
1409 if ((r = manager_load_unit(m, SPECIAL_CTRL_ALT_DEL_TARGET, &target)) < 0)
1410 log_error("Failed to load ctrl-alt-del target: %s", strerror(-r));
1411 else if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, true, NULL)) < 0)
1412 log_error("Failed to enqueue ctrl-alt-del job: %s", strerror(-r));
1413
1414 break;
1415 }
1416
1417 case SIGWINCH:
1418
1419 if (m->running_as == MANAGER_INIT) {
1420 Unit *target;
1421 int r;
1422
1423 if ((r = manager_load_unit(m, SPECIAL_KBREQUEST_TARGET, &target)) < 0)
1424 log_error("Failed to load kbrequest target: %s", strerror(-r));
1425 else if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, true, NULL)) < 0)
1426 log_error("Failed to enqueue kbrequest job: %s", strerror(-r));
1427
1428 break;
1429 }
1430
1431 /* This is a nop on non-init systemd's */
1432
1433 break;
6632c602
LP
1434
1435 default:
1436 log_info("Got unhandled signal <%s>.", strsignal(sfsi.ssi_signo));
b9cd2ec1 1437 }
9152c765
LP
1438 }
1439
1440 if (sigchld)
034c6ed7
LP
1441 return manager_dispatch_sigchld(m);
1442
1443 return 0;
1444}
1445
b9cd2ec1 1446static int process_event(Manager *m, struct epoll_event *ev, bool *quit) {
034c6ed7 1447 int r;
acbb0225 1448 Watch *w;
034c6ed7
LP
1449
1450 assert(m);
1451 assert(ev);
1452
acbb0225 1453 assert(w = ev->data.ptr);
034c6ed7 1454
acbb0225 1455 switch (w->type) {
034c6ed7 1456
ef734fd6 1457 case WATCH_SIGNAL:
034c6ed7 1458
acbb0225 1459 /* An incoming signal? */
f94ea366 1460 if (ev->events != EPOLLIN)
acbb0225 1461 return -EINVAL;
034c6ed7 1462
b9cd2ec1 1463 if ((r = manager_process_signal_fd(m, quit)) < 0)
acbb0225 1464 return r;
034c6ed7 1465
acbb0225 1466 break;
034c6ed7 1467
acbb0225 1468 case WATCH_FD:
034c6ed7 1469
acbb0225 1470 /* Some fd event, to be dispatched to the units */
ea430986 1471 UNIT_VTABLE(w->data.unit)->fd_event(w->data.unit, w->fd, ev->events, w);
acbb0225 1472 break;
034c6ed7 1473
acbb0225
LP
1474 case WATCH_TIMER: {
1475 uint64_t v;
1476 ssize_t k;
034c6ed7 1477
acbb0225 1478 /* Some timer event, to be dispatched to the units */
be888ebb 1479 if ((k = read(w->fd, &v, sizeof(v))) != sizeof(v)) {
034c6ed7 1480
acbb0225
LP
1481 if (k < 0 && (errno == EINTR || errno == EAGAIN))
1482 break;
034c6ed7 1483
acbb0225 1484 return k < 0 ? -errno : -EIO;
034c6ed7
LP
1485 }
1486
ea430986 1487 UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w);
acbb0225
LP
1488 break;
1489 }
1490
ef734fd6
LP
1491 case WATCH_MOUNT:
1492 /* Some mount table change, intended for the mount subsystem */
1493 mount_fd_event(m, ev->events);
1494 break;
1495
f94ea366
LP
1496 case WATCH_UDEV:
1497 /* Some notification from udev, intended for the device subsystem */
1498 device_fd_event(m, ev->events);
1499 break;
1500
ea430986
LP
1501 case WATCH_DBUS_WATCH:
1502 bus_watch_event(m, w, ev->events);
1503 break;
1504
1505 case WATCH_DBUS_TIMEOUT:
1506 bus_timeout_event(m, w, ev->events);
1507 break;
1508
acbb0225
LP
1509 default:
1510 assert_not_reached("Unknown epoll event type.");
034c6ed7 1511 }
9152c765
LP
1512
1513 return 0;
1514}
1515
1516int manager_loop(Manager *m) {
1517 int r;
b9cd2ec1 1518 bool quit = false;
9152c765 1519
ea430986
LP
1520 RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 1000);
1521
9152c765
LP
1522 assert(m);
1523
1524 for (;;) {
957ca890
LP
1525 struct epoll_event event;
1526 int n;
9152c765 1527
ea430986
LP
1528 if (!ratelimit_test(&rl)) {
1529 /* Yay, something is going seriously wrong, pause a little */
1530 log_warning("Looping too fast. Throttling execution a little.");
1531 sleep(1);
1532 }
1533
c1e1601e
LP
1534 if (manager_dispatch_load_queue(m) > 0)
1535 continue;
034c6ed7 1536
c1e1601e
LP
1537 if (manager_dispatch_run_queue(m) > 0)
1538 continue;
1539
1540 if (bus_dispatch(m) > 0)
1541 continue;
1542
1543 if (manager_dispatch_dbus_queue(m) > 0)
ea430986 1544 continue;
ea430986 1545
957ca890 1546 if ((n = epoll_wait(m->epoll_fd, &event, 1, -1)) < 0) {
9152c765
LP
1547
1548 if (errno == -EINTR)
1549 continue;
1550
1551 return -errno;
1552 }
1553
957ca890 1554 assert(n == 1);
b9cd2ec1 1555
957ca890
LP
1556 if ((r = process_event(m, &event, &quit)) < 0)
1557 return r;
1558
1559 if (quit)
1560 return 0;
83c60c9f
LP
1561 }
1562}
ea430986
LP
1563
1564int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u) {
1565 char *n;
1566 Unit *u;
1567
1568 assert(m);
1569 assert(s);
1570 assert(_u);
1571
1572 if (!startswith(s, "/org/freedesktop/systemd1/unit/"))
1573 return -EINVAL;
1574
1575 if (!(n = bus_path_unescape(s+31)))
1576 return -ENOMEM;
1577
1578 u = manager_get_unit(m, n);
1579 free(n);
1580
1581 if (!u)
1582 return -ENOENT;
1583
1584 *_u = u;
1585
1586 return 0;
1587}
86fbf370
LP
1588
1589int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
1590 Job *j;
1591 unsigned id;
1592 int r;
1593
1594 assert(m);
1595 assert(s);
1596 assert(_j);
1597
1598 if (!startswith(s, "/org/freedesktop/systemd1/job/"))
1599 return -EINVAL;
1600
1601 if ((r = safe_atou(s + 30, &id)) < 0)
1602 return r;
1603
1604 if (!(j = manager_get_job(m, id)))
1605 return -ENOENT;
1606
1607 *_j = j;
1608
1609 return 0;
1610}
dfcd764e
LP
1611
1612static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
1613 [MANAGER_INIT] = "init",
1614 [MANAGER_SYSTEM] = "system",
036643a2 1615 [MANAGER_SESSION] = "session"
dfcd764e
LP
1616};
1617
1618DEFINE_STRING_TABLE_LOOKUP(manager_running_as, ManagerRunningAs);