chiark / gitweb /
dbus: expose cgroup properties in introspection everywhere
[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 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                                       "Walked on cycle path to %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                         pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
738         }
739
740         return 0;
741 }
742
743 static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
744         Job *j, *f;
745
746         assert(tr);
747         assert(unit);
748
749         /* Looks for an existing prospective job and returns that. If
750          * it doesn't exist it is created and added to the prospective
751          * jobs list. */
752
753         f = hashmap_get(tr->jobs, unit);
754
755         LIST_FOREACH(transaction, j, f) {
756                 assert(j->unit == unit);
757
758                 if (j->type == type) {
759                         if (is_new)
760                                 *is_new = false;
761                         return j;
762                 }
763         }
764
765         j = job_new(unit, type);
766         if (!j)
767                 return NULL;
768
769         j->generation = 0;
770         j->marker = NULL;
771         j->matters_to_anchor = false;
772         j->override = override;
773         j->irreversible = tr->irreversible;
774
775         LIST_PREPEND(Job, transaction, f, j);
776
777         if (hashmap_replace(tr->jobs, unit, f) < 0) {
778                 LIST_REMOVE(Job, transaction, f, j);
779                 job_free(j);
780                 return NULL;
781         }
782
783         if (is_new)
784                 *is_new = true;
785
786         /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
787
788         return j;
789 }
790
791 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
792         assert(tr);
793         assert(j);
794
795         if (j->transaction_prev)
796                 j->transaction_prev->transaction_next = j->transaction_next;
797         else if (j->transaction_next)
798                 hashmap_replace(tr->jobs, j->unit, j->transaction_next);
799         else
800                 hashmap_remove_value(tr->jobs, j->unit, j);
801
802         if (j->transaction_next)
803                 j->transaction_next->transaction_prev = j->transaction_prev;
804
805         j->transaction_prev = j->transaction_next = NULL;
806
807         while (j->subject_list)
808                 job_dependency_free(j->subject_list);
809
810         while (j->object_list) {
811                 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
812
813                 job_dependency_free(j->object_list);
814
815                 if (other && delete_dependencies) {
816                         log_debug_unit(other->unit->id,
817                                        "Deleting job %s/%s as dependency of job %s/%s",
818                                        other->unit->id, job_type_to_string(other->type),
819                                        j->unit->id, job_type_to_string(j->type));
820                         transaction_delete_job(tr, other, delete_dependencies);
821                 }
822         }
823 }
824
825 int transaction_add_job_and_dependencies(
826                 Transaction *tr,
827                 JobType type,
828                 Unit *unit,
829                 Job *by,
830                 bool matters,
831                 bool override,
832                 bool conflicts,
833                 bool ignore_requirements,
834                 bool ignore_order,
835                 DBusError *e) {
836         Job *ret;
837         Iterator i;
838         Unit *dep;
839         int r;
840         bool is_new;
841
842         assert(tr);
843         assert(type < _JOB_TYPE_MAX);
844         assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
845         assert(unit);
846
847         /* log_debug("Pulling in %s/%s from %s/%s", */
848         /*           unit->id, job_type_to_string(type), */
849         /*           by ? by->unit->id : "NA", */
850         /*           by ? job_type_to_string(by->type) : "NA"); */
851
852         if (unit->load_state != UNIT_LOADED &&
853             unit->load_state != UNIT_ERROR &&
854             unit->load_state != UNIT_NOT_FOUND &&
855             unit->load_state != UNIT_MASKED) {
856                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
857                 return -EINVAL;
858         }
859
860         if (type != JOB_STOP && (unit->load_state == UNIT_ERROR || unit->load_state == UNIT_NOT_FOUND)) {
861                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
862                                "Unit %s failed to load: %s. "
863                                "See system logs and 'systemctl status %s' for details.",
864                                unit->id,
865                                strerror(-unit->load_error),
866                                unit->id);
867                 return -EINVAL;
868         }
869
870         if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
871                 dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id);
872                 return -EADDRNOTAVAIL;
873         }
874
875         if (!unit_job_is_applicable(unit, type)) {
876                 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);
877                 return -EBADR;
878         }
879
880         /* First add the job. */
881         ret = transaction_add_one_job(tr, type, unit, override, &is_new);
882         if (!ret)
883                 return -ENOMEM;
884
885         ret->ignore_order = ret->ignore_order || ignore_order;
886
887         /* Then, add a link to the job. */
888         if (by) {
889                 if (!job_dependency_new(by, ret, matters, conflicts))
890                         return -ENOMEM;
891         } else {
892                 /* If the job has no parent job, it is the anchor job. */
893                 assert(!tr->anchor_job);
894                 tr->anchor_job = ret;
895         }
896
897         if (is_new && !ignore_requirements && type != JOB_NOP) {
898                 Set *following;
899
900                 /* If we are following some other unit, make sure we
901                  * add all dependencies of everybody following. */
902                 if (unit_following_set(ret->unit, &following) > 0) {
903                         SET_FOREACH(dep, following, i) {
904                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
905                                 if (r < 0) {
906                                         log_warning_unit(dep->id,
907                                                          "Cannot add dependency job for unit %s, ignoring: %s",
908                                                          dep->id, bus_error(e, r));
909
910                                         if (e)
911                                                 dbus_error_free(e);
912                                 }
913                         }
914
915                         set_free(following);
916                 }
917
918                 /* Finally, recursively add in all dependencies. */
919                 if (type == JOB_START || type == JOB_RESTART) {
920                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
921                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
922                                 if (r < 0) {
923                                         if (r != -EBADR)
924                                                 goto fail;
925
926                                         if (e)
927                                                 dbus_error_free(e);
928                                 }
929                         }
930
931                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], 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_REQUIRES_OVERRIDABLE], i) {
943                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
944                                 if (r < 0) {
945                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
946                                                       "Cannot add dependency job for unit %s, ignoring: %s",
947                                                       dep->id, bus_error(e, r));
948
949                                         if (e)
950                                                 dbus_error_free(e);
951                                 }
952                         }
953
954                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
955                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
956                                 if (r < 0) {
957                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
958                                                       "Cannot add dependency job for unit %s, ignoring: %s",
959                                                       dep->id, bus_error(e, r));
960
961                                         if (e)
962                                                 dbus_error_free(e);
963                                 }
964                         }
965
966                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
967                                 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
968                                 if (r < 0) {
969                                         if (r != -EBADR)
970                                                 goto fail;
971
972                                         if (e)
973                                                 dbus_error_free(e);
974                                 }
975                         }
976
977                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
978                                 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
979                                 if (r < 0) {
980                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
981                                                       "Cannot add dependency job for unit %s, ignoring: %s",
982                                                       dep->id, bus_error(e, r));
983
984                                         if (e)
985                                                 dbus_error_free(e);
986                                 }
987                         }
988
989                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
990                                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
991                                 if (r < 0) {
992                                         if (r != -EBADR)
993                                                 goto fail;
994
995                                         if (e)
996                                                 dbus_error_free(e);
997                                 }
998                         }
999
1000                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
1001                                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
1002                                 if (r < 0) {
1003                                         log_warning_unit(dep->id,
1004                                                          "Cannot add dependency job for unit %s, ignoring: %s",
1005                                                          dep->id, bus_error(e, r));
1006
1007                                         if (e)
1008                                                 dbus_error_free(e);
1009                                 }
1010                         }
1011
1012                 }
1013
1014                 if (type == JOB_STOP || type == JOB_RESTART) {
1015
1016                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
1017                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1018                                 if (r < 0) {
1019                                         if (r != -EBADR)
1020                                                 goto fail;
1021
1022                                         if (e)
1023                                                 dbus_error_free(e);
1024                                 }
1025                         }
1026
1027                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_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_CONSISTS_OF], 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                 }
1050
1051                 if (type == JOB_RELOAD) {
1052
1053                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
1054                                 r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
1055                                 if (r < 0) {
1056                                         log_warning_unit(dep->id,
1057                                                          "Cannot add dependency reload job for unit %s, ignoring: %s",
1058                                                          dep->id, bus_error(e, r));
1059
1060                                         if (e)
1061                                                 dbus_error_free(e);
1062                                 }
1063                         }
1064                 }
1065
1066                 /* JOB_VERIFY_STARTED require no dependency handling */
1067         }
1068
1069         return 0;
1070
1071 fail:
1072         return r;
1073 }
1074
1075 int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
1076         Iterator i;
1077         Unit *u;
1078         char *k;
1079         int r;
1080
1081         assert(tr);
1082         assert(m);
1083
1084         HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1085
1086                 /* ignore aliases */
1087                 if (u->id != k)
1088                         continue;
1089
1090                 if (u->ignore_on_isolate)
1091                         continue;
1092
1093                 /* No need to stop inactive jobs */
1094                 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
1095                         continue;
1096
1097                 /* Is there already something listed for this? */
1098                 if (hashmap_get(tr->jobs, u))
1099                         continue;
1100
1101                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
1102                 if (r < 0)
1103                         log_warning_unit(u->id,
1104                                          "Cannot add isolate job for unit %s, ignoring: %s",
1105                                          u->id, strerror(-r));
1106         }
1107
1108         return 0;
1109 }
1110
1111 Transaction *transaction_new(bool irreversible) {
1112         Transaction *tr;
1113
1114         tr = new0(Transaction, 1);
1115         if (!tr)
1116                 return NULL;
1117
1118         tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func);
1119         if (!tr->jobs) {
1120                 free(tr);
1121                 return NULL;
1122         }
1123
1124         tr->irreversible = irreversible;
1125
1126         return tr;
1127 }
1128
1129 void transaction_free(Transaction *tr) {
1130         assert(hashmap_isempty(tr->jobs));
1131         hashmap_free(tr->jobs);
1132         free(tr);
1133 }