chiark / gitweb /
shutdown: issue a sync() as soon as shutdown.target is queued
[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                 job_shutdown_magic(j);
624         }
625
626         return 0;
627
628 rollback:
629
630         HASHMAP_FOREACH(j, tr->jobs, i)
631                 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
632
633         return r;
634 }
635
636 int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e) {
637         Iterator i;
638         Job *j;
639         int r;
640         unsigned generation = 1;
641
642         assert(tr);
643
644         /* This applies the changes recorded in tr->jobs to
645          * the actual list of jobs, if possible. */
646
647         /* Reset the generation counter of all installed jobs. The detection of cycles
648          * looks at installed jobs. If they had a non-zero generation from some previous
649          * walk of the graph, the algorithm would break. */
650         HASHMAP_FOREACH(j, m->jobs, i)
651                 j->generation = 0;
652
653         /* First step: figure out which jobs matter */
654         transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
655
656         /* Second step: Try not to stop any running services if
657          * we don't have to. Don't try to reverse running
658          * jobs if we don't have to. */
659         if (mode == JOB_FAIL)
660                 transaction_minimize_impact(tr);
661
662         /* Third step: Drop redundant jobs */
663         transaction_drop_redundant(tr);
664
665         for (;;) {
666                 /* Fourth step: Let's remove unneeded jobs that might
667                  * be lurking. */
668                 if (mode != JOB_ISOLATE)
669                         transaction_collect_garbage(tr);
670
671                 /* Fifth step: verify order makes sense and correct
672                  * cycles if necessary and possible */
673                 r = transaction_verify_order(tr, &generation, e);
674                 if (r >= 0)
675                         break;
676
677                 if (r != -EAGAIN) {
678                         log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, r));
679                         return r;
680                 }
681
682                 /* Let's see if the resulting transaction ordering
683                  * graph is still cyclic... */
684         }
685
686         for (;;) {
687                 /* Sixth step: let's drop unmergeable entries if
688                  * necessary and possible, merge entries we can
689                  * merge */
690                 r = transaction_merge_jobs(tr, e);
691                 if (r >= 0)
692                         break;
693
694                 if (r != -EAGAIN) {
695                         log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r));
696                         return r;
697                 }
698
699                 /* Seventh step: an entry got dropped, let's garbage
700                  * collect its dependencies. */
701                 if (mode != JOB_ISOLATE)
702                         transaction_collect_garbage(tr);
703
704                 /* Let's see if the resulting transaction still has
705                  * unmergeable entries ... */
706         }
707
708         /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
709         transaction_drop_redundant(tr);
710
711         /* Ninth step: check whether we can actually apply this */
712         if (mode == JOB_FAIL) {
713                 r = transaction_is_destructive(tr, e);
714                 if (r < 0) {
715                         log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r));
716                         return r;
717                 }
718         }
719
720         /* Tenth step: apply changes */
721         r = transaction_apply(tr, m, mode);
722         if (r < 0) {
723                 log_warning("Failed to apply transaction: %s", strerror(-r));
724                 return r;
725         }
726
727         assert(hashmap_isempty(tr->jobs));
728
729         if (!hashmap_isempty(m->jobs)) {
730                 /* Are there any jobs now? Then make sure we have the
731                  * idle pipe around. We don't really care too much
732                  * whether this works or not, as the idle pipe is a
733                  * feature for cosmetics, not actually useful for
734                  * anything beyond that. */
735
736                 if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0)
737                         pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
738         }
739
740         return 0;
741 }
742
743 static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
744         Job *j, *f;
745
746         assert(tr);
747         assert(unit);
748
749         /* Looks for an existing prospective job and returns that. If
750          * it doesn't exist it is created and added to the prospective
751          * jobs list. */
752
753         f = hashmap_get(tr->jobs, unit);
754
755         LIST_FOREACH(transaction, j, f) {
756                 assert(j->unit == unit);
757
758                 if (j->type == type) {
759                         if (is_new)
760                                 *is_new = false;
761                         return j;
762                 }
763         }
764
765         j = job_new(unit, type);
766         if (!j)
767                 return NULL;
768
769         j->generation = 0;
770         j->marker = NULL;
771         j->matters_to_anchor = false;
772         j->override = override;
773
774         LIST_PREPEND(Job, transaction, f, j);
775
776         if (hashmap_replace(tr->jobs, unit, f) < 0) {
777                 LIST_REMOVE(Job, transaction, f, j);
778                 job_free(j);
779                 return NULL;
780         }
781
782         if (is_new)
783                 *is_new = true;
784
785         /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
786
787         return j;
788 }
789
790 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
791         assert(tr);
792         assert(j);
793
794         if (j->transaction_prev)
795                 j->transaction_prev->transaction_next = j->transaction_next;
796         else if (j->transaction_next)
797                 hashmap_replace(tr->jobs, j->unit, j->transaction_next);
798         else
799                 hashmap_remove_value(tr->jobs, j->unit, j);
800
801         if (j->transaction_next)
802                 j->transaction_next->transaction_prev = j->transaction_prev;
803
804         j->transaction_prev = j->transaction_next = NULL;
805
806         while (j->subject_list)
807                 job_dependency_free(j->subject_list);
808
809         while (j->object_list) {
810                 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
811
812                 job_dependency_free(j->object_list);
813
814                 if (other && delete_dependencies) {
815                         log_debug_unit(other->unit->id,
816                                        "Deleting job %s/%s as dependency of job %s/%s",
817                                        other->unit->id, job_type_to_string(other->type),
818                                        j->unit->id, job_type_to_string(j->type));
819                         transaction_delete_job(tr, other, delete_dependencies);
820                 }
821         }
822 }
823
824 int transaction_add_job_and_dependencies(
825                 Transaction *tr,
826                 JobType type,
827                 Unit *unit,
828                 Job *by,
829                 bool matters,
830                 bool override,
831                 bool conflicts,
832                 bool ignore_requirements,
833                 bool ignore_order,
834                 DBusError *e) {
835         Job *ret;
836         Iterator i;
837         Unit *dep;
838         int r;
839         bool is_new;
840
841         assert(tr);
842         assert(type < _JOB_TYPE_MAX);
843         assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
844         assert(unit);
845
846         /* log_debug("Pulling in %s/%s from %s/%s", */
847         /*           unit->id, job_type_to_string(type), */
848         /*           by ? by->unit->id : "NA", */
849         /*           by ? job_type_to_string(by->type) : "NA"); */
850
851         if (unit->load_state != UNIT_LOADED &&
852             unit->load_state != UNIT_ERROR &&
853             unit->load_state != UNIT_MASKED) {
854                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
855                 return -EINVAL;
856         }
857
858         if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
859                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
860                                "Unit %s failed to load: %s. "
861                                "See system logs and 'systemctl status %s' for details.",
862                                unit->id,
863                                strerror(-unit->load_error),
864                                unit->id);
865                 return -EINVAL;
866         }
867
868         if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
869                 dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id);
870                 return -EADDRNOTAVAIL;
871         }
872
873         if (!unit_job_is_applicable(unit, type)) {
874                 dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id);
875                 return -EBADR;
876         }
877
878         /* First add the job. */
879         ret = transaction_add_one_job(tr, type, unit, override, &is_new);
880         if (!ret)
881                 return -ENOMEM;
882
883         ret->ignore_order = ret->ignore_order || ignore_order;
884
885         /* Then, add a link to the job. */
886         if (by) {
887                 if (!job_dependency_new(by, ret, matters, conflicts))
888                         return -ENOMEM;
889         } else {
890                 /* If the job has no parent job, it is the anchor job. */
891                 assert(!tr->anchor_job);
892                 tr->anchor_job = ret;
893         }
894
895         if (is_new && !ignore_requirements && type != JOB_NOP) {
896                 Set *following;
897
898                 /* If we are following some other unit, make sure we
899                  * add all dependencies of everybody following. */
900                 if (unit_following_set(ret->unit, &following) > 0) {
901                         SET_FOREACH(dep, following, i) {
902                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
903                                 if (r < 0) {
904                                         log_warning_unit(dep->id,
905                                                          "Cannot add dependency job for unit %s, ignoring: %s",
906                                                          dep->id, bus_error(e, r));
907
908                                         if (e)
909                                                 dbus_error_free(e);
910                                 }
911                         }
912
913                         set_free(following);
914                 }
915
916                 /* Finally, recursively add in all dependencies. */
917                 if (type == JOB_START || type == JOB_RESTART) {
918                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
919                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
920                                 if (r < 0) {
921                                         if (r != -EBADR)
922                                                 goto fail;
923
924                                         if (e)
925                                                 dbus_error_free(e);
926                                 }
927                         }
928
929                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
930                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
931                                 if (r < 0) {
932                                         if (r != -EBADR)
933                                                 goto fail;
934
935                                         if (e)
936                                                 dbus_error_free(e);
937                                 }
938                         }
939
940                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
941                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
942                                 if (r < 0) {
943                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
944                                                       "Cannot add dependency job for unit %s, ignoring: %s",
945                                                       dep->id, bus_error(e, r));
946
947                                         if (e)
948                                                 dbus_error_free(e);
949                                 }
950                         }
951
952                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
953                                 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
954                                 if (r < 0) {
955                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
956                                                       "Cannot add dependency job for unit %s, ignoring: %s",
957                                                       dep->id, bus_error(e, r));
958
959                                         if (e)
960                                                 dbus_error_free(e);
961                                 }
962                         }
963
964                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
965                                 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
966                                 if (r < 0) {
967                                         if (r != -EBADR)
968                                                 goto fail;
969
970                                         if (e)
971                                                 dbus_error_free(e);
972                                 }
973                         }
974
975                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
976                                 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
977                                 if (r < 0) {
978                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
979                                                       "Cannot add dependency job for unit %s, ignoring: %s",
980                                                       dep->id, bus_error(e, r));
981
982                                         if (e)
983                                                 dbus_error_free(e);
984                                 }
985                         }
986
987                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
988                                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
989                                 if (r < 0) {
990                                         if (r != -EBADR)
991                                                 goto fail;
992
993                                         if (e)
994                                                 dbus_error_free(e);
995                                 }
996                         }
997
998                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
999                                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
1000                                 if (r < 0) {
1001                                         log_warning_unit(dep->id,
1002                                                          "Cannot add dependency job for unit %s, ignoring: %s",
1003                                                          dep->id, bus_error(e, r));
1004
1005                                         if (e)
1006                                                 dbus_error_free(e);
1007                                 }
1008                         }
1009
1010                 }
1011
1012                 if (type == JOB_STOP || type == JOB_RESTART) {
1013
1014                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
1015                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1016                                 if (r < 0) {
1017                                         if (r != -EBADR)
1018                                                 goto fail;
1019
1020                                         if (e)
1021                                                 dbus_error_free(e);
1022                                 }
1023                         }
1024
1025                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
1026                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1027                                 if (r < 0) {
1028                                         if (r != -EBADR)
1029                                                 goto fail;
1030
1031                                         if (e)
1032                                                 dbus_error_free(e);
1033                                 }
1034                         }
1035
1036                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
1037                                 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1038                                 if (r < 0) {
1039                                         if (r != -EBADR)
1040                                                 goto fail;
1041
1042                                         if (e)
1043                                                 dbus_error_free(e);
1044                                 }
1045                         }
1046
1047                 }
1048
1049                 if (type == JOB_RELOAD) {
1050
1051                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
1052                                 r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
1053                                 if (r < 0) {
1054                                         log_warning_unit(dep->id,
1055                                                          "Cannot add dependency reload job for unit %s, ignoring: %s",
1056                                                          dep->id, bus_error(e, r));
1057
1058                                         if (e)
1059                                                 dbus_error_free(e);
1060                                 }
1061                         }
1062                 }
1063
1064                 /* JOB_VERIFY_STARTED require no dependency handling */
1065         }
1066
1067         return 0;
1068
1069 fail:
1070         return r;
1071 }
1072
1073 int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
1074         Iterator i;
1075         Unit *u;
1076         char *k;
1077         int r;
1078
1079         assert(tr);
1080         assert(m);
1081
1082         HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1083
1084                 /* ignore aliases */
1085                 if (u->id != k)
1086                         continue;
1087
1088                 if (u->ignore_on_isolate)
1089                         continue;
1090
1091                 /* No need to stop inactive jobs */
1092                 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
1093                         continue;
1094
1095                 /* Is there already something listed for this? */
1096                 if (hashmap_get(tr->jobs, u))
1097                         continue;
1098
1099                 r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
1100                 if (r < 0)
1101                         log_warning_unit(u->id,
1102                                          "Cannot add isolate job for unit %s, ignoring: %s",
1103                                          u->id, strerror(-r));
1104         }
1105
1106         return 0;
1107 }
1108
1109 Transaction *transaction_new(void) {
1110         Transaction *tr;
1111
1112         tr = new0(Transaction, 1);
1113         if (!tr)
1114                 return NULL;
1115
1116         tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func);
1117         if (!tr->jobs) {
1118                 free(tr);
1119                 return NULL;
1120         }
1121
1122         return tr;
1123 }
1124
1125 void transaction_free(Transaction *tr) {
1126         assert(hashmap_isempty(tr->jobs));
1127         hashmap_free(tr->jobs);
1128         free(tr);
1129 }