]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/transaction.c
catalog: don't say "systemd" when we mean "system"
[thirdparty/systemd.git] / src / core / transaction.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
7c0436b9
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
f2b68789 21#include <fcntl.h>
cf0fbc49 22#include <unistd.h>
f2b68789 23
b5efdb8a 24#include "alloc-util.h"
96aad8d1 25#include "bus-common-errors.h"
718db961 26#include "bus-error.h"
288a74cc 27#include "terminal-util.h"
b5efdb8a 28#include "transaction.h"
ee87525c 29#include "dbus-unit.h"
75778e21
MS
30
31static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
32
33static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependencies) {
34 assert(tr);
35 assert(j);
36
37 /* Deletes one job from the transaction */
38
39 transaction_unlink_job(tr, j, delete_dependencies);
40
d6a093d0 41 job_free(j);
75778e21
MS
42}
43
44static void transaction_delete_unit(Transaction *tr, Unit *u) {
45 Job *j;
46
47 /* Deletes all jobs associated with a certain unit from the
48 * transaction */
49
50 while ((j = hashmap_get(tr->jobs, u)))
51 transaction_delete_job(tr, j, true);
52}
53
54void transaction_abort(Transaction *tr) {
55 Job *j;
56
57 assert(tr);
58
59 while ((j = hashmap_first(tr->jobs)))
1b9cea0c 60 transaction_delete_job(tr, j, false);
75778e21
MS
61
62 assert(hashmap_isempty(tr->jobs));
75778e21
MS
63}
64
0d9989aa 65static void transaction_find_jobs_that_matter_to_anchor(Job *j, unsigned generation) {
75778e21
MS
66 JobDependency *l;
67
75778e21
MS
68 /* A recursive sweep through the graph that marks all units
69 * that matter to the anchor job, i.e. are directly or
70 * indirectly a dependency of the anchor job via paths that
71 * are fully marked as mattering. */
72
0d9989aa
MS
73 j->matters_to_anchor = true;
74 j->generation = generation;
75778e21 75
0d9989aa 76 LIST_FOREACH(subject, l, j->subject_list) {
75778e21
MS
77
78 /* This link does not matter */
79 if (!l->matters)
80 continue;
81
82 /* This unit has already been marked */
83 if (l->object->generation == generation)
84 continue;
85
0d9989aa 86 transaction_find_jobs_that_matter_to_anchor(l->object, generation);
75778e21
MS
87 }
88}
89
90static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other, JobType t) {
91 JobDependency *l, *last;
92
93 assert(j);
94 assert(other);
95 assert(j->unit == other->unit);
96 assert(!j->installed);
97
98 /* Merges 'other' into 'j' and then deletes 'other'. */
99
100 j->type = t;
101 j->state = JOB_WAITING;
23ade460 102 j->irreversible = j->irreversible || other->irreversible;
75778e21
MS
103 j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
104
105 /* Patch us in as new owner of the JobDependency objects */
106 last = NULL;
107 LIST_FOREACH(subject, l, other->subject_list) {
108 assert(l->subject == other);
109 l->subject = j;
110 last = l;
111 }
112
113 /* Merge both lists */
114 if (last) {
115 last->subject_next = j->subject_list;
116 if (j->subject_list)
117 j->subject_list->subject_prev = last;
118 j->subject_list = other->subject_list;
119 }
120
121 /* Patch us in as new owner of the JobDependency objects */
122 last = NULL;
123 LIST_FOREACH(object, l, other->object_list) {
124 assert(l->object == other);
125 l->object = j;
126 last = l;
127 }
128
129 /* Merge both lists */
130 if (last) {
131 last->object_next = j->object_list;
132 if (j->object_list)
133 j->object_list->object_prev = last;
134 j->object_list = other->object_list;
135 }
136
137 /* Kill the other job */
138 other->subject_list = NULL;
139 other->object_list = NULL;
140 transaction_delete_job(tr, other, true);
141}
142
44a6b1b6 143_pure_ static bool job_is_conflicted_by(Job *j) {
75778e21
MS
144 JobDependency *l;
145
146 assert(j);
147
148 /* Returns true if this job is pulled in by a least one
149 * ConflictedBy dependency. */
150
151 LIST_FOREACH(object, l, j->object_list)
152 if (l->conflicts)
153 return true;
154
155 return false;
156}
157
158static int delete_one_unmergeable_job(Transaction *tr, Job *j) {
159 Job *k;
160
161 assert(j);
162
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. */
167
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) {
172 Job *d;
173
174 /* Is this one mergeable? Then skip it */
175 if (job_type_is_mergeable(j->type, k->type))
176 continue;
177
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) {
181
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. */
190
f2341e0a 191 log_unit_debug(j->unit,
66870f90
ZJS
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)));
f2341e0a 195 log_unit_debug(k->unit,
66870f90
ZJS
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)));
75778e21
MS
199
200 if (j->type == JOB_STOP) {
201
202 if (job_is_conflicted_by(j))
203 d = k;
204 else
205 d = j;
206
207 } else if (k->type == JOB_STOP) {
208
209 if (job_is_conflicted_by(k))
210 d = j;
211 else
212 d = k;
213 } else
214 d = j;
215
216 } else if (!j->matters_to_anchor)
217 d = j;
218 else if (!k->matters_to_anchor)
219 d = k;
220 else
221 return -ENOEXEC;
222
223 /* Ok, we can drop one, so let's do so. */
f2341e0a 224 log_unit_debug(d->unit,
75cb8502
ZJS
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),
66870f90 228 d->unit->id, job_type_to_string(d->type));
75778e21
MS
229 transaction_delete_job(tr, d, true);
230 return 0;
231 }
232
233 return -EINVAL;
234}
235
718db961 236static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) {
75778e21
MS
237 Job *j;
238 Iterator i;
239 int r;
240
241 assert(tr);
242
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) {
246 JobType t;
247 Job *k;
248
249 t = j->type;
250 LIST_FOREACH(transaction, k, j->transaction_next) {
e0209d83 251 if (job_type_merge_and_collapse(&t, k->type, j->unit) >= 0)
75778e21
MS
252 continue;
253
254 /* OK, we could not merge all jobs for this
255 * action. Let's see if we can get rid of one
256 * of them */
257
258 r = delete_one_unmergeable_job(tr, j);
259 if (r >= 0)
260 /* Ok, we managed to drop one, now
261 * let's ask our callers to call us
262 * again after garbage collecting */
263 return -EAGAIN;
264
265 /* We couldn't merge anything. Failure */
7358dc02
ZJS
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),
271 k->unit->id);
75778e21
MS
272 }
273 }
274
275 /* Second step, merge the jobs. */
276 HASHMAP_FOREACH(j, tr->jobs, i) {
277 JobType t = j->type;
278 Job *k;
279
e0209d83 280 /* Merge all transaction jobs for j->unit */
75778e21 281 LIST_FOREACH(transaction, k, j->transaction_next)
e0209d83 282 assert_se(job_type_merge_and_collapse(&t, k->type, j->unit) == 0);
75778e21 283
75778e21 284 while ((k = j->transaction_next)) {
656bbffc 285 if (tr->anchor_job == k) {
75778e21
MS
286 transaction_merge_and_delete_job(tr, k, j, t);
287 j = k;
288 } else
289 transaction_merge_and_delete_job(tr, j, k, t);
290 }
291
75778e21
MS
292 assert(!j->transaction_next);
293 assert(!j->transaction_prev);
294 }
295
296 return 0;
297}
298
299static void transaction_drop_redundant(Transaction *tr) {
055163ad
MS
300 Job *j;
301 Iterator i;
75778e21 302
055163ad
MS
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. */
75778e21 306
055163ad 307 assert(tr);
75778e21 308
055163ad
MS
309rescan:
310 HASHMAP_FOREACH(j, tr->jobs, i) {
311 Job *k;
75778e21 312
055163ad 313 LIST_FOREACH(transaction, k, j) {
75778e21 314
055163ad
MS
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)))
318 goto next_unit;
75778e21
MS
319 }
320
055163ad
MS
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);
323 goto rescan;
324 next_unit:;
325 }
75778e21
MS
326}
327
44a6b1b6 328_pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) {
75778e21
MS
329 assert(u);
330 assert(!j->transaction_prev);
331
332 /* Checks whether at least one of the jobs for this unit
333 * matters to the anchor. */
334
335 LIST_FOREACH(transaction, j, j)
336 if (j->matters_to_anchor)
337 return true;
338
339 return false;
340}
341
924775e8
ZJS
342static char* merge_unit_ids(const char* unit_log_field, char **pairs) {
343 char **unit_id, **job_type, *ans = NULL;
344 size_t alloc = 0, size = 0, next;
345
346 STRV_FOREACH_PAIR(unit_id, job_type, pairs) {
347 next = strlen(unit_log_field) + strlen(*unit_id);
348 if (!GREEDY_REALLOC(ans, alloc, size + next + 1)) {
5fecf46d 349 return mfree(ans);
924775e8
ZJS
350 }
351
352 sprintf(ans + size, "%s%s", unit_log_field, *unit_id);
353 if (*(unit_id+1))
354 ans[size + next] = '\n';
355 size += next + 1;
356 }
357
358 return ans;
359}
360
718db961 361static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
75778e21
MS
362 Iterator i;
363 Unit *u;
eef85c4a 364 void *v;
75778e21
MS
365 int r;
366
367 assert(tr);
368 assert(j);
369 assert(!j->transaction_prev);
370
371 /* Does a recursive sweep through the ordering graph, looking
1244d8d6 372 * for a cycle. If we find a cycle we try to break it. */
75778e21
MS
373
374 /* Have we seen this before? */
375 if (j->generation == generation) {
924775e8
ZJS
376 Job *k, *delete = NULL;
377 _cleanup_free_ char **array = NULL, *unit_ids = NULL;
378 char **unit_id, **job_type;
75778e21
MS
379
380 /* If the marker is NULL we have been here already and
381 * decided the job was loop-free from here. Hence
382 * shortcut things and return right-away. */
383 if (!j->marker)
384 return 0;
385
924775e8
ZJS
386 /* So, the marker is not NULL and we already have been here. We have
387 * a cycle. Let's try to break it. We go backwards in our path and
388 * try to find a suitable job to remove. We use the marker to find
389 * our way back, since smart how we are we stored our way back in
390 * there. */
391
75778e21
MS
392 for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
393
924775e8
ZJS
394 /* For logging below */
395 if (strv_push_pair(&array, k->unit->id, (char*) job_type_to_string(k->type)) < 0)
396 log_oom();
75778e21 397
ece174c5 398 if (!delete && hashmap_get(tr->jobs, k->unit) && !unit_matters_to_anchor(k->unit, k))
924775e8 399 /* Ok, we can drop this one, so let's do so. */
75778e21 400 delete = k;
75778e21 401
924775e8 402 /* Check if this in fact was the beginning of the cycle */
75778e21
MS
403 if (k == j)
404 break;
405 }
406
924775e8
ZJS
407 unit_ids = merge_unit_ids(j->manager->unit_log_field, array); /* ignore error */
408
409 STRV_FOREACH_PAIR(unit_id, job_type, array)
410 /* logging for j not k here to provide a consistent narrative */
411 log_struct(LOG_WARNING,
412 "MESSAGE=%s: Found %s on %s/%s",
413 j->unit->id,
414 unit_id == array ? "ordering cycle" : "dependency",
415 *unit_id, *job_type,
416 unit_ids, NULL);
75778e21
MS
417
418 if (delete) {
dc9b5816 419 const char *status;
924775e8
ZJS
420 /* logging for j not k here to provide a consistent narrative */
421 log_struct(LOG_ERR,
422 "MESSAGE=%s: Job %s/%s deleted to break ordering cycle starting with %s/%s",
423 j->unit->id, delete->unit->id, job_type_to_string(delete->type),
424 j->unit->id, job_type_to_string(j->type),
425 unit_ids, NULL);
dc9b5816
ZJS
426
427 if (log_get_show_color())
428 status = ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL;
429 else
430 status = " SKIP ";
431
432 unit_status_printf(delete->unit, status,
297d0749 433 "Ordering cycle found, skipping %s");
75778e21
MS
434 transaction_delete_unit(tr, delete->unit);
435 return -EAGAIN;
436 }
437
924775e8
ZJS
438 log_struct(LOG_ERR,
439 "MESSAGE=%s: Unable to break cycle starting with %s/%s",
440 j->unit->id, j->unit->id, job_type_to_string(j->type),
441 unit_ids, NULL);
75778e21 442
7358dc02
ZJS
443 return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
444 "Transaction order is cyclic. See system logs for details.");
75778e21
MS
445 }
446
447 /* Make the marker point to where we come from, so that we can
448 * find our way backwards if we want to break a cycle. We use
449 * a special marker for the beginning: we point to
450 * ourselves. */
451 j->marker = from ? from : j;
452 j->generation = generation;
453
c5315881 454 /* We assume that the dependencies are bidirectional, and
75778e21 455 * hence can ignore UNIT_AFTER */
eef85c4a 456 HASHMAP_FOREACH_KEY(v, u, j->unit->dependencies[UNIT_BEFORE], i) {
75778e21
MS
457 Job *o;
458
459 /* Is there a job for this unit? */
460 o = hashmap_get(tr->jobs, u);
461 if (!o) {
462 /* Ok, there is no job for this in the
463 * transaction, but maybe there is already one
464 * running? */
465 o = u->job;
466 if (!o)
467 continue;
468 }
469
470 r = transaction_verify_order_one(tr, o, j, generation, e);
471 if (r < 0)
472 return r;
473 }
474
475 /* Ok, let's backtrack, and remember that this entry is not on
476 * our path anymore. */
477 j->marker = NULL;
478
479 return 0;
480}
481
718db961 482static int transaction_verify_order(Transaction *tr, unsigned *generation, sd_bus_error *e) {
75778e21
MS
483 Job *j;
484 int r;
485 Iterator i;
486 unsigned g;
487
488 assert(tr);
489 assert(generation);
490
491 /* Check if the ordering graph is cyclic. If it is, try to fix
492 * that up by dropping one of the jobs. */
493
494 g = (*generation)++;
495
3cc2aff1
LP
496 HASHMAP_FOREACH(j, tr->jobs, i) {
497 r = transaction_verify_order_one(tr, j, NULL, g, e);
498 if (r < 0)
75778e21 499 return r;
3cc2aff1 500 }
75778e21
MS
501
502 return 0;
503}
504
505static void transaction_collect_garbage(Transaction *tr) {
055163ad
MS
506 Iterator i;
507 Job *j;
75778e21
MS
508
509 assert(tr);
510
511 /* Drop jobs that are not required by any other job */
512
055163ad
MS
513rescan:
514 HASHMAP_FOREACH(j, tr->jobs, i) {
515 if (tr->anchor_job == j || j->object_list) {
516 /* log_debug("Keeping job %s/%s because of %s/%s", */
517 /* j->unit->id, job_type_to_string(j->type), */
518 /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */
519 /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
520 continue;
75778e21
MS
521 }
522
055163ad
MS
523 /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
524 transaction_delete_job(tr, j, true);
525 goto rescan;
526 }
75778e21
MS
527}
528
718db961 529static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_error *e) {
75778e21
MS
530 Iterator i;
531 Job *j;
532
533 assert(tr);
534
535 /* Checks whether applying this transaction means that
536 * existing jobs would be replaced */
537
538 HASHMAP_FOREACH(j, tr->jobs, i) {
539
540 /* Assume merged */
541 assert(!j->transaction_prev);
542 assert(!j->transaction_next);
543
23ade460 544 if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
c21b92ff 545 job_type_is_conflicting(j->unit->job->type, j->type))
7358dc02
ZJS
546 return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,
547 "Transaction is destructive.");
75778e21
MS
548 }
549
550 return 0;
551}
552
553static void transaction_minimize_impact(Transaction *tr) {
055163ad
MS
554 Job *j;
555 Iterator i;
556
75778e21
MS
557 assert(tr);
558
559 /* Drops all unnecessary jobs that reverse already active jobs
560 * or that stop a running service. */
561
055163ad
MS
562rescan:
563 HASHMAP_FOREACH(j, tr->jobs, i) {
564 LIST_FOREACH(transaction, j, j) {
565 bool stops_running_service, changes_existing_job;
75778e21 566
055163ad
MS
567 /* If it matters, we shouldn't drop it */
568 if (j->matters_to_anchor)
569 continue;
75778e21 570
055163ad
MS
571 /* Would this stop a running service?
572 * Would this change an existing job?
573 * If so, let's drop this entry */
75778e21 574
055163ad
MS
575 stops_running_service =
576 j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
75778e21 577
055163ad
MS
578 changes_existing_job =
579 j->unit->job &&
580 job_type_is_conflicting(j->type, j->unit->job->type);
75778e21 581
055163ad
MS
582 if (!stops_running_service && !changes_existing_job)
583 continue;
75778e21 584
055163ad 585 if (stops_running_service)
f2341e0a 586 log_unit_debug(j->unit,
66870f90
ZJS
587 "%s/%s would stop a running service.",
588 j->unit->id, job_type_to_string(j->type));
75778e21 589
055163ad 590 if (changes_existing_job)
f2341e0a 591 log_unit_debug(j->unit,
66870f90
ZJS
592 "%s/%s would change existing job.",
593 j->unit->id, job_type_to_string(j->type));
75778e21 594
055163ad 595 /* Ok, let's get rid of this */
f2341e0a 596 log_unit_debug(j->unit,
66870f90
ZJS
597 "Deleting %s/%s to minimize impact.",
598 j->unit->id, job_type_to_string(j->type));
75778e21 599
055163ad
MS
600 transaction_delete_job(tr, j, true);
601 goto rescan;
75778e21 602 }
055163ad 603 }
75778e21
MS
604}
605
606static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
607 Iterator i;
608 Job *j;
609 int r;
610
611 /* Moves the transaction jobs to the set of active jobs */
612
3742095b 613 if (IN_SET(mode, JOB_ISOLATE, JOB_FLUSH)) {
75778e21
MS
614
615 /* When isolating first kill all installed jobs which
616 * aren't part of the new transaction */
75778e21
MS
617 HASHMAP_FOREACH(j, m->jobs, i) {
618 assert(j->installed);
619
2de0b9e9
MO
620 if (j->unit->ignore_on_isolate)
621 continue;
622
75778e21
MS
623 if (hashmap_get(tr->jobs, j->unit))
624 continue;
625
5273510e
MS
626 /* Not invalidating recursively. Avoids triggering
627 * OnFailure= actions of dependent jobs. Also avoids
628 * invalidating our iterator. */
833f92ad 629 job_finish_and_invalidate(j, JOB_CANCELED, false, false);
75778e21
MS
630 }
631 }
632
633 HASHMAP_FOREACH(j, tr->jobs, i) {
634 /* Assume merged */
635 assert(!j->transaction_prev);
636 assert(!j->transaction_next);
637
75778e21
MS
638 r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j);
639 if (r < 0)
640 goto rollback;
641 }
642
643 while ((j = hashmap_steal_first(tr->jobs))) {
656bbffc
MS
644 Job *installed_job;
645
75778e21
MS
646 /* Clean the job dependencies */
647 transaction_unlink_job(tr, j, false);
648
656bbffc
MS
649 installed_job = job_install(j);
650 if (installed_job != j) {
651 /* j has been merged into a previously installed job */
652 if (tr->anchor_job == j)
653 tr->anchor_job = installed_job;
654 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
655 job_free(j);
656 j = installed_job;
657 }
05d576f1 658
75778e21
MS
659 job_add_to_run_queue(j);
660 job_add_to_dbus_queue(j);
a2df3ea4 661 job_start_timer(j, false);
c65eb836 662 job_shutdown_magic(j);
75778e21
MS
663 }
664
75778e21
MS
665 return 0;
666
667rollback:
668
d6a093d0 669 HASHMAP_FOREACH(j, tr->jobs, i)
75778e21 670 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
75778e21
MS
671
672 return r;
673}
674
718db961 675int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
4e7bd268
MS
676 Iterator i;
677 Job *j;
75778e21
MS
678 int r;
679 unsigned generation = 1;
680
681 assert(tr);
682
683 /* This applies the changes recorded in tr->jobs to
684 * the actual list of jobs, if possible. */
685
4e7bd268
MS
686 /* Reset the generation counter of all installed jobs. The detection of cycles
687 * looks at installed jobs. If they had a non-zero generation from some previous
688 * walk of the graph, the algorithm would break. */
689 HASHMAP_FOREACH(j, m->jobs, i)
690 j->generation = 0;
691
75778e21 692 /* First step: figure out which jobs matter */
0d9989aa 693 transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
75778e21
MS
694
695 /* Second step: Try not to stop any running services if
696 * we don't have to. Don't try to reverse running
697 * jobs if we don't have to. */
698 if (mode == JOB_FAIL)
699 transaction_minimize_impact(tr);
700
701 /* Third step: Drop redundant jobs */
702 transaction_drop_redundant(tr);
703
704 for (;;) {
705 /* Fourth step: Let's remove unneeded jobs that might
706 * be lurking. */
707 if (mode != JOB_ISOLATE)
708 transaction_collect_garbage(tr);
709
710 /* Fifth step: verify order makes sense and correct
711 * cycles if necessary and possible */
712 r = transaction_verify_order(tr, &generation, e);
713 if (r >= 0)
714 break;
715
716 if (r != -EAGAIN) {
718db961 717 log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e, r));
75778e21
MS
718 return r;
719 }
720
721 /* Let's see if the resulting transaction ordering
722 * graph is still cyclic... */
723 }
724
725 for (;;) {
726 /* Sixth step: let's drop unmergeable entries if
727 * necessary and possible, merge entries we can
728 * merge */
729 r = transaction_merge_jobs(tr, e);
730 if (r >= 0)
731 break;
732
733 if (r != -EAGAIN) {
718db961 734 log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e, r));
75778e21
MS
735 return r;
736 }
737
738 /* Seventh step: an entry got dropped, let's garbage
739 * collect its dependencies. */
740 if (mode != JOB_ISOLATE)
741 transaction_collect_garbage(tr);
742
743 /* Let's see if the resulting transaction still has
744 * unmergeable entries ... */
745 }
746
747 /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
748 transaction_drop_redundant(tr);
749
750 /* Ninth step: check whether we can actually apply this */
23ade460
MS
751 r = transaction_is_destructive(tr, mode, e);
752 if (r < 0) {
718db961 753 log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
23ade460 754 return r;
75778e21
MS
755 }
756
757 /* Tenth step: apply changes */
758 r = transaction_apply(tr, m, mode);
23bbb0de
MS
759 if (r < 0)
760 return log_warning_errno(r, "Failed to apply transaction: %m");
75778e21
MS
761
762 assert(hashmap_isempty(tr->jobs));
75778e21 763
f2b68789
LP
764 if (!hashmap_isempty(m->jobs)) {
765 /* Are there any jobs now? Then make sure we have the
766 * idle pipe around. We don't really care too much
767 * whether this works or not, as the idle pipe is a
768 * feature for cosmetics, not actually useful for
769 * anything beyond that. */
770
31a7eb86
ZJS
771 if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
772 m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
1afaa7e8
LP
773 (void) pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
774 (void) pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
31a7eb86 775 }
f2b68789
LP
776 }
777
75778e21
MS
778 return 0;
779}
780
4bd29fe5 781static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool *is_new) {
75778e21
MS
782 Job *j, *f;
783
784 assert(tr);
785 assert(unit);
786
787 /* Looks for an existing prospective job and returns that. If
788 * it doesn't exist it is created and added to the prospective
789 * jobs list. */
790
791 f = hashmap_get(tr->jobs, unit);
792
793 LIST_FOREACH(transaction, j, f) {
794 assert(j->unit == unit);
795
796 if (j->type == type) {
797 if (is_new)
798 *is_new = false;
799 return j;
800 }
801 }
802
3c956cfe
MS
803 j = job_new(unit, type);
804 if (!j)
805 return NULL;
75778e21
MS
806
807 j->generation = 0;
808 j->marker = NULL;
809 j->matters_to_anchor = false;
23ade460 810 j->irreversible = tr->irreversible;
75778e21 811
71fda00f 812 LIST_PREPEND(transaction, f, j);
75778e21
MS
813
814 if (hashmap_replace(tr->jobs, unit, f) < 0) {
71fda00f 815 LIST_REMOVE(transaction, f, j);
75778e21
MS
816 job_free(j);
817 return NULL;
818 }
819
820 if (is_new)
821 *is_new = true;
822
823 /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
824
825 return j;
826}
827
828static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
829 assert(tr);
830 assert(j);
831
832 if (j->transaction_prev)
833 j->transaction_prev->transaction_next = j->transaction_next;
834 else if (j->transaction_next)
835 hashmap_replace(tr->jobs, j->unit, j->transaction_next);
836 else
837 hashmap_remove_value(tr->jobs, j->unit, j);
838
839 if (j->transaction_next)
840 j->transaction_next->transaction_prev = j->transaction_prev;
841
842 j->transaction_prev = j->transaction_next = NULL;
843
844 while (j->subject_list)
e6eda1f2 845 job_dependency_free(j->subject_list);
75778e21
MS
846
847 while (j->object_list) {
848 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
849
e6eda1f2 850 job_dependency_free(j->object_list);
75778e21
MS
851
852 if (other && delete_dependencies) {
f2341e0a 853 log_unit_debug(other->unit,
66870f90
ZJS
854 "Deleting job %s/%s as dependency of job %s/%s",
855 other->unit->id, job_type_to_string(other->type),
856 j->unit->id, job_type_to_string(j->type));
75778e21
MS
857 transaction_delete_job(tr, other, delete_dependencies);
858 }
859 }
860}
861
15d167f8
JW
862void transaction_add_propagate_reload_jobs(Transaction *tr, Unit *unit, Job *by, bool ignore_order, sd_bus_error *e) {
863 Iterator i;
15d167f8 864 JobType nt;
eef85c4a
LP
865 Unit *dep;
866 void *v;
15d167f8
JW
867 int r;
868
869 assert(tr);
870 assert(unit);
871
eef85c4a 872 HASHMAP_FOREACH_KEY(v, dep, unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
15d167f8
JW
873 nt = job_type_collapse(JOB_TRY_RELOAD, dep);
874 if (nt == JOB_NOP)
875 continue;
876
877 r = transaction_add_job_and_dependencies(tr, nt, dep, by, false, false, false, ignore_order, e);
878 if (r < 0) {
879 log_unit_warning(dep,
880 "Cannot add dependency reload job, ignoring: %s",
881 bus_error_message(e, r));
882 sd_bus_error_free(e);
883 }
884 }
885}
886
75778e21
MS
887int transaction_add_job_and_dependencies(
888 Transaction *tr,
889 JobType type,
890 Unit *unit,
891 Job *by,
892 bool matters,
75778e21
MS
893 bool conflicts,
894 bool ignore_requirements,
895 bool ignore_order,
718db961 896 sd_bus_error *e) {
eef85c4a
LP
897
898 bool is_new;
75778e21
MS
899 Iterator i;
900 Unit *dep;
eef85c4a
LP
901 Job *ret;
902 void *v;
75778e21 903 int r;
75778e21
MS
904
905 assert(tr);
906 assert(type < _JOB_TYPE_MAX);
e0209d83 907 assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
75778e21
MS
908 assert(unit);
909
43706330
IS
910 /* Before adding jobs for this unit, let's ensure that its state has been loaded
911 * This matters when jobs are spawned as part of coldplugging itself (see e. g. path_coldplug()).
912 * This way, we "recursively" coldplug units, ensuring that we do not look at state of
913 * not-yet-coldplugged units. */
2c289ea8 914 if (MANAGER_IS_RELOADING(unit->manager))
43706330
IS
915 unit_coldplug(unit);
916
75778e21
MS
917 /* log_debug("Pulling in %s/%s from %s/%s", */
918 /* unit->id, job_type_to_string(type), */
919 /* by ? by->unit->id : "NA", */
920 /* by ? job_type_to_string(by->type) : "NA"); */
921
7358dc02 922 if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED))
c6497ccb 923 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
75778e21 924
ee87525c
FB
925 if (type != JOB_STOP) {
926 r = bus_unit_check_load_state(unit, e);
927 if (r < 0)
928 return r;
75778e21
MS
929 }
930
7358dc02
ZJS
931 if (!unit_job_is_applicable(unit, type))
932 return sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
933 "Job type %s is not applicable for unit %s.",
934 job_type_to_string(type), unit->id);
75778e21 935
75778e21
MS
936
937 /* First add the job. */
4bd29fe5 938 ret = transaction_add_one_job(tr, type, unit, &is_new);
75778e21
MS
939 if (!ret)
940 return -ENOMEM;
941
942 ret->ignore_order = ret->ignore_order || ignore_order;
943
944 /* Then, add a link to the job. */
e6eda1f2
MS
945 if (by) {
946 if (!job_dependency_new(by, ret, matters, conflicts))
947 return -ENOMEM;
948 } else {
949 /* If the job has no parent job, it is the anchor job. */
4483f694
MS
950 assert(!tr->anchor_job);
951 tr->anchor_job = ret;
b94fbd30 952 }
e0209d83
MS
953
954 if (is_new && !ignore_requirements && type != JOB_NOP) {
75778e21
MS
955 Set *following;
956
957 /* If we are following some other unit, make sure we
958 * add all dependencies of everybody following. */
959 if (unit_following_set(ret->unit, &following) > 0) {
960 SET_FOREACH(dep, following, i) {
4bd29fe5 961 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, false, false, ignore_order, e);
75778e21 962 if (r < 0) {
e0f65994
ZJS
963 log_unit_full(dep,
964 r == -ERFKILL ? LOG_INFO : LOG_WARNING,
965 r, "Cannot add dependency job, ignoring: %s",
966 bus_error_message(e, r));
69301c17 967 sd_bus_error_free(e);
75778e21
MS
968 }
969 }
970
971 set_free(following);
972 }
973
974 /* Finally, recursively add in all dependencies. */
3742095b 975 if (IN_SET(type, JOB_START, JOB_RESTART)) {
eef85c4a 976 HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
4bd29fe5 977 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
75778e21 978 if (r < 0) {
114400df 979 if (r != -EBADR) /* job type not applicable */
75778e21
MS
980 goto fail;
981
69301c17 982 sd_bus_error_free(e);
75778e21
MS
983 }
984 }
985
eef85c4a 986 HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
4bd29fe5 987 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
75778e21 988 if (r < 0) {
114400df 989 if (r != -EBADR) /* job type not applicable */
75778e21
MS
990 goto fail;
991
69301c17 992 sd_bus_error_free(e);
75778e21
MS
993 }
994 }
995
eef85c4a 996 HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_WANTS], i) {
4bd29fe5 997 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e);
75778e21 998 if (r < 0) {
114400df 999 /* unit masked, job type not applicable and unit not found are not considered as errors. */
f2341e0a 1000 log_unit_full(dep,
76ec966f 1001 IN_SET(r, -ERFKILL, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING,
f14637fc 1002 r, "Cannot add dependency job, ignoring: %s",
f2341e0a 1003 bus_error_message(e, r));
69301c17 1004 sd_bus_error_free(e);
75778e21
MS
1005 }
1006 }
1007
eef85c4a 1008 HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
4bd29fe5 1009 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, false, false, ignore_order, e);
75778e21 1010 if (r < 0) {
114400df 1011 if (r != -EBADR) /* job type not applicable */
75778e21
MS
1012 goto fail;
1013
69301c17 1014 sd_bus_error_free(e);
75778e21
MS
1015 }
1016 }
1017
eef85c4a 1018 HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
4bd29fe5 1019 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, true, false, ignore_order, e);
75778e21 1020 if (r < 0) {
114400df 1021 if (r != -EBADR) /* job type not applicable */
75778e21
MS
1022 goto fail;
1023
69301c17 1024 sd_bus_error_free(e);
75778e21
MS
1025 }
1026 }
1027
eef85c4a 1028 HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
4bd29fe5 1029 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, false, false, ignore_order, e);
75778e21 1030 if (r < 0) {
f2341e0a
LP
1031 log_unit_warning(dep,
1032 "Cannot add dependency job, ignoring: %s",
1033 bus_error_message(e, r));
69301c17 1034 sd_bus_error_free(e);
75778e21
MS
1035 }
1036 }
1037
1038 }
1039
3742095b 1040 if (IN_SET(type, JOB_STOP, JOB_RESTART)) {
ce74e769
LP
1041 static const UnitDependency propagate_deps[] = {
1042 UNIT_REQUIRED_BY,
1043 UNIT_REQUISITE_OF,
1044 UNIT_BOUND_BY,
1045 UNIT_CONSISTS_OF,
1046 };
75778e21 1047
c6497ccb 1048 JobType ptype;
ce74e769 1049 unsigned j;
75778e21 1050
c6497ccb
LP
1051 /* We propagate STOP as STOP, but RESTART only
1052 * as TRY_RESTART, in order not to start
1053 * dependencies that are not around. */
1054 ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type;
1055
ce74e769 1056 for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
eef85c4a 1057 HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[propagate_deps[j]], i) {
48894cd0 1058 JobType nt;
85e9a101 1059
48894cd0
LP
1060 nt = job_type_collapse(ptype, dep);
1061 if (nt == JOB_NOP)
1062 continue;
1063
4bd29fe5 1064 r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, false, false, ignore_order, e);
ce74e769 1065 if (r < 0) {
114400df 1066 if (r != -EBADR) /* job type not applicable */
ce74e769 1067 goto fail;
85e9a101 1068
718db961 1069 sd_bus_error_free(e);
ce74e769 1070 }
85e9a101 1071 }
75778e21
MS
1072 }
1073
15d167f8
JW
1074 if (type == JOB_RELOAD)
1075 transaction_add_propagate_reload_jobs(tr, ret->unit, ret, ignore_order, e);
75778e21 1076
e0209d83 1077 /* JOB_VERIFY_STARTED require no dependency handling */
75778e21
MS
1078 }
1079
75778e21
MS
1080 return 0;
1081
1082fail:
1083 return r;
1084}
1085
1086int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
1087 Iterator i;
1088 Unit *u;
1089 char *k;
1090 int r;
1091
1092 assert(tr);
1093 assert(m);
1094
1095 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1096
1097 /* ignore aliases */
1098 if (u->id != k)
1099 continue;
1100
1101 if (u->ignore_on_isolate)
1102 continue;
1103
1104 /* No need to stop inactive jobs */
1105 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
1106 continue;
1107
1108 /* Is there already something listed for this? */
1109 if (hashmap_get(tr->jobs, u))
1110 continue;
1111
4bd29fe5 1112 r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, NULL);
75778e21 1113 if (r < 0)
f2341e0a 1114 log_unit_warning_errno(u, r, "Cannot add isolate job, ignoring: %m");
75778e21
MS
1115 }
1116
1117 return 0;
1118}
1119
23ade460 1120Transaction *transaction_new(bool irreversible) {
75778e21
MS
1121 Transaction *tr;
1122
1123 tr = new0(Transaction, 1);
1124 if (!tr)
1125 return NULL;
1126
d5099efc 1127 tr->jobs = hashmap_new(NULL);
6b430fdb
ZJS
1128 if (!tr->jobs)
1129 return mfree(tr);
75778e21 1130
23ade460
MS
1131 tr->irreversible = irreversible;
1132
75778e21
MS
1133 return tr;
1134}
1135
1136void transaction_free(Transaction *tr) {
1137 assert(hashmap_isempty(tr->jobs));
1138 hashmap_free(tr->jobs);
1139 free(tr);
1140}