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