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)) {
353 sprintf(ans
+ size
, "%s%s", unit_log_field
, *unit_id
);
355 ans
[size
+ next
] = '\n';
362 static int transaction_verify_order_one(Transaction
*tr
, Job
*j
, Job
*from
, unsigned generation
, sd_bus_error
*e
) {
370 assert(!j
->transaction_prev
);
372 /* Does a recursive sweep through the ordering graph, looking
373 * for a cycle. If we find a cycle we try to break it. */
375 /* Have we seen this before? */
376 if (j
->generation
== generation
) {
377 Job
*k
, *delete = NULL
;
378 _cleanup_free_
char **array
= NULL
, *unit_ids
= NULL
;
379 char **unit_id
, **job_type
;
381 /* If the marker is NULL we have been here already and
382 * decided the job was loop-free from here. Hence
383 * shortcut things and return right-away. */
387 /* So, the marker is not NULL and we already have been here. We have
388 * a cycle. Let's try to break it. We go backwards in our path and
389 * try to find a suitable job to remove. We use the marker to find
390 * our way back, since smart how we are we stored our way back in
393 for (k
= from
; k
; k
= ((k
->generation
== generation
&& k
->marker
!= k
) ? k
->marker
: NULL
)) {
395 /* For logging below */
396 if (strv_push_pair(&array
, k
->unit
->id
, (char*) job_type_to_string(k
->type
)) < 0)
399 if (!delete && hashmap_get(tr
->jobs
, k
->unit
) && !unit_matters_to_anchor(k
->unit
, k
))
400 /* Ok, we can drop this one, so let's do so. */
403 /* Check if this in fact was the beginning of the cycle */
408 unit_ids
= merge_unit_ids(j
->manager
->unit_log_field
, array
); /* ignore error */
410 STRV_FOREACH_PAIR(unit_id
, job_type
, array
)
411 /* logging for j not k here to provide a consistent narrative */
412 log_struct(LOG_WARNING
,
413 "MESSAGE=%s: Found %s on %s/%s",
415 unit_id
== array
? "ordering cycle" : "dependency",
421 /* logging for j not k here to provide a consistent narrative */
423 "MESSAGE=%s: Job %s/%s deleted to break ordering cycle starting with %s/%s",
424 j
->unit
->id
, delete->unit
->id
, job_type_to_string(delete->type
),
425 j
->unit
->id
, job_type_to_string(j
->type
),
428 if (log_get_show_color())
429 status
= ANSI_HIGHLIGHT_RED
" SKIP " ANSI_NORMAL
;
433 unit_status_printf(delete->unit
, status
,
434 "Ordering cycle found, skipping %s");
435 transaction_delete_unit(tr
, delete->unit
);
440 "MESSAGE=%s: Unable to break cycle starting with %s/%s",
441 j
->unit
->id
, j
->unit
->id
, job_type_to_string(j
->type
),
444 return sd_bus_error_setf(e
, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC
,
445 "Transaction order is cyclic. See system logs for details.");
448 /* Make the marker point to where we come from, so that we can
449 * find our way backwards if we want to break a cycle. We use
450 * a special marker for the beginning: we point to
452 j
->marker
= from
? from
: j
;
453 j
->generation
= generation
;
455 /* We assume that the dependencies are bidirectional, and
456 * hence can ignore UNIT_AFTER */
457 HASHMAP_FOREACH_KEY(v
, u
, j
->unit
->dependencies
[UNIT_BEFORE
], i
) {
460 /* Is there a job for this unit? */
461 o
= hashmap_get(tr
->jobs
, u
);
463 /* Ok, there is no job for this in the
464 * transaction, but maybe there is already one
471 r
= transaction_verify_order_one(tr
, o
, j
, generation
, e
);
476 /* Ok, let's backtrack, and remember that this entry is not on
477 * our path anymore. */
483 static int transaction_verify_order(Transaction
*tr
, unsigned *generation
, sd_bus_error
*e
) {
492 /* Check if the ordering graph is cyclic. If it is, try to fix
493 * that up by dropping one of the jobs. */
497 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
498 r
= transaction_verify_order_one(tr
, j
, NULL
, g
, e
);
506 static void transaction_collect_garbage(Transaction
*tr
) {
512 /* Drop jobs that are not required by any other job */
515 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
516 if (tr
->anchor_job
== j
|| j
->object_list
) {
517 /* log_debug("Keeping job %s/%s because of %s/%s", */
518 /* j->unit->id, job_type_to_string(j->type), */
519 /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */
520 /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
524 /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
525 transaction_delete_job(tr
, j
, true);
530 static int transaction_is_destructive(Transaction
*tr
, JobMode mode
, sd_bus_error
*e
) {
536 /* Checks whether applying this transaction means that
537 * existing jobs would be replaced */
539 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
542 assert(!j
->transaction_prev
);
543 assert(!j
->transaction_next
);
545 if (j
->unit
->job
&& (mode
== JOB_FAIL
|| j
->unit
->job
->irreversible
) &&
546 job_type_is_conflicting(j
->unit
->job
->type
, j
->type
))
547 return sd_bus_error_setf(e
, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE
,
548 "Transaction is destructive.");
554 static void transaction_minimize_impact(Transaction
*tr
) {
560 /* Drops all unnecessary jobs that reverse already active jobs
561 * or that stop a running service. */
564 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
565 LIST_FOREACH(transaction
, j
, j
) {
566 bool stops_running_service
, changes_existing_job
;
568 /* If it matters, we shouldn't drop it */
569 if (j
->matters_to_anchor
)
572 /* Would this stop a running service?
573 * Would this change an existing job?
574 * If so, let's drop this entry */
576 stops_running_service
=
577 j
->type
== JOB_STOP
&& UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j
->unit
));
579 changes_existing_job
=
581 job_type_is_conflicting(j
->type
, j
->unit
->job
->type
);
583 if (!stops_running_service
&& !changes_existing_job
)
586 if (stops_running_service
)
587 log_unit_debug(j
->unit
,
588 "%s/%s would stop a running service.",
589 j
->unit
->id
, job_type_to_string(j
->type
));
591 if (changes_existing_job
)
592 log_unit_debug(j
->unit
,
593 "%s/%s would change existing job.",
594 j
->unit
->id
, job_type_to_string(j
->type
));
596 /* Ok, let's get rid of this */
597 log_unit_debug(j
->unit
,
598 "Deleting %s/%s to minimize impact.",
599 j
->unit
->id
, job_type_to_string(j
->type
));
601 transaction_delete_job(tr
, j
, true);
607 static int transaction_apply(Transaction
*tr
, Manager
*m
, JobMode mode
) {
612 /* Moves the transaction jobs to the set of active jobs */
614 if (IN_SET(mode
, JOB_ISOLATE
, JOB_FLUSH
)) {
616 /* When isolating first kill all installed jobs which
617 * aren't part of the new transaction */
618 HASHMAP_FOREACH(j
, m
->jobs
, i
) {
619 assert(j
->installed
);
621 if (j
->unit
->ignore_on_isolate
)
624 if (hashmap_get(tr
->jobs
, j
->unit
))
627 /* Not invalidating recursively. Avoids triggering
628 * OnFailure= actions of dependent jobs. Also avoids
629 * invalidating our iterator. */
630 job_finish_and_invalidate(j
, JOB_CANCELED
, false, false);
634 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
636 assert(!j
->transaction_prev
);
637 assert(!j
->transaction_next
);
639 r
= hashmap_put(m
->jobs
, UINT32_TO_PTR(j
->id
), j
);
644 while ((j
= hashmap_steal_first(tr
->jobs
))) {
647 /* Clean the job dependencies */
648 transaction_unlink_job(tr
, j
, false);
650 installed_job
= job_install(j
);
651 if (installed_job
!= j
) {
652 /* j has been merged into a previously installed job */
653 if (tr
->anchor_job
== j
)
654 tr
->anchor_job
= installed_job
;
655 hashmap_remove(m
->jobs
, UINT32_TO_PTR(j
->id
));
660 job_add_to_run_queue(j
);
661 job_add_to_dbus_queue(j
);
662 job_start_timer(j
, false);
663 job_shutdown_magic(j
);
670 HASHMAP_FOREACH(j
, tr
->jobs
, i
)
671 hashmap_remove(m
->jobs
, UINT32_TO_PTR(j
->id
));
676 int transaction_activate(Transaction
*tr
, Manager
*m
, JobMode mode
, sd_bus_error
*e
) {
680 unsigned generation
= 1;
684 /* This applies the changes recorded in tr->jobs to
685 * the actual list of jobs, if possible. */
687 /* Reset the generation counter of all installed jobs. The detection of cycles
688 * looks at installed jobs. If they had a non-zero generation from some previous
689 * walk of the graph, the algorithm would break. */
690 HASHMAP_FOREACH(j
, m
->jobs
, i
)
693 /* First step: figure out which jobs matter */
694 transaction_find_jobs_that_matter_to_anchor(tr
->anchor_job
, generation
++);
696 /* Second step: Try not to stop any running services if
697 * we don't have to. Don't try to reverse running
698 * jobs if we don't have to. */
699 if (mode
== JOB_FAIL
)
700 transaction_minimize_impact(tr
);
702 /* Third step: Drop redundant jobs */
703 transaction_drop_redundant(tr
);
706 /* Fourth step: Let's remove unneeded jobs that might
708 if (mode
!= JOB_ISOLATE
)
709 transaction_collect_garbage(tr
);
711 /* Fifth step: verify order makes sense and correct
712 * cycles if necessary and possible */
713 r
= transaction_verify_order(tr
, &generation
, e
);
718 log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e
, r
));
722 /* Let's see if the resulting transaction ordering
723 * graph is still cyclic... */
727 /* Sixth step: let's drop unmergeable entries if
728 * necessary and possible, merge entries we can
730 r
= transaction_merge_jobs(tr
, e
);
735 log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e
, r
));
739 /* Seventh step: an entry got dropped, let's garbage
740 * collect its dependencies. */
741 if (mode
!= JOB_ISOLATE
)
742 transaction_collect_garbage(tr
);
744 /* Let's see if the resulting transaction still has
745 * unmergeable entries ... */
748 /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
749 transaction_drop_redundant(tr
);
751 /* Ninth step: check whether we can actually apply this */
752 r
= transaction_is_destructive(tr
, mode
, e
);
754 log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e
, r
));
758 /* Tenth step: apply changes */
759 r
= transaction_apply(tr
, m
, mode
);
761 return log_warning_errno(r
, "Failed to apply transaction: %m");
763 assert(hashmap_isempty(tr
->jobs
));
765 if (!hashmap_isempty(m
->jobs
)) {
766 /* Are there any jobs now? Then make sure we have the
767 * idle pipe around. We don't really care too much
768 * whether this works or not, as the idle pipe is a
769 * feature for cosmetics, not actually useful for
770 * anything beyond that. */
772 if (m
->idle_pipe
[0] < 0 && m
->idle_pipe
[1] < 0 &&
773 m
->idle_pipe
[2] < 0 && m
->idle_pipe
[3] < 0) {
774 (void) pipe2(m
->idle_pipe
, O_NONBLOCK
|O_CLOEXEC
);
775 (void) pipe2(m
->idle_pipe
+ 2, O_NONBLOCK
|O_CLOEXEC
);
782 static Job
* transaction_add_one_job(Transaction
*tr
, JobType type
, Unit
*unit
, bool *is_new
) {
788 /* Looks for an existing prospective job and returns that. If
789 * it doesn't exist it is created and added to the prospective
792 f
= hashmap_get(tr
->jobs
, unit
);
794 LIST_FOREACH(transaction
, j
, f
) {
795 assert(j
->unit
== unit
);
797 if (j
->type
== type
) {
804 j
= job_new(unit
, type
);
810 j
->matters_to_anchor
= false;
811 j
->irreversible
= tr
->irreversible
;
813 LIST_PREPEND(transaction
, f
, j
);
815 if (hashmap_replace(tr
->jobs
, unit
, f
) < 0) {
816 LIST_REMOVE(transaction
, f
, j
);
824 /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
829 static void transaction_unlink_job(Transaction
*tr
, Job
*j
, bool delete_dependencies
) {
833 if (j
->transaction_prev
)
834 j
->transaction_prev
->transaction_next
= j
->transaction_next
;
835 else if (j
->transaction_next
)
836 hashmap_replace(tr
->jobs
, j
->unit
, j
->transaction_next
);
838 hashmap_remove_value(tr
->jobs
, j
->unit
, j
);
840 if (j
->transaction_next
)
841 j
->transaction_next
->transaction_prev
= j
->transaction_prev
;
843 j
->transaction_prev
= j
->transaction_next
= NULL
;
845 while (j
->subject_list
)
846 job_dependency_free(j
->subject_list
);
848 while (j
->object_list
) {
849 Job
*other
= j
->object_list
->matters
? j
->object_list
->subject
: NULL
;
851 job_dependency_free(j
->object_list
);
853 if (other
&& delete_dependencies
) {
854 log_unit_debug(other
->unit
,
855 "Deleting job %s/%s as dependency of job %s/%s",
856 other
->unit
->id
, job_type_to_string(other
->type
),
857 j
->unit
->id
, job_type_to_string(j
->type
));
858 transaction_delete_job(tr
, other
, delete_dependencies
);
863 void transaction_add_propagate_reload_jobs(Transaction
*tr
, Unit
*unit
, Job
*by
, bool ignore_order
, sd_bus_error
*e
) {
873 HASHMAP_FOREACH_KEY(v
, dep
, unit
->dependencies
[UNIT_PROPAGATES_RELOAD_TO
], i
) {
874 nt
= job_type_collapse(JOB_TRY_RELOAD
, dep
);
878 r
= transaction_add_job_and_dependencies(tr
, nt
, dep
, by
, false, false, false, ignore_order
, e
);
880 log_unit_warning(dep
,
881 "Cannot add dependency reload job, ignoring: %s",
882 bus_error_message(e
, r
));
883 sd_bus_error_free(e
);
888 int transaction_add_job_and_dependencies(
895 bool ignore_requirements
,
907 assert(type
< _JOB_TYPE_MAX
);
908 assert(type
< _JOB_TYPE_MAX_IN_TRANSACTION
);
911 /* Before adding jobs for this unit, let's ensure that its state has been loaded
912 * This matters when jobs are spawned as part of coldplugging itself (see e. g. path_coldplug()).
913 * This way, we "recursively" coldplug units, ensuring that we do not look at state of
914 * not-yet-coldplugged units. */
915 if (MANAGER_IS_RELOADING(unit
->manager
))
918 /* log_debug("Pulling in %s/%s from %s/%s", */
919 /* unit->id, job_type_to_string(type), */
920 /* by ? by->unit->id : "NA", */
921 /* by ? job_type_to_string(by->type) : "NA"); */
923 if (!IN_SET(unit
->load_state
, UNIT_LOADED
, UNIT_ERROR
, UNIT_NOT_FOUND
, UNIT_MASKED
))
924 return sd_bus_error_setf(e
, BUS_ERROR_LOAD_FAILED
, "Unit %s is not loaded properly.", unit
->id
);
926 if (type
!= JOB_STOP
) {
927 r
= bus_unit_check_load_state(unit
, e
);
932 if (!unit_job_is_applicable(unit
, type
))
933 return sd_bus_error_setf(e
, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE
,
934 "Job type %s is not applicable for unit %s.",
935 job_type_to_string(type
), unit
->id
);
938 /* First add the job. */
939 ret
= transaction_add_one_job(tr
, type
, unit
, &is_new
);
943 ret
->ignore_order
= ret
->ignore_order
|| ignore_order
;
945 /* Then, add a link to the job. */
947 if (!job_dependency_new(by
, ret
, matters
, conflicts
))
950 /* If the job has no parent job, it is the anchor job. */
951 assert(!tr
->anchor_job
);
952 tr
->anchor_job
= ret
;
955 if (is_new
&& !ignore_requirements
&& type
!= JOB_NOP
) {
958 /* If we are following some other unit, make sure we
959 * add all dependencies of everybody following. */
960 if (unit_following_set(ret
->unit
, &following
) > 0) {
961 SET_FOREACH(dep
, following
, i
) {
962 r
= transaction_add_job_and_dependencies(tr
, type
, dep
, ret
, false, false, false, ignore_order
, e
);
965 r
== -ERFKILL
? LOG_INFO
: LOG_WARNING
,
966 r
, "Cannot add dependency job, ignoring: %s",
967 bus_error_message(e
, r
));
968 sd_bus_error_free(e
);
975 /* Finally, recursively add in all dependencies. */
976 if (IN_SET(type
, JOB_START
, JOB_RESTART
)) {
977 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_REQUIRES
], i
) {
978 r
= transaction_add_job_and_dependencies(tr
, JOB_START
, dep
, ret
, true, false, false, ignore_order
, e
);
980 if (r
!= -EBADR
) /* job type not applicable */
983 sd_bus_error_free(e
);
987 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_BINDS_TO
], i
) {
988 r
= transaction_add_job_and_dependencies(tr
, JOB_START
, dep
, ret
, true, false, false, ignore_order
, e
);
990 if (r
!= -EBADR
) /* job type not applicable */
993 sd_bus_error_free(e
);
997 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_WANTS
], i
) {
998 r
= transaction_add_job_and_dependencies(tr
, JOB_START
, dep
, ret
, false, false, false, ignore_order
, e
);
1000 /* unit masked, job type not applicable and unit not found are not considered as errors. */
1002 IN_SET(r
, -ERFKILL
, -EBADR
, -ENOENT
) ? LOG_DEBUG
: LOG_WARNING
,
1003 r
, "Cannot add dependency job, ignoring: %s",
1004 bus_error_message(e
, r
));
1005 sd_bus_error_free(e
);
1009 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_REQUISITE
], i
) {
1010 r
= transaction_add_job_and_dependencies(tr
, JOB_VERIFY_ACTIVE
, dep
, ret
, true, false, false, ignore_order
, e
);
1012 if (r
!= -EBADR
) /* job type not applicable */
1015 sd_bus_error_free(e
);
1019 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_CONFLICTS
], i
) {
1020 r
= transaction_add_job_and_dependencies(tr
, JOB_STOP
, dep
, ret
, true, true, false, ignore_order
, e
);
1022 if (r
!= -EBADR
) /* job type not applicable */
1025 sd_bus_error_free(e
);
1029 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[UNIT_CONFLICTED_BY
], i
) {
1030 r
= transaction_add_job_and_dependencies(tr
, JOB_STOP
, dep
, ret
, false, false, false, ignore_order
, e
);
1032 log_unit_warning(dep
,
1033 "Cannot add dependency job, ignoring: %s",
1034 bus_error_message(e
, r
));
1035 sd_bus_error_free(e
);
1041 if (IN_SET(type
, JOB_STOP
, JOB_RESTART
)) {
1042 static const UnitDependency propagate_deps
[] = {
1052 /* We propagate STOP as STOP, but RESTART only
1053 * as TRY_RESTART, in order not to start
1054 * dependencies that are not around. */
1055 ptype
= type
== JOB_RESTART
? JOB_TRY_RESTART
: type
;
1057 for (j
= 0; j
< ELEMENTSOF(propagate_deps
); j
++)
1058 HASHMAP_FOREACH_KEY(v
, dep
, ret
->unit
->dependencies
[propagate_deps
[j
]], i
) {
1061 nt
= job_type_collapse(ptype
, dep
);
1065 r
= transaction_add_job_and_dependencies(tr
, nt
, dep
, ret
, true, false, false, ignore_order
, e
);
1067 if (r
!= -EBADR
) /* job type not applicable */
1070 sd_bus_error_free(e
);
1075 if (type
== JOB_RELOAD
)
1076 transaction_add_propagate_reload_jobs(tr
, ret
->unit
, ret
, ignore_order
, e
);
1078 /* JOB_VERIFY_STARTED require no dependency handling */
1087 int transaction_add_isolate_jobs(Transaction
*tr
, Manager
*m
) {
1096 HASHMAP_FOREACH_KEY(u
, k
, m
->units
, i
) {
1098 /* ignore aliases */
1102 if (u
->ignore_on_isolate
)
1105 /* No need to stop inactive jobs */
1106 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u
)) && !u
->job
)
1109 /* Is there already something listed for this? */
1110 if (hashmap_get(tr
->jobs
, u
))
1113 r
= transaction_add_job_and_dependencies(tr
, JOB_STOP
, u
, tr
->anchor_job
, true, false, false, false, NULL
);
1115 log_unit_warning_errno(u
, r
, "Cannot add isolate job, ignoring: %m");
1121 Transaction
*transaction_new(bool irreversible
) {
1124 tr
= new0(Transaction
, 1);
1128 tr
->jobs
= hashmap_new(NULL
);
1132 tr
->irreversible
= irreversible
;
1137 void transaction_free(Transaction
*tr
) {
1138 assert(hashmap_isempty(tr
->jobs
));
1139 hashmap_free(tr
->jobs
);