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