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 */
267 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),
277 /* Second step, merge the jobs. */
278 HASHMAP_FOREACH(j, tr->jobs, i) {
282 /* Merge all transaction jobs for j->unit */
283 LIST_FOREACH(transaction, k, j->transaction_next)
284 assert_se(job_type_merge_and_collapse(&t, k->type, j->unit) == 0);
286 while ((k = j->transaction_next)) {
287 if (tr->anchor_job == k) {
288 transaction_merge_and_delete_job(tr, k, j, t);
291 transaction_merge_and_delete_job(tr, j, k, t);
294 assert(!j->transaction_next);
295 assert(!j->transaction_prev);
301 static void transaction_drop_redundant(Transaction *tr) {
305 /* Goes through the transaction and removes all jobs of the units
306 * whose jobs are all noops. If not all of a unit's jobs are
307 * redundant, they are kept. */
312 HASHMAP_FOREACH(j, tr->jobs, i) {
315 LIST_FOREACH(transaction, k, j) {
317 if (tr->anchor_job == k ||
318 !job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
319 (k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type)))
323 /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */
324 transaction_delete_job(tr, j, false);
330 _pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) {
332 assert(!j->transaction_prev);
334 /* Checks whether at least one of the jobs for this unit
335 * matters to the anchor. */
337 LIST_FOREACH(transaction, j, j)
338 if (j->matters_to_anchor)
344 static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
351 assert(!j->transaction_prev);
353 /* Does a recursive sweep through the ordering graph, looking
354 * for a cycle. If we find a cycle we try to break it. */
356 /* Have we seen this before? */
357 if (j->generation == generation) {
360 /* If the marker is NULL we have been here already and
361 * decided the job was loop-free from here. Hence
362 * shortcut things and return right-away. */
366 /* So, the marker is not NULL and we already have been
367 * here. We have a cycle. Let's try to break it. We go
368 * backwards in our path and try to find a suitable
369 * job to remove. We use the marker to find our way
370 * back, since smart how we are we stored our way back
372 log_warning_unit(j->unit->id,
373 "Found ordering cycle on %s/%s",
374 j->unit->id, job_type_to_string(j->type));
377 for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
379 /* logging for j not k here here to provide consistent narrative */
380 log_info_unit(j->unit->id,
381 "Found dependency on %s/%s",
382 k->unit->id, job_type_to_string(k->type));
384 if (!delete && hashmap_get(tr->jobs, k->unit) &&
385 !unit_matters_to_anchor(k->unit, k)) {
386 /* Ok, we can drop this one, so let's
391 /* Check if this in fact was the beginning of
399 /* logging for j not k here here to provide consistent narrative */
400 log_warning_unit(j->unit->id,
401 "Breaking ordering cycle by deleting job %s/%s",
402 delete->unit->id, job_type_to_string(delete->type));
403 log_error_unit(delete->unit->id,
404 "Job %s/%s deleted to break ordering cycle starting with %s/%s",
405 delete->unit->id, job_type_to_string(delete->type),
406 j->unit->id, job_type_to_string(j->type));
407 unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF,
408 "Ordering cycle found, skipping %s");
409 transaction_delete_unit(tr, delete->unit);
413 log_error("Unable to break cycle");
415 sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
416 "Transaction order is cyclic. See system logs for details.");
420 /* Make the marker point to where we come from, so that we can
421 * find our way backwards if we want to break a cycle. We use
422 * a special marker for the beginning: we point to
424 j->marker = from ? from : j;
425 j->generation = generation;
427 /* We assume that the dependencies are bidirectional, and
428 * hence can ignore UNIT_AFTER */
429 SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) {
432 /* Is there a job for this unit? */
433 o = hashmap_get(tr->jobs, u);
435 /* Ok, there is no job for this in the
436 * transaction, but maybe there is already one
443 r = transaction_verify_order_one(tr, o, j, generation, e);
448 /* Ok, let's backtrack, and remember that this entry is not on
449 * our path anymore. */
455 static int transaction_verify_order(Transaction *tr, unsigned *generation, sd_bus_error *e) {
464 /* Check if the ordering graph is cyclic. If it is, try to fix
465 * that up by dropping one of the jobs. */
469 HASHMAP_FOREACH(j, tr->jobs, i)
470 if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0)
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_superset(j->type, j->unit->job->type)) {
518 sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,
519 "Transaction is destructive.");
527 static void transaction_minimize_impact(Transaction *tr) {
533 /* Drops all unnecessary jobs that reverse already active jobs
534 * or that stop a running service. */
537 HASHMAP_FOREACH(j, tr->jobs, i) {
538 LIST_FOREACH(transaction, j, j) {
539 bool stops_running_service, changes_existing_job;
541 /* If it matters, we shouldn't drop it */
542 if (j->matters_to_anchor)
545 /* Would this stop a running service?
546 * Would this change an existing job?
547 * If so, let's drop this entry */
549 stops_running_service =
550 j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
552 changes_existing_job =
554 job_type_is_conflicting(j->type, j->unit->job->type);
556 if (!stops_running_service && !changes_existing_job)
559 if (stops_running_service)
560 log_debug_unit(j->unit->id,
561 "%s/%s would stop a running service.",
562 j->unit->id, job_type_to_string(j->type));
564 if (changes_existing_job)
565 log_debug_unit(j->unit->id,
566 "%s/%s would change existing job.",
567 j->unit->id, job_type_to_string(j->type));
569 /* Ok, let's get rid of this */
570 log_debug_unit(j->unit->id,
571 "Deleting %s/%s to minimize impact.",
572 j->unit->id, job_type_to_string(j->type));
574 transaction_delete_job(tr, j, true);
580 static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
585 /* Moves the transaction jobs to the set of active jobs */
587 if (mode == JOB_ISOLATE || mode == JOB_FLUSH) {
589 /* When isolating first kill all installed jobs which
590 * aren't part of the new transaction */
591 HASHMAP_FOREACH(j, m->jobs, i) {
592 assert(j->installed);
594 if (hashmap_get(tr->jobs, j->unit))
597 /* Not invalidating recursively. Avoids triggering
598 * OnFailure= actions of dependent jobs. Also avoids
599 * invalidating our iterator. */
600 job_finish_and_invalidate(j, JOB_CANCELED, false);
604 HASHMAP_FOREACH(j, tr->jobs, i) {
606 assert(!j->transaction_prev);
607 assert(!j->transaction_next);
609 r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j);
614 while ((j = hashmap_steal_first(tr->jobs))) {
617 /* Clean the job dependencies */
618 transaction_unlink_job(tr, j, false);
620 installed_job = job_install(j);
621 if (installed_job != j) {
622 /* j has been merged into a previously installed job */
623 if (tr->anchor_job == j)
624 tr->anchor_job = installed_job;
625 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
630 job_add_to_run_queue(j);
631 job_add_to_dbus_queue(j);
633 job_shutdown_magic(j);
640 HASHMAP_FOREACH(j, tr->jobs, i)
641 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
646 int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
650 unsigned generation = 1;
654 /* This applies the changes recorded in tr->jobs to
655 * the actual list of jobs, if possible. */
657 /* Reset the generation counter of all installed jobs. The detection of cycles
658 * looks at installed jobs. If they had a non-zero generation from some previous
659 * walk of the graph, the algorithm would break. */
660 HASHMAP_FOREACH(j, m->jobs, i)
663 /* First step: figure out which jobs matter */
664 transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
666 /* Second step: Try not to stop any running services if
667 * we don't have to. Don't try to reverse running
668 * jobs if we don't have to. */
669 if (mode == JOB_FAIL)
670 transaction_minimize_impact(tr);
672 /* Third step: Drop redundant jobs */
673 transaction_drop_redundant(tr);
676 /* Fourth step: Let's remove unneeded jobs that might
678 if (mode != JOB_ISOLATE)
679 transaction_collect_garbage(tr);
681 /* Fifth step: verify order makes sense and correct
682 * cycles if necessary and possible */
683 r = transaction_verify_order(tr, &generation, e);
688 log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e, r));
692 /* Let's see if the resulting transaction ordering
693 * graph is still cyclic... */
697 /* Sixth step: let's drop unmergeable entries if
698 * necessary and possible, merge entries we can
700 r = transaction_merge_jobs(tr, e);
705 log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e, r));
709 /* Seventh step: an entry got dropped, let's garbage
710 * collect its dependencies. */
711 if (mode != JOB_ISOLATE)
712 transaction_collect_garbage(tr);
714 /* Let's see if the resulting transaction still has
715 * unmergeable entries ... */
718 /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
719 transaction_drop_redundant(tr);
721 /* Ninth step: check whether we can actually apply this */
722 r = transaction_is_destructive(tr, mode, e);
724 log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
728 /* Tenth step: apply changes */
729 r = transaction_apply(tr, m, mode);
731 log_warning("Failed to apply transaction: %s", strerror(-r));
735 assert(hashmap_isempty(tr->jobs));
737 if (!hashmap_isempty(m->jobs)) {
738 /* Are there any jobs now? Then make sure we have the
739 * idle pipe around. We don't really care too much
740 * whether this works or not, as the idle pipe is a
741 * feature for cosmetics, not actually useful for
742 * anything beyond that. */
744 if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
745 m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
746 pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
747 pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
754 static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
760 /* Looks for an existing prospective job and returns that. If
761 * it doesn't exist it is created and added to the prospective
764 f = hashmap_get(tr->jobs, unit);
766 LIST_FOREACH(transaction, j, f) {
767 assert(j->unit == unit);
769 if (j->type == type) {
776 j = job_new(unit, type);
782 j->matters_to_anchor = false;
783 j->override = override;
784 j->irreversible = tr->irreversible;
786 LIST_PREPEND(transaction, f, j);
788 if (hashmap_replace(tr->jobs, unit, f) < 0) {
789 LIST_REMOVE(transaction, f, j);
797 /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
802 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
806 if (j->transaction_prev)
807 j->transaction_prev->transaction_next = j->transaction_next;
808 else if (j->transaction_next)
809 hashmap_replace(tr->jobs, j->unit, j->transaction_next);
811 hashmap_remove_value(tr->jobs, j->unit, j);
813 if (j->transaction_next)
814 j->transaction_next->transaction_prev = j->transaction_prev;
816 j->transaction_prev = j->transaction_next = NULL;
818 while (j->subject_list)
819 job_dependency_free(j->subject_list);
821 while (j->object_list) {
822 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
824 job_dependency_free(j->object_list);
826 if (other && delete_dependencies) {
827 log_debug_unit(other->unit->id,
828 "Deleting job %s/%s as dependency of job %s/%s",
829 other->unit->id, job_type_to_string(other->type),
830 j->unit->id, job_type_to_string(j->type));
831 transaction_delete_job(tr, other, delete_dependencies);
836 int transaction_add_job_and_dependencies(
844 bool ignore_requirements,
854 assert(type < _JOB_TYPE_MAX);
855 assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
858 /* log_debug("Pulling in %s/%s from %s/%s", */
859 /* unit->id, job_type_to_string(type), */
860 /* by ? by->unit->id : "NA", */
861 /* by ? job_type_to_string(by->type) : "NA"); */
863 if (unit->load_state != UNIT_LOADED &&
864 unit->load_state != UNIT_ERROR &&
865 unit->load_state != UNIT_NOT_FOUND &&
866 unit->load_state != UNIT_MASKED) {
867 sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
868 "Unit %s is not loaded properly.", unit->id);
872 if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
873 if (unit->load_error == -ENOENT || unit->manager->test_run)
874 sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
875 "Unit %s failed to load: %s.",
877 strerror(-unit->load_error));
879 sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
880 "Unit %s failed to load: %s. "
881 "See system logs and 'systemctl status %s' for details.",
883 strerror(-unit->load_error),
888 if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND) {
889 sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
890 "Unit %s failed to load: %s.",
891 unit->id, strerror(-unit->load_error));
895 if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
896 sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED,
897 "Unit %s is masked.", unit->id);
898 return -EADDRNOTAVAIL;
901 if (!unit_job_is_applicable(unit, type)) {
902 sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
903 "Job type %s is not applicable for unit %s.",
904 job_type_to_string(type), unit->id);
908 /* First add the job. */
909 ret = transaction_add_one_job(tr, type, unit, override, &is_new);
913 ret->ignore_order = ret->ignore_order || ignore_order;
915 /* Then, add a link to the job. */
917 if (!job_dependency_new(by, ret, matters, conflicts))
920 /* If the job has no parent job, it is the anchor job. */
921 assert(!tr->anchor_job);
922 tr->anchor_job = ret;
925 if (is_new && !ignore_requirements && type != JOB_NOP) {
928 /* If we are following some other unit, make sure we
929 * add all dependencies of everybody following. */
930 if (unit_following_set(ret->unit, &following) > 0) {
931 SET_FOREACH(dep, following, i) {
932 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
934 log_warning_unit(dep->id,
935 "Cannot add dependency job for unit %s, ignoring: %s",
936 dep->id, bus_error_message(e, r));
939 sd_bus_error_free(e);
946 /* Finally, recursively add in all dependencies. */
947 if (type == JOB_START || type == JOB_RESTART) {
948 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
949 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
955 sd_bus_error_free(e);
959 SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
960 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
966 sd_bus_error_free(e);
970 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
971 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
973 log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
974 "Cannot add dependency job for unit %s, ignoring: %s",
975 dep->id, bus_error_message(e, r));
978 sd_bus_error_free(e);
982 SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
983 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
985 log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
986 "Cannot add dependency job for unit %s, ignoring: %s",
987 dep->id, bus_error_message(e, r));
990 sd_bus_error_free(e);
994 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
995 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
1001 sd_bus_error_free(e);
1005 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
1006 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
1008 log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
1009 "Cannot add dependency job for unit %s, ignoring: %s",
1010 dep->id, bus_error_message(e, r));
1013 sd_bus_error_free(e);
1017 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
1018 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
1024 sd_bus_error_free(e);
1028 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
1029 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
1031 log_warning_unit(dep->id,
1032 "Cannot add dependency job for unit %s, ignoring: %s",
1033 dep->id, bus_error_message(e, r));
1036 sd_bus_error_free(e);
1042 if (type == JOB_STOP || type == JOB_RESTART) {
1044 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
1045 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1051 sd_bus_error_free(e);
1055 SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
1056 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1062 sd_bus_error_free(e);
1066 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
1067 r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
1073 sd_bus_error_free(e);
1079 if (type == JOB_RELOAD) {
1081 SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
1082 r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
1084 log_warning_unit(dep->id,
1085 "Cannot add dependency reload job for unit %s, ignoring: %s",
1086 dep->id, bus_error_message(e, r));
1089 sd_bus_error_free(e);
1094 /* JOB_VERIFY_STARTED require no dependency handling */
1103 int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
1112 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1114 /* ignore aliases */
1118 if (u->ignore_on_isolate)
1121 /* No need to stop inactive jobs */
1122 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
1125 /* Is there already something listed for this? */
1126 if (hashmap_get(tr->jobs, u))
1129 r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
1131 log_warning_unit(u->id,
1132 "Cannot add isolate job for unit %s, ignoring: %s",
1133 u->id, strerror(-r));
1139 Transaction *transaction_new(bool irreversible) {
1142 tr = new0(Transaction, 1);
1146 tr->jobs = hashmap_new(NULL);
1152 tr->irreversible = irreversible;
1157 void transaction_free(Transaction *tr) {
1158 assert(hashmap_isempty(tr->jobs));
1159 hashmap_free(tr->jobs);