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

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
30
#include <sys/epoll.h>
#include <signal.h>
#include <sys/signalfd.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/poll.h>
31
32
33
#include <sys/reboot.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
Lennart Poettering's avatar
Lennart Poettering committed
34
35
#include <termios.h>
#include <fcntl.h>
36
37
#include <sys/types.h>
#include <sys/stat.h>
38
#include <dirent.h>
39
40

#ifdef HAVE_AUDIT
41
#include <libaudit.h>
42
#endif
Lennart Poettering's avatar
Lennart Poettering committed
43
44
45
46
47

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

62
63
64
65
/* 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 */
66
#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
67

68
/* Where clients shall send notification messages to */
69
70
#define NOTIFY_SOCKET_SYSTEM "/dev/.run/systemd/notify"
#define NOTIFY_SOCKET_USER "@/org/freedesktop/systemd1/notify"
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

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;

91
        if (getpid() != 1)
92
                snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET_USER "/%llu", random_ull());
93
94
        else {
                unlink(NOTIFY_SOCKET_SYSTEM);
95
                strncpy(sa.un.sun_path, NOTIFY_SOCKET_SYSTEM, sizeof(sa.un.sun_path));
96
        }
97
98
99

        if (sa.un.sun_path[0] == '@')
                sa.un.sun_path[0] = 0;
100

101
        if (bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
                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;

118
119
120
121
        if (sa.un.sun_path[0] == 0)
                sa.un.sun_path[0] = '@';

        if (!(m->notify_socket = strdup(sa.un.sun_path)))
122
123
                return -ENOMEM;

124
125
        log_debug("Using notification socket %s", m->notify_socket);

126
127
128
        return 0;
}

Lennart Poettering's avatar
Lennart Poettering committed
129
130
131
132
133
134
135
136
137
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");

138
        if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY)) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
139
140
141
142
143
144
145
146
147
148
149
150
                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;
}

151
static int manager_setup_signals(Manager *m) {
Lennart Poettering's avatar
Lennart Poettering committed
152
153
        sigset_t mask;
        struct epoll_event ev;
154
        struct sigaction sa;
Lennart Poettering's avatar
Lennart Poettering committed
155

156
157
        assert(m);

158
159
160
161
162
163
        /* 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);

164
        assert_se(sigemptyset(&mask) == 0);
165
166
167
168
169
170
171
172
173
174
175

        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 */
176
                        SIGRTMIN+1,  /* systemd: isolate rescue.target */
177
178
179
180
                        SIGRTMIN+2,  /* systemd: isolate emergency.target */
                        SIGRTMIN+3,  /* systemd: start halt.target */
                        SIGRTMIN+4,  /* systemd: start poweroff.target */
                        SIGRTMIN+5,  /* systemd: start reboot.target */
181
182
183
184
185
                        SIGRTMIN+6,  /* systemd: start kexec.target */
                        SIGRTMIN+13, /* systemd: Immediate halt */
                        SIGRTMIN+14, /* systemd: Immediate poweroff */
                        SIGRTMIN+15, /* systemd: Immediate reboot */
                        SIGRTMIN+16, /* systemd: Immediate kexec */
186
187
                        SIGRTMIN+20, /* systemd: enable status messages */
                        SIGRTMIN+21, /* systemd: disable status messages */
188
                        -1);
189
190
        assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);

Lennart Poettering's avatar
Lennart Poettering committed
191
        m->signal_watch.type = WATCH_SIGNAL;
192
193
194
195
196
197
198
199
200
201
        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;

202
        if (m->running_as == MANAGER_SYSTEM)
Lennart Poettering's avatar
Lennart Poettering committed
203
                return enable_special_signals(m);
204

205
206
207
        return 0;
}

208
int manager_new(ManagerRunningAs running_as, Manager **_m) {
209
        Manager *m;
210
211
212
        int r = -ENOMEM;

        assert(_m);
213
214
        assert(running_as >= 0);
        assert(running_as < _MANAGER_RUNNING_AS_MAX);
215

Lennart Poettering's avatar
Lennart Poettering committed
216
        if (!(m = new0(Manager, 1)))
217
                return -ENOMEM;
Lennart Poettering's avatar
Lennart Poettering committed
218

219
        dual_timestamp_get(&m->startup_timestamp);
220

221
        m->running_as = running_as;
222
        m->name_data_slot = m->subscribed_data_slot = -1;
223
        m->exit_code = _MANAGER_EXIT_CODE_INVALID;
224
        m->pin_cgroupfs_fd = -1;
Lennart Poettering's avatar
Lennart Poettering committed
225

226
227
228
229
#ifdef HAVE_AUDIT
        m->audit_fd = -1;
#endif

230
        m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = m->swap_watch.fd = -1;
231
        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
232

233
234
235
        if (!(m->environment = strv_copy(environ)))
                goto fail;

236
237
238
        if (!(m->default_controllers = strv_new("cpu", NULL)))
                goto fail;

Lennart Poettering's avatar
Lennart Poettering committed
239
        if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
Lennart Poettering's avatar
Lennart Poettering committed
240
241
242
243
244
                goto fail;

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

245
        if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
Lennart Poettering's avatar
Lennart Poettering committed
246
247
                goto fail;

Lennart Poettering's avatar
Lennart Poettering committed
248
249
250
        if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
                goto fail;

251
252
253
        if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
                goto fail;

254
255
256
        if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
                goto fail;

Lennart Poettering's avatar
Lennart Poettering committed
257
258
259
        if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
                goto fail;

260
        if ((r = lookup_paths_init(&m->lookup_paths, m->running_as)) < 0)
261
262
                goto fail;

263
264
265
266
        if ((r = manager_setup_signals(m)) < 0)
                goto fail;

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

269
270
271
        if ((r = manager_setup_notify(m)) < 0)
                goto fail;

272
        /* Try to connect to the busses, if possible. */
273
        if ((r = bus_init(m, running_as != MANAGER_SYSTEM)) < 0)
274
275
                goto fail;

276
#ifdef HAVE_AUDIT
277
278
        if ((m->audit_fd = audit_open()) < 0)
                log_error("Failed to connect to audit log: %m");
279
#endif
280

281
282
        *_m = m;
        return 0;
Lennart Poettering's avatar
Lennart Poettering committed
283
284
285

fail:
        manager_free(m);
286
        return r;
Lennart Poettering's avatar
Lennart Poettering committed
287
288
}

289
290
291
292
293
294
295
296
297
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);

298
                unit_free((Unit*) meta);
299
300
301
302
303
304
                n++;
        }

        return n;
}

Lennart Poettering's avatar
Lennart Poettering committed
305
enum {
Harald Hoyer's avatar
Harald Hoyer committed
306
        GC_OFFSET_IN_PATH,  /* This one is on the path we were traveling */
Lennart Poettering's avatar
Lennart Poettering committed
307
308
309
310
311
312
313
        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) {
314
315
        Iterator i;
        Unit *other;
Lennart Poettering's avatar
Lennart Poettering committed
316
        bool is_bad;
317
318
319

        assert(u);

Lennart Poettering's avatar
Lennart Poettering committed
320
321
322
        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)
323
324
                return;

Lennart Poettering's avatar
Lennart Poettering committed
325
        if (u->meta.in_cleanup_queue)
326
327
328
329
330
                goto bad;

        if (unit_check_gc(u))
                goto good;

Lennart Poettering's avatar
Lennart Poettering committed
331
332
333
334
        u->meta.gc_marker = gc_marker + GC_OFFSET_IN_PATH;

        is_bad = true;

335
336
337
        SET_FOREACH(other, u->meta.dependencies[UNIT_REFERENCED_BY], i) {
                unit_gc_sweep(other, gc_marker);

Lennart Poettering's avatar
Lennart Poettering committed
338
                if (other->meta.gc_marker == gc_marker + GC_OFFSET_GOOD)
339
                        goto good;
Lennart Poettering's avatar
Lennart Poettering committed
340
341
342

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

Lennart Poettering's avatar
Lennart Poettering committed
345
346
347
348
349
350
351
352
353
        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;

354
bad:
Lennart Poettering's avatar
Lennart Poettering committed
355
356
357
358
        /* 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);
359
360
361
        return;

good:
Lennart Poettering's avatar
Lennart Poettering committed
362
        u->meta.gc_marker = gc_marker + GC_OFFSET_GOOD;
363
364
365
366
367
}

static unsigned manager_dispatch_gc_queue(Manager *m) {
        Meta *meta;
        unsigned n = 0;
Lennart Poettering's avatar
Lennart Poettering committed
368
        unsigned gc_marker;
369
370
371
372
373
374
375
376
377
378

        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
379
380
        m->gc_marker += _GC_OFFSET_MAX;
        if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
Lennart Poettering's avatar
Lennart Poettering committed
381
                m->gc_marker = 1;
382

Lennart Poettering's avatar
Lennart Poettering committed
383
384
        gc_marker = m->gc_marker;

385
386
387
        while ((meta = m->gc_queue)) {
                assert(meta->in_gc_queue);

388
                unit_gc_sweep((Unit*) meta, gc_marker);
Lennart Poettering's avatar
Lennart Poettering committed
389

390
391
392
393
394
                LIST_REMOVE(Meta, gc_queue, m->gc_queue, meta);
                meta->in_gc_queue = false;

                n++;

Lennart Poettering's avatar
Lennart Poettering committed
395
396
                if (meta->gc_marker == gc_marker + GC_OFFSET_BAD ||
                    meta->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
397
                        log_debug("Collecting %s", meta->id);
Lennart Poettering's avatar
Lennart Poettering committed
398
                        meta->gc_marker = gc_marker + GC_OFFSET_BAD;
399
                        unit_add_to_cleanup_queue((Unit*) meta);
400
401
402
403
404
405
406
407
408
                }
        }

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

        return n;
}

409
static void manager_clear_jobs_and_units(Manager *m) {
410
        Job *j;
411
        Unit *u;
Lennart Poettering's avatar
Lennart Poettering committed
412
413
414

        assert(m);

Lennart Poettering's avatar
Lennart Poettering committed
415
        while ((j = hashmap_first(m->transaction_jobs)))
416
417
                job_free(j);

Lennart Poettering's avatar
Lennart Poettering committed
418
419
        while ((u = hashmap_first(m->units)))
                unit_free(u);
420
421
422
423
424
425
426
427
428
429
430
431
432

        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));
433
434
435
436
}

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

438
439
440
        assert(m);

        manager_clear_jobs_and_units(m);
441

442
443
444
445
        for (c = 0; c < _UNIT_TYPE_MAX; c++)
                if (unit_vtable[c]->shutdown)
                        unit_vtable[c]->shutdown(m);

446
447
        /* If we reexecute ourselves, we keep the root cgroup
         * around */
448
        manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
449

450
451
        manager_undo_generators(m);

452
        bus_done(m);
453

Lennart Poettering's avatar
Lennart Poettering committed
454
        hashmap_free(m->units);
Lennart Poettering's avatar
Lennart Poettering committed
455
        hashmap_free(m->jobs);
456
        hashmap_free(m->transaction_jobs);
Lennart Poettering's avatar
Lennart Poettering committed
457
        hashmap_free(m->watch_pids);
458
        hashmap_free(m->watch_bus);
Lennart Poettering's avatar
Lennart Poettering committed
459
460

        if (m->epoll_fd >= 0)
461
                close_nointr_nofail(m->epoll_fd);
462
        if (m->signal_watch.fd >= 0)
463
                close_nointr_nofail(m->signal_watch.fd);
464
465
        if (m->notify_watch.fd >= 0)
                close_nointr_nofail(m->notify_watch.fd);
Lennart Poettering's avatar
Lennart Poettering committed
466

467
468
469
470
471
#ifdef HAVE_AUDIT
        if (m->audit_fd >= 0)
                audit_close(m->audit_fd);
#endif

472
473
        free(m->notify_socket);

474
        lookup_paths_free(&m->lookup_paths);
475
        strv_free(m->environment);
476

477
478
        strv_free(m->default_controllers);

479
        hashmap_free(m->cgroup_bondings);
480
        set_free_free(m->unit_path_cache);
481

Lennart Poettering's avatar
Lennart Poettering committed
482
483
484
        free(m);
}

485
486
int manager_enumerate(Manager *m) {
        int r = 0, q;
Lennart Poettering's avatar
Lennart Poettering committed
487
488
489
490
        UnitType c;

        assert(m);

491
492
        /* Let's ask every type to load all units from disk/kernel
         * that it might know */
Lennart Poettering's avatar
Lennart Poettering committed
493
494
        for (c = 0; c < _UNIT_TYPE_MAX; c++)
                if (unit_vtable[c]->enumerate)
495
496
                        if ((q = unit_vtable[c]->enumerate(m)) < 0)
                                r = q;
Lennart Poettering's avatar
Lennart Poettering committed
497
498

        manager_dispatch_load_queue(m);
499
500
501
502
503
504
505
506
507
508
        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
509
510
511
512
513

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

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

517
518
                if ((q = unit_coldplug(u)) < 0)
                        r = q;
Lennart Poettering's avatar
Lennart Poettering committed
519
520
        }

521
522
523
        return r;
}

524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
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);
}

582
583
584
585
586
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
        int r, q;

        assert(m);

587
588
        manager_run_generators(m);

589
590
        manager_build_unit_path_cache(m);

591
592
593
594
595
596
        /* 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 ++;

597
598
599
600
601
602
603
604
605
606
607
608
        /* 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;

609
610
611
612
613
        if (serialization) {
                assert(m->n_deserializing > 0);
                m->n_deserializing --;
        }

614
        return r;
Lennart Poettering's avatar
Lennart Poettering committed
615
616
}

617
static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) {
Lennart Poettering's avatar
Lennart Poettering committed
618
619
620
        assert(m);
        assert(j);

Lennart Poettering's avatar
Lennart Poettering committed
621
622
        /* Deletes one job from the transaction */

623
        manager_transaction_unlink_job(m, j, delete_dependencies);
Lennart Poettering's avatar
Lennart Poettering committed
624

625
        if (!j->installed)
Lennart Poettering's avatar
Lennart Poettering committed
626
627
628
                job_free(j);
}

Lennart Poettering's avatar
Lennart Poettering committed
629
static void transaction_delete_unit(Manager *m, Unit *u) {
Lennart Poettering's avatar
Lennart Poettering committed
630
631
        Job *j;

Lennart Poettering's avatar
Lennart Poettering committed
632
        /* Deletes all jobs associated with a certain unit from the
Lennart Poettering's avatar
Lennart Poettering committed
633
634
         * transaction */

Lennart Poettering's avatar
Lennart Poettering committed
635
        while ((j = hashmap_get(m->transaction_jobs, u)))
636
                transaction_delete_job(m, j, true);
Lennart Poettering's avatar
Lennart Poettering committed
637
638
}

639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
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);
}

657
658
659
660
661
static void transaction_abort(Manager *m) {
        Job *j;

        assert(m);

662
        while ((j = hashmap_first(m->transaction_jobs)))
663
                if (j->installed)
664
                        transaction_delete_job(m, j, true);
665
666
667
668
                else
                        job_free(j);

        assert(hashmap_isempty(m->transaction_jobs));
669
670

        transaction_clean_dependencies(m);
671
672
673
674
675
676
677
}

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
678
        /* A recursive sweep through the graph that marks all units
Lennart Poettering's avatar
Lennart Poettering committed
679
680
681
682
         * 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
683
684
685
686
687
688
        if (j)
                l = j->subject_list;
        else
                l = m->transaction_anchor;

        LIST_FOREACH(subject, l, l) {
689
690
691
692
693

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

Lennart Poettering's avatar
Lennart Poettering committed
694
                /* This unit has already been marked */
695
696
697
698
699
700
701
702
703
704
                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);
        }
}

705
static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, JobType t) {
706
707
708
709
        JobDependency *l, *last;

        assert(j);
        assert(other);
Lennart Poettering's avatar
Lennart Poettering committed
710
        assert(j->unit == other->unit);
711
        assert(!j->installed);
712

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

715
716
        j->type = t;
        j->state = JOB_WAITING;
717
        j->override = j->override || other->override;
718
719
720
721
722

        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
723
        LIST_FOREACH(subject, l, other->subject_list) {
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
                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
739
        LIST_FOREACH(object, l, other->object_list) {
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
                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;
756
        transaction_delete_job(m, other, true);
757
}
758
759
760
761
762
763
764
765
766
767
768
769
770
771
static bool job_is_conflicted_by(Job *j) {
        JobDependency *l;

        assert(j);

        /* Returns true if this job is pulled in by a least one
         * ConflictedBy dependency. */

        LIST_FOREACH(object, l, j->object_list)
                if (l->conflicts)
                        return true;

        return false;
}
772

773
static int delete_one_unmergeable_job(Manager *m, Job *j) {
Lennart Poettering's avatar
Lennart Poettering committed
774
775
776
777
778
779
        Job *k;

        assert(j);

        /* Tries to delete one item in the linked list
         * j->transaction_next->transaction_next->... that conflicts
Harald Hoyer's avatar
Harald Hoyer committed
780
         * with another one, in an attempt to make an inconsistent
Lennart Poettering's avatar
Lennart Poettering committed
781
782
783
784
         * 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 */
785
786
        LIST_FOREACH(transaction, j, j)
                LIST_FOREACH(transaction, k, j->transaction_next) {
Lennart Poettering's avatar
Lennart Poettering committed
787
788
789
                        Job *d;

                        /* Is this one mergeable? Then skip it */
790
                        if (job_type_is_mergeable(j->type, k->type))
Lennart Poettering's avatar
Lennart Poettering committed
791
792
793
794
                                continue;

                        /* Ok, we found two that conflict, let's see if we can
                         * drop one of them */
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
                        if (!j->matters_to_anchor && !k->matters_to_anchor) {

                                /* Both jobs don't matter, so let's
                                 * find the one that is smarter to
                                 * remove. Let's think positive and
                                 * rather remove stops then starts --
                                 * except if something is being
                                 * stopped because it is conflicted by
                                 * another unit in which case we
                                 * rather remove the start. */

                                log_debug("Looking at job %s/%s conflicted_by=%s", j->unit->meta.id, job_type_to_string(j->type), yes_no(j->type == JOB_STOP && job_is_conflicted_by(j)));
                                log_debug("Looking at job %s/%s conflicted_by=%s", k->unit->meta.id, job_type_to_string(k->type), yes_no(k->type == JOB_STOP && job_is_conflicted_by(k)));

                                if (j->type == JOB_STOP) {

                                        if (job_is_conflicted_by(j))
                                                d = k;
                                        else
                                                d = j;

                                } else if (k->type == JOB_STOP) {

                                        if (job_is_conflicted_by(k))
                                                d = j;
                                        else
                                                d = k;
822
823
                                } else
                                        d = j;
824
825

                        } else if (!j->matters_to_anchor)
Lennart Poettering's avatar
Lennart Poettering committed
826
827
828
829
830
831
832
                                d = j;
                        else if (!k->matters_to_anchor)
                                d = k;
                        else
                                return -ENOEXEC;

                        /* Ok, we can drop one, so let's do so. */
833
                        log_debug("Fixing conflicting jobs by deleting job %s/%s", d->unit->meta.id, job_type_to_string(d->type));
834
                        transaction_delete_job(m, d, true);
Lennart Poettering's avatar
Lennart Poettering committed
835
836
837
838
839
840
                        return 0;
                }

        return -EINVAL;
}

841
static int transaction_merge_jobs(Manager *m, DBusError *e) {
842
        Job *j;
843
        Iterator i;
844
845
846
847
        int r;

        assert(m);

Lennart Poettering's avatar
Lennart Poettering committed
848
849
        /* First step, check whether any of the jobs for one specific
         * task conflict. If so, try to drop one of them. */
850
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
Lennart Poettering's avatar
Lennart Poettering committed
851
852
853
854
                JobType t;
                Job *k;

                t = j->type;
855
                LIST_FOREACH(transaction, k, j->transaction_next) {
856
                        if (job_type_merge(&t, k->type) >= 0)
Lennart Poettering's avatar
Lennart Poettering committed
857
858
859
860
861
862
                                continue;

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

863
                        if ((r = delete_one_unmergeable_job(m, j)) >= 0)
Lennart Poettering's avatar
Lennart Poettering committed
864
865
866
867
868
869
                                /* 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 */
870
871
                        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
872
873
874
875
876
                        return r;
                }
        }

        /* Second step, merge the jobs. */
877
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
878
879
880
                JobType t = j->type;
                Job *k;

881
                /* Merge all transactions */
882
                LIST_FOREACH(transaction, k, j->transaction_next)
Lennart Poettering's avatar
Lennart Poettering committed
883
                        assert_se(job_type_merge(&t, k->type) == 0);
884

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

889
                while ((k = j->transaction_next)) {
890
                        if (j->installed) {
891
                                transaction_merge_and_delete_job(m, k, j, t);
892
893
                                j = k;
                        } else
894
                                transaction_merge_and_delete_job(m, j, k, t);
895
896
897
898
899
900
                }

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

901
        return 0;
902
903
}

904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
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) &&
925
926
                                    (k->installed || job_type_is_redundant(k->type, unit_active_state(k->unit))) &&
                                    (!k->unit->meta.job || !job_type_is_conflicting(k->type, k->unit->meta.job->type)))
927
928
929
930
931
932
933
934
935
                                        continue;

                                changes_something = true;
                                break;
                        }

                        if (changes_something)
                                continue;

936
                        /* log_debug("Found redundant job %s/%s, dropping.", j->unit->meta.id, job_type_to_string(j->type)); */
937
938
939
940
941
942
943
944
                        transaction_delete_job(m, j, false);
                        again = true;
                        break;
                }

        } while (again);
}

Lennart Poettering's avatar
Lennart Poettering committed
945
946
static bool unit_matters_to_anchor(Unit *u, Job *j) {
        assert(u);
Lennart Poettering's avatar
Lennart Poettering committed
947
948
        assert(!j->transaction_prev);

Lennart Poettering's avatar
Lennart Poettering committed
949
        /* Checks whether at least one of the jobs for this unit
Lennart Poettering's avatar
Lennart Poettering committed
950
951
         * matters to the anchor. */

952
        LIST_FOREACH(transaction, j, j)
Lennart Poettering's avatar
Lennart Poettering committed
953
954
955
956
957
958
                if (j->matters_to_anchor)
                        return true;

        return false;
}

959
static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned generation, DBusError *e) {
960
        Iterator i;
Lennart Poettering's avatar
Lennart Poettering committed
961
        Unit *u;
962
        int r;
963
964
965

        assert(m);
        assert(j);
Lennart Poettering's avatar
Lennart Poettering committed
966
967
968
969
        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. */
970

971
972
        /* Have we seen this before? */
        if (j->generation == generation) {
973
                Job *k, *delete;
974

975
976
977
978
979
                /* 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;
980

981
982
983
984
985
986
                /* 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. */
987
                log_warning("Found ordering cycle on %s/%s", j->unit->meta.id, job_type_to_string(j->type));
988

989
                delete = NULL;
990
                for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
Lennart Poettering's avatar
Lennart Poettering committed
991

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

994
995
                        if (!delete &&
                            !k->installed &&
Lennart Poettering's avatar
Lennart Poettering committed
996
                            !unit_matters_to_anchor(k->unit, k)) {
Lennart Poettering's avatar
Lennart Poettering committed
997
998
                                /* Ok, we can drop this one, so let's
                                 * do so. */
999
                                delete = k;
1000
1001
1002
                        }

                        /* Check if this in fact was the beginning of
1003
                         * the cycle */
1004
1005
1006
1007
                        if (k == j)
                                break;
                }

1008
1009

                if (delete) {
1010
                        log_warning("Breaking ordering cycle by deleting job %s/%s", delete->unit->meta.id, job_type_to_string(delete->type));
1011
1012
1013
1014
                        transaction_delete_unit(m, delete->unit);
                        return -EAGAIN;
                }

1015
                log_error("Unable to break cycle");
1016

1017
                dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See system logs for details.");
Lennart Poettering's avatar
Lennart Poettering committed
1018
                return -ENOEXEC;
1019
1020
        }

Lennart Poettering's avatar
Lennart Poettering committed
1021
        /* Make the marker point to where we come from, so that we can
1022
1023
1024
1025
         * 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;
1026
1027
        j->generation = generation;

Lennart Poettering's avatar
Lennart Poettering committed
1028
        /* We assume that the the dependencies are bidirectional, and
Lennart Poettering's avatar
Lennart Poettering committed
1029
1030
         * hence can ignore UNIT_AFTER */
        SET_FOREACH(u, j->unit->meta.dependencies[UNIT_BEFORE], i) {
1031
1032
                Job *o;

Lennart Poettering's avatar
Lennart Poettering committed
1033
1034
                /* Is there a job for this unit? */
                if (!(o = hashmap_get(m->transaction_jobs, u)))
Lennart Poettering's avatar
Lennart Poettering committed
1035
1036
1037
1038

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

1042
                if ((r = transaction_verify_order_one(m, o, j, generation, e)) < 0)
1043
1044
1045
                        return r;
        }

1046
1047
1048
1049
        /* Ok, let's backtrack, and remember that this entry is not on
         * our path anymore. */
        j->marker = NULL;

1050
1051
1052
        return 0;
}

1053
static int transaction_verify_order(Manager *m, unsigned *generation, DBusError *e) {
Lennart Poettering's avatar
Lennart Poettering committed
1054
1055
        Job *j;
        int r;
1056
        Iterator i;
1057
        unsigned g;
Lennart Poettering's avatar
Lennart Poettering committed
1058

1059
1060
1061
        assert(m);
        assert(generation);

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

1065
1066
        g = (*generation)++;

1067
        HASHMAP_FOREACH(j, m->transaction_jobs, i)
1068
                if ((r = transaction_verify_order_one(m, j, NULL, g, e)) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
1069
                        return r;
1070
1071
1072
1073
1074
1075
1076
1077
1078

        return 0;
}

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

        assert(m);

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

1081
        do {
1082
                Iterator i;
1083
1084
1085
1086
                Job *j;

                again = false;

1087
                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1088
1089
1090
1091
1092
                        if (j->object_list) {
                                /* log_debug("Keeping job %s/%s because of %s/%s", */
                                /*           j->unit->meta.id, job_type_to_string(j->type), */
                                /*           j->object_list->subject ? j->object_list->subject->unit->meta.id : "root", */
                                /*           j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
1093
                                continue;
1094
                        }
1095

1096
                        /* log_debug("Garbage collecting job %s/%s", j->unit->meta.id, job_type_to_string(j->type)); */
1097
                        transaction_delete_job(m, j, true);
1098
1099
1100
1101
1102
1103
1104
                        again = true;
                        break;
                }

        } while (again);
}

1105
static int transaction_is_destructive(Manager *m, DBusError *e) {
1106
        Iterator i;
1107
        Job *j;
1108
1109
1110

        assert(m);

1111
1112
        /* Checks whether applying this transaction means that
         * existing jobs would be replaced */
1113

1114
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1115
1116
1117
1118
1119

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

Lennart Poettering's avatar
Lennart Poettering committed
1120
1121
                if (j->unit->meta.job &&
                    j->unit->meta.job != j &&
1122
1123
1124
                    !job_type_is_superset(j->type, j->unit->meta.job->type)) {

                        dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
1125
                        return -EEXIST;
1126
                }
1127
        }
1128

1129
1130
1131
        return 0;
}

1132
1133
1134
1135
1136
1137
1138
1139
1140
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;
1141
                Iterator i;
1142
1143
1144

                again = false;

1145
1146
                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
                        LIST_FOREACH(transaction, j, j) {
1147
                                bool stops_running_service, changes_existing_job;
1148
1149
1150
1151
1152
1153
1154
1155

                                /* 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 */
1156
1157
1158
1159
1160

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

                                changes_existing_job =
1161
1162
                                        j->unit->meta.job &&
                                        job_type_is_conflicting(j->type, j->unit->meta.job->type);
1163
1164

                                if (!stops_running_service && !changes_existing_job)
1165
1166
                                        continue;

1167
                                if (stops_running_service)
1168
                                        log_info("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type));
1169
1170

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

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