1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
25 #include "bus-common-errors.h"
26 #include "bus-error.h"
27 #include "terminal-util.h"
28 #include "transaction.h"
29 #include "dbus-unit.h"
31 static void transaction_unlink_job(Transaction
*tr
, Job
*j
, bool delete_dependencies
);
33 static void transaction_delete_job(Transaction
*tr
, Job
*j
, bool delete_dependencies
) {
37 /* Deletes one job from the transaction */
39 transaction_unlink_job(tr
, j
, delete_dependencies
);
44 static void transaction_delete_unit(Transaction
*tr
, Unit
*u
) {
47 /* Deletes all jobs associated with a certain unit from the
50 while ((j
= hashmap_get(tr
->jobs
, u
)))
51 transaction_delete_job(tr
, j
, true);
54 void transaction_abort(Transaction
*tr
) {
59 while ((j
= hashmap_first(tr
->jobs
)))
60 transaction_delete_job(tr
, j
, false);
62 assert(hashmap_isempty(tr
->jobs
));
65 static void transaction_find_jobs_that_matter_to_anchor(Job
*j
, unsigned generation
) {
68 /* A recursive sweep through the graph that marks all units
69 * that matter to the anchor job, i.e. are directly or
70 * indirectly a dependency of the anchor job via paths that
71 * are fully marked as mattering. */
73 j
->matters_to_anchor
= true;
74 j
->generation
= generation
;
76 LIST_FOREACH(subject
, l
, j
->subject_list
) {
78 /* This link does not matter */
82 /* This unit has already been marked */
83 if (l
->object
->generation
== generation
)
86 transaction_find_jobs_that_matter_to_anchor(l
->object
, generation
);
90 static void transaction_merge_and_delete_job(Transaction
*tr
, Job
*j
, Job
*other
, JobType t
) {
91 JobDependency
*l
, *last
;
95 assert(j
->unit
== other
->unit
);
96 assert(!j
->installed
);
98 /* Merges 'other' into 'j' and then deletes 'other'. */
101 j
->state
= JOB_WAITING
;
102 j
->irreversible
= j
->irreversible
|| other
->irreversible
;
103 j
->matters_to_anchor
= j
->matters_to_anchor
|| other
->matters_to_anchor
;
105 /* Patch us in as new owner of the JobDependency objects */
107 LIST_FOREACH(subject
, l
, other
->subject_list
) {
108 assert(l
->subject
== other
);
113 /* Merge both lists */
115 last
->subject_next
= j
->subject_list
;
117 j
->subject_list
->subject_prev
= last
;
118 j
->subject_list
= other
->subject_list
;
121 /* Patch us in as new owner of the JobDependency objects */
123 LIST_FOREACH(object
, l
, other
->object_list
) {
124 assert(l
->object
== other
);
129 /* Merge both lists */
131 last
->object_next
= j
->object_list
;
133 j
->object_list
->object_prev
= last
;
134 j
->object_list
= other
->object_list
;
137 /* Kill the other job */
138 other
->subject_list
= NULL
;
139 other
->object_list
= NULL
;
140 transaction_delete_job(tr
, other
, true);
143 _pure_
static bool job_is_conflicted_by(Job
*j
) {
148 /* Returns true if this job is pulled in by a least one
149 * ConflictedBy dependency. */
151 LIST_FOREACH(object
, l
, j
->object_list
)
158 static int delete_one_unmergeable_job(Transaction
*tr
, Job
*j
) {
163 /* Tries to delete one item in the linked list
164 * j->transaction_next->transaction_next->... that conflicts
165 * with another one, in an attempt to make an inconsistent
166 * transaction work. */
168 /* We rely here on the fact that if a merged with b does not
169 * merge with c, either a or b merge with c neither */
170 LIST_FOREACH(transaction
, j
, j
)
171 LIST_FOREACH(transaction
, k
, j
->transaction_next
) {
174 /* Is this one mergeable? Then skip it */
175 if (job_type_is_mergeable(j
->type
, k
->type
))
178 /* Ok, we found two that conflict, let's see if we can
179 * drop one of them */
180 if (!j
->matters_to_anchor
&& !k
->matters_to_anchor
) {
182 /* Both jobs don't matter, so let's
183 * find the one that is smarter to
184 * remove. Let's think positive and
185 * rather remove stops then starts --
186 * except if something is being
187 * stopped because it is conflicted by
188 * another unit in which case we
189 * rather remove the start. */
191 log_unit_debug(j
->unit
,
192 "Looking at job %s/%s conflicted_by=%s",
193 j
->unit
->id
, job_type_to_string(j
->type
),
194 yes_no(j
->type
== JOB_STOP
&& job_is_conflicted_by(j
)));
195 log_unit_debug(k
->unit
,
196 "Looking at job %s/%s conflicted_by=%s",
197 k
->unit
->id
, job_type_to_string(k
->type
),
198 yes_no(k
->type
== JOB_STOP
&& job_is_conflicted_by(k
)));
200 if (j
->type
== JOB_STOP
) {
202 if (job_is_conflicted_by(j
))
207 } else if (k
->type
== JOB_STOP
) {
209 if (job_is_conflicted_by(k
))
216 } else if (!j
->matters_to_anchor
)
218 else if (!k
->matters_to_anchor
)
223 /* Ok, we can drop one, so let's do so. */
224 log_unit_debug(d
->unit
,
225 "Fixing conflicting jobs %s/%s,%s/%s by deleting job %s/%s",
226 j
->unit
->id
, job_type_to_string(j
->type
),
227 k
->unit
->id
, job_type_to_string(k
->type
),
228 d
->unit
->id
, job_type_to_string(d
->type
));
229 transaction_delete_job(tr
, d
, true);
236 static int transaction_merge_jobs(Transaction
*tr
, sd_bus_error
*e
) {
243 /* First step, check whether any of the jobs for one specific
244 * task conflict. If so, try to drop one of them. */
245 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
250 LIST_FOREACH(transaction
, k
, j
->transaction_next
) {
251 if (job_type_merge_and_collapse(&t
, k
->type
, j
->unit
) >= 0)
254 /* OK, we could not merge all jobs for this
255 * action. Let's see if we can get rid of one
258 r
= delete_one_unmergeable_job(tr
, j
);
260 /* Ok, we managed to drop one, now
261 * let's ask our callers to call us
262 * again after garbage collecting */
265 /* We couldn't merge anything. Failure */
266 return sd_bus_error_setf(e
, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING
,
267 "Transaction contains conflicting jobs '%s' and '%s' for %s. "
268 "Probably contradicting requirement dependencies configured.",
269 job_type_to_string(t
),
270 job_type_to_string(k
->type
),
275 /* Second step, merge the jobs. */
276 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
280 /* Merge all transaction jobs for j->unit */
281 LIST_FOREACH(transaction
, k
, j
->transaction_next
)
282 assert_se(job_type_merge_and_collapse(&t
, k
->type
, j
->unit
) == 0);
284 while ((k
= j
->transaction_next
)) {
285 if (tr
->anchor_job
== k
) {
286 transaction_merge_and_delete_job(tr
, k
, j
, t
);
289 transaction_merge_and_delete_job(tr
, j
, k
, t
);
292 assert(!j
->transaction_next
);
293 assert(!j
->transaction_prev
);
299 static void transaction_drop_redundant(Transaction
*tr
) {
303 /* Goes through the transaction and removes all jobs of the units
304 * whose jobs are all noops. If not all of a unit's jobs are
305 * redundant, they are kept. */
310 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
313 LIST_FOREACH(transaction
, k
, j
) {
315 if (tr
->anchor_job
== k
||
316 !job_type_is_redundant(k
->type
, unit_active_state(k
->unit
)) ||
317 (k
->unit
->job
&& job_type_is_conflicting(k
->type
, k
->unit
->job
->type
)))
321 /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */
322 transaction_delete_job(tr
, j
, false);
328 _pure_
static bool unit_matters_to_anchor(Unit
*u
, Job
*j
) {
330 assert(!j
->transaction_prev
);
332 /* Checks whether at least one of the jobs for this unit
333 * matters to the anchor. */
335 LIST_FOREACH(transaction
, j
, j
)
336 if (j
->matters_to_anchor
)
342 static char* merge_unit_ids(const char* unit_log_field
, char **pairs
) {
343 char **unit_id
, **job_type
, *ans
= NULL
;
344 size_t alloc
= 0, size
= 0, next
;
346 STRV_FOREACH_PAIR(unit_id
, job_type
, pairs
) {
347 next
= strlen(unit_log_field
) + strlen(*unit_id
);
348 if (!GREEDY_REALLOC(ans
, alloc
, size
+ next
+ 1)) {
352 sprintf(ans
+ size
, "%s%s", unit_log_field
, *unit_id
);
354 ans
[size
+ next
] = '\n';
361 static int transaction_verify_order_one(Transaction
*tr
, Job
*j
, Job
*from
, unsigned generation
, sd_bus_error
*e
) {
369 assert(!j
->transaction_prev
);
371 /* Does a recursive sweep through the ordering graph, looking
372 * for a cycle. If we find a cycle we try to break it. */
374 /* Have we seen this before? */
375 if (j
->generation
== generation
) {
376 Job
*k
, *delete = NULL
;
377 _cleanup_free_
char **array
= NULL
, *unit_ids
= NULL
;
378 char **unit_id
, **job_type
;
380 /* If the marker is NULL we have been here already and
381 * decided the job was loop-free from here. Hence
382 * shortcut things and return right-away. */
386 /* So, the marker is not NULL and we already have been here. We have
387 * a cycle. Let's try to break it. We go backwards in our path and
388 * try to find a suitable job to remove. We use the marker to find
389 * our way back, since smart how we are we stored our way back in
392 for (k
= from
; k
; k
= ((k
->generation
== generation
&& k
->marker
!= k
) ? k
->marker
: NULL
)) {
394 /* For logging below */
395 if (strv_push_pair(&array
, k
->unit
->id
, (char*) job_type_to_string(k
->type
)) < 0)
398 if (!delete && hashmap_get(tr
->jobs
, k
->unit
) && !unit_matters_to_anchor(k
->unit
, k
))
399 /* Ok, we can drop this one, so let's do so. */
402 /* Check if this in fact was the beginning of the cycle */
407 unit_ids
= merge_unit_ids(j
->manager
->unit_log_field
, array
); /* ignore error */
409 STRV_FOREACH_PAIR(unit_id
, job_type
, array
)
410 /* logging for j not k here to provide a consistent narrative */
411 log_struct(LOG_WARNING
,
412 "MESSAGE=%s: Found %s on %s/%s",
414 unit_id
== array
? "ordering cycle" : "dependency",
420 /* logging for j not k here to provide a consistent narrative */
422 "MESSAGE=%s: Job %s/%s deleted to break ordering cycle starting with %s/%s",
423 j
->unit
->id
, delete->unit
->id
, job_type_to_string(delete->type
),
424 j
->unit
->id
, job_type_to_string(j
->type
),
427 if (log_get_show_color())
428 status
= ANSI_HIGHLIGHT_RED
" SKIP " ANSI_NORMAL
;
432 unit_status_printf(delete->unit
, status
,
433 "Ordering cycle found, skipping %s");
434 transaction_delete_unit(tr
, delete->unit
);
439 "MESSAGE=%s: Unable to break cycle starting with %s/%s",
440 j
->unit
->id
, j
->unit
->id
, job_type_to_string(j
->type
),
443 return sd_bus_error_setf(e
, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC
,
444 "Transaction order is cyclic. See system logs for details.");
447 /* Make the marker point to where we come from, so that we can
448 * find our way backwards if we want to break a cycle. We use
449 * a special marker for the beginning: we point to
451 j
->marker
= from
? from
: j
;
452 j
->generation
= generation
;
454 /* We assume that the dependencies are bidirectional, and
455 * hence can ignore UNIT_AFTER */
456 HASHMAP_FOREACH_KEY(v
, u
, j
->unit
->dependencies
[UNIT_BEFORE
], i
) {
459 /* Is there a job for this unit? */
460 o
= hashmap_get(tr
->jobs
, u
);
462 /* Ok, there is no job for this in the
463 * transaction, but maybe there is already one
470 r
= transaction_verify_order_one(tr
, o
, j
, generation
, e
);
475 /* Ok, let's backtrack, and remember that this entry is not on
476 * our path anymore. */
482 static int transaction_verify_order(Transaction
*tr
, unsigned *generation
, sd_bus_error
*e
) {
491 /* Check if the ordering graph is cyclic. If it is, try to fix
492 * that up by dropping one of the jobs. */
496 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
497 r
= transaction_verify_order_one(tr
, j
, NULL
, g
, e
);
505 static void transaction_collect_garbage(Transaction
*tr
) {
511 /* Drop jobs that are not required by any other job */
514 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
515 if (tr
->anchor_job
== j
|| j
->object_list
) {
516 /* log_debug("Keeping job %s/%s because of %s/%s", */
517 /* j->unit->id, job_type_to_string(j->type), */
518 /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */
519 /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
523 /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
524 transaction_delete_job(tr
, j
, true);
529 static int transaction_is_destructive(Transaction
*tr
, JobMode mode
, sd_bus_error
*e
) {
535 /* Checks whether applying this transaction means that
536 * existing jobs would be replaced */
538 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
541 assert(!j
->transaction_prev
);
542 assert(!j
->transaction_next
);
544 if (j
->unit
->job
&& (mode
== JOB_FAIL
|| j
->unit
->job
->irreversible
) &&
545 job_type_is_conflicting(j
->unit
->job
->type
, j
->type
))
546 return sd_bus_error_setf(e
, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE
,
547 "Transaction is destructive.");
553 static void transaction_minimize_impact(Transaction
*tr
) {
559 /* Drops all unnecessary jobs that reverse already active jobs
560 * or that stop a running service. */
563 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
564 LIST_FOREACH(transaction
, j
, j
) {
565 bool stops_running_service
, changes_existing_job
;
567 /* If it matters, we shouldn't drop it */
568 if (j
->matters_to_anchor
)
571 /* Would this stop a running service?
572 * Would this change an existing job?
573 * If so, let's drop this entry */
575 stops_running_service
=
576 j
->type
== JOB_STOP
&& UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j
->unit
));
578 changes_existing_job
=
580 job_type_is_conflicting(j
->type
, j
->unit
->job
->type
);
582 if (!stops_running_service
&& !changes_existing_job
)
585 if (stops_running_service
)
586 log_unit_debug(j
->unit
,
587 "%s/%s would stop a running service.",
588 j
->unit
->id
, job_type_to_string(j
->type
));
590 if (changes_existing_job
)
591 log_unit_debug(j
->unit
,
592 "%s/%s would change existing job.",
593 j
->unit
->id
, job_type_to_string(j
->type
));
595 /* Ok, let's get rid of this */
596 log_unit_debug(j
->unit
,
597 "Deleting %s/%s to minimize impact.",
598 j
->unit
->id
, job_type_to_string(j
->type
));
600 transaction_delete_job(tr
, j
, true);
606 static int transaction_apply(Transaction
*tr
, Manager
*m
, JobMode mode
) {
611 /* Moves the transaction jobs to the set of active jobs */
613 if (IN_SET(mode
, JOB_ISOLATE
, JOB_FLUSH
)) {
615 /* When isolating first kill all installed jobs which
616 * aren't part of the new transaction */
617 HASHMAP_FOREACH(j
, m
->jobs
, i
) {
618 assert(j
->installed
);
620 if (j
->unit
->ignore_on_isolate
)
623 if (hashmap_get(tr
->jobs
, j
->unit
))
626 /* Not invalidating recursively. Avoids triggering
627 * OnFailure= actions of dependent jobs. Also avoids
628 * invalidating our iterator. */
629 job_finish_and_invalidate(j
, JOB_CANCELED
, false, false);
633 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
635 assert(!j
->transaction_prev
);
636 assert(!j
->transaction_next
);
638 r
= hashmap_put(m
->jobs
, UINT32_TO_PTR(j
->id
), j
);
643 while ((j
= hashmap_steal_first(tr
->jobs
))) {
646 /* Clean the job dependencies */
647 transaction_unlink_job(tr
, j
, false);
649 installed_job
= job_install(j
);
650 if (installed_job
!= j
) {
651 /* j has been merged into a previously installed job */
652 if (tr
->anchor_job
== j
)
653 tr
->anchor_job
= installed_job
;
654 hashmap_remove(m
->jobs
, UINT32_TO_PTR(j
->id
));
659 job_add_to_run_queue(j
);
660 job_add_to_dbus_queue(j
);
661 job_start_timer(j
, false);
662 job_shutdown_magic(j
);
669 HASHMAP_FOREACH(j
, tr
->jobs
, i
)
670 hashmap_remove(m
->jobs
, UINT32_TO_PTR(j
->id
));
675 int transaction_activate(Transaction
*tr
, Manager
*m
, JobMode mode
, sd_bus_error
*e
) {
679 unsigned generation
= 1;
683 /* This applies the changes recorded in tr->jobs to
684 * the actual list of jobs, if possible. */
686 /* Reset the generation counter of all installed jobs. The detection of cycles
687 * looks at installed jobs. If they had a non-zero generation from some previous
688 * walk of the graph, the algorithm would break. */
689 HASHMAP_FOREACH(j
, m
->jobs
, i
)
692 /* First step: figure out which jobs matter */
693 transaction_find_jobs_that_matter_to_anchor(tr
->anchor_job
, generation
++);
695 /* Second step: Try not to stop any running services if
696 * we don't have to. Don't try to reverse running
697 * jobs if we don't have to. */
698 if (mode
== JOB_FAIL
)
699 transaction_minimize_impact(tr
);
701 /* Third step: Drop redundant jobs */
702 transaction_drop_redundant(tr
);
705 /* Fourth step: Let's remove unneeded jobs that might
707 if (mode
!= JOB_ISOLATE
)
708 transaction_collect_garbage(tr
);
710 /* Fifth step: verify order makes sense and correct
711 * cycles if necessary and possible */
712 r
= transaction_verify_order(tr
, &generation
, e
);
717 log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e
, r
));
721 /* Let's see if the resulting transaction ordering
722 * graph is still cyclic... */
726 /* Sixth step: let's drop unmergeable entries if
727 * necessary and possible, merge entries we can
729 r
= transaction_merge_jobs(tr
, e
);
734 log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e
, r
));
738 /* Seventh step: an entry got dropped, let's garbage
739 * collect its dependencies. */
740 if (mode
!= JOB_ISOLATE
)
741 transaction_collect_garbage(tr
);
743 /* Let's see if the resulting transaction still has
744 * unmergeable entries ... */
747 /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
748 transaction_drop_redundant(tr
);
750 /* Ninth step: check whether we can actually apply this */
751 r
= transaction_is_destructive(tr
, mode
, e
);
753 log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e
, r
));
757 /* Tenth step: apply changes */
758 r
= transaction_apply(tr
, m
, mode
);
760 return log_warning_errno(r
, "Failed to apply transaction: %m");
762 assert(hashmap_isempty(tr
->jobs
));
764 if (!hashmap_isempty(m
->jobs
)) {
765 /* Are there any jobs now? Then make sure we have the
766 * idle pipe around. We don't really care too much
767 * whether this works or not, as the idle pipe is a
768 * feature for cosmetics, not actually useful for
769 * anything beyond that. */
771 if (m
->idle_pipe
[0] < 0 && m
->idle_pipe
[1] < 0 &&
772 m
->idle_pipe
[2] < 0 && m
->idle_pipe
[3] < 0) {
773 (void) pipe2(m
->idle_pipe
, O_NONBLOCK
|O_CLOEXEC
);
774 (void) pipe2(m
->idle_pipe
+ 2, O_NONBLOCK
|O_CLOEXEC
);
781 static Job
* transaction_add_one_job(Transaction
*tr
, JobType type
, Unit
*unit
, bool *is_new
) {
787 /* Looks for an existing prospective job and returns that. If
788 * it doesn't exist it is created and added to the prospective
791 f
= hashmap_get(tr
->jobs
, unit
);
793 LIST_FOREACH(transaction
, j
, f
) {
794 assert(j
->unit
== unit
);
796 if (j
->type
== type
) {
803 j
= job_new(unit
, type
);
809 j
->matters_to_anchor
= false;
810 j
->irreversible
= tr
->irreversible
;
812 LIST_PREPEND(transaction
, f
, j
);
814 if (hashmap_replace(tr
->jobs
, unit
, f
) < 0) {
815 LIST_REMOVE(transaction
, f
, j
);
823 /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
828 static void transaction_unlink_job(Transaction
*tr
, Job
*j
, bool delete_dependencies
) {
832 if (j
->transaction_prev
)
833 j
->transaction_prev
->transaction_next
= j
->transaction_next
;
834 else if (j
->transaction_next
)
835 hashmap_replace(tr
->jobs
, j
->unit
, j
->transaction_next
);
837 hashmap_remove_value(tr
->jobs
, j
->unit
, j
);
839 if (j
->transaction_next
)
840 j
->transaction_next
->transaction_prev
= j
->transaction_prev
;
842 j
->transaction_prev
= j
->transaction_next
= NULL
;
844 while (j
->subject_list
)
845 job_dependency_free(j
->subject_list
);
847 while (j
->object_list
) {
848 Job
*other
= j
->object_list
->matters
? j
->object_list
->subject
: NULL
;
850 job_dependency_free(j
->object_list
);
852 if (other
&& delete_dependencies
) {
853 log_unit_debug(other
->unit
,
854 "Deleting job %s/%s as dependency of job %s/%s",
855 other
->unit
->id
, job_type_to_string(other
->type
),
856 j
->unit
->id
, job_type_to_string(j
->type
));
857 transaction_delete_job(tr
, other
, delete_dependencies
);
862 void transaction_add_propagate_reload_jobs(Transaction
*tr
, Unit
*unit
, Job
*by
, bool ignore_order
, sd_bus_error
*e
) {
872 HASHMAP_FOREACH_KEY(v
, dep
, unit
->dependencies
[UNIT_PROPAGATES_RELOAD_TO
], i
) {
873 nt
= job_type_collapse(JOB_TRY_RELOAD
, dep
);
877 r
= transaction_add_job_and_dependencies(tr
, nt
, dep
, by
, false, false, false, ignore_order
, e
);
879 log_unit_warning(dep
,
880 "Cannot add dependency reload job, ignoring: %s",
881 bus_error_message(e
, r
));
882 sd_bus_error_free(e
);
887 int transaction_add_job_and_dependencies(
894 bool ignore_requirements
,
906 assert(type
< _JOB_TYPE_MAX
);
907 assert(type
< _JOB_TYPE_MAX_IN_TRANSACTION
);
910 /* Before adding jobs for this unit, let's ensure that its state has been loaded
911 * This matters when jobs are spawned as part of coldplugging itself (see e. g. path_coldplug()).
912 * This way, we "recursively" coldplug units, ensuring that we do not look at state of
913 * not-yet-coldplugged units. */
914 if (MANAGER_IS_RELOADING(unit
->manager
))
917 /* log_debug("Pulling in %s/%s from %s/%s", */
918 /* unit->id, job_type_to_string(type), */
919 /* by ? by->unit->id : "NA", */
920 /* by ? job_type_to_string(by->type) : "NA"); */
922 if (!IN_SET(unit
->load_state
, UNIT_LOADED
, UNIT_ERROR
, UNIT_NOT_FOUND
, UNIT_MASKED
))
923 return sd_bus_error_setf(e
, BUS_ERROR_LOAD_FAILED
, "Unit %s is not loaded properly.", unit
->id
);
925 if (type
!= JOB_STOP
) {
926 r
= bus_unit_check_load_state(unit
, e
);
931 if (!unit_job_is_applicable(unit
, type
))
932 return sd_bus_error_setf(e
, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE
,
933 "Job type %s is not applicable for unit %s.",
934 job_type_to_string(type
), unit
->id
);
937 /* First add the job. */
938 ret
= transaction_add_one_job(tr
, type
, unit
, &is_new
);
942 ret
->ignore_order
= ret
->ignore_order
|| ignore_order
;
944 /* Then, add a link to the job. */
946 if (!job_dependency_new(by
, ret
, matters
, conflicts
))
949 /* If the job has no parent job, it is the anchor job. */
950 assert(!tr
->anchor_job
);
951 tr
->anchor_job
= ret
;
954 if (is_new
&& !ignore_requirements
&& type
!= JOB_NOP
) {
957 /* If we are following some other unit, make sure we
958 * add all dependencies of everybody following. */
959 if (unit_following_set(ret
->unit
, &following
) > 0) {
960 SET_FOREACH(dep
, following
, i
) {
961 r
= transaction_add_job_and_dependencies(tr
, type
, dep
, ret
, false, false, false, ignore_order
, e
);
964 r
== -ERFKILL
? LOG_INFO
: LOG_WARNING
,
965 r
, "Cannot add dependency job, ignoring: %s",
966 bus_error_message(e
, r
));
967 sd_bus_error_free(e
);
974 /* Finally, recursively add in all dependencies. */
975 if (IN_SET(type
, JOB_START
, JOB_RESTART
)) {
976 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_REQUIRES
], i
) {
977 r
= transaction_add_job_and_dependencies(tr
, JOB_START
, dep
, ret
, true, false, false, ignore_order
, e
);
979 if (r
!= -EBADR
) /* job type not applicable */
982 sd_bus_error_free(e
);
986 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_BINDS_TO
], i
) {
987 r
= transaction_add_job_and_dependencies(tr
, JOB_START
, dep
, ret
, true, false, false, ignore_order
, e
);
989 if (r
!= -EBADR
) /* job type not applicable */
992 sd_bus_error_free(e
);
996 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_WANTS
], i
) {
997 r
= transaction_add_job_and_dependencies(tr
, JOB_START
, dep
, ret
, false, false, false, ignore_order
, e
);
999 /* unit masked, job type not applicable and unit not found are not considered as errors. */
1001 IN_SET(r
, -ERFKILL
, -EBADR
, -ENOENT
) ? LOG_DEBUG
: LOG_WARNING
,
1002 r
, "Cannot add dependency job, ignoring: %s",
1003 bus_error_message(e
, r
));
1004 sd_bus_error_free(e
);
1008 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_REQUISITE
], i
) {
1009 r
= transaction_add_job_and_dependencies(tr
, JOB_VERIFY_ACTIVE
, dep
, ret
, true, false, false, ignore_order
, e
);
1011 if (r
!= -EBADR
) /* job type not applicable */
1014 sd_bus_error_free(e
);
1018 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_CONFLICTS
], i
) {
1019 r
= transaction_add_job_and_dependencies(tr
, JOB_STOP
, dep
, ret
, true, true, false, ignore_order
, e
);
1021 if (r
!= -EBADR
) /* job type not applicable */
1024 sd_bus_error_free(e
);
1028 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_CONFLICTED_BY
], i
) {
1029 r
= transaction_add_job_and_dependencies(tr
, JOB_STOP
, dep
, ret
, false, false, false, ignore_order
, e
);
1031 log_unit_warning(dep
,
1032 "Cannot add dependency job, ignoring: %s",
1033 bus_error_message(e
, r
));
1034 sd_bus_error_free(e
);
1040 if (IN_SET(type
, JOB_STOP
, JOB_RESTART
)) {
1041 static const UnitDependency propagate_deps
[] = {
1051 /* We propagate STOP as STOP, but RESTART only
1052 * as TRY_RESTART, in order not to start
1053 * dependencies that are not around. */
1054 ptype
= type
== JOB_RESTART
? JOB_TRY_RESTART
: type
;
1056 for (j
= 0; j
< ELEMENTSOF(propagate_deps
); j
++)
1057 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[propagate_deps
[j
]], i
) {
1060 nt
= job_type_collapse(ptype
, dep
);
1064 r
= transaction_add_job_and_dependencies(tr
, nt
, dep
, ret
, true, false, false, ignore_order
, e
);
1066 if (r
!= -EBADR
) /* job type not applicable */
1069 sd_bus_error_free(e
);
1074 if (type
== JOB_RELOAD
)
1075 transaction_add_propagate_reload_jobs(tr
, ret
->unit
, ret
, ignore_order
, e
);
1077 /* JOB_VERIFY_STARTED require no dependency handling */
1086 int transaction_add_isolate_jobs(Transaction
*tr
, Manager
*m
) {
1095 HASHMAP_FOREACH_KEY(u
, k
, m
->units
, i
) {
1097 /* ignore aliases */
1101 if (u
->ignore_on_isolate
)
1104 /* No need to stop inactive jobs */
1105 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u
)) && !u
->job
)
1108 /* Is there already something listed for this? */
1109 if (hashmap_get(tr
->jobs
, u
))
1112 r
= transaction_add_job_and_dependencies(tr
, JOB_STOP
, u
, tr
->anchor_job
, true, false, false, false, NULL
);
1114 log_unit_warning_errno(u
, r
, "Cannot add isolate job, ignoring: %m");
1120 Transaction
*transaction_new(bool irreversible
) {
1123 tr
= new0(Transaction
, 1);
1127 tr
->jobs
= hashmap_new(NULL
);
1131 tr
->irreversible
= irreversible
;
1136 void transaction_free(Transaction
*tr
) {
1137 assert(hashmap_isempty(tr
->jobs
));
1138 hashmap_free(tr
->jobs
);