chiark / gitweb /
203070fa2697f90f6e75989fbbff29b722d1b8db
[elogind.git] / src / core / transaction.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
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 Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 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   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <unistd.h>
23 #include <fcntl.h>
24
25 #include "transaction.h"
26 #include "bus-errors.h"
27 #include "dbus-common.h"
28
29 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
30
31 static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependencies) {
32         assert(tr);
33         assert(j);
34
35         /* Deletes one job from the transaction */
36
37         transaction_unlink_job(tr, j, delete_dependencies);
38
39         job_free(j);
40 }
41
42 static void transaction_delete_unit(Transaction *tr, Unit *u) {
43         Job *j;
44
45         /* Deletes all jobs associated with a certain unit from the
46          * transaction */
47
48         while ((j = hashmap_get(tr->jobs, u)))
49                 transaction_delete_job(tr, j, true);
50 }
51
52 void transaction_abort(Transaction *tr) {
53         Job *j;
54
55         assert(tr);
56
57         while ((j = hashmap_first(tr->jobs)))
58                 transaction_delete_job(tr, j, false);
59
60         assert(hashmap_isempty(tr->jobs));
61 }
62
63 static void transaction_find_jobs_that_matter_to_anchor(Job *j, unsigned generation) {
64         JobDependency *l;
65
66         /* A recursive sweep through the graph that marks all units
67          * that matter to the anchor job, i.e. are directly or
68          * indirectly a dependency of the anchor job via paths that
69          * are fully marked as mattering. */
70
71         j->matters_to_anchor = true;
72         j->generation = generation;
73
74         LIST_FOREACH(subject, l, j->subject_list) {
75
76                 /* This link does not matter */
77                 if (!l->matters)
78                         continue;
79
80                 /* This unit has already been marked */
81                 if (l->object->generation == generation)
82                         continue;
83
84                 transaction_find_jobs_that_matter_to_anchor(l->object, generation);
85         }
86 }
87
88 static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other, JobType t) {
89         JobDependency *l, *last;
90
91         assert(j);
92         assert(other);
93         assert(j->unit == other->unit);
94         assert(!j->installed);
95
96         /* Merges 'other' into 'j' and then deletes 'other'. */
97
98         j->type = t;
99         j->state = JOB_WAITING;
100         j->override = j->override || other->override;
101         j->irreversible = j->irreversible || other->irreversible;
102
103         j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
104
105         /* Patch us in as new owner of the JobDependency objects */
106         last = NULL;
107         LIST_FOREACH(subject, l, other->subject_list) {
108                 assert(l->subject == other);
109                 l->subject = j;
110                 last = l;
111         }
112
113         /* Merge both lists */
114         if (last) {
115                 last->subject_next = j->subject_list;
116                 if (j->subject_list)
117                         j->subject_list->subject_prev = last;
118                 j->subject_list = other->subject_list;
119         }
120
121         /* Patch us in as new owner of the JobDependency objects */
122         last = NULL;
123         LIST_FOREACH(object, l, other->object_list) {
124                 assert(l->object == other);
125                 l->object = j;
126                 last = l;
127         }
128
129         /* Merge both lists */
130         if (last) {
131                 last->object_next = j->object_list;
132                 if (j->object_list)
133                         j->object_list->object_prev = last;
134                 j->object_list = other->object_list;
135         }
136
137         /* Kill the other job */
138         other->subject_list = NULL;
139         other->object_list = NULL;
140         transaction_delete_job(tr, other, true);
141 }
142
143 _pure_ static bool job_is_conflicted_by(Job *j) {
144         JobDependency *l;
145
146         assert(j);
147
148         /* Returns true if this job is pulled in by a least one
149          * ConflictedBy dependency. */
150
151         LIST_FOREACH(object, l, j->object_list)
152                 if (l->conflicts)
153                         return true;
154
155         return false;
156 }
157
158 static int delete_one_unmergeable_job(Transaction *tr, Job *j) {
159         Job *k;
160
161         assert(j);
162
163         /* Tries to delete one item in the linked list
164          * j->transaction_next->transaction_next->... that conflicts
165          * with another one, in an attempt to make an inconsistent
166          * transaction work. */
167
168         /* We rely here on the fact that if a merged with b does not
169          * merge with c, either a or b merge with c neither */
170         LIST_FOREACH(transaction, j, j)
171                 LIST_FOREACH(transaction, k, j->transaction_next) {
172                         Job *d;
173
174                         /* Is this one mergeable? Then skip it */
175                         if (job_type_is_mergeable(j->type, k->type))
176                                 continue;
177
178                         /* Ok, we found two that conflict, let's see if we can
179                          * drop one of them */
180                         if (!j->matters_to_anchor && !k->matters_to_anchor) {
181
182                                 /* Both jobs don't matter, so let's
183                                  * find the one that is smarter to
184                                  * remove. Let's think positive and
185                                  * rather remove stops then starts --
186                                  * except if something is being
187                                  * stopped because it is conflicted by
188                                  * another unit in which case we
189                                  * rather remove the start. */
190
191                                 log_debug_unit(j->unit->id,
192                                                "Looking at job %s/%s conflicted_by=%s",
193                                                j->unit->id, job_type_to_string(j->type),
194                                                yes_no(j->type == JOB_STOP && job_is_conflicted_by(j)));
195                                 log_debug_unit(k->unit->id,
196                                                "Looking at job %s/%s conflicted_by=%s",
197                                                k->unit->id, job_type_to_string(k->type),
198                                                yes_no(k->type == JOB_STOP && job_is_conflicted_by(k)));
199
200                                 if (j->type == JOB_STOP) {
201
202                                         if (job_is_conflicted_by(j))
203                                                 d = k;
204                                         else
205                                                 d = j;
206
207                                 } else if (k->type == JOB_STOP) {
208
209                                         if (job_is_conflicted_by(k))
210                                                 d = j;
211                                         else
212                                                 d = k;
213                                 } else
214                                         d = j;
215
216                         } else if (!j->matters_to_anchor)
217                                 d = j;
218                         else if (!k->matters_to_anchor)
219                                 d = k;
220                         else
221                                 return -ENOEXEC;
222
223                         /* Ok, we can drop one, so let's do so. */
224                         log_debug_unit(d->unit->id,
225                                        "Fixing conflicting jobs by deleting job %s/%s",
226                                        d->unit->id, job_type_to_string(d->type));
227                         transaction_delete_job(tr, d, true);
228                         return 0;
229                 }
230
231         return -EINVAL;
232 }
233
234 static int transaction_merge_jobs(Transaction *tr, DBusError *e) {
235         Job *j;
236         Iterator i;
237         int r;
238
239         assert(tr);
240
241         /* First step, check whether any of the jobs for one specific
242          * task conflict. If so, try to drop one of them. */
243         HASHMAP_FOREACH(j, tr->jobs, i) {
244                 JobType t;
245                 Job *k;
246
247                 t = j->type;
248                 LIST_FOREACH(transaction, k, j->transaction_next) {
249                         if (job_type_merge_and_collapse(&t, k->type, j->unit) >= 0)
250                                 continue;
251
252                         /* OK, we could not merge all jobs for this
253                          * action. Let's see if we can get rid of one
254                          * of them */
255
256                         r = delete_one_unmergeable_job(tr, j);
257                         if (r >= 0)
258                                 /* Ok, we managed to drop one, now
259                                  * let's ask our callers to call us
260                                  * again after garbage collecting */
261                                 return -EAGAIN;
262
263                         /* We couldn't merge anything. Failure */
264                         dbus_set_error(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.",
265                                        job_type_to_string(t), job_type_to_string(k->type), k->unit->id);
266                         return r;
267                 }
268         }
269
270         /* Second step, merge the jobs. */
271         HASHMAP_FOREACH(j, tr->jobs, i) {
272                 JobType t = j->type;
273                 Job *k;
274
275                 /* Merge all transaction jobs for j->unit */
276                 LIST_FOREACH(transaction, k, j->transaction_next)
277                         assert_se(job_type_merge_and_collapse(&t, k->type, j->unit) == 0);
278
279                 while ((k = j->transaction_next)) {
280                         if (tr->anchor_job == k) {
281                                 transaction_merge_and_delete_job(tr, k, j, t);
282                                 j = k;
283                         } else
284                                 transaction_merge_and_delete_job(tr, j, k, t);
285                 }
286
287                 assert(!j->transaction_next);
288                 assert(!j->transaction_prev);
289         }
290
291         return 0;
292 }
293
294 static void transaction_drop_redundant(Transaction *tr) {
295         Job *j;
296         Iterator i;
297
298         /* Goes through the transaction and removes all jobs of the units
299          * whose jobs are all noops. If not all of a unit's jobs are
300          * redundant, they are kept. */
301
302         assert(tr);
303
304 rescan:
305         HASHMAP_FOREACH(j, tr->jobs, i) {
306                 Job *k;
307
308                 LIST_FOREACH(transaction, k, j) {
309
310                         if (tr->anchor_job == k ||
311                             !job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
312                             (k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type)))
313                                 goto next_unit;
314                 }
315
316                 /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */
317                 transaction_delete_job(tr, j, false);
318                 goto rescan;
319         next_unit:;
320         }
321 }
322
323 _pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) {
324         assert(u);
325         assert(!j->transaction_prev);
326
327         /* Checks whether at least one of the jobs for this unit
328          * matters to the anchor. */
329
330         LIST_FOREACH(transaction, j, j)
331                 if (j->matters_to_anchor)
332                         return true;
333
334         return false;
335 }
336
337 static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, DBusError *e) {
338         Iterator i;
339         Unit *u;
340         int r;
341
342         assert(tr);
343         assert(j);
344         assert(!j->transaction_prev);
345
346         /* Does a recursive sweep through the ordering graph, looking
347          * for a cycle. If we find a cycle we try to break it. */
348
349         /* Have we seen this before? */
350         if (j->generation == generation) {
351                 Job *k, *delete;
352
353                 /* If the marker is NULL we have been here already and
354                  * decided the job was loop-free from here. Hence
355                  * shortcut things and return right-away. */
356                 if (!j->marker)
357                         return 0;
358
359                 /* So, the marker is not NULL and we already have been
360                  * here. We have a cycle. Let's try to break it. We go
361                  * backwards in our path and try to find a suitable
362                  * job to remove. We use the marker to find our way
363                  * back, since smart how we are we stored our way back
364                  * in there. */
365                 log_warning_unit(j->unit->id,
366                                  "Found ordering cycle on %s/%s",
367                                  j->unit->id, job_type_to_string(j->type));
368
369                 delete = NULL;
370                 for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
371
372                         /* logging for j not k here here to provide consistent narrative */
373                         log_info_unit(j->unit->id,
374                                       "Found dependency on %s/%s",
375                                       k->unit->id, job_type_to_string(k->type));
376
377                         if (!delete &&
378                             !unit_matters_to_anchor(k->unit, k)) {
379                                 /* Ok, we can drop this one, so let's
380                                  * do so. */
381                                 delete = k;
382                         }
383
384                         /* Check if this in fact was the beginning of
385                          * the cycle */
386                         if (k == j)
387                                 break;
388                 }
389
390
391                 if (delete) {
392                         /* logging for j not k here here to provide consistent narrative */
393                         log_warning_unit(j->unit->id,
394                                          "Breaking ordering cycle by deleting job %s/%s",
395                                          delete->unit->id, job_type_to_string(delete->type));
396                         log_error_unit(delete->unit->id,
397                                        "Job %s/%s deleted to break ordering cycle starting with %s/%s",
398                                        delete->unit->id, job_type_to_string(delete->type),
399                                        j->unit->id, job_type_to_string(j->type));
400                         unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF,
401                                            "Ordering cycle found, skipping %s");
402                         transaction_delete_unit(tr, delete->unit);
403                         return -EAGAIN;
404                 }
405
406                 log_error("Unable to break cycle");
407
408                 dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
409                                "Transaction order is cyclic. See system logs for details.");
410                 return -ENOEXEC;
411         }
412
413         /* Make the marker point to where we come from, so that we can
414          * find our way backwards if we want to break a cycle. We use
415          * a special marker for the beginning: we point to
416          * ourselves. */
417         j->marker = from ? from : j;
418         j->generation = generation;
419
420         /* We assume that the dependencies are bidirectional, and
421          * hence can ignore UNIT_AFTER */
422         SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) {
423                 Job *o;
424
425                 /* Is there a job for this unit? */
426                 o = hashmap_get(tr->jobs, u);
427                 if (!o) {
428                         /* Ok, there is no job for this in the
429                          * transaction, but maybe there is already one
430                          * running? */
431                         o = u->job;
432                         if (!o)
433                                 continue;
434                 }
435
436                 r = transaction_verify_order_one(tr, o, j, generation, e);
437                 if (r < 0)
438                         return r;
439         }
440
441         /* Ok, let's backtrack, and remember that this entry is not on
442          * our path anymore. */
443         j->marker = NULL;
444
445         return 0;
446 }
447
448 static int transaction_verify_order(Transaction *tr, unsigned *generation, DBusError *e) {
449         Job *j;
450         int r;
451         Iterator i;
452         unsigned g;
453
454         assert(tr);
455         assert(generation);
456
457         /* Check if the ordering graph is cyclic. If it is, try to fix
458          * that up by dropping one of the jobs. */
459
460         g = (*generation)++;
461
462         HASHMAP_FOREACH(j, tr->jobs, i)
463                 if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0)
464                         return r;
465
466         return 0;
467 }
468
469 static void transaction_collect_garbage(Transaction *tr) {
470         Iterator i;
471         Job *j;
472
473         assert(tr);
474
475         /* Drop jobs that are not required by any other job */
476
477 rescan:
478         HASHMAP_FOREACH(j, tr->jobs, i) {
479                 if (tr->anchor_job == j || j->object_list) {
480                         /* log_debug("Keeping job %s/%s because of %s/%s", */
481                         /*           j->unit->id, job_type_to_string(j->type), */
482                         /*           j->object_list->subject ? j->object_list->subject->unit->id : "root", */
483                         /*           j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
484                         continue;
485                 }
486
487                 /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
488                 transaction_delete_job(tr, j, true);
489                 goto rescan;
490         }
491 }
492
493 static int transaction_is_destructive(Transaction *tr, JobMode mode, DBusError *e) {
494         Iterator i;
495         Job *j;
496
497         assert(tr);
498
499         /* Checks whether applying this transaction means that
500          * existing jobs would be replaced */
501
502         HASHMAP_FOREACH(j, tr->jobs, i) {
503
504                 /* Assume merged */
505                 assert(!j->transaction_prev);
506                 assert(!j->transaction_next);
507
508                 if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
509                     !job_type_is_superset(j->type, j->unit->job->type)) {
510
511                         dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
512                         return -EEXIST;
513                 }
514         }
515
516         return 0;
517 }
518
519 static void transaction_minimize_impact(Transaction *tr) {
520         Job *j;
521         Iterator i;
522
523         assert(tr);
524
525         /* Drops all unnecessary jobs that reverse already active jobs
526          * or that stop a running service. */
527
528 rescan:
529         HASHMAP_FOREACH(j, tr->jobs, i) {
530                 LIST_FOREACH(transaction, j, j) {
531                         bool stops_running_service, changes_existing_job;
532
533                         /* If it matters, we shouldn't drop it */
534                         if (j->matters_to_anchor)
535                                 continue;
536
537                         /* Would this stop a running service?
538                          * Would this change an existing job?
539                          * If so, let's drop this entry */
540
541                         stops_running_service =
542                                 j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
543
544                         changes_existing_job =
545                                 j->unit->job &&
546                                 job_type_is_conflicting(j->type, j->unit->job->type);
547
548                         if (!stops_running_service && !changes_existing_job)
549                                 continue;
550
551                         if (stops_running_service)
552                                 log_debug_unit(j->unit->id,
553                                                "%s/%s would stop a running service.",
554                                                j->unit->id, job_type_to_string(j->type));
555
556                         if (changes_existing_job)
557                                 log_debug_unit(j->unit->id,
558                                                "%s/%s would change existing job.",
559                                                j->unit->id, job_type_to_string(j->type));
560
561                         /* Ok, let's get rid of this */
562                         log_debug_unit(j->unit->id,
563                                        "Deleting %s/%s to minimize impact.",
564                                        j->unit->id, job_type_to_string(j->type));
565
566                         transaction_delete_job(tr, j, true);
567                         goto rescan;
568                 }
569         }
570 }
571
572 static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
573         Iterator i;
574         Job *j;
575         int r;
576
577         /* Moves the transaction jobs to the set of active jobs */
578
579         if (mode == JOB_ISOLATE) {
580
581                 /* When isolating first kill all installed jobs which
582                  * aren't part of the new transaction */
583                 HASHMAP_FOREACH(j, m->jobs, i) {
584                         assert(j->installed);
585
586                         if (hashmap_get(tr->jobs, j->unit))
587                                 continue;
588
589                         /* Not invalidating recursively. Avoids triggering
590                          * OnFailure= actions of dependent jobs. Also avoids
591                          * invalidating our iterator. */
592                         job_finish_and_invalidate(j, JOB_CANCELED, false);
593                 }
594         }
595
596         HASHMAP_FOREACH(j, tr->jobs, i) {
597                 /* Assume merged */
598                 assert(!j->transaction_prev);
599                 assert(!j->transaction_next);
600
601                 r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j);
602                 if (r < 0)
603                         goto rollback;
604         }
605
606         while ((j = hashmap_steal_first(tr->jobs))) {
607                 Job *installed_job;
608
609                 /* Clean the job dependencies */
610                 transaction_unlink_job(tr, j, false);
611
612                 installed_job = job_install(j);
613                 if (installed_job != j) {
614                         /* j has been merged into a previously installed job */
615                         if (tr->anchor_job == j)
616                                 tr->anchor_job = installed_job;
617                         hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
618                         job_free(j);
619                         j = installed_job;
620                 }
621
622                 job_add_to_run_queue(j);
623                 job_add_to_dbus_queue(j);
624                 job_start_timer(j);
625                 job_shutdown_magic(j);
626         }
627
628         return 0;
629
630 rollback:
631
632         HASHMAP_FOREACH(j, tr->jobs, i)
633                 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
634
635         return r;
636 }
637
638 int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e) {
639         Iterator i;
640         Job *j;
641         int r;
642         unsigned generation = 1;
643
644         assert(tr);
645
646         /* This applies the changes recorded in tr->jobs to
647          * the actual list of jobs, if possible. */
648
649         /* Reset the generation counter of all installed jobs. The detection of cycles
650          * looks at installed jobs. If they had a non-zero generation from some previous
651          * walk of the graph, the algorithm would break. */
652         HASHMAP_FOREACH(j, m->jobs, i)
653                 j->generation = 0;
654
655         /* First step: figure out which jobs matter */
656         transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
657
658         /* Second step: Try not to stop any running services if
659          * we don't have to. Don't try to reverse running
660          * jobs if we don't have to. */
661         if (mode == JOB_FAIL)
662                 transaction_minimize_impact(tr);
663
664         /* Third step: Drop redundant jobs */
665         transaction_drop_redundant(tr);
666
667         for (;;) {
668                 /* Fourth step: Let's remove unneeded jobs that might
669                  * be lurking. */
670                 if (mode != JOB_ISOLATE)
671                         transaction_collect_garbage(tr);
672
673                 /* Fifth step: verify order makes sense and correct
674                  * cycles if necessary and possible */
675                 r = transaction_verify_order(tr, &generation, e);
676                 if (r >= 0)
677                         break;
678
679                 if (r != -EAGAIN) {
680                         log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, r));
681                         return r;
682                 }
683
684                 /* Let's see if the resulting transaction ordering
685                  * graph is still cyclic... */
686         }
687
688         for (;;) {
689                 /* Sixth step: let's drop unmergeable entries if
690                  * necessary and possible, merge entries we can
691                  * merge */
692                 r = transaction_merge_jobs(tr, e);
693                 if (r >= 0)
694                         break;
695
696                 if (r != -EAGAIN) {
697                         log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r));
698                         return r;
699                 }
700
701                 /* Seventh step: an entry got dropped, let's garbage
702                  * collect its dependencies. */
703                 if (mode != JOB_ISOLATE)
704                         transaction_collect_garbage(tr);
705
706                 /* Let's see if the resulting transaction still has
707                  * unmergeable entries ... */
708         }
709
710         /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
711         transaction_drop_redundant(tr);
712
713         /* Ninth step: check whether we can actually apply this */
714         r = transaction_is_destructive(tr, mode, e);
715         if (r < 0) {
716                 log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r));
717                 return r;
718         }
719
720         /* Tenth step: apply changes */
721         r = transaction_apply(tr, m, mode);
722         if (r < 0) {
723                 log_warning("Failed to apply transaction: %s", strerror(-r));
724                 return r;
725         }
726
727         assert(hashmap_isempty(tr->jobs));
728
729         if (!hashmap_isempty(m->jobs)) {
730                 /* Are there any jobs now? Then make sure we have the
731                  * idle pipe around. We don't really care too much
732                  * whether this works or not, as the idle pipe is a
733                  * feature for cosmetics, not actually useful for
734                  * anything beyond that. */
735
736                 if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
737                     m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
738                         pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
739                         pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
740                 }
741         }
742
743         return 0;
744 }
745
746 static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
747         Job *j, *f;
748
749         assert(tr);
750         assert(unit);
751
752         /* Looks for an existing prospective job and returns that. If
753          * it doesn't exist it is created and added to the prospective
754          * jobs list. */
755
756         f = hashmap_get(tr->jobs, unit);
757
758         LIST_FOREACH(transaction, j, f) {
759                 assert(j->unit == unit);
760
761                 if (j->type == type) {
762                         if (is_new)
763                                 *is_new = false;
764                         return j;
765                 }
766         }
767
768         j = job_new(unit, type);
769         if (!j)
770                 return NULL;
771
772         j->generation = 0;
773         j->marker = NULL;
774         j->matters_to_anchor = false;
775         j->override = override;
776         j->irreversible = tr->irreversible;
777
778         LIST_PREPEND(Job, transaction, f, j);
779
780         if (hashmap_replace(tr->jobs, unit, f) < 0) {
781                 LIST_REMOVE(Job, transaction, f, j);
782                 job_free(j);
783                 return NULL;
784         }
785
786         if (is_new)
787                 *is_new = true;
788
789         /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
790
791         return j;
792 }
793
794 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
795         assert(tr);
796         assert(j);
797
798         if (j->transaction_prev)
799                 j->transaction_prev->transaction_next = j->transaction_next;
800         else if (j->transaction_next)
801                 hashmap_replace(tr->jobs, j->unit, j->transaction_next);
802         else
803                 hashmap_remove_value(tr->jobs, j->unit, j);
804
805         if (j->transaction_next)
806                 j->transaction_next->transaction_prev = j->transaction_prev;
807
808         j->transaction_prev = j->transaction_next = NULL;
809
810         while (j->subject_list)
811                 job_dependency_free(j->subject_list);
812
813         while (j->object_list) {
814                 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
815
816                 job_dependency_free(j->object_list);
817
818                 if (other && delete_dependencies) {
819                         log_debug_unit(other->unit->id,
820                                        "Deleting job %s/%s as dependency of job %s/%s",
821                                        other->unit->id, job_type_to_string(other->type),
822                                        j->unit->id, job_type_to_string(j->type));
823                         transaction_delete_job(tr, other, delete_dependencies);
824                 }
825         }
826 }
827
828 int transaction_add_job_and_dependencies(
829                 Transaction *tr,
830                 JobType type,
831                 Unit *unit,
832                 Job *by,
833                 bool matters,
834                 bool override,
835                 bool conflicts,
836                 bool ignore_requirements,
837                 bool ignore_order,
838                 DBusError *e) {
839         Job *ret;
840         Iterator i;
841         Unit *dep;
842         int r;
843         bool is_new;
844
845         assert(tr);
846         assert(type < _JOB_TYPE_MAX);
847         assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
848         assert(unit);
849
850         /* log_debug("Pulling in %s/%s from %s/%s", */
851         /*           unit->id, job_type_to_string(type), */
852         /*           by ? by->unit->id : "NA", */
853         /*           by ? job_type_to_string(by->type) : "NA"); */
854
855         if (unit->load_state != UNIT_LOADED &&
856             unit->load_state != UNIT_ERROR &&
857             unit->load_state != UNIT_NOT_FOUND &&
858             unit->load_state != UNIT_MASKED) {
859                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
860                 return -EINVAL;
861         }
862
863         if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
864                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
865                                "Unit %s failed to load: %s. "
866                                "See system logs and 'systemctl status %s' for details.",
867                                unit->id,
868                                strerror(-unit->load_error),
869                                unit->id);
870                 return -EINVAL;
871         }
872
873         if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND) {
874                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
875                                "Unit %s failed to load: %s.",
876                                unit->id,
877                                strerror(-unit->load_error));
878                 return -EINVAL;
879         }
880
881         if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
882                 dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id);
883                 return -EADDRNOTAVAIL;
884         }
885
886         if (!unit_job_is_applicable(unit, type)) {
887                 dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id);
888                 return -EBADR;
889         }
890
891         /* First add the job. */
892         ret = transaction_add_one_job(tr, type, unit, override, &is_new);
893         if (!ret)
894                 return -ENOMEM;
895
896         ret->ignore_order = ret->ignore_order || ignore_order;
897
898         /* Then, add a link to the job. */
899         if (by) {
900                 if (!job_dependency_new(by, ret, matters, conflicts))
901                         return -ENOMEM;
902         } else {
903                 /* If the job has no parent job, it is the anchor job. */
904                 assert(!tr->anchor_job);
905                 tr->anchor_job = ret;
906         }
907
908         if (is_new && !ignore_requirements && type != JOB_NOP) {
909                 Set *following;
910
911                 /* If we are following some other unit, make sure we
912                  * add all dependencies of everybody following. */
913                 if (unit_following_set(ret->unit, &following) > 0) {
914                         SET_FOREACH(dep, following, i) {
915                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
916                                 if (r < 0) {
917                                         log_warning_unit(dep->id,
918                                                          "Cannot add dependency job for unit %s, ignoring: %s",
919                                                          dep->id, bus_error(e, r));
920
921                                         if (e)
922                                                 dbus_error_free(e);
923                                 }
924                         }
925
926                         set_free(following);
927                 }
928
929                 /* Finally, recursively add in all dependencies. */
930                 if (type == JOB_START || type == JOB_RESTART) {
931                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
932                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
933                                 if (r < 0) {
934                                         if (r != -EBADR)
935                                                 goto fail;
936
937                                         if (e)
938                                                 dbus_error_free(e);
939                                 }
940                         }
941
942                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
943                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
944                                 if (r < 0) {
945                                         if (r != -EBADR)
946                                                 goto fail;
947
948                                         if (e)
949                                                 dbus_error_free(e);
950                                 }
951                         }
952
953                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
954                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
955                                 if (r < 0) {
956                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
957                                                       "Cannot add dependency job for unit %s, ignoring: %s",
958                                                       dep->id, bus_error(e, r));
959
960                                         if (e)
961                                                 dbus_error_free(e);
962                                 }
963                         }
964
965                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
966                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
967                                 if (r < 0) {
968                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
969                                                       "Cannot add dependency job for unit %s, ignoring: %s",
970                                                       dep->id, bus_error(e, r));
971
972                                         if (e)
973                                                 dbus_error_free(e);
974                                 }
975                         }
976
977                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
978                                 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
979                                 if (r < 0) {
980                                         if (r != -EBADR)
981                                                 goto fail;
982
983                                         if (e)
984                                                 dbus_error_free(e);
985                                 }
986                         }
987
988                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
989                                 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
990                                 if (r < 0) {
991                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
992                                                       "Cannot add dependency job for unit %s, ignoring: %s",
993                                                       dep->id, bus_error(e, r));
994
995                                         if (e)
996                                                 dbus_error_free(e);
997                                 }
998                         }
999
1000                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
1001                                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
1002                                 if (r < 0) {
1003                                         if (r != -EBADR)
1004                                                 goto fail;
1005
1006                                         if (e)
1007                                                 dbus_error_free(e);
1008                                 }
1009                         }
1010
1011                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
1012                                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
1013                                 if (r < 0) {
1014                                         log_warning_unit(dep->id,
1015                                                          "Cannot add dependency job for unit %s, ignoring: %s",
1016                                                          dep->id, bus_error(e, r));
1017
1018                                         if (e)
1019                                                 dbus_error_free(e);
1020                                 }
1021                         }
1022
1023                 }
1024
1025                 if (type == JOB_STOP || type == JOB_RESTART) {
1026
1027                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
1028                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1029                                 if (r < 0) {
1030                                         if (r != -EBADR)
1031                                                 goto fail;
1032
1033                                         if (e)
1034                                                 dbus_error_free(e);
1035                                 }
1036                         }
1037
1038                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
1039                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1040                                 if (r < 0) {
1041                                         if (r != -EBADR)
1042                                                 goto fail;
1043
1044                                         if (e)
1045                                                 dbus_error_free(e);
1046                                 }
1047                         }
1048
1049                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
1050                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1051                                 if (r < 0) {
1052                                         if (r != -EBADR)
1053                                                 goto fail;
1054
1055                                         if (e)
1056                                                 dbus_error_free(e);
1057                                 }
1058                         }
1059
1060                 }
1061
1062                 if (type == JOB_RELOAD) {
1063
1064                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
1065                                 r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
1066                                 if (r < 0) {
1067                                         log_warning_unit(dep->id,
1068                                                          "Cannot add dependency reload job for unit %s, ignoring: %s",
1069                                                          dep->id, bus_error(e, r));
1070
1071                                         if (e)
1072                                                 dbus_error_free(e);
1073                                 }
1074                         }
1075                 }
1076
1077                 /* JOB_VERIFY_STARTED require no dependency handling */
1078         }
1079
1080         return 0;
1081
1082 fail:
1083         return r;
1084 }
1085
1086 int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
1087         Iterator i;
1088         Unit *u;
1089         char *k;
1090         int r;
1091
1092         assert(tr);
1093         assert(m);
1094
1095         HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1096
1097                 /* ignore aliases */
1098                 if (u->id != k)
1099                         continue;
1100
1101                 if (u->ignore_on_isolate)
1102                         continue;
1103
1104                 /* No need to stop inactive jobs */
1105                 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
1106                         continue;
1107
1108                 /* Is there already something listed for this? */
1109                 if (hashmap_get(tr->jobs, u))
1110                         continue;
1111
1112                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
1113                 if (r < 0)
1114                         log_warning_unit(u->id,
1115                                          "Cannot add isolate job for unit %s, ignoring: %s",
1116                                          u->id, strerror(-r));
1117         }
1118
1119         return 0;
1120 }
1121
1122 Transaction *transaction_new(bool irreversible) {
1123         Transaction *tr;
1124
1125         tr = new0(Transaction, 1);
1126         if (!tr)
1127                 return NULL;
1128
1129         tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func);
1130         if (!tr->jobs) {
1131                 free(tr);
1132                 return NULL;
1133         }
1134
1135         tr->irreversible = irreversible;
1136
1137         return tr;
1138 }
1139
1140 void transaction_free(Transaction *tr) {
1141         assert(hashmap_isempty(tr->jobs));
1142         hashmap_free(tr->jobs);
1143         free(tr);
1144 }