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