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