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