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