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