]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/transaction.c
util-lib: split out allocation calls into alloc-util.[ch]
[thirdparty/systemd.git] / src / core / transaction.c
CommitLineData
7c0436b9
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
f2b68789
LP
22#include <unistd.h>
23#include <fcntl.h>
24
b5efdb8a 25#include "alloc-util.h"
96aad8d1 26#include "bus-common-errors.h"
718db961 27#include "bus-error.h"
288a74cc 28#include "terminal-util.h"
b5efdb8a 29#include "transaction.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;
102 j->override = j->override || other->override;
23ade460 103 j->irreversible = j->irreversible || other->irreversible;
75778e21
MS
104
105 j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
106
107 /* Patch us in as new owner of the JobDependency objects */
108 last = NULL;
109 LIST_FOREACH(subject, l, other->subject_list) {
110 assert(l->subject == other);
111 l->subject = j;
112 last = l;
113 }
114
115 /* Merge both lists */
116 if (last) {
117 last->subject_next = j->subject_list;
118 if (j->subject_list)
119 j->subject_list->subject_prev = last;
120 j->subject_list = other->subject_list;
121 }
122
123 /* Patch us in as new owner of the JobDependency objects */
124 last = NULL;
125 LIST_FOREACH(object, l, other->object_list) {
126 assert(l->object == other);
127 l->object = j;
128 last = l;
129 }
130
131 /* Merge both lists */
132 if (last) {
133 last->object_next = j->object_list;
134 if (j->object_list)
135 j->object_list->object_prev = last;
136 j->object_list = other->object_list;
137 }
138
139 /* Kill the other job */
140 other->subject_list = NULL;
141 other->object_list = NULL;
142 transaction_delete_job(tr, other, true);
143}
144
44a6b1b6 145_pure_ static bool job_is_conflicted_by(Job *j) {
75778e21
MS
146 JobDependency *l;
147
148 assert(j);
149
150 /* Returns true if this job is pulled in by a least one
151 * ConflictedBy dependency. */
152
153 LIST_FOREACH(object, l, j->object_list)
154 if (l->conflicts)
155 return true;
156
157 return false;
158}
159
160static int delete_one_unmergeable_job(Transaction *tr, Job *j) {
161 Job *k;
162
163 assert(j);
164
165 /* Tries to delete one item in the linked list
166 * j->transaction_next->transaction_next->... that conflicts
167 * with another one, in an attempt to make an inconsistent
168 * transaction work. */
169
170 /* We rely here on the fact that if a merged with b does not
171 * merge with c, either a or b merge with c neither */
172 LIST_FOREACH(transaction, j, j)
173 LIST_FOREACH(transaction, k, j->transaction_next) {
174 Job *d;
175
176 /* Is this one mergeable? Then skip it */
177 if (job_type_is_mergeable(j->type, k->type))
178 continue;
179
180 /* Ok, we found two that conflict, let's see if we can
181 * drop one of them */
182 if (!j->matters_to_anchor && !k->matters_to_anchor) {
183
184 /* Both jobs don't matter, so let's
185 * find the one that is smarter to
186 * remove. Let's think positive and
187 * rather remove stops then starts --
188 * except if something is being
189 * stopped because it is conflicted by
190 * another unit in which case we
191 * rather remove the start. */
192
f2341e0a 193 log_unit_debug(j->unit,
66870f90
ZJS
194 "Looking at job %s/%s conflicted_by=%s",
195 j->unit->id, job_type_to_string(j->type),
196 yes_no(j->type == JOB_STOP && job_is_conflicted_by(j)));
f2341e0a 197 log_unit_debug(k->unit,
66870f90
ZJS
198 "Looking at job %s/%s conflicted_by=%s",
199 k->unit->id, job_type_to_string(k->type),
200 yes_no(k->type == JOB_STOP && job_is_conflicted_by(k)));
75778e21
MS
201
202 if (j->type == JOB_STOP) {
203
204 if (job_is_conflicted_by(j))
205 d = k;
206 else
207 d = j;
208
209 } else if (k->type == JOB_STOP) {
210
211 if (job_is_conflicted_by(k))
212 d = j;
213 else
214 d = k;
215 } else
216 d = j;
217
218 } else if (!j->matters_to_anchor)
219 d = j;
220 else if (!k->matters_to_anchor)
221 d = k;
222 else
223 return -ENOEXEC;
224
225 /* Ok, we can drop one, so let's do so. */
f2341e0a 226 log_unit_debug(d->unit,
75cb8502
ZJS
227 "Fixing conflicting jobs %s/%s,%s/%s by deleting job %s/%s",
228 j->unit->id, job_type_to_string(j->type),
229 k->unit->id, job_type_to_string(k->type),
66870f90 230 d->unit->id, job_type_to_string(d->type));
75778e21
MS
231 transaction_delete_job(tr, d, true);
232 return 0;
233 }
234
235 return -EINVAL;
236}
237
718db961 238static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) {
75778e21
MS
239 Job *j;
240 Iterator i;
241 int r;
242
243 assert(tr);
244
245 /* First step, check whether any of the jobs for one specific
246 * task conflict. If so, try to drop one of them. */
247 HASHMAP_FOREACH(j, tr->jobs, i) {
248 JobType t;
249 Job *k;
250
251 t = j->type;
252 LIST_FOREACH(transaction, k, j->transaction_next) {
e0209d83 253 if (job_type_merge_and_collapse(&t, k->type, j->unit) >= 0)
75778e21
MS
254 continue;
255
256 /* OK, we could not merge all jobs for this
257 * action. Let's see if we can get rid of one
258 * of them */
259
260 r = delete_one_unmergeable_job(tr, j);
261 if (r >= 0)
262 /* Ok, we managed to drop one, now
263 * let's ask our callers to call us
264 * again after garbage collecting */
265 return -EAGAIN;
266
267 /* We couldn't merge anything. Failure */
7358dc02
ZJS
268 return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING,
269 "Transaction contains conflicting jobs '%s' and '%s' for %s. "
270 "Probably contradicting requirement dependencies configured.",
271 job_type_to_string(t),
272 job_type_to_string(k->type),
273 k->unit->id);
75778e21
MS
274 }
275 }
276
277 /* Second step, merge the jobs. */
278 HASHMAP_FOREACH(j, tr->jobs, i) {
279 JobType t = j->type;
280 Job *k;
281
e0209d83 282 /* Merge all transaction jobs for j->unit */
75778e21 283 LIST_FOREACH(transaction, k, j->transaction_next)
e0209d83 284 assert_se(job_type_merge_and_collapse(&t, k->type, j->unit) == 0);
75778e21 285
75778e21 286 while ((k = j->transaction_next)) {
656bbffc 287 if (tr->anchor_job == k) {
75778e21
MS
288 transaction_merge_and_delete_job(tr, k, j, t);
289 j = k;
290 } else
291 transaction_merge_and_delete_job(tr, j, k, t);
292 }
293
75778e21
MS
294 assert(!j->transaction_next);
295 assert(!j->transaction_prev);
296 }
297
298 return 0;
299}
300
301static void transaction_drop_redundant(Transaction *tr) {
055163ad
MS
302 Job *j;
303 Iterator i;
75778e21 304
055163ad
MS
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. */
75778e21 308
055163ad 309 assert(tr);
75778e21 310
055163ad
MS
311rescan:
312 HASHMAP_FOREACH(j, tr->jobs, i) {
313 Job *k;
75778e21 314
055163ad 315 LIST_FOREACH(transaction, k, j) {
75778e21 316
055163ad
MS
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)))
320 goto next_unit;
75778e21
MS
321 }
322
055163ad
MS
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);
325 goto rescan;
326 next_unit:;
327 }
75778e21
MS
328}
329
44a6b1b6 330_pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) {
75778e21
MS
331 assert(u);
332 assert(!j->transaction_prev);
333
334 /* Checks whether at least one of the jobs for this unit
335 * matters to the anchor. */
336
337 LIST_FOREACH(transaction, j, j)
338 if (j->matters_to_anchor)
339 return true;
340
341 return false;
342}
343
718db961 344static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
75778e21
MS
345 Iterator i;
346 Unit *u;
347 int r;
348
349 assert(tr);
350 assert(j);
351 assert(!j->transaction_prev);
352
353 /* Does a recursive sweep through the ordering graph, looking
1244d8d6 354 * for a cycle. If we find a cycle we try to break it. */
75778e21
MS
355
356 /* Have we seen this before? */
357 if (j->generation == generation) {
358 Job *k, *delete;
359
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. */
363 if (!j->marker)
364 return 0;
365
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
371 * in there. */
f2341e0a 372 log_unit_warning(j->unit,
66870f90
ZJS
373 "Found ordering cycle on %s/%s",
374 j->unit->id, job_type_to_string(j->type));
75778e21
MS
375
376 delete = NULL;
377 for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
378
66870f90 379 /* logging for j not k here here to provide consistent narrative */
f2341e0a 380 log_unit_warning(j->unit,
14fe721b
ZJS
381 "Found dependency on %s/%s",
382 k->unit->id, job_type_to_string(k->type));
75778e21 383
ece174c5 384 if (!delete && hashmap_get(tr->jobs, k->unit) && !unit_matters_to_anchor(k->unit, k))
75778e21
MS
385 /* Ok, we can drop this one, so let's
386 * do so. */
387 delete = k;
75778e21
MS
388
389 /* Check if this in fact was the beginning of
390 * the cycle */
391 if (k == j)
392 break;
393 }
394
395
396 if (delete) {
66870f90 397 /* logging for j not k here here to provide consistent narrative */
f2341e0a 398 log_unit_warning(j->unit,
66870f90
ZJS
399 "Breaking ordering cycle by deleting job %s/%s",
400 delete->unit->id, job_type_to_string(delete->type));
f2341e0a 401 log_unit_error(delete->unit,
66870f90
ZJS
402 "Job %s/%s deleted to break ordering cycle starting with %s/%s",
403 delete->unit->id, job_type_to_string(delete->type),
404 j->unit->id, job_type_to_string(j->type));
1fc464f6 405 unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL,
297d0749 406 "Ordering cycle found, skipping %s");
75778e21
MS
407 transaction_delete_unit(tr, delete->unit);
408 return -EAGAIN;
409 }
410
411 log_error("Unable to break cycle");
412
7358dc02
ZJS
413 return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
414 "Transaction order is cyclic. See system logs for details.");
75778e21
MS
415 }
416
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
420 * ourselves. */
421 j->marker = from ? from : j;
422 j->generation = generation;
423
c5315881 424 /* We assume that the dependencies are bidirectional, and
75778e21
MS
425 * hence can ignore UNIT_AFTER */
426 SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) {
427 Job *o;
428
429 /* Is there a job for this unit? */
430 o = hashmap_get(tr->jobs, u);
431 if (!o) {
432 /* Ok, there is no job for this in the
433 * transaction, but maybe there is already one
434 * running? */
435 o = u->job;
436 if (!o)
437 continue;
438 }
439
440 r = transaction_verify_order_one(tr, o, j, generation, e);
441 if (r < 0)
442 return r;
443 }
444
445 /* Ok, let's backtrack, and remember that this entry is not on
446 * our path anymore. */
447 j->marker = NULL;
448
449 return 0;
450}
451
718db961 452static int transaction_verify_order(Transaction *tr, unsigned *generation, sd_bus_error *e) {
75778e21
MS
453 Job *j;
454 int r;
455 Iterator i;
456 unsigned g;
457
458 assert(tr);
459 assert(generation);
460
461 /* Check if the ordering graph is cyclic. If it is, try to fix
462 * that up by dropping one of the jobs. */
463
464 g = (*generation)++;
465
3cc2aff1
LP
466 HASHMAP_FOREACH(j, tr->jobs, i) {
467 r = transaction_verify_order_one(tr, j, NULL, g, e);
468 if (r < 0)
75778e21 469 return r;
3cc2aff1 470 }
75778e21
MS
471
472 return 0;
473}
474
475static void transaction_collect_garbage(Transaction *tr) {
055163ad
MS
476 Iterator i;
477 Job *j;
75778e21
MS
478
479 assert(tr);
480
481 /* Drop jobs that are not required by any other job */
482
055163ad
MS
483rescan:
484 HASHMAP_FOREACH(j, tr->jobs, i) {
485 if (tr->anchor_job == j || j->object_list) {
486 /* log_debug("Keeping job %s/%s because of %s/%s", */
487 /* j->unit->id, job_type_to_string(j->type), */
488 /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */
489 /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
490 continue;
75778e21
MS
491 }
492
055163ad
MS
493 /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
494 transaction_delete_job(tr, j, true);
495 goto rescan;
496 }
75778e21
MS
497}
498
718db961 499static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_error *e) {
75778e21
MS
500 Iterator i;
501 Job *j;
502
503 assert(tr);
504
505 /* Checks whether applying this transaction means that
506 * existing jobs would be replaced */
507
508 HASHMAP_FOREACH(j, tr->jobs, i) {
509
510 /* Assume merged */
511 assert(!j->transaction_prev);
512 assert(!j->transaction_next);
513
23ade460 514 if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
c21b92ff 515 job_type_is_conflicting(j->unit->job->type, j->type))
7358dc02
ZJS
516 return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,
517 "Transaction is destructive.");
75778e21
MS
518 }
519
520 return 0;
521}
522
523static void transaction_minimize_impact(Transaction *tr) {
055163ad
MS
524 Job *j;
525 Iterator i;
526
75778e21
MS
527 assert(tr);
528
529 /* Drops all unnecessary jobs that reverse already active jobs
530 * or that stop a running service. */
531
055163ad
MS
532rescan:
533 HASHMAP_FOREACH(j, tr->jobs, i) {
534 LIST_FOREACH(transaction, j, j) {
535 bool stops_running_service, changes_existing_job;
75778e21 536
055163ad
MS
537 /* If it matters, we shouldn't drop it */
538 if (j->matters_to_anchor)
539 continue;
75778e21 540
055163ad
MS
541 /* Would this stop a running service?
542 * Would this change an existing job?
543 * If so, let's drop this entry */
75778e21 544
055163ad
MS
545 stops_running_service =
546 j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
75778e21 547
055163ad
MS
548 changes_existing_job =
549 j->unit->job &&
550 job_type_is_conflicting(j->type, j->unit->job->type);
75778e21 551
055163ad
MS
552 if (!stops_running_service && !changes_existing_job)
553 continue;
75778e21 554
055163ad 555 if (stops_running_service)
f2341e0a 556 log_unit_debug(j->unit,
66870f90
ZJS
557 "%s/%s would stop a running service.",
558 j->unit->id, job_type_to_string(j->type));
75778e21 559
055163ad 560 if (changes_existing_job)
f2341e0a 561 log_unit_debug(j->unit,
66870f90
ZJS
562 "%s/%s would change existing job.",
563 j->unit->id, job_type_to_string(j->type));
75778e21 564
055163ad 565 /* Ok, let's get rid of this */
f2341e0a 566 log_unit_debug(j->unit,
66870f90
ZJS
567 "Deleting %s/%s to minimize impact.",
568 j->unit->id, job_type_to_string(j->type));
75778e21 569
055163ad
MS
570 transaction_delete_job(tr, j, true);
571 goto rescan;
75778e21 572 }
055163ad 573 }
75778e21
MS
574}
575
576static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
577 Iterator i;
578 Job *j;
579 int r;
580
581 /* Moves the transaction jobs to the set of active jobs */
582
255baef6 583 if (mode == JOB_ISOLATE || mode == JOB_FLUSH) {
75778e21
MS
584
585 /* When isolating first kill all installed jobs which
586 * aren't part of the new transaction */
75778e21
MS
587 HASHMAP_FOREACH(j, m->jobs, i) {
588 assert(j->installed);
589
590 if (hashmap_get(tr->jobs, j->unit))
591 continue;
592
5273510e
MS
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);
75778e21
MS
597 }
598 }
599
600 HASHMAP_FOREACH(j, tr->jobs, i) {
601 /* Assume merged */
602 assert(!j->transaction_prev);
603 assert(!j->transaction_next);
604
75778e21
MS
605 r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j);
606 if (r < 0)
607 goto rollback;
608 }
609
610 while ((j = hashmap_steal_first(tr->jobs))) {
656bbffc
MS
611 Job *installed_job;
612
75778e21
MS
613 /* Clean the job dependencies */
614 transaction_unlink_job(tr, j, false);
615
656bbffc
MS
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));
622 job_free(j);
623 j = installed_job;
624 }
05d576f1 625
75778e21
MS
626 job_add_to_run_queue(j);
627 job_add_to_dbus_queue(j);
628 job_start_timer(j);
c65eb836 629 job_shutdown_magic(j);
75778e21
MS
630 }
631
75778e21
MS
632 return 0;
633
634rollback:
635
d6a093d0 636 HASHMAP_FOREACH(j, tr->jobs, i)
75778e21 637 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
75778e21
MS
638
639 return r;
640}
641
718db961 642int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
4e7bd268
MS
643 Iterator i;
644 Job *j;
75778e21
MS
645 int r;
646 unsigned generation = 1;
647
648 assert(tr);
649
650 /* This applies the changes recorded in tr->jobs to
651 * the actual list of jobs, if possible. */
652
4e7bd268
MS
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)
657 j->generation = 0;
658
75778e21 659 /* First step: figure out which jobs matter */
0d9989aa 660 transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
75778e21
MS
661
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);
667
668 /* Third step: Drop redundant jobs */
669 transaction_drop_redundant(tr);
670
671 for (;;) {
672 /* Fourth step: Let's remove unneeded jobs that might
673 * be lurking. */
674 if (mode != JOB_ISOLATE)
675 transaction_collect_garbage(tr);
676
677 /* Fifth step: verify order makes sense and correct
678 * cycles if necessary and possible */
679 r = transaction_verify_order(tr, &generation, e);
680 if (r >= 0)
681 break;
682
683 if (r != -EAGAIN) {
718db961 684 log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e, r));
75778e21
MS
685 return r;
686 }
687
688 /* Let's see if the resulting transaction ordering
689 * graph is still cyclic... */
690 }
691
692 for (;;) {
693 /* Sixth step: let's drop unmergeable entries if
694 * necessary and possible, merge entries we can
695 * merge */
696 r = transaction_merge_jobs(tr, e);
697 if (r >= 0)
698 break;
699
700 if (r != -EAGAIN) {
718db961 701 log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e, r));
75778e21
MS
702 return r;
703 }
704
705 /* Seventh step: an entry got dropped, let's garbage
706 * collect its dependencies. */
707 if (mode != JOB_ISOLATE)
708 transaction_collect_garbage(tr);
709
710 /* Let's see if the resulting transaction still has
711 * unmergeable entries ... */
712 }
713
714 /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
715 transaction_drop_redundant(tr);
716
717 /* Ninth step: check whether we can actually apply this */
23ade460
MS
718 r = transaction_is_destructive(tr, mode, e);
719 if (r < 0) {
718db961 720 log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
23ade460 721 return r;
75778e21
MS
722 }
723
724 /* Tenth step: apply changes */
725 r = transaction_apply(tr, m, mode);
23bbb0de
MS
726 if (r < 0)
727 return log_warning_errno(r, "Failed to apply transaction: %m");
75778e21
MS
728
729 assert(hashmap_isempty(tr->jobs));
75778e21 730
f2b68789
LP
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. */
737
31a7eb86
ZJS
738 if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
739 m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
1afaa7e8
LP
740 (void) pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
741 (void) pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
31a7eb86 742 }
f2b68789
LP
743 }
744
75778e21
MS
745 return 0;
746}
747
748static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
749 Job *j, *f;
750
751 assert(tr);
752 assert(unit);
753
754 /* Looks for an existing prospective job and returns that. If
755 * it doesn't exist it is created and added to the prospective
756 * jobs list. */
757
758 f = hashmap_get(tr->jobs, unit);
759
760 LIST_FOREACH(transaction, j, f) {
761 assert(j->unit == unit);
762
763 if (j->type == type) {
764 if (is_new)
765 *is_new = false;
766 return j;
767 }
768 }
769
3c956cfe
MS
770 j = job_new(unit, type);
771 if (!j)
772 return NULL;
75778e21
MS
773
774 j->generation = 0;
775 j->marker = NULL;
776 j->matters_to_anchor = false;
777 j->override = override;
23ade460 778 j->irreversible = tr->irreversible;
75778e21 779
71fda00f 780 LIST_PREPEND(transaction, f, j);
75778e21
MS
781
782 if (hashmap_replace(tr->jobs, unit, f) < 0) {
71fda00f 783 LIST_REMOVE(transaction, f, j);
75778e21
MS
784 job_free(j);
785 return NULL;
786 }
787
788 if (is_new)
789 *is_new = true;
790
791 /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
792
793 return j;
794}
795
796static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
797 assert(tr);
798 assert(j);
799
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);
804 else
805 hashmap_remove_value(tr->jobs, j->unit, j);
806
807 if (j->transaction_next)
808 j->transaction_next->transaction_prev = j->transaction_prev;
809
810 j->transaction_prev = j->transaction_next = NULL;
811
812 while (j->subject_list)
e6eda1f2 813 job_dependency_free(j->subject_list);
75778e21
MS
814
815 while (j->object_list) {
816 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
817
e6eda1f2 818 job_dependency_free(j->object_list);
75778e21
MS
819
820 if (other && delete_dependencies) {
f2341e0a 821 log_unit_debug(other->unit,
66870f90
ZJS
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));
75778e21
MS
825 transaction_delete_job(tr, other, delete_dependencies);
826 }
827 }
828}
829
830int transaction_add_job_and_dependencies(
831 Transaction *tr,
832 JobType type,
833 Unit *unit,
834 Job *by,
835 bool matters,
836 bool override,
837 bool conflicts,
838 bool ignore_requirements,
839 bool ignore_order,
718db961 840 sd_bus_error *e) {
75778e21
MS
841 Job *ret;
842 Iterator i;
843 Unit *dep;
844 int r;
845 bool is_new;
846
847 assert(tr);
848 assert(type < _JOB_TYPE_MAX);
e0209d83 849 assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
75778e21
MS
850 assert(unit);
851
43706330
IS
852 /* Before adding jobs for this unit, let's ensure that its state has been loaded
853 * This matters when jobs are spawned as part of coldplugging itself (see e. g. path_coldplug()).
854 * This way, we "recursively" coldplug units, ensuring that we do not look at state of
855 * not-yet-coldplugged units. */
856 if (unit->manager->n_reloading > 0)
857 unit_coldplug(unit);
858
75778e21
MS
859 /* log_debug("Pulling in %s/%s from %s/%s", */
860 /* unit->id, job_type_to_string(type), */
861 /* by ? by->unit->id : "NA", */
862 /* by ? job_type_to_string(by->type) : "NA"); */
863
7358dc02 864 if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED))
c6497ccb 865 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
75778e21 866
1244d8d6 867 if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
d8aa69b9 868 if (unit->load_error == -ENOENT || unit->manager->test_run)
7358dc02
ZJS
869 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
870 "Unit %s failed to load: %s.",
871 unit->id,
872 strerror(-unit->load_error));
04ef5b03 873 else
7358dc02
ZJS
874 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
875 "Unit %s failed to load: %s. "
876 "See system logs and 'systemctl status %s' for details.",
877 unit->id,
878 strerror(-unit->load_error),
879 unit->id);
75778e21
MS
880 }
881
7358dc02
ZJS
882 if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND)
883 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
884 "Unit %s failed to load: %s.",
885 unit->id, strerror(-unit->load_error));
1244d8d6 886
7358dc02
ZJS
887 if (type != JOB_STOP && unit->load_state == UNIT_MASKED)
888 return sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED,
889 "Unit %s is masked.", unit->id);
890
891 if (!unit_job_is_applicable(unit, type))
892 return sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
893 "Job type %s is not applicable for unit %s.",
894 job_type_to_string(type), unit->id);
75778e21 895
75778e21
MS
896
897 /* First add the job. */
898 ret = transaction_add_one_job(tr, type, unit, override, &is_new);
899 if (!ret)
900 return -ENOMEM;
901
902 ret->ignore_order = ret->ignore_order || ignore_order;
903
904 /* Then, add a link to the job. */
e6eda1f2
MS
905 if (by) {
906 if (!job_dependency_new(by, ret, matters, conflicts))
907 return -ENOMEM;
908 } else {
909 /* If the job has no parent job, it is the anchor job. */
4483f694
MS
910 assert(!tr->anchor_job);
911 tr->anchor_job = ret;
b94fbd30 912 }
e0209d83
MS
913
914 if (is_new && !ignore_requirements && type != JOB_NOP) {
75778e21
MS
915 Set *following;
916
917 /* If we are following some other unit, make sure we
918 * add all dependencies of everybody following. */
919 if (unit_following_set(ret->unit, &following) > 0) {
920 SET_FOREACH(dep, following, i) {
b94fbd30 921 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
75778e21 922 if (r < 0) {
f2341e0a 923 log_unit_warning(dep, "Cannot add dependency job for, ignoring: %s", bus_error_message(e, r));
69301c17 924 sd_bus_error_free(e);
75778e21
MS
925 }
926 }
927
928 set_free(following);
929 }
930
931 /* Finally, recursively add in all dependencies. */
e0209d83 932 if (type == JOB_START || type == JOB_RESTART) {
75778e21 933 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
b94fbd30 934 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
75778e21
MS
935 if (r < 0) {
936 if (r != -EBADR)
937 goto fail;
938
69301c17 939 sd_bus_error_free(e);
75778e21
MS
940 }
941 }
942
7f2cddae 943 SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
b94fbd30 944 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
75778e21
MS
945 if (r < 0) {
946 if (r != -EBADR)
947 goto fail;
948
69301c17 949 sd_bus_error_free(e);
75778e21
MS
950 }
951 }
952
953 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
b94fbd30 954 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
75778e21 955 if (r < 0) {
f2341e0a
LP
956 log_unit_full(dep,
957 r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
958 "Cannot add dependency job, ignoring: %s",
959 bus_error_message(e, r));
69301c17 960 sd_bus_error_free(e);
75778e21
MS
961 }
962 }
963
964 SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
b94fbd30 965 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
75778e21 966 if (r < 0) {
f2341e0a
LP
967 log_unit_full(dep,
968 r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
969 "Cannot add dependency job, ignoring: %s",
970 bus_error_message(e, r));
69301c17 971 sd_bus_error_free(e);
75778e21
MS
972 }
973 }
974
975 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
b94fbd30 976 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
75778e21
MS
977 if (r < 0) {
978 if (r != -EBADR)
979 goto fail;
980
69301c17 981 sd_bus_error_free(e);
75778e21
MS
982 }
983 }
984
985 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
b94fbd30 986 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
75778e21 987 if (r < 0) {
f2341e0a
LP
988 log_unit_full(dep,
989 r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
990 "Cannot add dependency job, ignoring: %s",
991 bus_error_message(e, r));
69301c17 992 sd_bus_error_free(e);
75778e21
MS
993 }
994 }
995
996 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
b94fbd30 997 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
75778e21
MS
998 if (r < 0) {
999 if (r != -EBADR)
1000 goto fail;
1001
69301c17 1002 sd_bus_error_free(e);
75778e21
MS
1003 }
1004 }
1005
1006 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
b94fbd30 1007 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
75778e21 1008 if (r < 0) {
f2341e0a
LP
1009 log_unit_warning(dep,
1010 "Cannot add dependency job, ignoring: %s",
1011 bus_error_message(e, r));
69301c17 1012 sd_bus_error_free(e);
75778e21
MS
1013 }
1014 }
1015
1016 }
1017
e0209d83 1018 if (type == JOB_STOP || type == JOB_RESTART) {
ce74e769
LP
1019 static const UnitDependency propagate_deps[] = {
1020 UNIT_REQUIRED_BY,
1021 UNIT_REQUISITE_OF,
1022 UNIT_BOUND_BY,
1023 UNIT_CONSISTS_OF,
1024 };
75778e21 1025
c6497ccb 1026 JobType ptype;
ce74e769 1027 unsigned j;
75778e21 1028
c6497ccb
LP
1029 /* We propagate STOP as STOP, but RESTART only
1030 * as TRY_RESTART, in order not to start
1031 * dependencies that are not around. */
1032 ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type;
1033
ce74e769
LP
1034 for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
1035 SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
48894cd0 1036 JobType nt;
85e9a101 1037
48894cd0
LP
1038 nt = job_type_collapse(ptype, dep);
1039 if (nt == JOB_NOP)
1040 continue;
1041
1042 r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, override, false, false, ignore_order, e);
ce74e769
LP
1043 if (r < 0) {
1044 if (r != -EBADR)
1045 goto fail;
85e9a101 1046
718db961 1047 sd_bus_error_free(e);
ce74e769 1048 }
85e9a101 1049 }
75778e21
MS
1050 }
1051
e0209d83 1052 if (type == JOB_RELOAD) {
75778e21 1053
7f2cddae 1054 SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
b94fbd30 1055 r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
75778e21 1056 if (r < 0) {
f2341e0a
LP
1057 log_unit_warning(dep,
1058 "Cannot add dependency reload job, ignoring: %s",
1059 bus_error_message(e, r));
69301c17 1060 sd_bus_error_free(e);
75778e21
MS
1061 }
1062 }
1063 }
1064
e0209d83 1065 /* JOB_VERIFY_STARTED require no dependency handling */
75778e21
MS
1066 }
1067
75778e21
MS
1068 return 0;
1069
1070fail:
1071 return r;
1072}
1073
1074int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
1075 Iterator i;
1076 Unit *u;
1077 char *k;
1078 int r;
1079
1080 assert(tr);
1081 assert(m);
1082
1083 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1084
1085 /* ignore aliases */
1086 if (u->id != k)
1087 continue;
1088
1089 if (u->ignore_on_isolate)
1090 continue;
1091
1092 /* No need to stop inactive jobs */
1093 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
1094 continue;
1095
1096 /* Is there already something listed for this? */
1097 if (hashmap_get(tr->jobs, u))
1098 continue;
1099
4483f694 1100 r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
75778e21 1101 if (r < 0)
f2341e0a 1102 log_unit_warning_errno(u, r, "Cannot add isolate job, ignoring: %m");
75778e21
MS
1103 }
1104
1105 return 0;
1106}
1107
23ade460 1108Transaction *transaction_new(bool irreversible) {
75778e21
MS
1109 Transaction *tr;
1110
1111 tr = new0(Transaction, 1);
1112 if (!tr)
1113 return NULL;
1114
d5099efc 1115 tr->jobs = hashmap_new(NULL);
75778e21
MS
1116 if (!tr->jobs) {
1117 free(tr);
1118 return NULL;
1119 }
1120
23ade460
MS
1121 tr->irreversible = irreversible;
1122
75778e21
MS
1123 return tr;
1124}
1125
1126void transaction_free(Transaction *tr) {
1127 assert(hashmap_isempty(tr->jobs));
1128 hashmap_free(tr->jobs);
1129 free(tr);
1130}