chiark / gitweb /
socket: properly serialize/desrialize mqueue fds
[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_and_collapse(&t, k->type, j->unit) >= 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 transaction jobs for j->unit */
266                 LIST_FOREACH(transaction, k, j->transaction_next)
267                         assert_se(job_type_merge_and_collapse(&t, k->type, j->unit) == 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_error("Breaking ordering cycle by deleting job %s/%s", delete->unit->id, job_type_to_string(delete->type));
378                         status_printf(ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF, true, "Ordering cycle found, skip %s", unit_description(delete->unit));
379                         transaction_delete_unit(tr, delete->unit);
380                         return -EAGAIN;
381                 }
382
383                 log_error("Unable to break cycle");
384
385                 dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See system logs for details.");
386                 return -ENOEXEC;
387         }
388
389         /* Make the marker point to where we come from, so that we can
390          * find our way backwards if we want to break a cycle. We use
391          * a special marker for the beginning: we point to
392          * ourselves. */
393         j->marker = from ? from : j;
394         j->generation = generation;
395
396         /* We assume that the dependencies are bidirectional, and
397          * hence can ignore UNIT_AFTER */
398         SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) {
399                 Job *o;
400
401                 /* Is there a job for this unit? */
402                 o = hashmap_get(tr->jobs, u);
403                 if (!o) {
404                         /* Ok, there is no job for this in the
405                          * transaction, but maybe there is already one
406                          * running? */
407                         o = u->job;
408                         if (!o)
409                                 continue;
410                 }
411
412                 r = transaction_verify_order_one(tr, o, j, generation, e);
413                 if (r < 0)
414                         return r;
415         }
416
417         /* Ok, let's backtrack, and remember that this entry is not on
418          * our path anymore. */
419         j->marker = NULL;
420
421         return 0;
422 }
423
424 static int transaction_verify_order(Transaction *tr, unsigned *generation, DBusError *e) {
425         Job *j;
426         int r;
427         Iterator i;
428         unsigned g;
429
430         assert(tr);
431         assert(generation);
432
433         /* Check if the ordering graph is cyclic. If it is, try to fix
434          * that up by dropping one of the jobs. */
435
436         g = (*generation)++;
437
438         HASHMAP_FOREACH(j, tr->jobs, i)
439                 if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0)
440                         return r;
441
442         return 0;
443 }
444
445 static void transaction_collect_garbage(Transaction *tr) {
446         Iterator i;
447         Job *j;
448
449         assert(tr);
450
451         /* Drop jobs that are not required by any other job */
452
453 rescan:
454         HASHMAP_FOREACH(j, tr->jobs, i) {
455                 if (tr->anchor_job == j || j->object_list) {
456                         /* log_debug("Keeping job %s/%s because of %s/%s", */
457                         /*           j->unit->id, job_type_to_string(j->type), */
458                         /*           j->object_list->subject ? j->object_list->subject->unit->id : "root", */
459                         /*           j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
460                         continue;
461                 }
462
463                 /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
464                 transaction_delete_job(tr, j, true);
465                 goto rescan;
466         }
467 }
468
469 static int transaction_is_destructive(Transaction *tr, DBusError *e) {
470         Iterator i;
471         Job *j;
472
473         assert(tr);
474
475         /* Checks whether applying this transaction means that
476          * existing jobs would be replaced */
477
478         HASHMAP_FOREACH(j, tr->jobs, i) {
479
480                 /* Assume merged */
481                 assert(!j->transaction_prev);
482                 assert(!j->transaction_next);
483
484                 if (j->unit->job &&
485                     !job_type_is_superset(j->type, j->unit->job->type)) {
486
487                         dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
488                         return -EEXIST;
489                 }
490         }
491
492         return 0;
493 }
494
495 static void transaction_minimize_impact(Transaction *tr) {
496         Job *j;
497         Iterator i;
498
499         assert(tr);
500
501         /* Drops all unnecessary jobs that reverse already active jobs
502          * or that stop a running service. */
503
504 rescan:
505         HASHMAP_FOREACH(j, tr->jobs, i) {
506                 LIST_FOREACH(transaction, j, j) {
507                         bool stops_running_service, changes_existing_job;
508
509                         /* If it matters, we shouldn't drop it */
510                         if (j->matters_to_anchor)
511                                 continue;
512
513                         /* Would this stop a running service?
514                          * Would this change an existing job?
515                          * If so, let's drop this entry */
516
517                         stops_running_service =
518                                 j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
519
520                         changes_existing_job =
521                                 j->unit->job &&
522                                 job_type_is_conflicting(j->type, j->unit->job->type);
523
524                         if (!stops_running_service && !changes_existing_job)
525                                 continue;
526
527                         if (stops_running_service)
528                                 log_debug("%s/%s would stop a running service.", j->unit->id, job_type_to_string(j->type));
529
530                         if (changes_existing_job)
531                                 log_debug("%s/%s would change existing job.", j->unit->id, job_type_to_string(j->type));
532
533                         /* Ok, let's get rid of this */
534                         log_debug("Deleting %s/%s to minimize impact.", j->unit->id, job_type_to_string(j->type));
535
536                         transaction_delete_job(tr, j, true);
537                         goto rescan;
538                 }
539         }
540 }
541
542 static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
543         Iterator i;
544         Job *j;
545         int r;
546
547         /* Moves the transaction jobs to the set of active jobs */
548
549         if (mode == JOB_ISOLATE) {
550
551                 /* When isolating first kill all installed jobs which
552                  * aren't part of the new transaction */
553                 HASHMAP_FOREACH(j, m->jobs, i) {
554                         assert(j->installed);
555
556                         if (hashmap_get(tr->jobs, j->unit))
557                                 continue;
558
559                         /* Not invalidating recursively. Avoids triggering
560                          * OnFailure= actions of dependent jobs. Also avoids
561                          * invalidating our iterator. */
562                         job_finish_and_invalidate(j, JOB_CANCELED, false);
563                 }
564         }
565
566         HASHMAP_FOREACH(j, tr->jobs, i) {
567                 /* Assume merged */
568                 assert(!j->transaction_prev);
569                 assert(!j->transaction_next);
570
571                 r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j);
572                 if (r < 0)
573                         goto rollback;
574         }
575
576         while ((j = hashmap_steal_first(tr->jobs))) {
577                 Job *installed_job;
578
579                 /* Clean the job dependencies */
580                 transaction_unlink_job(tr, j, false);
581
582                 installed_job = job_install(j);
583                 if (installed_job != j) {
584                         /* j has been merged into a previously installed job */
585                         if (tr->anchor_job == j)
586                                 tr->anchor_job = installed_job;
587                         hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
588                         job_free(j);
589                         j = installed_job;
590                 }
591
592                 job_add_to_run_queue(j);
593                 job_add_to_dbus_queue(j);
594                 job_start_timer(j);
595         }
596
597         return 0;
598
599 rollback:
600
601         HASHMAP_FOREACH(j, tr->jobs, i)
602                 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
603
604         return r;
605 }
606
607 int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e) {
608         Iterator i;
609         Job *j;
610         int r;
611         unsigned generation = 1;
612
613         assert(tr);
614
615         /* This applies the changes recorded in tr->jobs to
616          * the actual list of jobs, if possible. */
617
618         /* Reset the generation counter of all installed jobs. The detection of cycles
619          * looks at installed jobs. If they had a non-zero generation from some previous
620          * walk of the graph, the algorithm would break. */
621         HASHMAP_FOREACH(j, m->jobs, i)
622                 j->generation = 0;
623
624         /* First step: figure out which jobs matter */
625         transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
626
627         /* Second step: Try not to stop any running services if
628          * we don't have to. Don't try to reverse running
629          * jobs if we don't have to. */
630         if (mode == JOB_FAIL)
631                 transaction_minimize_impact(tr);
632
633         /* Third step: Drop redundant jobs */
634         transaction_drop_redundant(tr);
635
636         for (;;) {
637                 /* Fourth step: Let's remove unneeded jobs that might
638                  * be lurking. */
639                 if (mode != JOB_ISOLATE)
640                         transaction_collect_garbage(tr);
641
642                 /* Fifth step: verify order makes sense and correct
643                  * cycles if necessary and possible */
644                 r = transaction_verify_order(tr, &generation, e);
645                 if (r >= 0)
646                         break;
647
648                 if (r != -EAGAIN) {
649                         log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, r));
650                         return r;
651                 }
652
653                 /* Let's see if the resulting transaction ordering
654                  * graph is still cyclic... */
655         }
656
657         for (;;) {
658                 /* Sixth step: let's drop unmergeable entries if
659                  * necessary and possible, merge entries we can
660                  * merge */
661                 r = transaction_merge_jobs(tr, e);
662                 if (r >= 0)
663                         break;
664
665                 if (r != -EAGAIN) {
666                         log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r));
667                         return r;
668                 }
669
670                 /* Seventh step: an entry got dropped, let's garbage
671                  * collect its dependencies. */
672                 if (mode != JOB_ISOLATE)
673                         transaction_collect_garbage(tr);
674
675                 /* Let's see if the resulting transaction still has
676                  * unmergeable entries ... */
677         }
678
679         /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
680         transaction_drop_redundant(tr);
681
682         /* Ninth step: check whether we can actually apply this */
683         if (mode == JOB_FAIL) {
684                 r = transaction_is_destructive(tr, e);
685                 if (r < 0) {
686                         log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r));
687                         return r;
688                 }
689         }
690
691         /* Tenth step: apply changes */
692         r = transaction_apply(tr, m, mode);
693         if (r < 0) {
694                 log_warning("Failed to apply transaction: %s", strerror(-r));
695                 return r;
696         }
697
698         assert(hashmap_isempty(tr->jobs));
699
700         if (!hashmap_isempty(m->jobs)) {
701                 /* Are there any jobs now? Then make sure we have the
702                  * idle pipe around. We don't really care too much
703                  * whether this works or not, as the idle pipe is a
704                  * feature for cosmetics, not actually useful for
705                  * anything beyond that. */
706
707                 if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0)
708                         pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
709         }
710
711         return 0;
712 }
713
714 static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
715         Job *j, *f;
716
717         assert(tr);
718         assert(unit);
719
720         /* Looks for an existing prospective job and returns that. If
721          * it doesn't exist it is created and added to the prospective
722          * jobs list. */
723
724         f = hashmap_get(tr->jobs, unit);
725
726         LIST_FOREACH(transaction, j, f) {
727                 assert(j->unit == unit);
728
729                 if (j->type == type) {
730                         if (is_new)
731                                 *is_new = false;
732                         return j;
733                 }
734         }
735
736         j = job_new(unit, type);
737         if (!j)
738                 return NULL;
739
740         j->generation = 0;
741         j->marker = NULL;
742         j->matters_to_anchor = false;
743         j->override = override;
744
745         LIST_PREPEND(Job, transaction, f, j);
746
747         if (hashmap_replace(tr->jobs, unit, f) < 0) {
748                 LIST_REMOVE(Job, transaction, f, j);
749                 job_free(j);
750                 return NULL;
751         }
752
753         if (is_new)
754                 *is_new = true;
755
756         /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
757
758         return j;
759 }
760
761 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
762         assert(tr);
763         assert(j);
764
765         if (j->transaction_prev)
766                 j->transaction_prev->transaction_next = j->transaction_next;
767         else if (j->transaction_next)
768                 hashmap_replace(tr->jobs, j->unit, j->transaction_next);
769         else
770                 hashmap_remove_value(tr->jobs, j->unit, j);
771
772         if (j->transaction_next)
773                 j->transaction_next->transaction_prev = j->transaction_prev;
774
775         j->transaction_prev = j->transaction_next = NULL;
776
777         while (j->subject_list)
778                 job_dependency_free(j->subject_list);
779
780         while (j->object_list) {
781                 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
782
783                 job_dependency_free(j->object_list);
784
785                 if (other && delete_dependencies) {
786                         log_debug("Deleting job %s/%s as dependency of job %s/%s",
787                                   other->unit->id, job_type_to_string(other->type),
788                                   j->unit->id, job_type_to_string(j->type));
789                         transaction_delete_job(tr, other, delete_dependencies);
790                 }
791         }
792 }
793
794 int transaction_add_job_and_dependencies(
795                 Transaction *tr,
796                 JobType type,
797                 Unit *unit,
798                 Job *by,
799                 bool matters,
800                 bool override,
801                 bool conflicts,
802                 bool ignore_requirements,
803                 bool ignore_order,
804                 DBusError *e) {
805         Job *ret;
806         Iterator i;
807         Unit *dep;
808         int r;
809         bool is_new;
810
811         assert(tr);
812         assert(type < _JOB_TYPE_MAX);
813         assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
814         assert(unit);
815
816         /* log_debug("Pulling in %s/%s from %s/%s", */
817         /*           unit->id, job_type_to_string(type), */
818         /*           by ? by->unit->id : "NA", */
819         /*           by ? job_type_to_string(by->type) : "NA"); */
820
821         if (unit->load_state != UNIT_LOADED &&
822             unit->load_state != UNIT_ERROR &&
823             unit->load_state != UNIT_MASKED) {
824                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
825                 return -EINVAL;
826         }
827
828         if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
829                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
830                                "Unit %s failed to load: %s. "
831                                "See system logs and 'systemctl status %s' for details.",
832                                unit->id,
833                                strerror(-unit->load_error),
834                                unit->id);
835                 return -EINVAL;
836         }
837
838         if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
839                 dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id);
840                 return -EADDRNOTAVAIL;
841         }
842
843         if (!unit_job_is_applicable(unit, type)) {
844                 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);
845                 return -EBADR;
846         }
847
848         /* First add the job. */
849         ret = transaction_add_one_job(tr, type, unit, override, &is_new);
850         if (!ret)
851                 return -ENOMEM;
852
853         ret->ignore_order = ret->ignore_order || ignore_order;
854
855         /* Then, add a link to the job. */
856         if (by) {
857                 if (!job_dependency_new(by, ret, matters, conflicts))
858                         return -ENOMEM;
859         } else {
860                 /* If the job has no parent job, it is the anchor job. */
861                 assert(!tr->anchor_job);
862                 tr->anchor_job = ret;
863         }
864
865         if (is_new && !ignore_requirements && type != JOB_NOP) {
866                 Set *following;
867
868                 /* If we are following some other unit, make sure we
869                  * add all dependencies of everybody following. */
870                 if (unit_following_set(ret->unit, &following) > 0) {
871                         SET_FOREACH(dep, following, i) {
872                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
873                                 if (r < 0) {
874                                         log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
875
876                                         if (e)
877                                                 dbus_error_free(e);
878                                 }
879                         }
880
881                         set_free(following);
882                 }
883
884                 /* Finally, recursively add in all dependencies. */
885                 if (type == JOB_START || type == JOB_RESTART) {
886                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
887                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
888                                 if (r < 0) {
889                                         if (r != -EBADR)
890                                                 goto fail;
891
892                                         if (e)
893                                                 dbus_error_free(e);
894                                 }
895                         }
896
897                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
898                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
899                                 if (r < 0) {
900                                         if (r != -EBADR)
901                                                 goto fail;
902
903                                         if (e)
904                                                 dbus_error_free(e);
905                                 }
906                         }
907
908                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
909                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
910                                 if (r < 0) {
911                                         log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
912                                                  "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
913
914                                         if (e)
915                                                 dbus_error_free(e);
916                                 }
917                         }
918
919                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
920                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
921                                 if (r < 0) {
922                                         log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
923                                                  "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
924
925                                         if (e)
926                                                 dbus_error_free(e);
927                                 }
928                         }
929
930                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
931                                 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
932                                 if (r < 0) {
933                                         if (r != -EBADR)
934                                                 goto fail;
935
936                                         if (e)
937                                                 dbus_error_free(e);
938                                 }
939                         }
940
941                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
942                                 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
943                                 if (r < 0) {
944                                         log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
945                                                  "Cannot add dependency job for unit %s, ignoring: %s", 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_CONFLICTS], i) {
953                                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
954                                 if (r < 0) {
955                                         if (r != -EBADR)
956                                                 goto fail;
957
958                                         if (e)
959                                                 dbus_error_free(e);
960                                 }
961                         }
962
963                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
964                                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
965                                 if (r < 0) {
966                                         log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
967
968                                         if (e)
969                                                 dbus_error_free(e);
970                                 }
971                         }
972
973                 }
974
975                 if (type == JOB_STOP || type == JOB_RESTART) {
976
977                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
978                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
979                                 if (r < 0) {
980                                         if (r != -EBADR)
981                                                 goto fail;
982
983                                         if (e)
984                                                 dbus_error_free(e);
985                                 }
986                         }
987
988                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
989                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
990                                 if (r < 0) {
991                                         if (r != -EBADR)
992                                                 goto fail;
993
994                                         if (e)
995                                                 dbus_error_free(e);
996                                 }
997                         }
998
999                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
1000                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1001                                 if (r < 0) {
1002                                         if (r != -EBADR)
1003                                                 goto fail;
1004
1005                                         if (e)
1006                                                 dbus_error_free(e);
1007                                 }
1008                         }
1009
1010                 }
1011
1012                 if (type == JOB_RELOAD) {
1013
1014                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
1015                                 r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
1016                                 if (r < 0) {
1017                                         log_warning("Cannot add dependency reload job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
1018
1019                                         if (e)
1020                                                 dbus_error_free(e);
1021                                 }
1022                         }
1023                 }
1024
1025                 /* JOB_VERIFY_STARTED require no dependency handling */
1026         }
1027
1028         return 0;
1029
1030 fail:
1031         return r;
1032 }
1033
1034 int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
1035         Iterator i;
1036         Unit *u;
1037         char *k;
1038         int r;
1039
1040         assert(tr);
1041         assert(m);
1042
1043         HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1044
1045                 /* ignore aliases */
1046                 if (u->id != k)
1047                         continue;
1048
1049                 if (u->ignore_on_isolate)
1050                         continue;
1051
1052                 /* No need to stop inactive jobs */
1053                 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
1054                         continue;
1055
1056                 /* Is there already something listed for this? */
1057                 if (hashmap_get(tr->jobs, u))
1058                         continue;
1059
1060                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
1061                 if (r < 0)
1062                         log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->id, strerror(-r));
1063         }
1064
1065         return 0;
1066 }
1067
1068 Transaction *transaction_new(void) {
1069         Transaction *tr;
1070
1071         tr = new0(Transaction, 1);
1072         if (!tr)
1073                 return NULL;
1074
1075         tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func);
1076         if (!tr->jobs) {
1077                 free(tr);
1078                 return NULL;
1079         }
1080
1081         return tr;
1082 }
1083
1084 void transaction_free(Transaction *tr) {
1085         assert(hashmap_isempty(tr->jobs));
1086         hashmap_free(tr->jobs);
1087         free(tr);
1088 }