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-errors.h"
27 #include "bus-error.h"
28 #include "transaction.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_debug_unit(j->unit->id,
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_debug_unit(k->unit->id,
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_debug_unit(d->unit->id,
226 "Fixing conflicting jobs by deleting job %s/%s",
227 d->unit->id, job_type_to_string(d->type));
228 transaction_delete_job(tr, d, true);
235 static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) {
242 /* First step, check whether any of the jobs for one specific
243 * task conflict. If so, try to drop one of them. */
244 HASHMAP_FOREACH(j, tr->jobs, i) {
249 LIST_FOREACH(transaction, k, j->transaction_next) {
250 if (job_type_merge_and_collapse(&t, k->type, j->unit) >= 0)
253 /* OK, we could not merge all jobs for this
254 * action. Let's see if we can get rid of one
257 r = delete_one_unmergeable_job(tr, j);
259 /* Ok, we managed to drop one, now
260 * let's ask our callers to call us
261 * again after garbage collecting */
264 /* We couldn't merge anything. Failure */
266 e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.",
267 job_type_to_string(t), job_type_to_string(k->type), k->unit->id);
272 /* Second step, merge the jobs. */
273 HASHMAP_FOREACH(j, tr->jobs, i) {
277 /* Merge all transaction jobs for j->unit */
278 LIST_FOREACH(transaction, k, j->transaction_next)
279 assert_se(job_type_merge_and_collapse(&t, k->type, j->unit) == 0);
281 while ((k = j->transaction_next)) {
282 if (tr->anchor_job == k) {
283 transaction_merge_and_delete_job(tr, k, j, t);
286 transaction_merge_and_delete_job(tr, j, k, t);
289 assert(!j->transaction_next);
290 assert(!j->transaction_prev);
296 static void transaction_drop_redundant(Transaction *tr) {
300 /* Goes through the transaction and removes all jobs of the units
301 * whose jobs are all noops. If not all of a unit's jobs are
302 * redundant, they are kept. */
307 HASHMAP_FOREACH(j, tr->jobs, i) {
310 LIST_FOREACH(transaction, k, j) {
312 if (tr->anchor_job == k ||
313 !job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
314 (k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type)))
318 /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */
319 transaction_delete_job(tr, j, false);
325 _pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) {
327 assert(!j->transaction_prev);
329 /* Checks whether at least one of the jobs for this unit
330 * matters to the anchor. */
332 LIST_FOREACH(transaction, j, j)
333 if (j->matters_to_anchor)
339 static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
346 assert(!j->transaction_prev);
348 /* Does a recursive sweep through the ordering graph, looking
349 * for a cycle. If we find a cycle we try to break it. */
351 /* Have we seen this before? */
352 if (j->generation == generation) {
355 /* If the marker is NULL we have been here already and
356 * decided the job was loop-free from here. Hence
357 * shortcut things and return right-away. */
361 /* So, the marker is not NULL and we already have been
362 * here. We have a cycle. Let's try to break it. We go
363 * backwards in our path and try to find a suitable
364 * job to remove. We use the marker to find our way
365 * back, since smart how we are we stored our way back
367 log_warning_unit(j->unit->id,
368 "Found ordering cycle on %s/%s",
369 j->unit->id, job_type_to_string(j->type));
372 for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
374 /* logging for j not k here here to provide consistent narrative */
375 log_info_unit(j->unit->id,
376 "Found dependency on %s/%s",
377 k->unit->id, job_type_to_string(k->type));
380 !unit_matters_to_anchor(k->unit, k)) {
381 /* Ok, we can drop this one, so let's
386 /* Check if this in fact was the beginning of
394 /* logging for j not k here here to provide consistent narrative */
395 log_warning_unit(j->unit->id,
396 "Breaking ordering cycle by deleting job %s/%s",
397 delete->unit->id, job_type_to_string(delete->type));
398 log_error_unit(delete->unit->id,
399 "Job %s/%s deleted to break ordering cycle starting with %s/%s",
400 delete->unit->id, job_type_to_string(delete->type),
401 j->unit->id, job_type_to_string(j->type));
402 unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF,
403 "Ordering cycle found, skipping %s");
404 transaction_delete_unit(tr, delete->unit);
408 log_error("Unable to break cycle");
410 sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
411 "Transaction order is cyclic. See system logs for details.");
415 /* Make the marker point to where we come from, so that we can
416 * find our way backwards if we want to break a cycle. We use
417 * a special marker for the beginning: we point to
419 j->marker = from ? from : j;
420 j->generation = generation;
422 /* We assume that the dependencies are bidirectional, and
423 * hence can ignore UNIT_AFTER */
424 SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) {
427 /* Is there a job for this unit? */
428 o = hashmap_get(tr->jobs, u);
430 /* Ok, there is no job for this in the
431 * transaction, but maybe there is already one
438 r = transaction_verify_order_one(tr, o, j, generation, e);
443 /* Ok, let's backtrack, and remember that this entry is not on
444 * our path anymore. */
450 static int transaction_verify_order(Transaction *tr, unsigned *generation, sd_bus_error *e) {
459 /* Check if the ordering graph is cyclic. If it is, try to fix
460 * that up by dropping one of the jobs. */
464 HASHMAP_FOREACH(j, tr->jobs, i)
465 if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0)
471 static void transaction_collect_garbage(Transaction *tr) {
477 /* Drop jobs that are not required by any other job */
480 HASHMAP_FOREACH(j, tr->jobs, i) {
481 if (tr->anchor_job == j || j->object_list) {
482 /* log_debug("Keeping job %s/%s because of %s/%s", */
483 /* j->unit->id, job_type_to_string(j->type), */
484 /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */
485 /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
489 /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
490 transaction_delete_job(tr, j, true);
495 static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_error *e) {
501 /* Checks whether applying this transaction means that
502 * existing jobs would be replaced */
504 HASHMAP_FOREACH(j, tr->jobs, i) {
507 assert(!j->transaction_prev);
508 assert(!j->transaction_next);
510 if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
511 !job_type_is_superset(j->type, j->unit->job->type)) {
513 sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "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_debug_unit(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_debug_unit(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_debug_unit(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 log_warning("Failed to apply transaction: %s", strerror(-r));
729 assert(hashmap_isempty(tr->jobs));
731 if (!hashmap_isempty(m->jobs)) {
732 /* Are there any jobs now? Then make sure we have the
733 * idle pipe around. We don't really care too much
734 * whether this works or not, as the idle pipe is a
735 * feature for cosmetics, not actually useful for
736 * anything beyond that. */
738 if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
739 m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
740 pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
741 pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
748 static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
754 /* Looks for an existing prospective job and returns that. If
755 * it doesn't exist it is created and added to the prospective
758 f = hashmap_get(tr->jobs, unit);
760 LIST_FOREACH(transaction, j, f) {
761 assert(j->unit == unit);
763 if (j->type == type) {
770 j = job_new(unit, type);
776 j->matters_to_anchor = false;
777 j->override = override;
778 j->irreversible = tr->irreversible;
780 LIST_PREPEND(transaction, f, j);
782 if (hashmap_replace(tr->jobs, unit, f) < 0) {
783 LIST_REMOVE(transaction, f, j);
791 /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
796 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
800 if (j->transaction_prev)
801 j->transaction_prev->transaction_next = j->transaction_next;
802 else if (j->transaction_next)
803 hashmap_replace(tr->jobs, j->unit, j->transaction_next);
805 hashmap_remove_value(tr->jobs, j->unit, j);
807 if (j->transaction_next)
808 j->transaction_next->transaction_prev = j->transaction_prev;
810 j->transaction_prev = j->transaction_next = NULL;
812 while (j->subject_list)
813 job_dependency_free(j->subject_list);
815 while (j->object_list) {
816 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
818 job_dependency_free(j->object_list);
820 if (other && delete_dependencies) {
821 log_debug_unit(other->unit->id,
822 "Deleting job %s/%s as dependency of job %s/%s",
823 other->unit->id, job_type_to_string(other->type),
824 j->unit->id, job_type_to_string(j->type));
825 transaction_delete_job(tr, other, delete_dependencies);
830 int transaction_add_job_and_dependencies(
838 bool ignore_requirements,
848 assert(type < _JOB_TYPE_MAX);
849 assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
852 /* log_debug("Pulling in %s/%s from %s/%s", */
853 /* unit->id, job_type_to_string(type), */
854 /* by ? by->unit->id : "NA", */
855 /* by ? job_type_to_string(by->type) : "NA"); */
857 if (unit->load_state != UNIT_LOADED &&
858 unit->load_state != UNIT_ERROR &&
859 unit->load_state != UNIT_NOT_FOUND &&
860 unit->load_state != UNIT_MASKED) {
861 sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
865 if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
866 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),
875 if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND) {
876 sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
877 "Unit %s failed to load: %s.",
879 strerror(-unit->load_error));
883 if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
884 sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", unit->id);
885 return -EADDRNOTAVAIL;
888 if (!unit_job_is_applicable(unit, type)) {
889 sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id);
893 /* First add the job. */
894 ret = transaction_add_one_job(tr, type, unit, override, &is_new);
898 ret->ignore_order = ret->ignore_order || ignore_order;
900 /* Then, add a link to the job. */
902 if (!job_dependency_new(by, ret, matters, conflicts))
905 /* If the job has no parent job, it is the anchor job. */
906 assert(!tr->anchor_job);
907 tr->anchor_job = ret;
910 if (is_new && !ignore_requirements && type != JOB_NOP) {
913 /* If we are following some other unit, make sure we
914 * add all dependencies of everybody following. */
915 if (unit_following_set(ret->unit, &following) > 0) {
916 SET_FOREACH(dep, following, i) {
917 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
919 log_warning_unit(dep->id,
920 "Cannot add dependency job for unit %s, ignoring: %s",
921 dep->id, bus_error_message(e, r));
924 sd_bus_error_free(e);
931 /* Finally, recursively add in all dependencies. */
932 if (type == JOB_START || type == JOB_RESTART) {
933 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
934 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);
951 sd_bus_error_free(e);
955 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
956 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
958 log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
959 "Cannot add dependency job for unit %s, ignoring: %s",
960 dep->id, bus_error_message(e, r));
963 sd_bus_error_free(e);
967 SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
968 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
970 log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
971 "Cannot add dependency job for unit %s, ignoring: %s",
972 dep->id, bus_error_message(e, r));
975 sd_bus_error_free(e);
979 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
980 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
986 sd_bus_error_free(e);
990 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
991 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
993 log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
994 "Cannot add dependency job for unit %s, ignoring: %s",
995 dep->id, bus_error_message(e, r));
998 sd_bus_error_free(e);
1002 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
1003 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
1009 sd_bus_error_free(e);
1013 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
1014 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
1016 log_warning_unit(dep->id,
1017 "Cannot add dependency job for unit %s, ignoring: %s",
1018 dep->id, bus_error_message(e, r));
1021 sd_bus_error_free(e);
1027 if (type == JOB_STOP || type == JOB_RESTART) {
1029 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
1030 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1036 sd_bus_error_free(e);
1040 SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
1041 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1047 sd_bus_error_free(e);
1051 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
1052 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1058 sd_bus_error_free(e);
1064 if (type == JOB_RELOAD) {
1066 SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
1067 r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
1069 log_warning_unit(dep->id,
1070 "Cannot add dependency reload job for unit %s, ignoring: %s",
1071 dep->id, bus_error_message(e, r));
1074 sd_bus_error_free(e);
1079 /* JOB_VERIFY_STARTED require no dependency handling */
1088 int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
1097 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1099 /* ignore aliases */
1103 if (u->ignore_on_isolate)
1106 /* No need to stop inactive jobs */
1107 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
1110 /* Is there already something listed for this? */
1111 if (hashmap_get(tr->jobs, u))
1114 r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
1116 log_warning_unit(u->id,
1117 "Cannot add isolate job for unit %s, ignoring: %s",
1118 u->id, strerror(-r));
1124 Transaction *transaction_new(bool irreversible) {
1127 tr = new0(Transaction, 1);
1131 tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func);
1137 tr->irreversible = irreversible;
1142 void transaction_free(Transaction *tr) {
1143 assert(hashmap_isempty(tr->jobs));
1144 hashmap_free(tr->jobs);