manager.c 74.1 KB
Newer Older
Lennart Poettering's avatar
Lennart Poettering committed
1
2
/*-*- Mode: C; c-basic-offset: 8 -*-*/

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/***
  This file is part of systemd.

  Copyright 2010 Lennart Poettering

  systemd is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  systemd is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/

Lennart Poettering's avatar
Lennart Poettering committed
22
23
#include <assert.h>
#include <errno.h>
24
#include <string.h>
Lennart Poettering's avatar
Lennart Poettering committed
25
26
27
28
29
#include <sys/epoll.h>
#include <signal.h>
#include <sys/signalfd.h>
#include <sys/wait.h>
#include <unistd.h>
30
#include <utmpx.h>
Lennart Poettering's avatar
Lennart Poettering committed
31
#include <sys/poll.h>
32
33
34
#include <sys/reboot.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
Lennart Poettering's avatar
Lennart Poettering committed
35
36
#include <termios.h>
#include <fcntl.h>
37
38
#include <sys/types.h>
#include <sys/stat.h>
39
#include <dirent.h>
Lennart Poettering's avatar
Lennart Poettering committed
40
41
42
43
44

#include "manager.h"
#include "hashmap.h"
#include "macro.h"
#include "strv.h"
45
#include "log.h"
46
#include "util.h"
47
#include "ratelimit.h"
48
49
#include "cgroup.h"
#include "mount-setup.h"
50
#include "utmp-wtmp.h"
51
#include "unit-name.h"
52
53
#include "dbus-unit.h"
#include "dbus-job.h"
54
#include "missing.h"
55
#include "path-lookup.h"
56
#include "special.h"
57
#include "bus-errors.h"
Lennart Poettering's avatar
Lennart Poettering committed
58

59
60
61
62
/* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
#define GC_QUEUE_ENTRIES_MAX 16

/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
63
#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/* Where clients shall send notification messages to */
#define NOTIFY_SOCKET "/org/freedesktop/systemd1/notify"

static int manager_setup_notify(Manager *m) {
        union {
                struct sockaddr sa;
                struct sockaddr_un un;
        } sa;
        struct epoll_event ev;
        int one = 1;

        assert(m);

        m->notify_watch.type = WATCH_NOTIFY;
        if ((m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
                log_error("Failed to allocate notification socket: %m");
                return -errno;
        }

        zero(sa);
        sa.sa.sa_family = AF_UNIX;

87
        if (getpid() != 1)
88
89
90
91
                snprintf(sa.un.sun_path+1, sizeof(sa.un.sun_path)-1, NOTIFY_SOCKET "/%llu", random_ull());
        else
                strncpy(sa.un.sun_path+1, NOTIFY_SOCKET, sizeof(sa.un.sun_path)-1);

92
        if (bind(m->notify_watch.fd, &sa.sa, sizeof(sa_family_t) + 1 + strlen(sa.un.sun_path+1)) < 0) {
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
                log_error("bind() failed: %m");
                return -errno;
        }

        if (setsockopt(m->notify_watch.fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
                log_error("SO_PASSCRED failed: %m");
                return -errno;
        }

        zero(ev);
        ev.events = EPOLLIN;
        ev.data.ptr = &m->notify_watch;

        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0)
                return -errno;

109
        if (!(m->notify_socket = strdup(sa.un.sun_path+1)))
110
111
112
113
114
                return -ENOMEM;

        return 0;
}

Lennart Poettering's avatar
Lennart Poettering committed
115
116
117
118
119
120
121
122
123
static int enable_special_signals(Manager *m) {
        char fd;

        assert(m);

        /* Enable that we get SIGINT on control-alt-del */
        if (reboot(RB_DISABLE_CAD) < 0)
                log_warning("Failed to enable ctrl-alt-del handling: %m");

124
        if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY)) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
125
126
127
128
129
130
131
132
133
134
135
136
                log_warning("Failed to open /dev/tty0: %m");
        else {
                /* Enable that we get SIGWINCH on kbrequest */
                if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
                        log_warning("Failed to enable kbrequest handling: %s", strerror(errno));

                close_nointr_nofail(fd);
        }

        return 0;
}

137
static int manager_setup_signals(Manager *m) {
Lennart Poettering's avatar
Lennart Poettering committed
138
139
        sigset_t mask;
        struct epoll_event ev;
140
        struct sigaction sa;
Lennart Poettering's avatar
Lennart Poettering committed
141

142
143
        assert(m);

144
145
146
147
148
149
        /* We are not interested in SIGSTOP and friends. */
        zero(sa);
        sa.sa_handler = SIG_DFL;
        sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
        assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);

150
        assert_se(sigemptyset(&mask) == 0);
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

        sigset_add_many(&mask,
                        SIGCHLD,     /* Child died */
                        SIGTERM,     /* Reexecute daemon */
                        SIGHUP,      /* Reload configuration */
                        SIGUSR1,     /* systemd/upstart: reconnect to D-Bus */
                        SIGUSR2,     /* systemd: dump status */
                        SIGINT,      /* Kernel sends us this on control-alt-del */
                        SIGWINCH,    /* Kernel sends us this on kbrequest (alt-arrowup) */
                        SIGPWR,      /* Some kernel drivers and upsd send us this on power failure */
                        SIGRTMIN+0,  /* systemd: start default.target */
                        SIGRTMIN+1,  /* systemd: start rescue.target */
                        SIGRTMIN+2,  /* systemd: isolate emergency.target */
                        SIGRTMIN+3,  /* systemd: start halt.target */
                        SIGRTMIN+4,  /* systemd: start poweroff.target */
                        SIGRTMIN+5,  /* systemd: start reboot.target */
                        -1);
168
169
        assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);

Lennart Poettering's avatar
Lennart Poettering committed
170
        m->signal_watch.type = WATCH_SIGNAL;
171
172
173
174
175
176
177
178
179
180
        if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0)
                return -errno;

        zero(ev);
        ev.events = EPOLLIN;
        ev.data.ptr = &m->signal_watch;

        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
                return -errno;

181
        if (m->running_as == MANAGER_SYSTEM)
Lennart Poettering's avatar
Lennart Poettering committed
182
                return enable_special_signals(m);
183

184
185
186
        return 0;
}

187
int manager_new(ManagerRunningAs running_as, Manager **_m) {
188
        Manager *m;
189
190
191
        int r = -ENOMEM;

        assert(_m);
192
193
        assert(running_as >= 0);
        assert(running_as < _MANAGER_RUNNING_AS_MAX);
194

Lennart Poettering's avatar
Lennart Poettering committed
195
        if (!(m = new0(Manager, 1)))
196
                return -ENOMEM;
Lennart Poettering's avatar
Lennart Poettering committed
197

198
        dual_timestamp_get(&m->startup_timestamp);
199

200
        m->running_as = running_as;
201
        m->name_data_slot = m->subscribed_data_slot = -1;
202
        m->exit_code = _MANAGER_EXIT_CODE_INVALID;
203
        m->pin_cgroupfs_fd = -1;
Lennart Poettering's avatar
Lennart Poettering committed
204

205
        m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1;
206
        m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
Lennart Poettering's avatar
Lennart Poettering committed
207

208
209
210
        if (!(m->environment = strv_copy(environ)))
                goto fail;

Lennart Poettering's avatar
Lennart Poettering committed
211
        if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
Lennart Poettering's avatar
Lennart Poettering committed
212
213
214
215
216
                goto fail;

        if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
                goto fail;

217
        if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
Lennart Poettering's avatar
Lennart Poettering committed
218
219
                goto fail;

Lennart Poettering's avatar
Lennart Poettering committed
220
221
222
        if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
                goto fail;

223
224
225
        if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
                goto fail;

226
227
228
        if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
                goto fail;

Lennart Poettering's avatar
Lennart Poettering committed
229
230
231
        if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
                goto fail;

232
        if ((r = lookup_paths_init(&m->lookup_paths, m->running_as)) < 0)
233
234
                goto fail;

235
236
237
238
        if ((r = manager_setup_signals(m)) < 0)
                goto fail;

        if ((r = manager_setup_cgroup(m)) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
239
240
                goto fail;

241
242
243
        if ((r = manager_setup_notify(m)) < 0)
                goto fail;

244
        /* Try to connect to the busses, if possible. */
245
        if ((r = bus_init(m)) < 0)
246
247
                goto fail;

248
249
        *_m = m;
        return 0;
Lennart Poettering's avatar
Lennart Poettering committed
250
251
252

fail:
        manager_free(m);
253
        return r;
Lennart Poettering's avatar
Lennart Poettering committed
254
255
}

256
257
258
259
260
261
262
263
264
static unsigned manager_dispatch_cleanup_queue(Manager *m) {
        Meta *meta;
        unsigned n = 0;

        assert(m);

        while ((meta = m->cleanup_queue)) {
                assert(meta->in_cleanup_queue);

265
                unit_free((Unit*) meta);
266
267
268
269
270
271
                n++;
        }

        return n;
}

Lennart Poettering's avatar
Lennart Poettering committed
272
273
274
275
276
277
278
279
280
enum {
        GC_OFFSET_IN_PATH,  /* This one is on the path we were travelling */
        GC_OFFSET_UNSURE,   /* No clue */
        GC_OFFSET_GOOD,     /* We still need this unit */
        GC_OFFSET_BAD,      /* We don't need this unit anymore */
        _GC_OFFSET_MAX
};

static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
281
282
        Iterator i;
        Unit *other;
Lennart Poettering's avatar
Lennart Poettering committed
283
        bool is_bad;
284
285
286

        assert(u);

Lennart Poettering's avatar
Lennart Poettering committed
287
288
289
        if (u->meta.gc_marker == gc_marker + GC_OFFSET_GOOD ||
            u->meta.gc_marker == gc_marker + GC_OFFSET_BAD ||
            u->meta.gc_marker == gc_marker + GC_OFFSET_IN_PATH)
290
291
                return;

Lennart Poettering's avatar
Lennart Poettering committed
292
        if (u->meta.in_cleanup_queue)
293
294
295
296
297
                goto bad;

        if (unit_check_gc(u))
                goto good;

Lennart Poettering's avatar
Lennart Poettering committed
298
299
300
301
        u->meta.gc_marker = gc_marker + GC_OFFSET_IN_PATH;

        is_bad = true;

302
303
304
        SET_FOREACH(other, u->meta.dependencies[UNIT_REFERENCED_BY], i) {
                unit_gc_sweep(other, gc_marker);

Lennart Poettering's avatar
Lennart Poettering committed
305
                if (other->meta.gc_marker == gc_marker + GC_OFFSET_GOOD)
306
                        goto good;
Lennart Poettering's avatar
Lennart Poettering committed
307
308
309

                if (other->meta.gc_marker != gc_marker + GC_OFFSET_BAD)
                        is_bad = false;
310
311
        }

Lennart Poettering's avatar
Lennart Poettering committed
312
313
314
315
316
317
318
319
320
        if (is_bad)
                goto bad;

        /* We were unable to find anything out about this entry, so
         * let's investigate it later */
        u->meta.gc_marker = gc_marker + GC_OFFSET_UNSURE;
        unit_add_to_gc_queue(u);
        return;

321
bad:
Lennart Poettering's avatar
Lennart Poettering committed
322
323
324
325
        /* We definitely know that this one is not useful anymore, so
         * let's mark it for deletion */
        u->meta.gc_marker = gc_marker + GC_OFFSET_BAD;
        unit_add_to_cleanup_queue(u);
326
327
328
        return;

good:
Lennart Poettering's avatar
Lennart Poettering committed
329
        u->meta.gc_marker = gc_marker + GC_OFFSET_GOOD;
330
331
332
333
334
}

static unsigned manager_dispatch_gc_queue(Manager *m) {
        Meta *meta;
        unsigned n = 0;
Lennart Poettering's avatar
Lennart Poettering committed
335
        unsigned gc_marker;
336
337
338
339
340
341
342
343
344
345

        assert(m);

        if ((m->n_in_gc_queue < GC_QUEUE_ENTRIES_MAX) &&
            (m->gc_queue_timestamp <= 0 ||
             (m->gc_queue_timestamp + GC_QUEUE_USEC_MAX) > now(CLOCK_MONOTONIC)))
                return 0;

        log_debug("Running GC...");

Lennart Poettering's avatar
Lennart Poettering committed
346
347
        m->gc_marker += _GC_OFFSET_MAX;
        if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
Lennart Poettering's avatar
Lennart Poettering committed
348
                m->gc_marker = 1;
349

Lennart Poettering's avatar
Lennart Poettering committed
350
351
        gc_marker = m->gc_marker;

352
353
354
        while ((meta = m->gc_queue)) {
                assert(meta->in_gc_queue);

355
                unit_gc_sweep((Unit*) meta, gc_marker);
Lennart Poettering's avatar
Lennart Poettering committed
356

357
358
359
360
361
                LIST_REMOVE(Meta, gc_queue, m->gc_queue, meta);
                meta->in_gc_queue = false;

                n++;

Lennart Poettering's avatar
Lennart Poettering committed
362
363
                if (meta->gc_marker == gc_marker + GC_OFFSET_BAD ||
                    meta->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
364
                        log_debug("Collecting %s", meta->id);
Lennart Poettering's avatar
Lennart Poettering committed
365
                        meta->gc_marker = gc_marker + GC_OFFSET_BAD;
366
                        unit_add_to_cleanup_queue((Unit*) meta);
367
368
369
370
371
372
373
374
375
                }
        }

        m->n_in_gc_queue = 0;
        m->gc_queue_timestamp = 0;

        return n;
}

376
static void manager_clear_jobs_and_units(Manager *m) {
377
        Job *j;
378
        Unit *u;
Lennart Poettering's avatar
Lennart Poettering committed
379
380
381

        assert(m);

Lennart Poettering's avatar
Lennart Poettering committed
382
        while ((j = hashmap_first(m->transaction_jobs)))
383
384
                job_free(j);

Lennart Poettering's avatar
Lennart Poettering committed
385
386
        while ((u = hashmap_first(m->units)))
                unit_free(u);
387
388
389
390
391
392
393
394
395
396
397
398
399

        manager_dispatch_cleanup_queue(m);

        assert(!m->load_queue);
        assert(!m->run_queue);
        assert(!m->dbus_unit_queue);
        assert(!m->dbus_job_queue);
        assert(!m->cleanup_queue);
        assert(!m->gc_queue);

        assert(hashmap_isempty(m->transaction_jobs));
        assert(hashmap_isempty(m->jobs));
        assert(hashmap_isempty(m->units));
400
401
402
403
}

void manager_free(Manager *m) {
        UnitType c;
Lennart Poettering's avatar
Lennart Poettering committed
404

405
406
407
        assert(m);

        manager_clear_jobs_and_units(m);
408

409
410
411
412
        for (c = 0; c < _UNIT_TYPE_MAX; c++)
                if (unit_vtable[c]->shutdown)
                        unit_vtable[c]->shutdown(m);

413
414
        /* If we reexecute ourselves, we keep the root cgroup
         * around */
415
        manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
416

417
        bus_done(m);
418

Lennart Poettering's avatar
Lennart Poettering committed
419
        hashmap_free(m->units);
Lennart Poettering's avatar
Lennart Poettering committed
420
        hashmap_free(m->jobs);
421
        hashmap_free(m->transaction_jobs);
Lennart Poettering's avatar
Lennart Poettering committed
422
        hashmap_free(m->watch_pids);
423
        hashmap_free(m->watch_bus);
Lennart Poettering's avatar
Lennart Poettering committed
424
425

        if (m->epoll_fd >= 0)
426
                close_nointr_nofail(m->epoll_fd);
427
        if (m->signal_watch.fd >= 0)
428
                close_nointr_nofail(m->signal_watch.fd);
429
430
        if (m->notify_watch.fd >= 0)
                close_nointr_nofail(m->notify_watch.fd);
Lennart Poettering's avatar
Lennart Poettering committed
431

432
433
        free(m->notify_socket);

434
        lookup_paths_free(&m->lookup_paths);
435
        strv_free(m->environment);
436

437
        hashmap_free(m->cgroup_bondings);
438
        set_free_free(m->unit_path_cache);
439

Lennart Poettering's avatar
Lennart Poettering committed
440
441
442
        free(m);
}

443
444
int manager_enumerate(Manager *m) {
        int r = 0, q;
Lennart Poettering's avatar
Lennart Poettering committed
445
446
447
448
        UnitType c;

        assert(m);

449
450
        /* Let's ask every type to load all units from disk/kernel
         * that it might know */
Lennart Poettering's avatar
Lennart Poettering committed
451
452
        for (c = 0; c < _UNIT_TYPE_MAX; c++)
                if (unit_vtable[c]->enumerate)
453
454
                        if ((q = unit_vtable[c]->enumerate(m)) < 0)
                                r = q;
Lennart Poettering's avatar
Lennart Poettering committed
455
456

        manager_dispatch_load_queue(m);
457
458
459
460
461
462
463
464
465
466
        return r;
}

int manager_coldplug(Manager *m) {
        int r = 0, q;
        Iterator i;
        Unit *u;
        char *k;

        assert(m);
Lennart Poettering's avatar
Lennart Poettering committed
467
468
469
470
471

        /* Then, let's set up their initial state. */
        HASHMAP_FOREACH_KEY(u, k, m->units, i) {

                /* ignore aliases */
472
                if (u->meta.id != k)
Lennart Poettering's avatar
Lennart Poettering committed
473
474
                        continue;

475
476
                if ((q = unit_coldplug(u)) < 0)
                        r = q;
Lennart Poettering's avatar
Lennart Poettering committed
477
478
        }

479
480
481
        return r;
}

482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
static void manager_build_unit_path_cache(Manager *m) {
        char **i;
        DIR *d = NULL;
        int r;

        assert(m);

        set_free_free(m->unit_path_cache);

        if (!(m->unit_path_cache = set_new(string_hash_func, string_compare_func))) {
                log_error("Failed to allocate unit path cache.");
                return;
        }

        /* This simply builds a list of files we know exist, so that
         * we don't always have to go to disk */

        STRV_FOREACH(i, m->lookup_paths.unit_path) {
                struct dirent *de;

                if (!(d = opendir(*i))) {
                        log_error("Failed to open directory: %m");
                        continue;
                }

                while ((de = readdir(d))) {
                        char *p;

                        if (ignore_file(de->d_name))
                                continue;

                        if (asprintf(&p, "%s/%s", streq(*i, "/") ? "" : *i, de->d_name) < 0) {
                                r = -ENOMEM;
                                goto fail;
                        }

                        if ((r = set_put(m->unit_path_cache, p)) < 0) {
                                free(p);
                                goto fail;
                        }
                }

                closedir(d);
                d = NULL;
        }

        return;

fail:
        log_error("Failed to build unit path cache: %s", strerror(-r));

        set_free_free(m->unit_path_cache);
        m->unit_path_cache = NULL;

        if (d)
                closedir(d);
}

540
541
542
543
544
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
        int r, q;

        assert(m);

545
546
        manager_build_unit_path_cache(m);

547
548
549
550
551
552
        /* If we will deserialize make sure that during enumeration
         * this is already known, so we increase the counter here
         * already */
        if (serialization)
                m->n_deserializing ++;

553
554
555
556
557
558
559
560
561
562
563
564
        /* First, enumerate what we can from all config files */
        r = manager_enumerate(m);

        /* Second, deserialize if there is something to deserialize */
        if (serialization)
                if ((q = manager_deserialize(m, serialization, fds)) < 0)
                        r = q;

        /* Third, fire things up! */
        if ((q = manager_coldplug(m)) < 0)
                r = q;

565
566
567
568
569
        if (serialization) {
                assert(m->n_deserializing > 0);
                m->n_deserializing --;
        }

570
571
572
573
        /* Now that the initial devices are available, let's see if we
         * can write the utmp file */
        manager_write_utmp_reboot(m);

574
        return r;
Lennart Poettering's avatar
Lennart Poettering committed
575
576
}

577
static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) {
Lennart Poettering's avatar
Lennart Poettering committed
578
579
580
        assert(m);
        assert(j);

Lennart Poettering's avatar
Lennart Poettering committed
581
582
        /* Deletes one job from the transaction */

583
        manager_transaction_unlink_job(m, j, delete_dependencies);
Lennart Poettering's avatar
Lennart Poettering committed
584

585
        if (!j->installed)
Lennart Poettering's avatar
Lennart Poettering committed
586
587
588
                job_free(j);
}

Lennart Poettering's avatar
Lennart Poettering committed
589
static void transaction_delete_unit(Manager *m, Unit *u) {
Lennart Poettering's avatar
Lennart Poettering committed
590
591
        Job *j;

Lennart Poettering's avatar
Lennart Poettering committed
592
        /* Deletes all jobs associated with a certain unit from the
Lennart Poettering's avatar
Lennart Poettering committed
593
594
         * transaction */

Lennart Poettering's avatar
Lennart Poettering committed
595
        while ((j = hashmap_get(m->transaction_jobs, u)))
596
                transaction_delete_job(m, j, true);
Lennart Poettering's avatar
Lennart Poettering committed
597
598
}

599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
static void transaction_clean_dependencies(Manager *m) {
        Iterator i;
        Job *j;

        assert(m);

        /* Drops all dependencies of all installed jobs */

        HASHMAP_FOREACH(j, m->jobs, i) {
                while (j->subject_list)
                        job_dependency_free(j->subject_list);
                while (j->object_list)
                        job_dependency_free(j->object_list);
        }

        assert(!m->transaction_anchor);
}

617
618
619
620
621
static void transaction_abort(Manager *m) {
        Job *j;

        assert(m);

622
        while ((j = hashmap_first(m->transaction_jobs)))
623
                if (j->installed)
624
                        transaction_delete_job(m, j, true);
625
626
627
628
                else
                        job_free(j);

        assert(hashmap_isempty(m->transaction_jobs));
629
630

        transaction_clean_dependencies(m);
631
632
633
634
635
636
637
}

static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsigned generation) {
        JobDependency *l;

        assert(m);

Lennart Poettering's avatar
Lennart Poettering committed
638
        /* A recursive sweep through the graph that marks all units
Lennart Poettering's avatar
Lennart Poettering committed
639
640
641
642
         * that matter to the anchor job, i.e. are directly or
         * indirectly a dependency of the anchor job via paths that
         * are fully marked as mattering. */

Lennart Poettering's avatar
Lennart Poettering committed
643
644
645
646
647
648
        if (j)
                l = j->subject_list;
        else
                l = m->transaction_anchor;

        LIST_FOREACH(subject, l, l) {
649
650
651
652
653

                /* This link does not matter */
                if (!l->matters)
                        continue;

Lennart Poettering's avatar
Lennart Poettering committed
654
                /* This unit has already been marked */
655
656
657
658
659
660
661
662
663
664
                if (l->object->generation == generation)
                        continue;

                l->object->matters_to_anchor = true;
                l->object->generation = generation;

                transaction_find_jobs_that_matter_to_anchor(m, l->object, generation);
        }
}

665
static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, JobType t) {
666
667
668
669
        JobDependency *l, *last;

        assert(j);
        assert(other);
Lennart Poettering's avatar
Lennart Poettering committed
670
        assert(j->unit == other->unit);
671
        assert(!j->installed);
672

Lennart Poettering's avatar
Lennart Poettering committed
673
674
        /* Merges 'other' into 'j' and then deletes j. */

675
676
        j->type = t;
        j->state = JOB_WAITING;
677
        j->override = j->override || other->override;
678
679
680
681
682

        j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;

        /* Patch us in as new owner of the JobDependency objects */
        last = NULL;
Lennart Poettering's avatar
Lennart Poettering committed
683
        LIST_FOREACH(subject, l, other->subject_list) {
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
                assert(l->subject == other);
                l->subject = j;
                last = l;
        }

        /* Merge both lists */
        if (last) {
                last->subject_next = j->subject_list;
                if (j->subject_list)
                        j->subject_list->subject_prev = last;
                j->subject_list = other->subject_list;
        }

        /* Patch us in as new owner of the JobDependency objects */
        last = NULL;
Lennart Poettering's avatar
Lennart Poettering committed
699
        LIST_FOREACH(object, l, other->object_list) {
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
                assert(l->object == other);
                l->object = j;
                last = l;
        }

        /* Merge both lists */
        if (last) {
                last->object_next = j->object_list;
                if (j->object_list)
                        j->object_list->object_prev = last;
                j->object_list = other->object_list;
        }

        /* Kill the other job */
        other->subject_list = NULL;
        other->object_list = NULL;
716
        transaction_delete_job(m, other, true);
717
718
}

719
static int delete_one_unmergeable_job(Manager *m, Job *j) {
Lennart Poettering's avatar
Lennart Poettering committed
720
721
722
723
724
725
726
727
728
729
730
        Job *k;

        assert(j);

        /* Tries to delete one item in the linked list
         * j->transaction_next->transaction_next->... that conflicts
         * whith another one, in an attempt to make an inconsistent
         * transaction work. */

        /* We rely here on the fact that if a merged with b does not
         * merge with c, either a or b merge with c neither */
731
732
        LIST_FOREACH(transaction, j, j)
                LIST_FOREACH(transaction, k, j->transaction_next) {
Lennart Poettering's avatar
Lennart Poettering committed
733
734
735
                        Job *d;

                        /* Is this one mergeable? Then skip it */
736
                        if (job_type_is_mergeable(j->type, k->type))
Lennart Poettering's avatar
Lennart Poettering committed
737
738
739
740
741
742
743
744
745
746
747
748
                                continue;

                        /* Ok, we found two that conflict, let's see if we can
                         * drop one of them */
                        if (!j->matters_to_anchor)
                                d = j;
                        else if (!k->matters_to_anchor)
                                d = k;
                        else
                                return -ENOEXEC;

                        /* Ok, we can drop one, so let's do so. */
749
                        log_notice("Trying to fix job merging by deleting job %s/%s", d->unit->meta.id, job_type_to_string(d->type));
750
                        transaction_delete_job(m, d, true);
Lennart Poettering's avatar
Lennart Poettering committed
751
752
753
754
755
756
                        return 0;
                }

        return -EINVAL;
}

757
static int transaction_merge_jobs(Manager *m, DBusError *e) {
758
        Job *j;
759
        Iterator i;
760
761
762
763
        int r;

        assert(m);

Lennart Poettering's avatar
Lennart Poettering committed
764
765
        /* First step, check whether any of the jobs for one specific
         * task conflict. If so, try to drop one of them. */
766
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
Lennart Poettering's avatar
Lennart Poettering committed
767
768
769
770
                JobType t;
                Job *k;

                t = j->type;
771
                LIST_FOREACH(transaction, k, j->transaction_next) {
Lennart Poettering's avatar
Lennart Poettering committed
772
773
774
775
776
777
778
                        if ((r = job_type_merge(&t, k->type)) >= 0)
                                continue;

                        /* OK, we could not merge all jobs for this
                         * action. Let's see if we can get rid of one
                         * of them */

779
                        if ((r = delete_one_unmergeable_job(m, j)) >= 0)
Lennart Poettering's avatar
Lennart Poettering committed
780
781
782
783
784
785
                                /* Ok, we managed to drop one, now
                                 * let's ask our callers to call us
                                 * again after garbage collecting */
                                return -EAGAIN;

                        /* We couldn't merge anything. Failure */
786
787
                        dbus_set_error(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.",
                                       job_type_to_string(t), job_type_to_string(k->type), k->unit->meta.id);
Lennart Poettering's avatar
Lennart Poettering committed
788
789
790
791
792
                        return r;
                }
        }

        /* Second step, merge the jobs. */
793
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
794
795
796
                JobType t = j->type;
                Job *k;

797
                /* Merge all transactions */
798
                LIST_FOREACH(transaction, k, j->transaction_next)
Lennart Poettering's avatar
Lennart Poettering committed
799
                        assert_se(job_type_merge(&t, k->type) == 0);
800

801
                /* If an active job is mergeable, merge it too */
Lennart Poettering's avatar
Lennart Poettering committed
802
803
                if (j->unit->meta.job)
                        job_type_merge(&t, j->unit->meta.job->type); /* Might fail. Which is OK */
804

805
                while ((k = j->transaction_next)) {
806
                        if (j->installed) {
807
                                transaction_merge_and_delete_job(m, k, j, t);
808
809
                                j = k;
                        } else
810
                                transaction_merge_and_delete_job(m, j, k, t);
811
812
813
814
815
816
                }

                assert(!j->transaction_next);
                assert(!j->transaction_prev);
        }

817
        return 0;
818
819
}

820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
static void transaction_drop_redundant(Manager *m) {
        bool again;

        assert(m);

        /* Goes through the transaction and removes all jobs that are
         * a noop */

        do {
                Job *j;
                Iterator i;

                again = false;

                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
                        bool changes_something = false;
                        Job *k;

                        LIST_FOREACH(transaction, k, j) {

                                if (!job_is_anchor(k) &&
                                    job_type_is_redundant(k->type, unit_active_state(k->unit)))
                                        continue;

                                changes_something = true;
                                break;
                        }

                        if (changes_something)
                                continue;

851
                        log_debug("Found redundant job %s/%s, dropping.", j->unit->meta.id, job_type_to_string(j->type));
852
853
854
855
856
857
858
859
                        transaction_delete_job(m, j, false);
                        again = true;
                        break;
                }

        } while (again);
}

Lennart Poettering's avatar
Lennart Poettering committed
860
861
static bool unit_matters_to_anchor(Unit *u, Job *j) {
        assert(u);
Lennart Poettering's avatar
Lennart Poettering committed
862
863
        assert(!j->transaction_prev);

Lennart Poettering's avatar
Lennart Poettering committed
864
        /* Checks whether at least one of the jobs for this unit
Lennart Poettering's avatar
Lennart Poettering committed
865
866
         * matters to the anchor. */

867
        LIST_FOREACH(transaction, j, j)
Lennart Poettering's avatar
Lennart Poettering committed
868
869
870
871
872
873
                if (j->matters_to_anchor)
                        return true;

        return false;
}

874
static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned generation, DBusError *e) {
875
        Iterator i;
Lennart Poettering's avatar
Lennart Poettering committed
876
        Unit *u;
877
        int r;
878
879
880

        assert(m);
        assert(j);
Lennart Poettering's avatar
Lennart Poettering committed
881
882
883
884
        assert(!j->transaction_prev);

        /* Does a recursive sweep through the ordering graph, looking
         * for a cycle. If we find cycle we try to break it. */
885

886
887
        /* Have we seen this before? */
        if (j->generation == generation) {
888
889
                Job *k;

890
891
892
893
894
                /* If the marker is NULL we have been here already and
                 * decided the job was loop-free from here. Hence
                 * shortcut things and return right-away. */
                if (!j->marker)
                        return 0;
895

896
897
898
899
900
901
                /* So, the marker is not NULL and we already have been
                 * here. We have a cycle. Let's try to break it. We go
                 * backwards in our path and try to find a suitable
                 * job to remove. We use the marker to find our way
                 * back, since smart how we are we stored our way back
                 * in there. */
902
                log_warning("Found ordering cycle on %s/%s", j->unit->meta.id, job_type_to_string(j->type));
903

904
                for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
Lennart Poettering's avatar
Lennart Poettering committed
905

906
                        log_info("Walked on cycle path to %s/%s", k->unit->meta.id, job_type_to_string(k->type));
907

908
                        if (!k->installed &&
Lennart Poettering's avatar
Lennart Poettering committed
909
                            !unit_matters_to_anchor(k->unit, k)) {
Lennart Poettering's avatar
Lennart Poettering committed
910
911
                                /* Ok, we can drop this one, so let's
                                 * do so. */
912
                                log_warning("Breaking order cycle by deleting job %s/%s", k->unit->meta.id, job_type_to_string(k->type));
Lennart Poettering's avatar
Lennart Poettering committed
913
                                transaction_delete_unit(m, k->unit);
914
915
916
917
                                return -EAGAIN;
                        }

                        /* Check if this in fact was the beginning of
918
                         * the cycle */
919
920
921
922
                        if (k == j)
                                break;
                }

923
                log_error("Unable to break cycle");
924

925
                dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See logs for details.");
Lennart Poettering's avatar
Lennart Poettering committed
926
                return -ENOEXEC;
927
928
        }

Lennart Poettering's avatar
Lennart Poettering committed
929
        /* Make the marker point to where we come from, so that we can
930
931
932
933
         * find our way backwards if we want to break a cycle. We use
         * a special marker for the beginning: we point to
         * ourselves. */
        j->marker = from ? from : j;
934
935
        j->generation = generation;

Lennart Poettering's avatar
Lennart Poettering committed
936
        /* We assume that the the dependencies are bidirectional, and
Lennart Poettering's avatar
Lennart Poettering committed
937
938
         * hence can ignore UNIT_AFTER */
        SET_FOREACH(u, j->unit->meta.dependencies[UNIT_BEFORE], i) {
939
940
                Job *o;

Lennart Poettering's avatar
Lennart Poettering committed
941
942
                /* Is there a job for this unit? */
                if (!(o = hashmap_get(m->transaction_jobs, u)))
Lennart Poettering's avatar
Lennart Poettering committed
943
944
945
946

                        /* Ok, there is no job for this in the
                         * transaction, but maybe there is already one
                         * running? */
Lennart Poettering's avatar
Lennart Poettering committed
947
                        if (!(o = u->meta.job))
948
949
                                continue;

950
                if ((r = transaction_verify_order_one(m, o, j, generation, e)) < 0)
951
952
953
                        return r;
        }

954
955
956
957
        /* Ok, let's backtrack, and remember that this entry is not on
         * our path anymore. */
        j->marker = NULL;

958
959
960
        return 0;
}

961
static int transaction_verify_order(Manager *m, unsigned *generation, DBusError *e) {
Lennart Poettering's avatar
Lennart Poettering committed
962
963
        Job *j;
        int r;
964
        Iterator i;
965
        unsigned g;
Lennart Poettering's avatar
Lennart Poettering committed
966

967
968
969
        assert(m);
        assert(generation);

Lennart Poettering's avatar
Lennart Poettering committed
970
971
        /* Check if the ordering graph is cyclic. If it is, try to fix
         * that up by dropping one of the jobs. */
972

973
974
        g = (*generation)++;

975
        HASHMAP_FOREACH(j, m->transaction_jobs, i)
976
                if ((r = transaction_verify_order_one(m, j, NULL, g, e)) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
977
                        return r;
978
979
980
981
982
983
984
985
986

        return 0;
}

static void transaction_collect_garbage(Manager *m) {
        bool again;

        assert(m);

Lennart Poettering's avatar
Lennart Poettering committed
987
988
        /* Drop jobs that are not required by any other job */

989
        do {
990
                Iterator i;
991
992
993
994
                Job *j;

                again = false;

995
                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
996
997
998
                        if (j->object_list)
                                continue;

999
                        log_debug("Garbage collecting job %s/%s", j->unit->meta.id, job_type_to_string(j->type));
1000
                        transaction_delete_job(m, j, true);
1001
1002
1003
1004
1005
1006
1007
                        again = true;
                        break;
                }

        } while (again);
}

1008
static int transaction_is_destructive(Manager *m, DBusError *e) {
1009
        Iterator i;
1010
        Job *j;
1011
1012
1013

        assert(m);

1014
1015
        /* Checks whether applying this transaction means that
         * existing jobs would be replaced */
1016

1017
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1018
1019
1020
1021
1022

                /* Assume merged */
                assert(!j->transaction_prev);
                assert(!j->transaction_next);

Lennart Poettering's avatar
Lennart Poettering committed
1023
1024
                if (j->unit->meta.job &&
                    j->unit->meta.job != j &&
1025
1026
1027
                    !job_type_is_superset(j->type, j->unit->meta.job->type)) {

                        dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
1028
                        return -EEXIST;
1029
                }
1030
        }
1031

1032
1033
1034
        return 0;
}

1035
1036
1037
1038
1039
1040
1041
1042
1043
static void transaction_minimize_impact(Manager *m) {
        bool again;
        assert(m);

        /* Drops all unnecessary jobs that reverse already active jobs
         * or that stop a running service. */

        do {
                Job *j;
1044
                Iterator i;
1045
1046
1047

                again = false;

1048
1049
                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
                        LIST_FOREACH(transaction, j, j) {
1050
                                bool stops_running_service, changes_existing_job;
1051
1052
1053
1054
1055
1056
1057
1058

                                /* If it matters, we shouldn't drop it */
                                if (j->matters_to_anchor)
                                        continue;

                                /* Would this stop a running service?
                                 * Would this change an existing job?
                                 * If so, let's drop this entry */
1059
1060
1061
1062
1063
1064
1065
1066

                                stops_running_service =
                                        j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));

                                changes_existing_job =
                                        j->unit->meta.job && job_type_is_conflicting(j->type, j->unit->meta.job->state);

                                if (!stops_running_service && !changes_existing_job)
1067
1068
                                        continue;

1069
                                if (stops_running_service)
1070
                                        log_info("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type));
1071
1072

                                if (changes_existing_job)
1073
                                        log_info("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type));
1074

1075
                                /* Ok, let's get rid of this */
1076
                                log_info("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type));
1077

1078
                                transaction_delete_job(m, j, true);
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
                                again = true;
                                break;
                        }

                        if (again)
                                break;
                }

        } while (again);
}

1090
static int transaction_apply(Manager *m) {
1091
        Iterator i;
1092
1093
1094
        Job *j;
        int r;

Lennart Poettering's avatar
Lennart Poettering committed
1095
1096
        /* Moves the transaction jobs to the set of active jobs */

1097
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1098
1099
1100
1101
                /* Assume merged */
                assert(!j->transaction_prev);
                assert(!j->transaction_next);

1102
                if (j->installed)
1103
1104
1105
                        continue;

                if ((r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j)) < 0)
1106
1107
1108
                        goto rollback;
        }

1109
        while ((j = hashmap_steal_first(m->transaction_jobs))) {
1110
                if (j->installed)
1111
1112
                        continue;

Lennart Poettering's avatar
Lennart Poettering committed
1113
1114
                if (j->unit->meta.job)
                        job_free(j->unit->meta.job);
1115

Lennart Poettering's avatar
Lennart Poettering committed
1116
                j->unit->meta.job = j;
1117
                j->installed = true;
1118

1119
1120
1121
1122
1123
1124
                /* We're fully installed. Now let's free data we don't
                 * need anymore. */

                assert(!j->transaction_next);
                assert(!j->transaction_prev);

1125
1126
                job_add_to_run_queue(j);
                job_add_to_dbus_queue(j);
1127
                job_start_timer(j);
1128
1129
1130
        }

        /* As last step, kill all remaining job dependencies. */
1131
        transaction_clean_dependencies(m);
Lennart Poettering's avatar
Lennart Poettering committed
1132

1133
1134
1135
1136
        return 0;

rollback:

1137
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1138
                if (j->installed)
1139
1140
1141
1142
1143
1144
1145
1146
                        continue;

                hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
        }

        return r;
}

1147
static int transaction_activate(Manager *m, JobMode mode, DBusError *e) {
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
        int r;
        unsigned generation = 1;

        assert(m);

        /* This applies the changes recorded in transaction_jobs to
         * the actual list of jobs, if possible. */

        /* First step: figure out which jobs matter */
        transaction_find_jobs_that_matter_to_anchor(m, NULL, generation++);

1159
1160
1161
1162
1163
        /* Second step: Try not to stop any running services if
         * we don't have to. Don't try to reverse running
         * jobs if we don't have to. */
        transaction_minimize_impact(m);

1164
1165
1166
        /* Third step: Drop redundant jobs */
        transaction_drop_redundant(m);

Lennart Poettering's avatar
Lennart Poettering committed
1167
        for (;;) {
1168
                /* Fourth step: Let's remove unneeded jobs that might
Lennart Poettering's avatar
Lennart Poettering committed
1169
1170
                 * be lurking. */
                transaction_collect_garbage(m);
1171

1172
                /* Fifth step: verify order makes sense and correct
Lennart Poettering's avatar
Lennart Poettering committed
1173
                 * cycles if necessary and possible */
1174
                if ((r = transaction_verify_order(m, &generation, e)) >= 0)
Lennart Poettering's avatar
Lennart Poettering committed
1175
                        break;
1176

1177
                if (r != -EAGAIN) {
1178
                        log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, r));
Lennart Poettering's avatar
Lennart Poettering committed
1179
                        goto rollback;
1180
                }
1181

Lennart Poettering's avatar
Lennart Poettering committed
1182
1183
1184
1185
1186
                /* Let's see if the resulting transaction ordering
                 * graph is still cyclic... */
        }

        for (;;) {
1187
                /* S