1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
25 #include "bus-common-errors.h"
26 #include "bus-error.h"
27 #include "transaction.h"
28 #include "terminal-util.h"
30 static void transaction_unlink_job(Transaction
*tr
, Job
*j
, bool delete_dependencies
);
32 static void transaction_delete_job(Transaction
*tr
, Job
*j
, bool delete_dependencies
) {
36 /* Deletes one job from the transaction */
38 transaction_unlink_job(tr
, j
, delete_dependencies
);
43 static void transaction_delete_unit(Transaction
*tr
, Unit
*u
) {
46 /* Deletes all jobs associated with a certain unit from the
49 while ((j
= hashmap_get(tr
->jobs
, u
)))
50 transaction_delete_job(tr
, j
, true);
53 void transaction_abort(Transaction
*tr
) {
58 while ((j
= hashmap_first(tr
->jobs
)))
59 transaction_delete_job(tr
, j
, false);
61 assert(hashmap_isempty(tr
->jobs
));
64 static void transaction_find_jobs_that_matter_to_anchor(Job
*j
, unsigned generation
) {
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. */
72 j
->matters_to_anchor
= true;
73 j
->generation
= generation
;
75 LIST_FOREACH(subject
, l
, j
->subject_list
) {
77 /* This link does not matter */
81 /* This unit has already been marked */
82 if (l
->object
->generation
== generation
)
85 transaction_find_jobs_that_matter_to_anchor(l
->object
, generation
);
89 static void transaction_merge_and_delete_job(Transaction
*tr
, Job
*j
, Job
*other
, JobType t
) {
90 JobDependency
*l
, *last
;
94 assert(j
->unit
== other
->unit
);
95 assert(!j
->installed
);
97 /* Merges 'other' into 'j' and then deletes 'other'. */
100 j
->state
= JOB_WAITING
;
101 j
->override
= j
->override
|| other
->override
;
102 j
->irreversible
= j
->irreversible
|| other
->irreversible
;
104 j
->matters_to_anchor
= j
->matters_to_anchor
|| other
->matters_to_anchor
;
106 /* Patch us in as new owner of the JobDependency objects */
108 LIST_FOREACH(subject
, l
, other
->subject_list
) {
109 assert(l
->subject
== other
);
114 /* Merge both lists */
116 last
->subject_next
= j
->subject_list
;
118 j
->subject_list
->subject_prev
= last
;
119 j
->subject_list
= other
->subject_list
;
122 /* Patch us in as new owner of the JobDependency objects */
124 LIST_FOREACH(object
, l
, other
->object_list
) {
125 assert(l
->object
== other
);
130 /* Merge both lists */
132 last
->object_next
= j
->object_list
;
134 j
->object_list
->object_prev
= last
;
135 j
->object_list
= other
->object_list
;
138 /* Kill the other job */
139 other
->subject_list
= NULL
;
140 other
->object_list
= NULL
;
141 transaction_delete_job(tr
, other
, true);
144 _pure_
static bool job_is_conflicted_by(Job
*j
) {
149 /* Returns true if this job is pulled in by a least one
150 * ConflictedBy dependency. */
152 LIST_FOREACH(object
, l
, j
->object_list
)
159 static int delete_one_unmergeable_job(Transaction
*tr
, Job
*j
) {
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. */
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
) {
175 /* Is this one mergeable? Then skip it */
176 if (job_type_is_mergeable(j
->type
, k
->type
))
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
) {
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. */
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
)));
201 if (j
->type
== JOB_STOP
) {
203 if (job_is_conflicted_by(j
))
208 } else if (k
->type
== JOB_STOP
) {
210 if (job_is_conflicted_by(k
))
217 } else if (!j
->matters_to_anchor
)
219 else if (!k
->matters_to_anchor
)
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);
237 static int transaction_merge_jobs(Transaction
*tr
, sd_bus_error
*e
) {
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
) {
251 LIST_FOREACH(transaction
, k
, j
->transaction_next
) {
252 if (job_type_merge_and_collapse(&t
, k
->type
, j
->unit
) >= 0)
255 /* OK, we could not merge all jobs for this
256 * action. Let's see if we can get rid of one
259 r
= delete_one_unmergeable_job(tr
, j
);
261 /* Ok, we managed to drop one, now
262 * let's ask our callers to call us
263 * again after garbage collecting */
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
),
276 /* Second step, merge the jobs. */
277 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
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);
285 while ((k
= j
->transaction_next
)) {
286 if (tr
->anchor_job
== k
) {
287 transaction_merge_and_delete_job(tr
, k
, j
, t
);
290 transaction_merge_and_delete_job(tr
, j
, k
, t
);
293 assert(!j
->transaction_next
);
294 assert(!j
->transaction_prev
);
300 static void transaction_drop_redundant(Transaction
*tr
) {
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. */
311 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
314 LIST_FOREACH(transaction
, k
, j
) {
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
)))
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);
329 _pure_
static bool unit_matters_to_anchor(Unit
*u
, Job
*j
) {
331 assert(!j
->transaction_prev
);
333 /* Checks whether at least one of the jobs for this unit
334 * matters to the anchor. */
336 LIST_FOREACH(transaction
, j
, j
)
337 if (j
->matters_to_anchor
)
343 static int transaction_verify_order_one(Transaction
*tr
, Job
*j
, Job
*from
, unsigned generation
, sd_bus_error
*e
) {
350 assert(!j
->transaction_prev
);
352 /* Does a recursive sweep through the ordering graph, looking
353 * for a cycle. If we find a cycle we try to break it. */
355 /* Have we seen this before? */
356 if (j
->generation
== generation
) {
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. */
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
371 log_unit_warning(j
->unit
,
372 "Found ordering cycle on %s/%s",
373 j
->unit
->id
, job_type_to_string(j
->type
));
376 for (k
= from
; k
; k
= ((k
->generation
== generation
&& k
->marker
!= k
) ? k
->marker
: NULL
)) {
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
));
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
390 /* Check if this in fact was the beginning of
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
);
412 log_error("Unable to break cycle");
414 return sd_bus_error_setf(e
, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC
,
415 "Transaction order is cyclic. See system logs for details.");
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
422 j
->marker
= from
? from
: j
;
423 j
->generation
= generation
;
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
) {
430 /* Is there a job for this unit? */
431 o
= hashmap_get(tr
->jobs
, u
);
433 /* Ok, there is no job for this in the
434 * transaction, but maybe there is already one
441 r
= transaction_verify_order_one(tr
, o
, j
, generation
, e
);
446 /* Ok, let's backtrack, and remember that this entry is not on
447 * our path anymore. */
453 static int transaction_verify_order(Transaction
*tr
, unsigned *generation
, sd_bus_error
*e
) {
462 /* Check if the ordering graph is cyclic. If it is, try to fix
463 * that up by dropping one of the jobs. */
467 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
468 r
= transaction_verify_order_one(tr
, j
, NULL
, g
, e
);
476 static void transaction_collect_garbage(Transaction
*tr
) {
482 /* Drop jobs that are not required by any other job */
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"); */
494 /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
495 transaction_delete_job(tr
, j
, true);
500 static int transaction_is_destructive(Transaction
*tr
, JobMode mode
, sd_bus_error
*e
) {
506 /* Checks whether applying this transaction means that
507 * existing jobs would be replaced */
509 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
512 assert(!j
->transaction_prev
);
513 assert(!j
->transaction_next
);
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.");
524 static void transaction_minimize_impact(Transaction
*tr
) {
530 /* Drops all unnecessary jobs that reverse already active jobs
531 * or that stop a running service. */
534 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
535 LIST_FOREACH(transaction
, j
, j
) {
536 bool stops_running_service
, changes_existing_job
;
538 /* If it matters, we shouldn't drop it */
539 if (j
->matters_to_anchor
)
542 /* Would this stop a running service?
543 * Would this change an existing job?
544 * If so, let's drop this entry */
546 stops_running_service
=
547 j
->type
== JOB_STOP
&& UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j
->unit
));
549 changes_existing_job
=
551 job_type_is_conflicting(j
->type
, j
->unit
->job
->type
);
553 if (!stops_running_service
&& !changes_existing_job
)
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
));
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
));
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
));
571 transaction_delete_job(tr
, j
, true);
577 static int transaction_apply(Transaction
*tr
, Manager
*m
, JobMode mode
) {
582 /* Moves the transaction jobs to the set of active jobs */
584 if (mode
== JOB_ISOLATE
|| mode
== JOB_FLUSH
) {
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
);
591 if (hashmap_get(tr
->jobs
, j
->unit
))
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);
601 HASHMAP_FOREACH(j
, tr
->jobs
, i
) {
603 assert(!j
->transaction_prev
);
604 assert(!j
->transaction_next
);
606 r
= hashmap_put(m
->jobs
, UINT32_TO_PTR(j
->id
), j
);
611 while ((j
= hashmap_steal_first(tr
->jobs
))) {
614 /* Clean the job dependencies */
615 transaction_unlink_job(tr
, j
, false);
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
));
627 job_add_to_run_queue(j
);
628 job_add_to_dbus_queue(j
);
630 job_shutdown_magic(j
);
637 HASHMAP_FOREACH(j
, tr
->jobs
, i
)
638 hashmap_remove(m
->jobs
, UINT32_TO_PTR(j
->id
));
643 int transaction_activate(Transaction
*tr
, Manager
*m
, JobMode mode
, sd_bus_error
*e
) {
647 unsigned generation
= 1;
651 /* This applies the changes recorded in tr->jobs to
652 * the actual list of jobs, if possible. */
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
)
660 /* First step: figure out which jobs matter */
661 transaction_find_jobs_that_matter_to_anchor(tr
->anchor_job
, generation
++);
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
);
669 /* Third step: Drop redundant jobs */
670 transaction_drop_redundant(tr
);
673 /* Fourth step: Let's remove unneeded jobs that might
675 if (mode
!= JOB_ISOLATE
)
676 transaction_collect_garbage(tr
);
678 /* Fifth step: verify order makes sense and correct
679 * cycles if necessary and possible */
680 r
= transaction_verify_order(tr
, &generation
, e
);
685 log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e
, r
));
689 /* Let's see if the resulting transaction ordering
690 * graph is still cyclic... */
694 /* Sixth step: let's drop unmergeable entries if
695 * necessary and possible, merge entries we can
697 r
= transaction_merge_jobs(tr
, e
);
702 log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e
, r
));
706 /* Seventh step: an entry got dropped, let's garbage
707 * collect its dependencies. */
708 if (mode
!= JOB_ISOLATE
)
709 transaction_collect_garbage(tr
);
711 /* Let's see if the resulting transaction still has
712 * unmergeable entries ... */
715 /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
716 transaction_drop_redundant(tr
);
718 /* Ninth step: check whether we can actually apply this */
719 r
= transaction_is_destructive(tr
, mode
, e
);
721 log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e
, r
));
725 /* Tenth step: apply changes */
726 r
= transaction_apply(tr
, m
, mode
);
728 return log_warning_errno(r
, "Failed to apply transaction: %m");
730 assert(hashmap_isempty(tr
->jobs
));
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. */
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
);
749 static Job
* transaction_add_one_job(Transaction
*tr
, JobType type
, Unit
*unit
, bool override
, bool *is_new
) {
755 /* Looks for an existing prospective job and returns that. If
756 * it doesn't exist it is created and added to the prospective
759 f
= hashmap_get(tr
->jobs
, unit
);
761 LIST_FOREACH(transaction
, j
, f
) {
762 assert(j
->unit
== unit
);
764 if (j
->type
== type
) {
771 j
= job_new(unit
, type
);
777 j
->matters_to_anchor
= false;
778 j
->override
= override
;
779 j
->irreversible
= tr
->irreversible
;
781 LIST_PREPEND(transaction
, f
, j
);
783 if (hashmap_replace(tr
->jobs
, unit
, f
) < 0) {
784 LIST_REMOVE(transaction
, f
, j
);
792 /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
797 static void transaction_unlink_job(Transaction
*tr
, Job
*j
, bool delete_dependencies
) {
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
);
806 hashmap_remove_value(tr
->jobs
, j
->unit
, j
);
808 if (j
->transaction_next
)
809 j
->transaction_next
->transaction_prev
= j
->transaction_prev
;
811 j
->transaction_prev
= j
->transaction_next
= NULL
;
813 while (j
->subject_list
)
814 job_dependency_free(j
->subject_list
);
816 while (j
->object_list
) {
817 Job
*other
= j
->object_list
->matters
? j
->object_list
->subject
: NULL
;
819 job_dependency_free(j
->object_list
);
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
);
831 int transaction_add_job_and_dependencies(
839 bool ignore_requirements
,
849 assert(type
< _JOB_TYPE_MAX
);
850 assert(type
< _JOB_TYPE_MAX_IN_TRANSACTION
);
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)
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"); */
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
);
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.",
873 strerror(-unit
->load_error
));
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.",
879 strerror(-unit
->load_error
),
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
));
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
);
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
);
898 /* First add the job. */
899 ret
= transaction_add_one_job(tr
, type
, unit
, override
, &is_new
);
903 ret
->ignore_order
= ret
->ignore_order
|| ignore_order
;
905 /* Then, add a link to the job. */
907 if (!job_dependency_new(by
, ret
, matters
, conflicts
))
910 /* If the job has no parent job, it is the anchor job. */
911 assert(!tr
->anchor_job
);
912 tr
->anchor_job
= ret
;
915 if (is_new
&& !ignore_requirements
&& type
!= JOB_NOP
) {
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
);
924 log_unit_warning(dep
, "Cannot add dependency job for, ignoring: %s", bus_error_message(e
, r
));
925 sd_bus_error_free(e
);
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
);
940 sd_bus_error_free(e
);
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
);
950 sd_bus_error_free(e
);
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
);
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
);
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
);
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
);
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
);
982 sd_bus_error_free(e
);
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
);
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
);
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
);
1003 sd_bus_error_free(e
);
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
);
1010 log_unit_warning(dep
,
1011 "Cannot add dependency job, ignoring: %s",
1012 bus_error_message(e
, r
));
1013 sd_bus_error_free(e
);
1019 if (type
== JOB_STOP
|| type
== JOB_RESTART
) {
1020 static const UnitDependency propagate_deps
[] = {
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
;
1035 for (j
= 0; j
< ELEMENTSOF(propagate_deps
); j
++)
1036 SET_FOREACH(dep
, ret
->unit
->dependencies
[propagate_deps
[j
]], i
) {
1039 nt
= job_type_collapse(ptype
, dep
);
1043 r
= transaction_add_job_and_dependencies(tr
, nt
, dep
, ret
, true, override
, false, false, ignore_order
, e
);
1048 sd_bus_error_free(e
);
1053 if (type
== JOB_RELOAD
) {
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
);
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
);
1066 /* JOB_VERIFY_STARTED require no dependency handling */
1075 int transaction_add_isolate_jobs(Transaction
*tr
, Manager
*m
) {
1084 HASHMAP_FOREACH_KEY(u
, k
, m
->units
, i
) {
1086 /* ignore aliases */
1090 if (u
->ignore_on_isolate
)
1093 /* No need to stop inactive jobs */
1094 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u
)) && !u
->job
)
1097 /* Is there already something listed for this? */
1098 if (hashmap_get(tr
->jobs
, u
))
1101 r
= transaction_add_job_and_dependencies(tr
, JOB_STOP
, u
, tr
->anchor_job
, true, false, false, false, false, NULL
);
1103 log_unit_warning_errno(u
, r
, "Cannot add isolate job, ignoring: %m");
1109 Transaction
*transaction_new(bool irreversible
) {
1112 tr
= new0(Transaction
, 1);
1116 tr
->jobs
= hashmap_new(NULL
);
1122 tr
->irreversible
= irreversible
;
1127 void transaction_free(Transaction
*tr
) {
1128 assert(hashmap_isempty(tr
->jobs
));
1129 hashmap_free(tr
->jobs
);