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