]> git.ipfire.org Git - people/ms/systemd.git/blame - manager.c
add mount enumerator
[people/ms/systemd.git] / manager.c
CommitLineData
60918275
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3#include <assert.h>
4#include <errno.h>
87d1515d 5#include <string.h>
9152c765
LP
6#include <sys/epoll.h>
7#include <signal.h>
8#include <sys/signalfd.h>
9#include <sys/wait.h>
10#include <unistd.h>
11#include <sys/poll.h>
60918275
LP
12
13#include "manager.h"
14#include "hashmap.h"
15#include "macro.h"
16#include "strv.h"
16354eff 17#include "log.h"
2a987ee8 18#include "util.h"
60918275 19
ce578209
LP
20static const char * const special_table[_SPECIAL_UNIT_MAX] = {
21 [SPECIAL_SYSLOG_SERVICE] = "syslog.service",
22 [SPECIAL_DBUS_SERVICE] = "messagebus.service",
98b5b298
LP
23 [SPECIAL_LOGGER_SOCKET] = "systemd-logger.socket",
24 [SPECIAL_KBREQUEST_TARGET] = "kbrequest.target",
25 [SPECIAL_CTRL_ALT_DEL_TARGET] = "ctrl-alt-del.target"
ce578209
LP
26};
27
28static int manager_setup_signals(Manager *m) {
9152c765
LP
29 sigset_t mask;
30 struct epoll_event ev;
60918275 31
ce578209
LP
32 assert(m);
33
34 assert_se(reset_all_signal_handlers() == 0);
35
36 assert_se(sigemptyset(&mask) == 0);
37 assert_se(sigaddset(&mask, SIGCHLD) == 0);
38 assert_se(sigaddset(&mask, SIGINT) == 0); /* Kernel sends us this on control-alt-del */
39 assert_se(sigaddset(&mask, SIGWINCH) == 0); /* Kernel sends us this on kbrequest (alt-arrowup) */
40 assert_se(sigaddset(&mask, SIGTERM) == 0);
41 assert_se(sigaddset(&mask, SIGHUP) == 0);
42 assert_se(sigaddset(&mask, SIGUSR1) == 0);
43 assert_se(sigaddset(&mask, SIGUSR2) == 0);
44 assert_se(sigaddset(&mask, SIGPIPE) == 0);
45 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
46
47 m->signal_watch.type = WATCH_SIGNAL_FD;
48 if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0)
49 return -errno;
50
51 zero(ev);
52 ev.events = EPOLLIN;
53 ev.data.ptr = &m->signal_watch;
54
55 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
56 return -errno;
57
58 return 0;
59}
60
61static int manager_load_special_units(Manager *m) {
62 SpecialUnit c;
63 int r;
64
65 assert(m);
66
67 /* Loads all 'special' units, so that we have easy access to them later */
68
69 for (c = 0; c < _SPECIAL_UNIT_MAX; c++)
70 if ((r = manager_load_unit(m, special_table[c], m->special_units+c)) < 0)
71 return r;
72
73 return 0;
7824bbeb
LP
74}
75
76static int manager_enumerate(Manager *m) {
77 int r;
78 UnitType c;
79
80 assert(m);
81
82 for (c = 0; c < _UNIT_TYPE_MAX; c++)
83 if (unit_vtable[c]->enumerate)
84 if ((r = unit_vtable[c]->enumerate(m)) < 0)
85 return r;
86
87 return 0;
88}
ce578209
LP
89
90Manager* manager_new(void) {
91 Manager *m;
92
60918275
LP
93 if (!(m = new0(Manager, 1)))
94 return NULL;
95
acbb0225 96 m->signal_watch.fd = m->epoll_fd = -1;
9152c765 97
87f0e418 98 if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
60918275
LP
99 goto fail;
100
101 if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
102 goto fail;
103
e5b5ae50 104 if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
60918275
LP
105 goto fail;
106
9152c765
LP
107 if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
108 goto fail;
109
110 if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
111 goto fail;
112
ce578209 113 if (manager_setup_signals(m) < 0)
9152c765
LP
114 goto fail;
115
ce578209 116 if (manager_load_special_units(m) < 0)
9152c765
LP
117 goto fail;
118
7824bbeb
LP
119 if (manager_enumerate(m) < 0)
120 goto fail;
121
60918275
LP
122 return m;
123
124fail:
125 manager_free(m);
126 return NULL;
127}
128
129void manager_free(Manager *m) {
7824bbeb 130 UnitType c;
87f0e418 131 Unit *u;
e5b5ae50 132 Job *j;
60918275
LP
133
134 assert(m);
135
87f0e418 136 while ((j = hashmap_first(m->transaction_jobs)))
e5b5ae50
LP
137 job_free(j);
138
87f0e418
LP
139 while ((u = hashmap_first(m->units)))
140 unit_free(u);
141
7824bbeb
LP
142 for (c = 0; c < _UNIT_TYPE_MAX; c++)
143 if (unit_vtable[c]->shutdown)
144 unit_vtable[c]->shutdown(m);
145
87f0e418 146 hashmap_free(m->units);
60918275 147 hashmap_free(m->jobs);
e5b5ae50 148 hashmap_free(m->transaction_jobs);
9152c765
LP
149 hashmap_free(m->watch_pids);
150
151 if (m->epoll_fd >= 0)
152 close_nointr(m->epoll_fd);
acbb0225
LP
153 if (m->signal_watch.fd >= 0)
154 close_nointr(m->signal_watch.fd);
60918275
LP
155
156 free(m);
157}
158
302d0040
LP
159static void transaction_delete_job(Manager *m, Job *j) {
160 assert(m);
161 assert(j);
162
1ffba6fe
LP
163 /* Deletes one job from the transaction */
164
302d0040
LP
165 manager_transaction_unlink_job(m, j);
166
ac1135be 167 if (!j->installed)
302d0040
LP
168 job_free(j);
169}
170
87f0e418 171static void transaction_delete_unit(Manager *m, Unit *u) {
1ffba6fe
LP
172 Job *j;
173
87f0e418 174 /* Deletes all jobs associated with a certain unit from the
1ffba6fe
LP
175 * transaction */
176
87f0e418 177 while ((j = hashmap_get(m->transaction_jobs, u)))
1ffba6fe
LP
178 transaction_delete_job(m, j);
179}
180
f04fa1d5
LP
181static void transaction_clean_dependencies(Manager *m) {
182 Iterator i;
183 Job *j;
184
185 assert(m);
186
187 /* Drops all dependencies of all installed jobs */
188
189 HASHMAP_FOREACH(j, m->jobs, i) {
190 while (j->subject_list)
191 job_dependency_free(j->subject_list);
192 while (j->object_list)
193 job_dependency_free(j->object_list);
194 }
195
196 assert(!m->transaction_anchor);
197}
198
11dd41ce
LP
199static void transaction_abort(Manager *m) {
200 Job *j;
201
202 assert(m);
11dd41ce 203
e5b5ae50 204 while ((j = hashmap_first(m->transaction_jobs)))
ac1135be 205 if (j->installed)
302d0040 206 transaction_delete_job(m, j);
e5b5ae50
LP
207 else
208 job_free(j);
209
210 assert(hashmap_isempty(m->transaction_jobs));
f04fa1d5
LP
211
212 transaction_clean_dependencies(m);
e5b5ae50
LP
213}
214
215static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsigned generation) {
216 JobDependency *l;
217
218 assert(m);
219
87f0e418 220 /* A recursive sweep through the graph that marks all units
1ffba6fe
LP
221 * that matter to the anchor job, i.e. are directly or
222 * indirectly a dependency of the anchor job via paths that
223 * are fully marked as mattering. */
224
44d8db9e
LP
225 if (j)
226 l = j->subject_list;
227 else
228 l = m->transaction_anchor;
229
230 LIST_FOREACH(subject, l, l) {
e5b5ae50
LP
231
232 /* This link does not matter */
233 if (!l->matters)
234 continue;
235
87f0e418 236 /* This unit has already been marked */
e5b5ae50
LP
237 if (l->object->generation == generation)
238 continue;
239
240 l->object->matters_to_anchor = true;
241 l->object->generation = generation;
242
243 transaction_find_jobs_that_matter_to_anchor(m, l->object, generation);
244 }
245}
246
7fad411c 247static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, JobType t) {
e5b5ae50
LP
248 JobDependency *l, *last;
249
250 assert(j);
251 assert(other);
87f0e418 252 assert(j->unit == other->unit);
ac1135be 253 assert(!j->installed);
e5b5ae50 254
1ffba6fe
LP
255 /* Merges 'other' into 'j' and then deletes j. */
256
e5b5ae50
LP
257 j->type = t;
258 j->state = JOB_WAITING;
5cb5a6ff 259 j->forced = j->forced || other->forced;
e5b5ae50
LP
260
261 j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
262
263 /* Patch us in as new owner of the JobDependency objects */
264 last = NULL;
44d8db9e 265 LIST_FOREACH(subject, l, other->subject_list) {
e5b5ae50
LP
266 assert(l->subject == other);
267 l->subject = j;
268 last = l;
269 }
270
271 /* Merge both lists */
272 if (last) {
273 last->subject_next = j->subject_list;
274 if (j->subject_list)
275 j->subject_list->subject_prev = last;
276 j->subject_list = other->subject_list;
277 }
278
279 /* Patch us in as new owner of the JobDependency objects */
280 last = NULL;
44d8db9e 281 LIST_FOREACH(object, l, other->object_list) {
e5b5ae50
LP
282 assert(l->object == other);
283 l->object = j;
284 last = l;
285 }
286
287 /* Merge both lists */
288 if (last) {
289 last->object_next = j->object_list;
290 if (j->object_list)
291 j->object_list->object_prev = last;
292 j->object_list = other->object_list;
293 }
294
e5b5ae50
LP
295 /* Kill the other job */
296 other->subject_list = NULL;
297 other->object_list = NULL;
302d0040 298 transaction_delete_job(m, other);
e5b5ae50
LP
299}
300
5cb5a6ff 301static int delete_one_unmergeable_job(Manager *m, Job *j) {
1ffba6fe
LP
302 Job *k;
303
304 assert(j);
305
306 /* Tries to delete one item in the linked list
307 * j->transaction_next->transaction_next->... that conflicts
308 * whith another one, in an attempt to make an inconsistent
309 * transaction work. */
310
311 /* We rely here on the fact that if a merged with b does not
312 * merge with c, either a or b merge with c neither */
034c6ed7
LP
313 LIST_FOREACH(transaction, j, j)
314 LIST_FOREACH(transaction, k, j->transaction_next) {
1ffba6fe
LP
315 Job *d;
316
317 /* Is this one mergeable? Then skip it */
5cb5a6ff 318 if (job_type_is_mergeable(j->type, k->type))
1ffba6fe
LP
319 continue;
320
321 /* Ok, we found two that conflict, let's see if we can
322 * drop one of them */
323 if (!j->matters_to_anchor)
324 d = j;
325 else if (!k->matters_to_anchor)
326 d = k;
327 else
328 return -ENOEXEC;
329
330 /* Ok, we can drop one, so let's do so. */
87f0e418 331 log_debug("Try to fix job merging by deleting job %s/%s", unit_id(d->unit), job_type_to_string(d->type));
1ffba6fe
LP
332 transaction_delete_job(m, d);
333 return 0;
334 }
335
336 return -EINVAL;
337}
338
e5b5ae50 339static int transaction_merge_jobs(Manager *m) {
11dd41ce 340 Job *j;
034c6ed7 341 Iterator i;
e5b5ae50
LP
342 int r;
343
344 assert(m);
345
1ffba6fe
LP
346 /* First step, check whether any of the jobs for one specific
347 * task conflict. If so, try to drop one of them. */
034c6ed7 348 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1ffba6fe
LP
349 JobType t;
350 Job *k;
351
352 t = j->type;
034c6ed7 353 LIST_FOREACH(transaction, k, j->transaction_next) {
1ffba6fe
LP
354 if ((r = job_type_merge(&t, k->type)) >= 0)
355 continue;
356
357 /* OK, we could not merge all jobs for this
358 * action. Let's see if we can get rid of one
359 * of them */
360
5cb5a6ff 361 if ((r = delete_one_unmergeable_job(m, j)) >= 0)
1ffba6fe
LP
362 /* Ok, we managed to drop one, now
363 * let's ask our callers to call us
364 * again after garbage collecting */
365 return -EAGAIN;
366
367 /* We couldn't merge anything. Failure */
368 return r;
369 }
370 }
371
372 /* Second step, merge the jobs. */
034c6ed7 373 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e5b5ae50
LP
374 JobType t = j->type;
375 Job *k;
376
e094e853 377 /* Merge all transactions */
034c6ed7 378 LIST_FOREACH(transaction, k, j->transaction_next)
1ffba6fe 379 assert_se(job_type_merge(&t, k->type) == 0);
e5b5ae50 380
5cb5a6ff 381 /* If an active job is mergeable, merge it too */
87f0e418
LP
382 if (j->unit->meta.job)
383 job_type_merge(&t, j->unit->meta.job->type); /* Might fail. Which is OK */
e094e853 384
e5b5ae50 385 while ((k = j->transaction_next)) {
ac1135be 386 if (j->installed) {
7fad411c 387 transaction_merge_and_delete_job(m, k, j, t);
e5b5ae50
LP
388 j = k;
389 } else
7fad411c 390 transaction_merge_and_delete_job(m, j, k, t);
e5b5ae50
LP
391 }
392
393 assert(!j->transaction_next);
394 assert(!j->transaction_prev);
395 }
396
7fad411c 397 return 0;
e5b5ae50
LP
398}
399
87f0e418
LP
400static bool unit_matters_to_anchor(Unit *u, Job *j) {
401 assert(u);
1ffba6fe
LP
402 assert(!j->transaction_prev);
403
87f0e418 404 /* Checks whether at least one of the jobs for this unit
1ffba6fe
LP
405 * matters to the anchor. */
406
034c6ed7 407 LIST_FOREACH(transaction, j, j)
1ffba6fe
LP
408 if (j->matters_to_anchor)
409 return true;
410
411 return false;
412}
413
e5b5ae50 414static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned generation) {
034c6ed7 415 Iterator i;
87f0e418 416 Unit *u;
11dd41ce 417 int r;
e5b5ae50
LP
418
419 assert(m);
420 assert(j);
1ffba6fe
LP
421 assert(!j->transaction_prev);
422
423 /* Does a recursive sweep through the ordering graph, looking
424 * for a cycle. If we find cycle we try to break it. */
e5b5ae50 425
7fad411c 426 /* Did we find a cycle? */
e5b5ae50
LP
427 if (j->marker && j->generation == generation) {
428 Job *k;
429
430 /* So, we already have been here. We have a
1ffba6fe
LP
431 * cycle. Let's try to break it. We go backwards in
432 * our path and try to find a suitable job to
433 * remove. We use the marker to find our way back,
434 * since smart how we are we stored our way back in
435 * there. */
e5b5ae50
LP
436
437 for (k = from; k; k = (k->generation == generation ? k->marker : NULL)) {
1ffba6fe 438
ac1135be 439 if (!k->installed &&
87f0e418 440 !unit_matters_to_anchor(k->unit, k)) {
1ffba6fe
LP
441 /* Ok, we can drop this one, so let's
442 * do so. */
87f0e418
LP
443 log_debug("Breaking order cycle by deleting job %s/%s", unit_id(k->unit), job_type_to_string(k->type));
444 transaction_delete_unit(m, k->unit);
e5b5ae50
LP
445 return -EAGAIN;
446 }
447
448 /* Check if this in fact was the beginning of
7fad411c 449 * the cycle */
e5b5ae50
LP
450 if (k == j)
451 break;
452 }
453
1ffba6fe 454 return -ENOEXEC;
e5b5ae50
LP
455 }
456
1ffba6fe
LP
457 /* Make the marker point to where we come from, so that we can
458 * find our way backwards if we want to break a cycle */
e5b5ae50
LP
459 j->marker = from;
460 j->generation = generation;
461
1ffba6fe 462 /* We assume that the the dependencies are bidirectional, and
87f0e418
LP
463 * hence can ignore UNIT_AFTER */
464 SET_FOREACH(u, j->unit->meta.dependencies[UNIT_BEFORE], i) {
e5b5ae50
LP
465 Job *o;
466
87f0e418
LP
467 /* Is there a job for this unit? */
468 if (!(o = hashmap_get(m->transaction_jobs, u)))
1ffba6fe
LP
469
470 /* Ok, there is no job for this in the
471 * transaction, but maybe there is already one
472 * running? */
87f0e418 473 if (!(o = u->meta.job))
e5b5ae50
LP
474 continue;
475
476 if ((r = transaction_verify_order_one(m, o, j, generation)) < 0)
477 return r;
478 }
479
480 return 0;
481}
482
483static int transaction_verify_order(Manager *m, unsigned *generation) {
1ffba6fe
LP
484 Job *j;
485 int r;
034c6ed7 486 Iterator i;
1ffba6fe 487
e5b5ae50
LP
488 assert(m);
489 assert(generation);
490
1ffba6fe
LP
491 /* Check if the ordering graph is cyclic. If it is, try to fix
492 * that up by dropping one of the jobs. */
e5b5ae50 493
034c6ed7 494 HASHMAP_FOREACH(j, m->transaction_jobs, i)
1ffba6fe
LP
495 if ((r = transaction_verify_order_one(m, j, NULL, (*generation)++)) < 0)
496 return r;
e5b5ae50
LP
497
498 return 0;
499}
500
501static void transaction_collect_garbage(Manager *m) {
502 bool again;
503
504 assert(m);
505
1ffba6fe
LP
506 /* Drop jobs that are not required by any other job */
507
e5b5ae50 508 do {
034c6ed7 509 Iterator i;
e5b5ae50
LP
510 Job *j;
511
512 again = false;
513
034c6ed7 514 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e5b5ae50
LP
515 if (j->object_list)
516 continue;
517
87f0e418 518 log_debug("Garbage collecting job %s/%s", unit_id(j->unit), job_type_to_string(j->type));
302d0040 519 transaction_delete_job(m, j);
e5b5ae50
LP
520 again = true;
521 break;
522 }
523
524 } while (again);
525}
526
527static int transaction_is_destructive(Manager *m, JobMode mode) {
034c6ed7 528 Iterator i;
e5b5ae50 529 Job *j;
11dd41ce
LP
530
531 assert(m);
11dd41ce 532
e5b5ae50
LP
533 /* Checks whether applying this transaction means that
534 * existing jobs would be replaced */
11dd41ce 535
034c6ed7 536 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e094e853
LP
537
538 /* Assume merged */
539 assert(!j->transaction_prev);
540 assert(!j->transaction_next);
541
87f0e418
LP
542 if (j->unit->meta.job &&
543 j->unit->meta.job != j &&
544 !job_type_is_superset(j->type, j->unit->meta.job->type))
e5b5ae50 545 return -EEXIST;
e094e853 546 }
11dd41ce 547
e5b5ae50
LP
548 return 0;
549}
550
e094e853
LP
551static void transaction_minimize_impact(Manager *m) {
552 bool again;
553 assert(m);
554
555 /* Drops all unnecessary jobs that reverse already active jobs
556 * or that stop a running service. */
557
558 do {
559 Job *j;
034c6ed7 560 Iterator i;
e094e853
LP
561
562 again = false;
563
034c6ed7
LP
564 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
565 LIST_FOREACH(transaction, j, j) {
e094e853
LP
566
567 /* If it matters, we shouldn't drop it */
568 if (j->matters_to_anchor)
569 continue;
570
571 /* Would this stop a running service?
572 * Would this change an existing job?
573 * If so, let's drop this entry */
87f0e418
LP
574 if ((j->type != JOB_STOP || UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j->unit))) &&
575 (!j->unit->meta.job || job_type_is_conflicting(j->type, j->unit->meta.job->state)))
e094e853
LP
576 continue;
577
578 /* Ok, let's get rid of this */
87f0e418 579 log_debug("Deleting %s/%s to minimize impact", unit_id(j->unit), job_type_to_string(j->type));
e094e853
LP
580 transaction_delete_job(m, j);
581 again = true;
582 break;
583 }
584
585 if (again)
586 break;
587 }
588
589 } while (again);
590}
591
e5b5ae50 592static int transaction_apply(Manager *m, JobMode mode) {
034c6ed7 593 Iterator i;
e5b5ae50
LP
594 Job *j;
595 int r;
596
1ffba6fe
LP
597 /* Moves the transaction jobs to the set of active jobs */
598
034c6ed7 599 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
e094e853
LP
600 /* Assume merged */
601 assert(!j->transaction_prev);
602 assert(!j->transaction_next);
603
ac1135be 604 if (j->installed)
e5b5ae50
LP
605 continue;
606
607 if ((r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j)) < 0)
11dd41ce
LP
608 goto rollback;
609 }
610
e5b5ae50 611 while ((j = hashmap_steal_first(m->transaction_jobs))) {
ac1135be 612 if (j->installed)
e5b5ae50
LP
613 continue;
614
87f0e418
LP
615 if (j->unit->meta.job)
616 job_free(j->unit->meta.job);
11dd41ce 617
87f0e418 618 j->unit->meta.job = j;
ac1135be 619 j->installed = true;
11dd41ce 620
e5b5ae50
LP
621 /* We're fully installed. Now let's free data we don't
622 * need anymore. */
623
624 assert(!j->transaction_next);
625 assert(!j->transaction_prev);
626
acbb0225 627 job_schedule_run(j);
01184e04
LP
628 }
629
630 /* As last step, kill all remaining job dependencies. */
f04fa1d5 631 transaction_clean_dependencies(m);
1ffba6fe 632
11dd41ce
LP
633 return 0;
634
635rollback:
636
034c6ed7 637 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
ac1135be 638 if (j->installed)
e5b5ae50
LP
639 continue;
640
641 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
642 }
643
644 return r;
645}
646
e5b5ae50
LP
647static int transaction_activate(Manager *m, JobMode mode) {
648 int r;
649 unsigned generation = 1;
650
651 assert(m);
652
653 /* This applies the changes recorded in transaction_jobs to
654 * the actual list of jobs, if possible. */
655
656 /* First step: figure out which jobs matter */
657 transaction_find_jobs_that_matter_to_anchor(m, NULL, generation++);
658
e094e853
LP
659 /* Second step: Try not to stop any running services if
660 * we don't have to. Don't try to reverse running
661 * jobs if we don't have to. */
662 transaction_minimize_impact(m);
663
1ffba6fe 664 for (;;) {
e094e853 665 /* Third step: Let's remove unneeded jobs that might
1ffba6fe
LP
666 * be lurking. */
667 transaction_collect_garbage(m);
e5b5ae50 668
e094e853 669 /* Fourth step: verify order makes sense and correct
1ffba6fe
LP
670 * cycles if necessary and possible */
671 if ((r = transaction_verify_order(m, &generation)) >= 0)
672 break;
e5b5ae50 673
1ffba6fe
LP
674 if (r != -EAGAIN)
675 goto rollback;
e5b5ae50 676
1ffba6fe
LP
677 /* Let's see if the resulting transaction ordering
678 * graph is still cyclic... */
679 }
680
681 for (;;) {
5cb5a6ff 682 /* Fifth step: let's drop unmergeable entries if
1ffba6fe
LP
683 * necessary and possible, merge entries we can
684 * merge */
685 if ((r = transaction_merge_jobs(m)) >= 0)
686 break;
687
688 if (r != -EAGAIN)
689 goto rollback;
690
e094e853 691 /* Sixth step: an entry got dropped, let's garbage
1ffba6fe
LP
692 * collect its dependencies. */
693 transaction_collect_garbage(m);
694
695 /* Let's see if the resulting transaction still has
5cb5a6ff 696 * unmergeable entries ... */
1ffba6fe
LP
697 }
698
e094e853 699 /* Seventh step: check whether we can actually apply this */
e5b5ae50
LP
700 if (mode == JOB_FAIL)
701 if ((r = transaction_is_destructive(m, mode)) < 0)
702 goto rollback;
703
e094e853 704 /* Eights step: apply changes */
e5b5ae50
LP
705 if ((r = transaction_apply(m, mode)) < 0)
706 goto rollback;
707
708 assert(hashmap_isempty(m->transaction_jobs));
709 assert(!m->transaction_anchor);
710
711 return 0;
11dd41ce 712
e5b5ae50 713rollback:
11dd41ce
LP
714 transaction_abort(m);
715 return r;
716}
717
87f0e418 718static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool force, bool *is_new) {
e5b5ae50 719 Job *j, *f;
60918275
LP
720 int r;
721
722 assert(m);
87f0e418 723 assert(unit);
60918275 724
e5b5ae50
LP
725 /* Looks for an axisting prospective job and returns that. If
726 * it doesn't exist it is created and added to the prospective
727 * jobs list. */
60918275 728
87f0e418 729 f = hashmap_get(m->transaction_jobs, unit);
60918275 730
034c6ed7 731 LIST_FOREACH(transaction, j, f) {
87f0e418 732 assert(j->unit == unit);
60918275 733
e5b5ae50
LP
734 if (j->type == type) {
735 if (is_new)
736 *is_new = false;
737 return j;
738 }
739 }
60918275 740
87f0e418
LP
741 if (unit->meta.job && unit->meta.job->type == type)
742 j = unit->meta.job;
743 else if (!(j = job_new(m, type, unit)))
e5b5ae50 744 return NULL;
60918275 745
e5b5ae50
LP
746 j->generation = 0;
747 j->marker = NULL;
748 j->matters_to_anchor = false;
5cb5a6ff 749 j->forced = force;
60918275 750
034c6ed7
LP
751 LIST_PREPEND(Job, transaction, f, j);
752
87f0e418 753 if ((r = hashmap_replace(m->transaction_jobs, unit, f)) < 0) {
034c6ed7
LP
754 job_free(j);
755 return NULL;
756 }
757
e5b5ae50
LP
758 if (is_new)
759 *is_new = true;
60918275 760
e5b5ae50
LP
761 return j;
762}
11dd41ce 763
302d0040 764void manager_transaction_unlink_job(Manager *m, Job *j) {
e5b5ae50
LP
765 assert(m);
766 assert(j);
11dd41ce 767
e5b5ae50
LP
768 if (j->transaction_prev)
769 j->transaction_prev->transaction_next = j->transaction_next;
770 else if (j->transaction_next)
87f0e418 771 hashmap_replace(m->transaction_jobs, j->unit, j->transaction_next);
e5b5ae50 772 else
87f0e418 773 hashmap_remove_value(m->transaction_jobs, j->unit, j);
e5b5ae50
LP
774
775 if (j->transaction_next)
776 j->transaction_next->transaction_prev = j->transaction_prev;
777
778 j->transaction_prev = j->transaction_next = NULL;
779
780 while (j->subject_list)
781 job_dependency_free(j->subject_list);
1e198baf
LP
782
783 while (j->object_list) {
784 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
785
e5b5ae50 786 job_dependency_free(j->object_list);
1e198baf
LP
787
788 if (other) {
5cb5a6ff 789 log_debug("Deleting job %s/%s as dependency of job %s/%s",
87f0e418
LP
790 unit_id(other->unit), job_type_to_string(other->type),
791 unit_id(j->unit), job_type_to_string(j->type));
302d0040 792 transaction_delete_job(m, other);
1e198baf
LP
793 }
794 }
e5b5ae50
LP
795}
796
87f0e418 797static int transaction_add_job_and_dependencies(Manager *m, JobType type, Unit *unit, Job *by, bool matters, bool force, Job **_ret) {
e5b5ae50 798 Job *ret;
034c6ed7 799 Iterator i;
87f0e418 800 Unit *dep;
e5b5ae50
LP
801 int r;
802 bool is_new;
803
804 assert(m);
805 assert(type < _JOB_TYPE_MAX);
87f0e418 806 assert(unit);
e5b5ae50 807
87f0e418 808 if (unit->meta.load_state != UNIT_LOADED)
21b293e8
LP
809 return -EINVAL;
810
87f0e418 811 if (!unit_job_is_applicable(unit, type))
cd2dbd7d
LP
812 return -EBADR;
813
e5b5ae50 814 /* First add the job. */
87f0e418 815 if (!(ret = transaction_add_one_job(m, type, unit, force, &is_new)))
e5b5ae50
LP
816 return -ENOMEM;
817
818 /* Then, add a link to the job. */
819 if (!job_dependency_new(by, ret, matters))
820 return -ENOMEM;
821
822 if (is_new) {
823 /* Finally, recursively add in all dependencies. */
824 if (type == JOB_START || type == JOB_RELOAD_OR_START) {
87f0e418 825 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i)
542563ba 826 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
e5b5ae50 827 goto fail;
87f0e418 828 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_SOFT_REQUIRES], i)
542563ba 829 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !force, force, NULL)) < 0 && r != -EBADR)
e5b5ae50 830 goto fail;
87f0e418 831 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i)
542563ba 832 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, force, NULL)) < 0 && r != -EBADR)
e5b5ae50 833 goto fail;
87f0e418 834 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i)
542563ba 835 if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
e5b5ae50 836 goto fail;
87f0e418 837 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_SOFT_REQUISITE], i)
542563ba 838 if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !force, force, NULL)) < 0 && r != -EBADR)
e5b5ae50 839 goto fail;
87f0e418 840 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i)
542563ba 841 if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
e5b5ae50
LP
842 goto fail;
843
844 } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
845
87f0e418 846 SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i)
542563ba 847 if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
e5b5ae50
LP
848 goto fail;
849 }
850
851 /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */
852 }
60918275
LP
853
854 return 0;
855
856fail:
e5b5ae50
LP
857 return r;
858}
859
87f0e418 860int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, Job **_ret) {
e5b5ae50
LP
861 int r;
862 Job *ret;
863
864 assert(m);
865 assert(type < _JOB_TYPE_MAX);
87f0e418 866 assert(unit);
e5b5ae50 867 assert(mode < _JOB_MODE_MAX);
60918275 868
87f0e418 869 if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, force, &ret))) {
11dd41ce 870 transaction_abort(m);
e5b5ae50
LP
871 return r;
872 }
11dd41ce 873
e5b5ae50
LP
874 if ((r = transaction_activate(m, mode)) < 0)
875 return r;
876
877 if (_ret)
878 *_ret = ret;
60918275 879
e5b5ae50
LP
880 return 0;
881}
60918275
LP
882
883Job *manager_get_job(Manager *m, uint32_t id) {
884 assert(m);
885
886 return hashmap_get(m->jobs, UINT32_TO_PTR(id));
887}
888
87f0e418 889Unit *manager_get_unit(Manager *m, const char *name) {
60918275
LP
890 assert(m);
891 assert(name);
892
87f0e418 893 return hashmap_get(m->units, name);
60918275
LP
894}
895
034c6ed7 896static void dispatch_load_queue(Manager *m) {
60918275
LP
897 Meta *meta;
898
899 assert(m);
900
223dabab
LP
901 /* Make sure we are not run recursively */
902 if (m->dispatching_load_queue)
034c6ed7 903 return;
223dabab
LP
904
905 m->dispatching_load_queue = true;
906
87f0e418 907 /* Dispatches the load queue. Takes a unit from the queue and
60918275
LP
908 * tries to load its data until the queue is empty */
909
910 while ((meta = m->load_queue)) {
034c6ed7
LP
911 assert(meta->in_load_queue);
912
87f0e418 913 unit_load(UNIT(meta));
60918275
LP
914 }
915
223dabab 916 m->dispatching_load_queue = false;
60918275
LP
917}
918
0301abf4 919int manager_load_unit(Manager *m, const char *path, Unit **_ret) {
87f0e418 920 Unit *ret;
60918275 921 int r;
0301abf4 922 const char *name;
60918275
LP
923
924 assert(m);
0301abf4 925 assert(path);
60918275 926 assert(_ret);
60918275 927
223dabab 928 /* This will load the service information files, but not actually
0301abf4
LP
929 * start any services or anything. */
930
931 name = file_name_from_path(path);
60918275 932
87f0e418 933 if ((ret = manager_get_unit(m, name))) {
034c6ed7
LP
934 *_ret = ret;
935 return 0;
936 }
60918275 937
87f0e418 938 if (!(ret = unit_new(m)))
60918275
LP
939 return -ENOMEM;
940
0301abf4
LP
941 if (is_path(path)) {
942 if (!(ret->meta.load_path = strdup(path))) {
943 unit_free(ret);
944 return -ENOMEM;
945 }
946 }
947
87f0e418
LP
948 if ((r = unit_add_name(ret, name)) < 0) {
949 unit_free(ret);
1ffba6fe 950 return r;
60918275
LP
951 }
952
87f0e418 953 unit_add_to_load_queue(ret);
60918275
LP
954 dispatch_load_queue(m);
955
60918275
LP
956 *_ret = ret;
957 return 0;
958}
a66d02c3 959
cea8e32e 960void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
034c6ed7 961 Iterator i;
a66d02c3
LP
962 Job *j;
963
964 assert(s);
965 assert(f);
966
034c6ed7 967 HASHMAP_FOREACH(j, s->jobs, i)
cea8e32e 968 job_dump(j, f, prefix);
a66d02c3
LP
969}
970
87f0e418 971void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
034c6ed7 972 Iterator i;
87f0e418 973 Unit *u;
11dd41ce 974 const char *t;
a66d02c3
LP
975
976 assert(s);
977 assert(f);
978
87f0e418
LP
979 HASHMAP_FOREACH_KEY(u, t, s->units, i)
980 if (unit_id(u) == t)
981 unit_dump(u, f, prefix);
a66d02c3 982}
7fad411c
LP
983
984void manager_clear_jobs(Manager *m) {
985 Job *j;
986
987 assert(m);
988
989 transaction_abort(m);
990
991 while ((j = hashmap_first(m->jobs)))
992 job_free(j);
993}
83c60c9f 994
034c6ed7 995void manager_dispatch_run_queue(Manager *m) {
83c60c9f 996 Job *j;
83c60c9f 997
034c6ed7
LP
998 if (m->dispatching_run_queue)
999 return;
1000
1001 m->dispatching_run_queue = true;
9152c765 1002
034c6ed7 1003 while ((j = m->run_queue)) {
ac1135be 1004 assert(j->installed);
034c6ed7
LP
1005 assert(j->in_run_queue);
1006
1007 job_run_and_invalidate(j);
9152c765 1008 }
034c6ed7
LP
1009
1010 m->dispatching_run_queue = false;
9152c765
LP
1011}
1012
034c6ed7 1013static int manager_dispatch_sigchld(Manager *m) {
9152c765
LP
1014 assert(m);
1015
acbb0225
LP
1016 log_debug("dispatching SIGCHLD");
1017
9152c765
LP
1018 for (;;) {
1019 siginfo_t si;
87f0e418 1020 Unit *u;
9152c765
LP
1021
1022 zero(si);
acbb0225
LP
1023 if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG) < 0) {
1024
1025 if (errno == ECHILD)
1026 break;
1027
9152c765 1028 return -errno;
acbb0225 1029 }
9152c765
LP
1030
1031 if (si.si_pid == 0)
1032 break;
1033
034c6ed7
LP
1034 if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED)
1035 continue;
1036
acbb0225
LP
1037 log_debug("child %llu died (code=%s, status=%i)", (long long unsigned) si.si_pid, sigchld_code(si.si_code), si.si_status);
1038
87f0e418 1039 if (!(u = hashmap_remove(m->watch_pids, UINT32_TO_PTR(si.si_pid))))
9152c765
LP
1040 continue;
1041
87f0e418 1042 UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
9152c765
LP
1043 }
1044
1045 return 0;
1046}
1047
b9cd2ec1 1048static int manager_process_signal_fd(Manager *m, bool *quit) {
9152c765
LP
1049 ssize_t n;
1050 struct signalfd_siginfo sfsi;
1051 bool sigchld = false;
1052
1053 assert(m);
1054
1055 for (;;) {
acbb0225 1056 if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
9152c765
LP
1057
1058 if (n >= 0)
1059 return -EIO;
1060
1061 if (errno == EAGAIN)
acbb0225 1062 break;
9152c765
LP
1063
1064 return -errno;
1065 }
1066
b9cd2ec1
LP
1067 switch (sfsi.ssi_signo) {
1068
1069 case SIGCHLD:
9152c765 1070 sigchld = true;
b9cd2ec1
LP
1071 break;
1072
1073 case SIGINT:
6632c602 1074 case SIGTERM:
b9cd2ec1
LP
1075 *quit = true;
1076 return 0;
6632c602
LP
1077
1078 default:
1079 log_info("Got unhandled signal <%s>.", strsignal(sfsi.ssi_signo));
b9cd2ec1 1080 }
9152c765
LP
1081 }
1082
1083 if (sigchld)
034c6ed7
LP
1084 return manager_dispatch_sigchld(m);
1085
1086 return 0;
1087}
1088
b9cd2ec1 1089static int process_event(Manager *m, struct epoll_event *ev, bool *quit) {
034c6ed7 1090 int r;
acbb0225 1091 Watch *w;
034c6ed7
LP
1092
1093 assert(m);
1094 assert(ev);
1095
acbb0225 1096 assert(w = ev->data.ptr);
034c6ed7 1097
acbb0225 1098 switch (w->type) {
034c6ed7 1099
acbb0225 1100 case WATCH_SIGNAL_FD:
034c6ed7 1101
acbb0225
LP
1102 /* An incoming signal? */
1103 if (ev->events != POLLIN)
1104 return -EINVAL;
034c6ed7 1105
b9cd2ec1 1106 if ((r = manager_process_signal_fd(m, quit)) < 0)
acbb0225 1107 return r;
034c6ed7 1108
acbb0225 1109 break;
034c6ed7 1110
acbb0225 1111 case WATCH_FD:
034c6ed7 1112
acbb0225
LP
1113 /* Some fd event, to be dispatched to the units */
1114 UNIT_VTABLE(w->unit)->fd_event(w->unit, w->fd, ev->events, w);
1115 break;
034c6ed7 1116
acbb0225
LP
1117 case WATCH_TIMER: {
1118 uint64_t v;
1119 ssize_t k;
034c6ed7 1120
acbb0225
LP
1121 /* Some timer event, to be dispatched to the units */
1122 if ((k = read(ev->data.fd, &v, sizeof(v))) != sizeof(v)) {
034c6ed7 1123
acbb0225
LP
1124 if (k < 0 && (errno == EINTR || errno == EAGAIN))
1125 break;
034c6ed7 1126
acbb0225 1127 return k < 0 ? -errno : -EIO;
034c6ed7
LP
1128 }
1129
acbb0225
LP
1130 UNIT_VTABLE(w->unit)->timer_event(w->unit, v, w);
1131 break;
1132 }
1133
1134 default:
1135 assert_not_reached("Unknown epoll event type.");
034c6ed7 1136 }
9152c765
LP
1137
1138 return 0;
1139}
1140
1141int manager_loop(Manager *m) {
1142 int r;
b9cd2ec1 1143 bool quit = false;
9152c765
LP
1144
1145 assert(m);
1146
1147 for (;;) {
957ca890
LP
1148 struct epoll_event event;
1149 int n;
9152c765 1150
034c6ed7
LP
1151 manager_dispatch_run_queue(m);
1152
957ca890 1153 if ((n = epoll_wait(m->epoll_fd, &event, 1, -1)) < 0) {
9152c765
LP
1154
1155 if (errno == -EINTR)
1156 continue;
1157
1158 return -errno;
1159 }
1160
957ca890 1161 assert(n == 1);
b9cd2ec1 1162
957ca890
LP
1163 if ((r = process_event(m, &event, &quit)) < 0)
1164 return r;
1165
1166 if (quit)
1167 return 0;
83c60c9f
LP
1168 }
1169}