]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/transaction.c
Merge pull request #2068 from grawity/cgls-error-v2
[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 22#include <fcntl.h>
cf0fbc49 23#include <unistd.h>
f2b68789 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;
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
718db961 342static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
75778e21
MS
343 Iterator i;
344 Unit *u;
345 int r;
346
347 assert(tr);
348 assert(j);
349 assert(!j->transaction_prev);
350
351 /* Does a recursive sweep through the ordering graph, looking
1244d8d6 352 * for a cycle. If we find a cycle we try to break it. */
75778e21
MS
353
354 /* Have we seen this before? */
355 if (j->generation == generation) {
356 Job *k, *delete;
357
358 /* If the marker is NULL we have been here already and
359 * decided the job was loop-free from here. Hence
360 * shortcut things and return right-away. */
361 if (!j->marker)
362 return 0;
363
364 /* So, the marker is not NULL and we already have been
365 * here. We have a cycle. Let's try to break it. We go
366 * backwards in our path and try to find a suitable
367 * job to remove. We use the marker to find our way
368 * back, since smart how we are we stored our way back
369 * in there. */
f2341e0a 370 log_unit_warning(j->unit,
66870f90
ZJS
371 "Found ordering cycle on %s/%s",
372 j->unit->id, job_type_to_string(j->type));
75778e21
MS
373
374 delete = NULL;
375 for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
376
66870f90 377 /* logging for j not k here here to provide consistent narrative */
f2341e0a 378 log_unit_warning(j->unit,
14fe721b
ZJS
379 "Found dependency on %s/%s",
380 k->unit->id, job_type_to_string(k->type));
75778e21 381
ece174c5 382 if (!delete && hashmap_get(tr->jobs, k->unit) && !unit_matters_to_anchor(k->unit, k))
75778e21
MS
383 /* Ok, we can drop this one, so let's
384 * do so. */
385 delete = k;
75778e21
MS
386
387 /* Check if this in fact was the beginning of
388 * the cycle */
389 if (k == j)
390 break;
391 }
392
393
394 if (delete) {
66870f90 395 /* logging for j not k here here to provide consistent narrative */
f2341e0a 396 log_unit_warning(j->unit,
66870f90
ZJS
397 "Breaking ordering cycle by deleting job %s/%s",
398 delete->unit->id, job_type_to_string(delete->type));
f2341e0a 399 log_unit_error(delete->unit,
66870f90
ZJS
400 "Job %s/%s deleted to break ordering cycle starting with %s/%s",
401 delete->unit->id, job_type_to_string(delete->type),
402 j->unit->id, job_type_to_string(j->type));
1fc464f6 403 unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL,
297d0749 404 "Ordering cycle found, skipping %s");
75778e21
MS
405 transaction_delete_unit(tr, delete->unit);
406 return -EAGAIN;
407 }
408
409 log_error("Unable to break cycle");
410
7358dc02
ZJS
411 return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
412 "Transaction order is cyclic. See system logs for details.");
75778e21
MS
413 }
414
415 /* Make the marker point to where we come from, so that we can
416 * find our way backwards if we want to break a cycle. We use
417 * a special marker for the beginning: we point to
418 * ourselves. */
419 j->marker = from ? from : j;
420 j->generation = generation;
421
c5315881 422 /* We assume that the dependencies are bidirectional, and
75778e21
MS
423 * hence can ignore UNIT_AFTER */
424 SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) {
425 Job *o;
426
427 /* Is there a job for this unit? */
428 o = hashmap_get(tr->jobs, u);
429 if (!o) {
430 /* Ok, there is no job for this in the
431 * transaction, but maybe there is already one
432 * running? */
433 o = u->job;
434 if (!o)
435 continue;
436 }
437
438 r = transaction_verify_order_one(tr, o, j, generation, e);
439 if (r < 0)
440 return r;
441 }
442
443 /* Ok, let's backtrack, and remember that this entry is not on
444 * our path anymore. */
445 j->marker = NULL;
446
447 return 0;
448}
449
718db961 450static int transaction_verify_order(Transaction *tr, unsigned *generation, sd_bus_error *e) {
75778e21
MS
451 Job *j;
452 int r;
453 Iterator i;
454 unsigned g;
455
456 assert(tr);
457 assert(generation);
458
459 /* Check if the ordering graph is cyclic. If it is, try to fix
460 * that up by dropping one of the jobs. */
461
462 g = (*generation)++;
463
3cc2aff1
LP
464 HASHMAP_FOREACH(j, tr->jobs, i) {
465 r = transaction_verify_order_one(tr, j, NULL, g, e);
466 if (r < 0)
75778e21 467 return r;
3cc2aff1 468 }
75778e21
MS
469
470 return 0;
471}
472
473static void transaction_collect_garbage(Transaction *tr) {
055163ad
MS
474 Iterator i;
475 Job *j;
75778e21
MS
476
477 assert(tr);
478
479 /* Drop jobs that are not required by any other job */
480
055163ad
MS
481rescan:
482 HASHMAP_FOREACH(j, tr->jobs, i) {
483 if (tr->anchor_job == j || j->object_list) {
484 /* log_debug("Keeping job %s/%s because of %s/%s", */
485 /* j->unit->id, job_type_to_string(j->type), */
486 /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */
487 /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
488 continue;
75778e21
MS
489 }
490
055163ad
MS
491 /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
492 transaction_delete_job(tr, j, true);
493 goto rescan;
494 }
75778e21
MS
495}
496
718db961 497static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_error *e) {
75778e21
MS
498 Iterator i;
499 Job *j;
500
501 assert(tr);
502
503 /* Checks whether applying this transaction means that
504 * existing jobs would be replaced */
505
506 HASHMAP_FOREACH(j, tr->jobs, i) {
507
508 /* Assume merged */
509 assert(!j->transaction_prev);
510 assert(!j->transaction_next);
511
23ade460 512 if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
c21b92ff 513 job_type_is_conflicting(j->unit->job->type, j->type))
7358dc02
ZJS
514 return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,
515 "Transaction is destructive.");
75778e21
MS
516 }
517
518 return 0;
519}
520
521static void transaction_minimize_impact(Transaction *tr) {
055163ad
MS
522 Job *j;
523 Iterator i;
524
75778e21
MS
525 assert(tr);
526
527 /* Drops all unnecessary jobs that reverse already active jobs
528 * or that stop a running service. */
529
055163ad
MS
530rescan:
531 HASHMAP_FOREACH(j, tr->jobs, i) {
532 LIST_FOREACH(transaction, j, j) {
533 bool stops_running_service, changes_existing_job;
75778e21 534
055163ad
MS
535 /* If it matters, we shouldn't drop it */
536 if (j->matters_to_anchor)
537 continue;
75778e21 538
055163ad
MS
539 /* Would this stop a running service?
540 * Would this change an existing job?
541 * If so, let's drop this entry */
75778e21 542
055163ad
MS
543 stops_running_service =
544 j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
75778e21 545
055163ad
MS
546 changes_existing_job =
547 j->unit->job &&
548 job_type_is_conflicting(j->type, j->unit->job->type);
75778e21 549
055163ad
MS
550 if (!stops_running_service && !changes_existing_job)
551 continue;
75778e21 552
055163ad 553 if (stops_running_service)
f2341e0a 554 log_unit_debug(j->unit,
66870f90
ZJS
555 "%s/%s would stop a running service.",
556 j->unit->id, job_type_to_string(j->type));
75778e21 557
055163ad 558 if (changes_existing_job)
f2341e0a 559 log_unit_debug(j->unit,
66870f90
ZJS
560 "%s/%s would change existing job.",
561 j->unit->id, job_type_to_string(j->type));
75778e21 562
055163ad 563 /* Ok, let's get rid of this */
f2341e0a 564 log_unit_debug(j->unit,
66870f90
ZJS
565 "Deleting %s/%s to minimize impact.",
566 j->unit->id, job_type_to_string(j->type));
75778e21 567
055163ad
MS
568 transaction_delete_job(tr, j, true);
569 goto rescan;
75778e21 570 }
055163ad 571 }
75778e21
MS
572}
573
574static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
575 Iterator i;
576 Job *j;
577 int r;
578
579 /* Moves the transaction jobs to the set of active jobs */
580
255baef6 581 if (mode == JOB_ISOLATE || mode == JOB_FLUSH) {
75778e21
MS
582
583 /* When isolating first kill all installed jobs which
584 * aren't part of the new transaction */
75778e21
MS
585 HASHMAP_FOREACH(j, m->jobs, i) {
586 assert(j->installed);
587
588 if (hashmap_get(tr->jobs, j->unit))
589 continue;
590
5273510e
MS
591 /* Not invalidating recursively. Avoids triggering
592 * OnFailure= actions of dependent jobs. Also avoids
593 * invalidating our iterator. */
594 job_finish_and_invalidate(j, JOB_CANCELED, false);
75778e21
MS
595 }
596 }
597
598 HASHMAP_FOREACH(j, tr->jobs, i) {
599 /* Assume merged */
600 assert(!j->transaction_prev);
601 assert(!j->transaction_next);
602
75778e21
MS
603 r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j);
604 if (r < 0)
605 goto rollback;
606 }
607
608 while ((j = hashmap_steal_first(tr->jobs))) {
656bbffc
MS
609 Job *installed_job;
610
75778e21
MS
611 /* Clean the job dependencies */
612 transaction_unlink_job(tr, j, false);
613
656bbffc
MS
614 installed_job = job_install(j);
615 if (installed_job != j) {
616 /* j has been merged into a previously installed job */
617 if (tr->anchor_job == j)
618 tr->anchor_job = installed_job;
619 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
620 job_free(j);
621 j = installed_job;
622 }
05d576f1 623
75778e21
MS
624 job_add_to_run_queue(j);
625 job_add_to_dbus_queue(j);
626 job_start_timer(j);
c65eb836 627 job_shutdown_magic(j);
75778e21
MS
628 }
629
75778e21
MS
630 return 0;
631
632rollback:
633
d6a093d0 634 HASHMAP_FOREACH(j, tr->jobs, i)
75778e21 635 hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
75778e21
MS
636
637 return r;
638}
639
718db961 640int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
4e7bd268
MS
641 Iterator i;
642 Job *j;
75778e21
MS
643 int r;
644 unsigned generation = 1;
645
646 assert(tr);
647
648 /* This applies the changes recorded in tr->jobs to
649 * the actual list of jobs, if possible. */
650
4e7bd268
MS
651 /* Reset the generation counter of all installed jobs. The detection of cycles
652 * looks at installed jobs. If they had a non-zero generation from some previous
653 * walk of the graph, the algorithm would break. */
654 HASHMAP_FOREACH(j, m->jobs, i)
655 j->generation = 0;
656
75778e21 657 /* First step: figure out which jobs matter */
0d9989aa 658 transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
75778e21
MS
659
660 /* Second step: Try not to stop any running services if
661 * we don't have to. Don't try to reverse running
662 * jobs if we don't have to. */
663 if (mode == JOB_FAIL)
664 transaction_minimize_impact(tr);
665
666 /* Third step: Drop redundant jobs */
667 transaction_drop_redundant(tr);
668
669 for (;;) {
670 /* Fourth step: Let's remove unneeded jobs that might
671 * be lurking. */
672 if (mode != JOB_ISOLATE)
673 transaction_collect_garbage(tr);
674
675 /* Fifth step: verify order makes sense and correct
676 * cycles if necessary and possible */
677 r = transaction_verify_order(tr, &generation, e);
678 if (r >= 0)
679 break;
680
681 if (r != -EAGAIN) {
718db961 682 log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e, r));
75778e21
MS
683 return r;
684 }
685
686 /* Let's see if the resulting transaction ordering
687 * graph is still cyclic... */
688 }
689
690 for (;;) {
691 /* Sixth step: let's drop unmergeable entries if
692 * necessary and possible, merge entries we can
693 * merge */
694 r = transaction_merge_jobs(tr, e);
695 if (r >= 0)
696 break;
697
698 if (r != -EAGAIN) {
718db961 699 log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e, r));
75778e21
MS
700 return r;
701 }
702
703 /* Seventh step: an entry got dropped, let's garbage
704 * collect its dependencies. */
705 if (mode != JOB_ISOLATE)
706 transaction_collect_garbage(tr);
707
708 /* Let's see if the resulting transaction still has
709 * unmergeable entries ... */
710 }
711
712 /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
713 transaction_drop_redundant(tr);
714
715 /* Ninth step: check whether we can actually apply this */
23ade460
MS
716 r = transaction_is_destructive(tr, mode, e);
717 if (r < 0) {
718db961 718 log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
23ade460 719 return r;
75778e21
MS
720 }
721
722 /* Tenth step: apply changes */
723 r = transaction_apply(tr, m, mode);
23bbb0de
MS
724 if (r < 0)
725 return log_warning_errno(r, "Failed to apply transaction: %m");
75778e21
MS
726
727 assert(hashmap_isempty(tr->jobs));
75778e21 728
f2b68789
LP
729 if (!hashmap_isempty(m->jobs)) {
730 /* Are there any jobs now? Then make sure we have the
731 * idle pipe around. We don't really care too much
732 * whether this works or not, as the idle pipe is a
733 * feature for cosmetics, not actually useful for
734 * anything beyond that. */
735
31a7eb86
ZJS
736 if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
737 m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
1afaa7e8
LP
738 (void) pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
739 (void) pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
31a7eb86 740 }
f2b68789
LP
741 }
742
75778e21
MS
743 return 0;
744}
745
4bd29fe5 746static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool *is_new) {
75778e21
MS
747 Job *j, *f;
748
749 assert(tr);
750 assert(unit);
751
752 /* Looks for an existing prospective job and returns that. If
753 * it doesn't exist it is created and added to the prospective
754 * jobs list. */
755
756 f = hashmap_get(tr->jobs, unit);
757
758 LIST_FOREACH(transaction, j, f) {
759 assert(j->unit == unit);
760
761 if (j->type == type) {
762 if (is_new)
763 *is_new = false;
764 return j;
765 }
766 }
767
3c956cfe
MS
768 j = job_new(unit, type);
769 if (!j)
770 return NULL;
75778e21
MS
771
772 j->generation = 0;
773 j->marker = NULL;
774 j->matters_to_anchor = false;
23ade460 775 j->irreversible = tr->irreversible;
75778e21 776
71fda00f 777 LIST_PREPEND(transaction, f, j);
75778e21
MS
778
779 if (hashmap_replace(tr->jobs, unit, f) < 0) {
71fda00f 780 LIST_REMOVE(transaction, f, j);
75778e21
MS
781 job_free(j);
782 return NULL;
783 }
784
785 if (is_new)
786 *is_new = true;
787
788 /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
789
790 return j;
791}
792
793static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
794 assert(tr);
795 assert(j);
796
797 if (j->transaction_prev)
798 j->transaction_prev->transaction_next = j->transaction_next;
799 else if (j->transaction_next)
800 hashmap_replace(tr->jobs, j->unit, j->transaction_next);
801 else
802 hashmap_remove_value(tr->jobs, j->unit, j);
803
804 if (j->transaction_next)
805 j->transaction_next->transaction_prev = j->transaction_prev;
806
807 j->transaction_prev = j->transaction_next = NULL;
808
809 while (j->subject_list)
e6eda1f2 810 job_dependency_free(j->subject_list);
75778e21
MS
811
812 while (j->object_list) {
813 Job *other = j->object_list->matters ? j->object_list->subject : NULL;
814
e6eda1f2 815 job_dependency_free(j->object_list);
75778e21
MS
816
817 if (other && delete_dependencies) {
f2341e0a 818 log_unit_debug(other->unit,
66870f90
ZJS
819 "Deleting job %s/%s as dependency of job %s/%s",
820 other->unit->id, job_type_to_string(other->type),
821 j->unit->id, job_type_to_string(j->type));
75778e21
MS
822 transaction_delete_job(tr, other, delete_dependencies);
823 }
824 }
825}
826
827int transaction_add_job_and_dependencies(
828 Transaction *tr,
829 JobType type,
830 Unit *unit,
831 Job *by,
832 bool matters,
75778e21
MS
833 bool conflicts,
834 bool ignore_requirements,
835 bool ignore_order,
718db961 836 sd_bus_error *e) {
75778e21
MS
837 Job *ret;
838 Iterator i;
839 Unit *dep;
840 int r;
841 bool is_new;
842
843 assert(tr);
844 assert(type < _JOB_TYPE_MAX);
e0209d83 845 assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
75778e21
MS
846 assert(unit);
847
43706330
IS
848 /* Before adding jobs for this unit, let's ensure that its state has been loaded
849 * This matters when jobs are spawned as part of coldplugging itself (see e. g. path_coldplug()).
850 * This way, we "recursively" coldplug units, ensuring that we do not look at state of
851 * not-yet-coldplugged units. */
852 if (unit->manager->n_reloading > 0)
853 unit_coldplug(unit);
854
75778e21
MS
855 /* log_debug("Pulling in %s/%s from %s/%s", */
856 /* unit->id, job_type_to_string(type), */
857 /* by ? by->unit->id : "NA", */
858 /* by ? job_type_to_string(by->type) : "NA"); */
859
7358dc02 860 if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED))
c6497ccb 861 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
75778e21 862
1244d8d6 863 if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
d8aa69b9 864 if (unit->load_error == -ENOENT || unit->manager->test_run)
7358dc02
ZJS
865 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
866 "Unit %s failed to load: %s.",
867 unit->id,
868 strerror(-unit->load_error));
04ef5b03 869 else
7358dc02
ZJS
870 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
871 "Unit %s failed to load: %s. "
872 "See system logs and 'systemctl status %s' for details.",
873 unit->id,
874 strerror(-unit->load_error),
875 unit->id);
75778e21
MS
876 }
877
7358dc02
ZJS
878 if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND)
879 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
880 "Unit %s failed to load: %s.",
881 unit->id, strerror(-unit->load_error));
1244d8d6 882
7358dc02
ZJS
883 if (type != JOB_STOP && unit->load_state == UNIT_MASKED)
884 return sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED,
885 "Unit %s is masked.", unit->id);
886
887 if (!unit_job_is_applicable(unit, type))
888 return sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
889 "Job type %s is not applicable for unit %s.",
890 job_type_to_string(type), unit->id);
75778e21 891
75778e21
MS
892
893 /* First add the job. */
4bd29fe5 894 ret = transaction_add_one_job(tr, type, unit, &is_new);
75778e21
MS
895 if (!ret)
896 return -ENOMEM;
897
898 ret->ignore_order = ret->ignore_order || ignore_order;
899
900 /* Then, add a link to the job. */
e6eda1f2
MS
901 if (by) {
902 if (!job_dependency_new(by, ret, matters, conflicts))
903 return -ENOMEM;
904 } else {
905 /* If the job has no parent job, it is the anchor job. */
4483f694
MS
906 assert(!tr->anchor_job);
907 tr->anchor_job = ret;
b94fbd30 908 }
e0209d83
MS
909
910 if (is_new && !ignore_requirements && type != JOB_NOP) {
75778e21
MS
911 Set *following;
912
913 /* If we are following some other unit, make sure we
914 * add all dependencies of everybody following. */
915 if (unit_following_set(ret->unit, &following) > 0) {
916 SET_FOREACH(dep, following, i) {
4bd29fe5 917 r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, false, false, ignore_order, e);
75778e21 918 if (r < 0) {
f2341e0a 919 log_unit_warning(dep, "Cannot add dependency job for, ignoring: %s", bus_error_message(e, r));
69301c17 920 sd_bus_error_free(e);
75778e21
MS
921 }
922 }
923
924 set_free(following);
925 }
926
927 /* Finally, recursively add in all dependencies. */
e0209d83 928 if (type == JOB_START || type == JOB_RESTART) {
75778e21 929 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
4bd29fe5 930 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
75778e21
MS
931 if (r < 0) {
932 if (r != -EBADR)
933 goto fail;
934
69301c17 935 sd_bus_error_free(e);
75778e21
MS
936 }
937 }
938
7f2cddae 939 SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
4bd29fe5 940 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
75778e21
MS
941 if (r < 0) {
942 if (r != -EBADR)
943 goto fail;
944
69301c17 945 sd_bus_error_free(e);
75778e21
MS
946 }
947 }
948
75778e21 949 SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
4bd29fe5 950 r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e);
75778e21 951 if (r < 0) {
f2341e0a
LP
952 log_unit_full(dep,
953 r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
954 "Cannot add dependency job, ignoring: %s",
955 bus_error_message(e, r));
69301c17 956 sd_bus_error_free(e);
75778e21
MS
957 }
958 }
959
960 SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
4bd29fe5 961 r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, false, false, ignore_order, e);
75778e21
MS
962 if (r < 0) {
963 if (r != -EBADR)
964 goto fail;
965
69301c17 966 sd_bus_error_free(e);
75778e21
MS
967 }
968 }
969
75778e21 970 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
4bd29fe5 971 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, true, false, ignore_order, e);
75778e21
MS
972 if (r < 0) {
973 if (r != -EBADR)
974 goto fail;
975
69301c17 976 sd_bus_error_free(e);
75778e21
MS
977 }
978 }
979
980 SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
4bd29fe5 981 r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, false, false, ignore_order, e);
75778e21 982 if (r < 0) {
f2341e0a
LP
983 log_unit_warning(dep,
984 "Cannot add dependency job, ignoring: %s",
985 bus_error_message(e, r));
69301c17 986 sd_bus_error_free(e);
75778e21
MS
987 }
988 }
989
990 }
991
e0209d83 992 if (type == JOB_STOP || type == JOB_RESTART) {
ce74e769
LP
993 static const UnitDependency propagate_deps[] = {
994 UNIT_REQUIRED_BY,
995 UNIT_REQUISITE_OF,
996 UNIT_BOUND_BY,
997 UNIT_CONSISTS_OF,
998 };
75778e21 999
c6497ccb 1000 JobType ptype;
ce74e769 1001 unsigned j;
75778e21 1002
c6497ccb
LP
1003 /* We propagate STOP as STOP, but RESTART only
1004 * as TRY_RESTART, in order not to start
1005 * dependencies that are not around. */
1006 ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type;
1007
ce74e769
LP
1008 for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
1009 SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
48894cd0 1010 JobType nt;
85e9a101 1011
48894cd0
LP
1012 nt = job_type_collapse(ptype, dep);
1013 if (nt == JOB_NOP)
1014 continue;
1015
4bd29fe5 1016 r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, false, false, ignore_order, e);
ce74e769
LP
1017 if (r < 0) {
1018 if (r != -EBADR)
1019 goto fail;
85e9a101 1020
718db961 1021 sd_bus_error_free(e);
ce74e769 1022 }
85e9a101 1023 }
75778e21
MS
1024 }
1025
e0209d83 1026 if (type == JOB_RELOAD) {
75778e21 1027
7f2cddae 1028 SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
4bd29fe5 1029 r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, false, false, ignore_order, e);
75778e21 1030 if (r < 0) {
f2341e0a
LP
1031 log_unit_warning(dep,
1032 "Cannot add dependency reload job, ignoring: %s",
1033 bus_error_message(e, r));
69301c17 1034 sd_bus_error_free(e);
75778e21
MS
1035 }
1036 }
1037 }
1038
e0209d83 1039 /* JOB_VERIFY_STARTED require no dependency handling */
75778e21
MS
1040 }
1041
75778e21
MS
1042 return 0;
1043
1044fail:
1045 return r;
1046}
1047
1048int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
1049 Iterator i;
1050 Unit *u;
1051 char *k;
1052 int r;
1053
1054 assert(tr);
1055 assert(m);
1056
1057 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1058
1059 /* ignore aliases */
1060 if (u->id != k)
1061 continue;
1062
1063 if (u->ignore_on_isolate)
1064 continue;
1065
1066 /* No need to stop inactive jobs */
1067 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
1068 continue;
1069
1070 /* Is there already something listed for this? */
1071 if (hashmap_get(tr->jobs, u))
1072 continue;
1073
4bd29fe5 1074 r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, NULL);
75778e21 1075 if (r < 0)
f2341e0a 1076 log_unit_warning_errno(u, r, "Cannot add isolate job, ignoring: %m");
75778e21
MS
1077 }
1078
1079 return 0;
1080}
1081
23ade460 1082Transaction *transaction_new(bool irreversible) {
75778e21
MS
1083 Transaction *tr;
1084
1085 tr = new0(Transaction, 1);
1086 if (!tr)
1087 return NULL;
1088
d5099efc 1089 tr->jobs = hashmap_new(NULL);
75778e21
MS
1090 if (!tr->jobs) {
1091 free(tr);
1092 return NULL;
1093 }
1094
23ade460
MS
1095 tr->irreversible = irreversible;
1096
75778e21
MS
1097 return tr;
1098}
1099
1100void transaction_free(Transaction *tr) {
1101 assert(hashmap_isempty(tr->jobs));
1102 hashmap_free(tr->jobs);
1103 free(tr);
1104}