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"
29 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
31 static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependencies) {
35 /* Deletes one job from the transaction */
37 transaction_unlink_job(tr, j, delete_dependencies);
42 static void transaction_delete_unit(Transaction *tr, Unit *u) {
45 /* Deletes all jobs associated with a certain unit from the
48 while ((j = hashmap_get(tr->jobs, u)))
49 transaction_delete_job(tr, j, true);
52 void transaction_abort(Transaction *tr) {
57 while ((j = hashmap_first(tr->jobs)))
58 transaction_delete_job(tr, j, false);
60 assert(hashmap_isempty(tr->jobs));
63 static void transaction_find_jobs_that_matter_to_anchor(Job *j, unsigned generation) {
66 /* A recursive sweep through the graph that marks all units
67 * that matter to the anchor job, i.e. are directly or
68 * indirectly a dependency of the anchor job via paths that
69 * are fully marked as mattering. */
71 j->matters_to_anchor = true;
72 j->generation = generation;
74 LIST_FOREACH(subject, l, j->subject_list) {
76 /* This link does not matter */
80 /* This unit has already been marked */
81 if (l->object->generation == generation)
84 transaction_find_jobs_that_matter_to_anchor(l->object, generation);
88 static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other, JobType t) {
89 JobDependency *l, *last;
93 assert(j->unit == other->unit);
94 assert(!j->installed);
96 /* Merges 'other' into 'j' and then deletes 'other'. */
99 j->state = JOB_WAITING;
100 j->override = j->override || other->override;
101 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->id,
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->id,
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->id,
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 int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
349 assert(!j->transaction_prev);
351 /* Does a recursive sweep through the ordering graph, looking
352 * for a cycle. If we find a cycle we try to break it. */
354 /* Have we seen this before? */
355 if (j->generation == generation) {
358 /* If the marker is NULL we have been here already and
359 * decided the job was loop-free from here. Hence
360 * shortcut things and return right-away. */
364 /* So, the marker is not NULL and we already have been
365 * here. We have a cycle. Let's try to break it. We go
366 * backwards in our path and try to find a suitable
367 * job to remove. We use the marker to find our way
368 * back, since smart how we are we stored our way back
370 log_unit_warning(j->unit->id,
371 "Found ordering cycle on %s/%s",
372 j->unit->id, job_type_to_string(j->type));
375 for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
377 /* logging for j not k here here to provide consistent narrative */
378 log_unit_warning(j->unit->id,
379 "Found dependency on %s/%s",
380 k->unit->id, job_type_to_string(k->type));
382 if (!delete && hashmap_get(tr->jobs, k->unit) &&
383 !unit_matters_to_anchor(k->unit, k)) {
384 /* Ok, we can drop this one, so let's
389 /* Check if this in fact was the beginning of
397 /* logging for j not k here here to provide consistent narrative */
398 log_unit_warning(j->unit->id,
399 "Breaking ordering cycle by deleting job %s/%s",
400 delete->unit->id, job_type_to_string(delete->type));
401 log_unit_error(delete->unit->id,
402 "Job %s/%s deleted to break ordering cycle starting with %s/%s",
403 delete->unit->id, job_type_to_string(delete->type),
404 j->unit->id, job_type_to_string(j->type));
405 unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF,
406 "Ordering cycle found, skipping %s");
407 transaction_delete_unit(tr, delete->unit);
411 log_error("Unable to break cycle");
413 return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
414 "Transaction order is cyclic. See system logs for details.");
417 /* Make the marker point to where we come from, so that we can
418 * find our way backwards if we want to break a cycle. We use
419 * a special marker for the beginning: we point to
421 j->marker = from ? from : j;
422 j->generation = generation;
424 /* We assume that the dependencies are bidirectional, and
425 * hence can ignore UNIT_AFTER */
426 SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) {
429 /* Is there a job for this unit? */
430 o = hashmap_get(tr->jobs, u);
432 /* Ok, there is no job for this in the
433 * transaction, but maybe there is already one
440 r = transaction_verify_order_one(tr, o, j, generation, e);
445 /* Ok, let's backtrack, and remember that this entry is not on
446 * our path anymore. */
452 static int transaction_verify_order(Transaction *tr, unsigned *generation, sd_bus_error *e) {
461 /* Check if the ordering graph is cyclic. If it is, try to fix
462 * that up by dropping one of the jobs. */
466 HASHMAP_FOREACH(j, tr->jobs, i)
467 if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0)
473 static void transaction_collect_garbage(Transaction *tr) {
479 /* Drop jobs that are not required by any other job */
482 HASHMAP_FOREACH(j, tr->jobs, i) {
483 if (tr->anchor_job == j || j->object_list) {
484 /* log_debug("Keeping job %s/%s because of %s/%s", */
485 /* j->unit->id, job_type_to_string(j->type), */
486 /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */
487 /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
491 /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
492 transaction_delete_job(tr, j, true);
497 static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_error *e) {
503 /* Checks whether applying this transaction means that
504 * existing jobs would be replaced */
506 HASHMAP_FOREACH(j, tr->jobs, i) {
509 assert(!j->transaction_prev);
510 assert(!j->transaction_next);
512 if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
513 job_type_is_conflicting(j->unit->job->type, j->type))
514 return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,
515 "Transaction is destructive.");
521 static void transaction_minimize_impact(Transaction *tr) {
527 /* Drops all unnecessary jobs that reverse already active jobs
528 * or that stop a running service. */
531 HASHMAP_FOREACH(j, tr->jobs, i) {
532 LIST_FOREACH(transaction, j, j) {
533 bool stops_running_service, changes_existing_job;
535 /* If it matters, we shouldn't drop it */
536 if (j->matters_to_anchor)
539 /* Would this stop a running service?
540 * Would this change an existing job?
541 * If so, let's drop this entry */
543 stops_running_service =
544 j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
546 changes_existing_job =
548 job_type_is_conflicting(j->type, j->unit->job->type);
550 if (!stops_running_service && !changes_existing_job)
553 if (stops_running_service)
554 log_unit_debug(j->unit->id,
555 "%s/%s would stop a running service.",
556 j->unit->id, job_type_to_string(j->type));
558 if (changes_existing_job)
559 log_unit_debug(j->unit->id,
560 "%s/%s would change existing job.",
561 j->unit->id, job_type_to_string(j->type));
563 /* Ok, let's get rid of this */
564 log_unit_debug(j->unit->id,
565 "Deleting %s/%s to minimize impact.",
566 j->unit->id, job_type_to_string(j->type));
568 transaction_delete_job(tr, j, true);
574 static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
579 /* Moves the transaction jobs to the set of active jobs */
581 if (mode == JOB_ISOLATE || mode == JOB_FLUSH) {
583 /* When isolating first kill all installed jobs which
584 * aren't part of the new transaction */
585 HASHMAP_FOREACH(j, m->jobs, i) {
586 assert(j->installed);
588 if (hashmap_get(tr->jobs, j->unit))
591 /* Not invalidating recursively. Avoids triggering
592 * OnFailure= actions of dependent jobs. Also avoids
593 * invalidating our iterator. */
594 job_finish_and_invalidate(j, JOB_CANCELED, false);
598 HASHMAP_FOREACH(j, tr->jobs, i) {
600 assert(!j->transaction_prev);
601 assert(!j->transaction_next);
603 r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j);
608 while ((j = hashmap_steal_first(tr->jobs))) {
611 /* Clean the job dependencies */
612 transaction_unlink_job(tr, j, false);
614 installed_job = job_install(j);
615 if (installed_job != j) {
616 /* j has been merged into a previously installed job */
617 if (tr->anchor_job == j)
618 tr->anchor_job = installed_job;
619 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
624 job_add_to_run_queue(j);
625 job_add_to_dbus_queue(j);
627 job_shutdown_magic(j);
634 HASHMAP_FOREACH(j, tr->jobs, i)
635 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
640 int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
644 unsigned generation = 1;
648 /* This applies the changes recorded in tr->jobs to
649 * the actual list of jobs, if possible. */
651 /* Reset the generation counter of all installed jobs. The detection of cycles
652 * looks at installed jobs. If they had a non-zero generation from some previous
653 * walk of the graph, the algorithm would break. */
654 HASHMAP_FOREACH(j, m->jobs, i)
657 /* First step: figure out which jobs matter */
658 transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
660 /* Second step: Try not to stop any running services if
661 * we don't have to. Don't try to reverse running
662 * jobs if we don't have to. */
663 if (mode == JOB_FAIL)
664 transaction_minimize_impact(tr);
666 /* Third step: Drop redundant jobs */
667 transaction_drop_redundant(tr);
670 /* Fourth step: Let's remove unneeded jobs that might
672 if (mode != JOB_ISOLATE)
673 transaction_collect_garbage(tr);
675 /* Fifth step: verify order makes sense and correct
676 * cycles if necessary and possible */
677 r = transaction_verify_order(tr, &generation, e);
682 log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e, r));
686 /* Let's see if the resulting transaction ordering
687 * graph is still cyclic... */
691 /* Sixth step: let's drop unmergeable entries if
692 * necessary and possible, merge entries we can
694 r = transaction_merge_jobs(tr, e);
699 log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e, r));
703 /* Seventh step: an entry got dropped, let's garbage
704 * collect its dependencies. */
705 if (mode != JOB_ISOLATE)
706 transaction_collect_garbage(tr);
708 /* Let's see if the resulting transaction still has
709 * unmergeable entries ... */
712 /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
713 transaction_drop_redundant(tr);
715 /* Ninth step: check whether we can actually apply this */
716 r = transaction_is_destructive(tr, mode, e);
718 log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
722 /* Tenth step: apply changes */
723 r = transaction_apply(tr, m, mode);
725 return log_warning_errno(r, "Failed to apply transaction: %m");
727 assert(hashmap_isempty(tr->jobs));
729 if (!hashmap_isempty(m->jobs)) {
730 /* Are there any jobs now? Then make sure we have the
731 * idle pipe around. We don't really care too much
732 * whether this works or not, as the idle pipe is a
733 * feature for cosmetics, not actually useful for
734 * anything beyond that. */
736 if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
737 m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
738 pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
739 pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
746 static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
752 /* Looks for an existing prospective job and returns that. If
753 * it doesn't exist it is created and added to the prospective
756 f = hashmap_get(tr->jobs, unit);
758 LIST_FOREACH(transaction, j, f) {
759 assert(j->unit == unit);
761 if (j->type == type) {
768 j = job_new(unit, type);
774 j->matters_to_anchor = false;
775 j->override = override;
776 j->irreversible = tr->irreversible;
778 LIST_PREPEND(transaction, f, j);
780 if (hashmap_replace(tr->jobs, unit, f) < 0) {
781 LIST_REMOVE(transaction, f, j);
789 /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
794 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
798 if (j->transaction_prev)
799 j->transaction_prev->transaction_next = j->transaction_next;
800 else if (j->transaction_next)
801 hashmap_replace(tr->jobs, j->unit, j->transaction_next);
803 hashmap_remove_value(tr->jobs, j->unit, j);
805 if (j->transaction_next)
806 j->transaction_next->transaction_prev = j->transaction_prev;
808 j->transaction_prev = j->transaction_next = NULL;
810 while (j->subject_list)
811 job_dependency_free(j->subject_list);
813 while (j->object_list) {
814 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
816 job_dependency_free(j->object_list);
818 if (other && delete_dependencies) {
819 log_unit_debug(other->unit->id,
820 "Deleting job %s/%s as dependency of job %s/%s",
821 other->unit->id, job_type_to_string(other->type),
822 j->unit->id, job_type_to_string(j->type));
823 transaction_delete_job(tr, other, delete_dependencies);
828 int transaction_add_job_and_dependencies(
836 bool ignore_requirements,
846 assert(type < _JOB_TYPE_MAX);
847 assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
850 /* log_debug("Pulling in %s/%s from %s/%s", */
851 /* unit->id, job_type_to_string(type), */
852 /* by ? by->unit->id : "NA", */
853 /* by ? job_type_to_string(by->type) : "NA"); */
855 if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED))
856 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
857 "Unit %s is not loaded properly.", unit->id);
859 if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
860 if (unit->load_error == -ENOENT || unit->manager->test_run)
861 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
862 "Unit %s failed to load: %s.",
864 strerror(-unit->load_error));
866 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
867 "Unit %s failed to load: %s. "
868 "See system logs and 'systemctl status %s' for details.",
870 strerror(-unit->load_error),
874 if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND)
875 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
876 "Unit %s failed to load: %s.",
877 unit->id, strerror(-unit->load_error));
879 if (type != JOB_STOP && unit->load_state == UNIT_MASKED)
880 return sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED,
881 "Unit %s is masked.", unit->id);
883 if (!unit_job_is_applicable(unit, type))
884 return sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
885 "Job type %s is not applicable for unit %s.",
886 job_type_to_string(type), unit->id);
889 /* First add the job. */
890 ret = transaction_add_one_job(tr, type, unit, override, &is_new);
894 ret->ignore_order = ret->ignore_order || ignore_order;
896 /* Then, add a link to the job. */
898 if (!job_dependency_new(by, ret, matters, conflicts))
901 /* If the job has no parent job, it is the anchor job. */
902 assert(!tr->anchor_job);
903 tr->anchor_job = ret;
906 if (is_new && !ignore_requirements && type != JOB_NOP) {
909 /* If we are following some other unit, make sure we
910 * add all dependencies of everybody following. */
911 if (unit_following_set(ret->unit, &following) > 0) {
912 SET_FOREACH(dep, following, i) {
913 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
915 log_unit_warning(dep->id,
916 "Cannot add dependency job for unit %s, ignoring: %s",
917 dep->id, bus_error_message(e, r));
920 sd_bus_error_free(e);
927 /* Finally, recursively add in all dependencies. */
928 if (type == JOB_START || type == JOB_RESTART) {
929 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
930 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
936 sd_bus_error_free(e);
940 SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
941 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
947 sd_bus_error_free(e);
951 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
952 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
954 log_unit_full(dep->id,
955 r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
956 "Cannot add dependency job for unit %s, ignoring: %s",
957 dep->id, bus_error_message(e, r));
960 sd_bus_error_free(e);
964 SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
965 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
967 log_unit_full(dep->id,
968 r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
969 "Cannot add dependency job for unit %s, ignoring: %s",
970 dep->id, bus_error_message(e, r));
973 sd_bus_error_free(e);
977 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
978 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
984 sd_bus_error_free(e);
988 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
989 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
991 log_unit_full(dep->id,
992 r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
993 "Cannot add dependency job for unit %s, ignoring: %s",
994 dep->id, bus_error_message(e, r));
997 sd_bus_error_free(e);
1001 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
1002 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
1008 sd_bus_error_free(e);
1012 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
1013 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
1015 log_unit_warning(dep->id,
1016 "Cannot add dependency job for unit %s, ignoring: %s",
1017 dep->id, bus_error_message(e, r));
1020 sd_bus_error_free(e);
1026 if (type == JOB_STOP || type == JOB_RESTART) {
1028 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
1029 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1035 sd_bus_error_free(e);
1039 SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
1040 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1046 sd_bus_error_free(e);
1050 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
1051 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1057 sd_bus_error_free(e);
1063 if (type == JOB_RELOAD) {
1065 SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
1066 r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
1068 log_unit_warning(dep->id,
1069 "Cannot add dependency reload job for unit %s, ignoring: %s",
1070 dep->id, bus_error_message(e, r));
1073 sd_bus_error_free(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, false, NULL);
1115 log_unit_warning(u->id,
1116 "Cannot add isolate job for unit %s, ignoring: %s",
1117 u->id, strerror(-r));
1123 Transaction *transaction_new(bool irreversible) {
1126 tr = new0(Transaction, 1);
1130 tr->jobs = hashmap_new(NULL);
1136 tr->irreversible = irreversible;
1141 void transaction_free(Transaction *tr) {
1142 assert(hashmap_isempty(tr->jobs));
1143 hashmap_free(tr->jobs);