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 %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 */
268 e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.",
269 job_type_to_string(t), job_type_to_string(k->type), k->unit->id);
274 /* Second step, merge the jobs. */
275 HASHMAP_FOREACH(j, tr->jobs, i) {
279 /* Merge all transaction jobs for j->unit */
280 LIST_FOREACH(transaction, k, j->transaction_next)
281 assert_se(job_type_merge_and_collapse(&t, k->type, j->unit) == 0);
283 while ((k = j->transaction_next)) {
284 if (tr->anchor_job == k) {
285 transaction_merge_and_delete_job(tr, k, j, t);
288 transaction_merge_and_delete_job(tr, j, k, t);
291 assert(!j->transaction_next);
292 assert(!j->transaction_prev);
298 static void transaction_drop_redundant(Transaction *tr) {
302 /* Goes through the transaction and removes all jobs of the units
303 * whose jobs are all noops. If not all of a unit's jobs are
304 * redundant, they are kept. */
309 HASHMAP_FOREACH(j, tr->jobs, i) {
312 LIST_FOREACH(transaction, k, j) {
314 if (tr->anchor_job == k ||
315 !job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
316 (k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type)))
320 /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */
321 transaction_delete_job(tr, j, false);
327 _pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) {
329 assert(!j->transaction_prev);
331 /* Checks whether at least one of the jobs for this unit
332 * matters to the anchor. */
334 LIST_FOREACH(transaction, j, j)
335 if (j->matters_to_anchor)
341 static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
348 assert(!j->transaction_prev);
350 /* Does a recursive sweep through the ordering graph, looking
351 * for a cycle. If we find a cycle we try to break it. */
353 /* Have we seen this before? */
354 if (j->generation == generation) {
357 /* If the marker is NULL we have been here already and
358 * decided the job was loop-free from here. Hence
359 * shortcut things and return right-away. */
363 /* So, the marker is not NULL and we already have been
364 * here. We have a cycle. Let's try to break it. We go
365 * backwards in our path and try to find a suitable
366 * job to remove. We use the marker to find our way
367 * back, since smart how we are we stored our way back
369 log_warning_unit(j->unit->id,
370 "Found ordering cycle on %s/%s",
371 j->unit->id, job_type_to_string(j->type));
374 for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
376 /* logging for j not k here here to provide consistent narrative */
377 log_info_unit(j->unit->id,
378 "Found dependency on %s/%s",
379 k->unit->id, job_type_to_string(k->type));
382 !unit_matters_to_anchor(k->unit, k)) {
383 /* Ok, we can drop this one, so let's
388 /* Check if this in fact was the beginning of
396 /* logging for j not k here here to provide consistent narrative */
397 log_warning_unit(j->unit->id,
398 "Breaking ordering cycle by deleting job %s/%s",
399 delete->unit->id, job_type_to_string(delete->type));
400 log_error_unit(delete->unit->id,
401 "Job %s/%s deleted to break ordering cycle starting with %s/%s",
402 delete->unit->id, job_type_to_string(delete->type),
403 j->unit->id, job_type_to_string(j->type));
404 unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF,
405 "Ordering cycle found, skipping %s");
406 transaction_delete_unit(tr, delete->unit);
410 log_error("Unable to break cycle");
412 sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
413 "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_superset(j->type, j->unit->job->type)) {
515 sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
523 static void transaction_minimize_impact(Transaction *tr) {
529 /* Drops all unnecessary jobs that reverse already active jobs
530 * or that stop a running service. */
533 HASHMAP_FOREACH(j, tr->jobs, i) {
534 LIST_FOREACH(transaction, j, j) {
535 bool stops_running_service, changes_existing_job;
537 /* If it matters, we shouldn't drop it */
538 if (j->matters_to_anchor)
541 /* Would this stop a running service?
542 * Would this change an existing job?
543 * If so, let's drop this entry */
545 stops_running_service =
546 j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
548 changes_existing_job =
550 job_type_is_conflicting(j->type, j->unit->job->type);
552 if (!stops_running_service && !changes_existing_job)
555 if (stops_running_service)
556 log_debug_unit(j->unit->id,
557 "%s/%s would stop a running service.",
558 j->unit->id, job_type_to_string(j->type));
560 if (changes_existing_job)
561 log_debug_unit(j->unit->id,
562 "%s/%s would change existing job.",
563 j->unit->id, job_type_to_string(j->type));
565 /* Ok, let's get rid of this */
566 log_debug_unit(j->unit->id,
567 "Deleting %s/%s to minimize impact.",
568 j->unit->id, job_type_to_string(j->type));
570 transaction_delete_job(tr, j, true);
576 static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
581 /* Moves the transaction jobs to the set of active jobs */
583 if (mode == JOB_ISOLATE || mode == JOB_FLUSH) {
585 /* When isolating first kill all installed jobs which
586 * aren't part of the new transaction */
587 HASHMAP_FOREACH(j, m->jobs, i) {
588 assert(j->installed);
590 if (hashmap_get(tr->jobs, j->unit))
593 /* Not invalidating recursively. Avoids triggering
594 * OnFailure= actions of dependent jobs. Also avoids
595 * invalidating our iterator. */
596 job_finish_and_invalidate(j, JOB_CANCELED, false);
600 HASHMAP_FOREACH(j, tr->jobs, i) {
602 assert(!j->transaction_prev);
603 assert(!j->transaction_next);
605 r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j);
610 while ((j = hashmap_steal_first(tr->jobs))) {
613 /* Clean the job dependencies */
614 transaction_unlink_job(tr, j, false);
616 installed_job = job_install(j);
617 if (installed_job != j) {
618 /* j has been merged into a previously installed job */
619 if (tr->anchor_job == j)
620 tr->anchor_job = installed_job;
621 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
626 job_add_to_run_queue(j);
627 job_add_to_dbus_queue(j);
629 job_shutdown_magic(j);
636 HASHMAP_FOREACH(j, tr->jobs, i)
637 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
642 int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
646 unsigned generation = 1;
650 /* This applies the changes recorded in tr->jobs to
651 * the actual list of jobs, if possible. */
653 /* Reset the generation counter of all installed jobs. The detection of cycles
654 * looks at installed jobs. If they had a non-zero generation from some previous
655 * walk of the graph, the algorithm would break. */
656 HASHMAP_FOREACH(j, m->jobs, i)
659 /* First step: figure out which jobs matter */
660 transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
662 /* Second step: Try not to stop any running services if
663 * we don't have to. Don't try to reverse running
664 * jobs if we don't have to. */
665 if (mode == JOB_FAIL)
666 transaction_minimize_impact(tr);
668 /* Third step: Drop redundant jobs */
669 transaction_drop_redundant(tr);
672 /* Fourth step: Let's remove unneeded jobs that might
674 if (mode != JOB_ISOLATE)
675 transaction_collect_garbage(tr);
677 /* Fifth step: verify order makes sense and correct
678 * cycles if necessary and possible */
679 r = transaction_verify_order(tr, &generation, e);
684 log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e, r));
688 /* Let's see if the resulting transaction ordering
689 * graph is still cyclic... */
693 /* Sixth step: let's drop unmergeable entries if
694 * necessary and possible, merge entries we can
696 r = transaction_merge_jobs(tr, e);
701 log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e, r));
705 /* Seventh step: an entry got dropped, let's garbage
706 * collect its dependencies. */
707 if (mode != JOB_ISOLATE)
708 transaction_collect_garbage(tr);
710 /* Let's see if the resulting transaction still has
711 * unmergeable entries ... */
714 /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
715 transaction_drop_redundant(tr);
717 /* Ninth step: check whether we can actually apply this */
718 r = transaction_is_destructive(tr, mode, e);
720 log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
724 /* Tenth step: apply changes */
725 r = transaction_apply(tr, m, mode);
727 log_warning("Failed to apply transaction: %s", strerror(-r));
731 assert(hashmap_isempty(tr->jobs));
733 if (!hashmap_isempty(m->jobs)) {
734 /* Are there any jobs now? Then make sure we have the
735 * idle pipe around. We don't really care too much
736 * whether this works or not, as the idle pipe is a
737 * feature for cosmetics, not actually useful for
738 * anything beyond that. */
740 if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
741 m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
742 pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
743 pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
750 static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
756 /* Looks for an existing prospective job and returns that. If
757 * it doesn't exist it is created and added to the prospective
760 f = hashmap_get(tr->jobs, unit);
762 LIST_FOREACH(transaction, j, f) {
763 assert(j->unit == unit);
765 if (j->type == type) {
772 j = job_new(unit, type);
778 j->matters_to_anchor = false;
779 j->override = override;
780 j->irreversible = tr->irreversible;
782 LIST_PREPEND(transaction, f, j);
784 if (hashmap_replace(tr->jobs, unit, f) < 0) {
785 LIST_REMOVE(transaction, f, j);
793 /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
798 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
802 if (j->transaction_prev)
803 j->transaction_prev->transaction_next = j->transaction_next;
804 else if (j->transaction_next)
805 hashmap_replace(tr->jobs, j->unit, j->transaction_next);
807 hashmap_remove_value(tr->jobs, j->unit, j);
809 if (j->transaction_next)
810 j->transaction_next->transaction_prev = j->transaction_prev;
812 j->transaction_prev = j->transaction_next = NULL;
814 while (j->subject_list)
815 job_dependency_free(j->subject_list);
817 while (j->object_list) {
818 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
820 job_dependency_free(j->object_list);
822 if (other && delete_dependencies) {
823 log_debug_unit(other->unit->id,
824 "Deleting job %s/%s as dependency of job %s/%s",
825 other->unit->id, job_type_to_string(other->type),
826 j->unit->id, job_type_to_string(j->type));
827 transaction_delete_job(tr, other, delete_dependencies);
832 int transaction_add_job_and_dependencies(
840 bool ignore_requirements,
850 assert(type < _JOB_TYPE_MAX);
851 assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
854 /* log_debug("Pulling in %s/%s from %s/%s", */
855 /* unit->id, job_type_to_string(type), */
856 /* by ? by->unit->id : "NA", */
857 /* by ? job_type_to_string(by->type) : "NA"); */
859 if (unit->load_state != UNIT_LOADED &&
860 unit->load_state != UNIT_ERROR &&
861 unit->load_state != UNIT_NOT_FOUND &&
862 unit->load_state != UNIT_MASKED) {
863 sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
867 if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
868 sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
869 "Unit %s failed to load: %s. "
870 "See system logs and 'systemctl status %s' for details.",
872 strerror(-unit->load_error),
877 if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND) {
878 sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
879 "Unit %s failed to load: %s.",
881 strerror(-unit->load_error));
885 if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
886 sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", unit->id);
887 return -EADDRNOTAVAIL;
890 if (!unit_job_is_applicable(unit, type)) {
891 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);
895 /* First add the job. */
896 ret = transaction_add_one_job(tr, type, unit, override, &is_new);
900 ret->ignore_order = ret->ignore_order || ignore_order;
902 /* Then, add a link to the job. */
904 if (!job_dependency_new(by, ret, matters, conflicts))
907 /* If the job has no parent job, it is the anchor job. */
908 assert(!tr->anchor_job);
909 tr->anchor_job = ret;
912 if (is_new && !ignore_requirements && type != JOB_NOP) {
915 /* If we are following some other unit, make sure we
916 * add all dependencies of everybody following. */
917 if (unit_following_set(ret->unit, &following) > 0) {
918 SET_FOREACH(dep, following, i) {
919 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
921 log_warning_unit(dep->id,
922 "Cannot add dependency job for unit %s, ignoring: %s",
923 dep->id, bus_error_message(e, r));
926 sd_bus_error_free(e);
933 /* Finally, recursively add in all dependencies. */
934 if (type == JOB_START || type == JOB_RESTART) {
935 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
936 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
942 sd_bus_error_free(e);
946 SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
947 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
953 sd_bus_error_free(e);
957 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
958 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
960 log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
961 "Cannot add dependency job for unit %s, ignoring: %s",
962 dep->id, bus_error_message(e, r));
965 sd_bus_error_free(e);
969 SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
970 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
972 log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
973 "Cannot add dependency job for unit %s, ignoring: %s",
974 dep->id, bus_error_message(e, r));
977 sd_bus_error_free(e);
981 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
982 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
988 sd_bus_error_free(e);
992 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
993 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
995 log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
996 "Cannot add dependency job for unit %s, ignoring: %s",
997 dep->id, bus_error_message(e, r));
1000 sd_bus_error_free(e);
1004 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
1005 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
1011 sd_bus_error_free(e);
1015 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
1016 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
1018 log_warning_unit(dep->id,
1019 "Cannot add dependency job for unit %s, ignoring: %s",
1020 dep->id, bus_error_message(e, r));
1023 sd_bus_error_free(e);
1029 if (type == JOB_STOP || type == JOB_RESTART) {
1031 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
1032 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1038 sd_bus_error_free(e);
1042 SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
1043 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1049 sd_bus_error_free(e);
1053 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
1054 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1060 sd_bus_error_free(e);
1066 if (type == JOB_RELOAD) {
1068 SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
1069 r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
1071 log_warning_unit(dep->id,
1072 "Cannot add dependency reload job for unit %s, ignoring: %s",
1073 dep->id, bus_error_message(e, r));
1076 sd_bus_error_free(e);
1081 /* JOB_VERIFY_STARTED require no dependency handling */
1090 int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
1099 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1101 /* ignore aliases */
1105 if (u->ignore_on_isolate)
1108 /* No need to stop inactive jobs */
1109 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
1112 /* Is there already something listed for this? */
1113 if (hashmap_get(tr->jobs, u))
1116 r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
1118 log_warning_unit(u->id,
1119 "Cannot add isolate job for unit %s, ignoring: %s",
1120 u->id, strerror(-r));
1126 Transaction *transaction_new(bool irreversible) {
1129 tr = new0(Transaction, 1);
1133 tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func);
1139 tr->irreversible = irreversible;
1144 void transaction_free(Transaction *tr) {
1145 assert(hashmap_isempty(tr->jobs));
1146 hashmap_free(tr->jobs);