manager.c 78 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"
Lennart Poettering's avatar
Lennart Poettering committed
60

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

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/* 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;

89
        if (getpid() != 1)
90
91
92
93
                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);

94
        if (bind(m->notify_watch.fd, &sa.sa, sizeof(sa_family_t) + 1 + strlen(sa.un.sun_path+1)) < 0) {
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
                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;

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

        return 0;
}

Lennart Poettering's avatar
Lennart Poettering committed
117
118
119
120
121
122
123
124
125
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");

126
        if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY)) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
127
128
129
130
131
132
133
134
135
136
137
138
                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;
}

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

144
145
        assert(m);

146
147
148
149
150
151
        /* 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);

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

        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);
170
171
        assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);

Lennart Poettering's avatar
Lennart Poettering committed
172
        m->signal_watch.type = WATCH_SIGNAL;
173
174
175
176
177
178
179
180
181
182
        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;

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

186
187
188
        return 0;
}

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

        assert(_m);
194
195
        assert(running_as >= 0);
        assert(running_as < _MANAGER_RUNNING_AS_MAX);
196

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

200
        dual_timestamp_get(&m->startup_timestamp);
201

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

207
208
209
210
#ifdef HAVE_AUDIT
        m->audit_fd = -1;
#endif

211
        m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1;
212
        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
213

214
215
216
        if (!(m->environment = strv_copy(environ)))
                goto fail;

Lennart Poettering's avatar
Lennart Poettering committed
217
        if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
Lennart Poettering's avatar
Lennart Poettering committed
218
219
220
221
222
                goto fail;

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

223
        if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
Lennart Poettering's avatar
Lennart Poettering committed
224
225
                goto fail;

Lennart Poettering's avatar
Lennart Poettering committed
226
227
228
        if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
                goto fail;

229
230
231
        if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
                goto fail;

232
233
234
        if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
                goto fail;

Lennart Poettering's avatar
Lennart Poettering committed
235
236
237
        if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
                goto fail;

238
        if ((r = lookup_paths_init(&m->lookup_paths, m->running_as)) < 0)
239
240
                goto fail;

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

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

247
248
249
        if ((r = manager_setup_notify(m)) < 0)
                goto fail;

250
        /* Try to connect to the busses, if possible. */
251
        if ((r = bus_init(m)) < 0)
252
253
                goto fail;

254
#ifdef HAVE_AUDIT
255
256
        if ((m->audit_fd = audit_open()) < 0)
                log_error("Failed to connect to audit log: %m");
257
#endif
258

259
260
        *_m = m;
        return 0;
Lennart Poettering's avatar
Lennart Poettering committed
261
262
263

fail:
        manager_free(m);
264
        return r;
Lennart Poettering's avatar
Lennart Poettering committed
265
266
}

267
268
269
270
271
272
273
274
275
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);

276
                unit_free((Unit*) meta);
277
278
279
280
281
282
                n++;
        }

        return n;
}

Lennart Poettering's avatar
Lennart Poettering committed
283
284
285
286
287
288
289
290
291
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) {
292
293
        Iterator i;
        Unit *other;
Lennart Poettering's avatar
Lennart Poettering committed
294
        bool is_bad;
295
296
297

        assert(u);

Lennart Poettering's avatar
Lennart Poettering committed
298
299
300
        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)
301
302
                return;

Lennart Poettering's avatar
Lennart Poettering committed
303
        if (u->meta.in_cleanup_queue)
304
305
306
307
308
                goto bad;

        if (unit_check_gc(u))
                goto good;

Lennart Poettering's avatar
Lennart Poettering committed
309
310
311
312
        u->meta.gc_marker = gc_marker + GC_OFFSET_IN_PATH;

        is_bad = true;

313
314
315
        SET_FOREACH(other, u->meta.dependencies[UNIT_REFERENCED_BY], i) {
                unit_gc_sweep(other, gc_marker);

Lennart Poettering's avatar
Lennart Poettering committed
316
                if (other->meta.gc_marker == gc_marker + GC_OFFSET_GOOD)
317
                        goto good;
Lennart Poettering's avatar
Lennart Poettering committed
318
319
320

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

Lennart Poettering's avatar
Lennart Poettering committed
323
324
325
326
327
328
329
330
331
        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;

332
bad:
Lennart Poettering's avatar
Lennart Poettering committed
333
334
335
336
        /* 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);
337
338
339
        return;

good:
Lennart Poettering's avatar
Lennart Poettering committed
340
        u->meta.gc_marker = gc_marker + GC_OFFSET_GOOD;
341
342
343
344
345
}

static unsigned manager_dispatch_gc_queue(Manager *m) {
        Meta *meta;
        unsigned n = 0;
Lennart Poettering's avatar
Lennart Poettering committed
346
        unsigned gc_marker;
347
348
349
350
351
352
353
354
355
356

        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
357
358
        m->gc_marker += _GC_OFFSET_MAX;
        if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
Lennart Poettering's avatar
Lennart Poettering committed
359
                m->gc_marker = 1;
360

Lennart Poettering's avatar
Lennart Poettering committed
361
362
        gc_marker = m->gc_marker;

363
364
365
        while ((meta = m->gc_queue)) {
                assert(meta->in_gc_queue);

366
                unit_gc_sweep((Unit*) meta, gc_marker);
Lennart Poettering's avatar
Lennart Poettering committed
367

368
369
370
371
372
                LIST_REMOVE(Meta, gc_queue, m->gc_queue, meta);
                meta->in_gc_queue = false;

                n++;

Lennart Poettering's avatar
Lennart Poettering committed
373
374
                if (meta->gc_marker == gc_marker + GC_OFFSET_BAD ||
                    meta->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
375
                        log_debug("Collecting %s", meta->id);
Lennart Poettering's avatar
Lennart Poettering committed
376
                        meta->gc_marker = gc_marker + GC_OFFSET_BAD;
377
                        unit_add_to_cleanup_queue((Unit*) meta);
378
379
380
381
382
383
384
385
386
                }
        }

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

        return n;
}

387
static void manager_clear_jobs_and_units(Manager *m) {
388
        Job *j;
389
        Unit *u;
Lennart Poettering's avatar
Lennart Poettering committed
390
391
392

        assert(m);

Lennart Poettering's avatar
Lennart Poettering committed
393
        while ((j = hashmap_first(m->transaction_jobs)))
394
395
                job_free(j);

Lennart Poettering's avatar
Lennart Poettering committed
396
397
        while ((u = hashmap_first(m->units)))
                unit_free(u);
398
399
400
401
402
403
404
405
406
407
408
409
410

        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));
411
412
413
414
}

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

416
417
418
        assert(m);

        manager_clear_jobs_and_units(m);
419

420
421
422
423
        for (c = 0; c < _UNIT_TYPE_MAX; c++)
                if (unit_vtable[c]->shutdown)
                        unit_vtable[c]->shutdown(m);

424
425
        /* If we reexecute ourselves, we keep the root cgroup
         * around */
426
        manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
427

428
        bus_done(m);
429

Lennart Poettering's avatar
Lennart Poettering committed
430
        hashmap_free(m->units);
Lennart Poettering's avatar
Lennart Poettering committed
431
        hashmap_free(m->jobs);
432
        hashmap_free(m->transaction_jobs);
Lennart Poettering's avatar
Lennart Poettering committed
433
        hashmap_free(m->watch_pids);
434
        hashmap_free(m->watch_bus);
Lennart Poettering's avatar
Lennart Poettering committed
435
436

        if (m->epoll_fd >= 0)
437
                close_nointr_nofail(m->epoll_fd);
438
        if (m->signal_watch.fd >= 0)
439
                close_nointr_nofail(m->signal_watch.fd);
440
441
        if (m->notify_watch.fd >= 0)
                close_nointr_nofail(m->notify_watch.fd);
Lennart Poettering's avatar
Lennart Poettering committed
442

443
444
445
446
447
#ifdef HAVE_AUDIT
        if (m->audit_fd >= 0)
                audit_close(m->audit_fd);
#endif

448
449
        free(m->notify_socket);

450
        lookup_paths_free(&m->lookup_paths);
451
        strv_free(m->environment);
452

453
        hashmap_free(m->cgroup_bondings);
454
        set_free_free(m->unit_path_cache);
455

Lennart Poettering's avatar
Lennart Poettering committed
456
457
458
        free(m);
}

459
460
int manager_enumerate(Manager *m) {
        int r = 0, q;
Lennart Poettering's avatar
Lennart Poettering committed
461
462
463
464
        UnitType c;

        assert(m);

465
466
        /* Let's ask every type to load all units from disk/kernel
         * that it might know */
Lennart Poettering's avatar
Lennart Poettering committed
467
468
        for (c = 0; c < _UNIT_TYPE_MAX; c++)
                if (unit_vtable[c]->enumerate)
469
470
                        if ((q = unit_vtable[c]->enumerate(m)) < 0)
                                r = q;
Lennart Poettering's avatar
Lennart Poettering committed
471
472

        manager_dispatch_load_queue(m);
473
474
475
476
477
478
479
480
481
482
        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
483
484
485
486
487

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

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

491
492
                if ((q = unit_coldplug(u)) < 0)
                        r = q;
Lennart Poettering's avatar
Lennart Poettering committed
493
494
        }

495
496
497
        return r;
}

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
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
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);
}

556
557
558
559
560
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
        int r, q;

        assert(m);

561
562
        manager_build_unit_path_cache(m);

563
564
565
566
567
568
        /* 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 ++;

569
570
571
572
573
574
575
576
577
578
579
580
        /* 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;

581
582
583
584
585
        if (serialization) {
                assert(m->n_deserializing > 0);
                m->n_deserializing --;
        }

586
        return r;
Lennart Poettering's avatar
Lennart Poettering committed
587
588
}

589
static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) {
Lennart Poettering's avatar
Lennart Poettering committed
590
591
592
        assert(m);
        assert(j);

Lennart Poettering's avatar
Lennart Poettering committed
593
594
        /* Deletes one job from the transaction */

595
        manager_transaction_unlink_job(m, j, delete_dependencies);
Lennart Poettering's avatar
Lennart Poettering committed
596

597
        if (!j->installed)
Lennart Poettering's avatar
Lennart Poettering committed
598
599
600
                job_free(j);
}

Lennart Poettering's avatar
Lennart Poettering committed
601
static void transaction_delete_unit(Manager *m, Unit *u) {
Lennart Poettering's avatar
Lennart Poettering committed
602
603
        Job *j;

Lennart Poettering's avatar
Lennart Poettering committed
604
        /* Deletes all jobs associated with a certain unit from the
Lennart Poettering's avatar
Lennart Poettering committed
605
606
         * transaction */

Lennart Poettering's avatar
Lennart Poettering committed
607
        while ((j = hashmap_get(m->transaction_jobs, u)))
608
                transaction_delete_job(m, j, true);
Lennart Poettering's avatar
Lennart Poettering committed
609
610
}

611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
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);
}

629
630
631
632
633
static void transaction_abort(Manager *m) {
        Job *j;

        assert(m);

634
        while ((j = hashmap_first(m->transaction_jobs)))
635
                if (j->installed)
636
                        transaction_delete_job(m, j, true);
637
638
639
640
                else
                        job_free(j);

        assert(hashmap_isempty(m->transaction_jobs));
641
642

        transaction_clean_dependencies(m);
643
644
645
646
647
648
649
}

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
650
        /* A recursive sweep through the graph that marks all units
Lennart Poettering's avatar
Lennart Poettering committed
651
652
653
654
         * 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
655
656
657
658
659
660
        if (j)
                l = j->subject_list;
        else
                l = m->transaction_anchor;

        LIST_FOREACH(subject, l, l) {
661
662
663
664
665

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

Lennart Poettering's avatar
Lennart Poettering committed
666
                /* This unit has already been marked */
667
668
669
670
671
672
673
674
675
676
                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);
        }
}

677
static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, JobType t) {
678
679
680
681
        JobDependency *l, *last;

        assert(j);
        assert(other);
Lennart Poettering's avatar
Lennart Poettering committed
682
        assert(j->unit == other->unit);
683
        assert(!j->installed);
684

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

687
688
        j->type = t;
        j->state = JOB_WAITING;
689
        j->override = j->override || other->override;
690
691
692
693
694

        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
695
        LIST_FOREACH(subject, l, other->subject_list) {
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
                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
711
        LIST_FOREACH(object, l, other->object_list) {
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
                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;
728
        transaction_delete_job(m, other, true);
729
}
730
731
732
733
734
735
736
737
738
739
740
741
742
743
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;
}
744

745
static int delete_one_unmergeable_job(Manager *m, Job *j) {
Lennart Poettering's avatar
Lennart Poettering committed
746
747
748
749
750
751
752
753
754
755
756
        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 */
757
758
        LIST_FOREACH(transaction, j, j)
                LIST_FOREACH(transaction, k, j->transaction_next) {
Lennart Poettering's avatar
Lennart Poettering committed
759
760
761
                        Job *d;

                        /* Is this one mergeable? Then skip it */
762
                        if (job_type_is_mergeable(j->type, k->type))
Lennart Poettering's avatar
Lennart Poettering committed
763
764
765
766
                                continue;

                        /* Ok, we found two that conflict, let's see if we can
                         * drop one of them */
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
                        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;
794
795
                                } else
                                        d = j;
796
797

                        } else if (!j->matters_to_anchor)
Lennart Poettering's avatar
Lennart Poettering committed
798
799
800
801
802
803
804
                                d = j;
                        else if (!k->matters_to_anchor)
                                d = k;
                        else
                                return -ENOEXEC;

                        /* Ok, we can drop one, so let's do so. */
805
                        log_debug("Fixing conflicting jobs by deleting job %s/%s", d->unit->meta.id, job_type_to_string(d->type));
806
                        transaction_delete_job(m, d, true);
Lennart Poettering's avatar
Lennart Poettering committed
807
808
809
810
811
812
                        return 0;
                }

        return -EINVAL;
}

813
static int transaction_merge_jobs(Manager *m, DBusError *e) {
814
        Job *j;
815
        Iterator i;
816
817
818
819
        int r;

        assert(m);

Lennart Poettering's avatar
Lennart Poettering committed
820
821
        /* First step, check whether any of the jobs for one specific
         * task conflict. If so, try to drop one of them. */
822
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
Lennart Poettering's avatar
Lennart Poettering committed
823
824
825
826
                JobType t;
                Job *k;

                t = j->type;
827
                LIST_FOREACH(transaction, k, j->transaction_next) {
828
                        if (job_type_merge(&t, k->type) >= 0)
Lennart Poettering's avatar
Lennart Poettering committed
829
830
831
832
833
834
                                continue;

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

835
                        if ((r = delete_one_unmergeable_job(m, j)) >= 0)
Lennart Poettering's avatar
Lennart Poettering committed
836
837
838
839
840
841
                                /* 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 */
842
843
                        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
844
845
846
847
848
                        return r;
                }
        }

        /* Second step, merge the jobs. */
849
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
850
851
852
                JobType t = j->type;
                Job *k;

853
                /* Merge all transactions */
854
                LIST_FOREACH(transaction, k, j->transaction_next)
Lennart Poettering's avatar
Lennart Poettering committed
855
                        assert_se(job_type_merge(&t, k->type) == 0);
856

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

861
                while ((k = j->transaction_next)) {
862
                        if (j->installed) {
863
                                transaction_merge_and_delete_job(m, k, j, t);
864
865
                                j = k;
                        } else
866
                                transaction_merge_and_delete_job(m, j, k, t);
867
868
869
870
871
872
                }

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

873
        return 0;
874
875
}

876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
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;

907
                        log_debug("Found redundant job %s/%s, dropping.", j->unit->meta.id, job_type_to_string(j->type));
908
909
910
911
912
913
914
915
                        transaction_delete_job(m, j, false);
                        again = true;
                        break;
                }

        } while (again);
}

Lennart Poettering's avatar
Lennart Poettering committed
916
917
static bool unit_matters_to_anchor(Unit *u, Job *j) {
        assert(u);
Lennart Poettering's avatar
Lennart Poettering committed
918
919
        assert(!j->transaction_prev);

Lennart Poettering's avatar
Lennart Poettering committed
920
        /* Checks whether at least one of the jobs for this unit
Lennart Poettering's avatar
Lennart Poettering committed
921
922
         * matters to the anchor. */

923
        LIST_FOREACH(transaction, j, j)
Lennart Poettering's avatar
Lennart Poettering committed
924
925
926
927
928
929
                if (j->matters_to_anchor)
                        return true;

        return false;
}

930
static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned generation, DBusError *e) {
931
        Iterator i;
Lennart Poettering's avatar
Lennart Poettering committed
932
        Unit *u;
933
        int r;
934
935
936

        assert(m);
        assert(j);
Lennart Poettering's avatar
Lennart Poettering committed
937
938
939
940
        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. */
941

942
943
        /* Have we seen this before? */
        if (j->generation == generation) {
944
                Job *k, *delete;
945

946
947
948
949
950
                /* 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;
951

952
953
954
955
956
957
                /* 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. */
958
                log_warning("Found ordering cycle on %s/%s", j->unit->meta.id, job_type_to_string(j->type));
959

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

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

965
966
                        if (!delete &&
                            !k->installed &&
Lennart Poettering's avatar
Lennart Poettering committed
967
                            !unit_matters_to_anchor(k->unit, k)) {
Lennart Poettering's avatar
Lennart Poettering committed
968
969
                                /* Ok, we can drop this one, so let's
                                 * do so. */
970
                                delete = k;
971
972
973
                        }

                        /* Check if this in fact was the beginning of
974
                         * the cycle */
975
976
977
978
                        if (k == j)
                                break;
                }

979
980
981
982
983
984
985

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

986
                log_error("Unable to break cycle");
987

988
                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
989
                return -ENOEXEC;
990
991
        }

Lennart Poettering's avatar
Lennart Poettering committed
992
        /* Make the marker point to where we come from, so that we can
993
994
995
996
         * 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;
997
998
        j->generation = generation;

Lennart Poettering's avatar
Lennart Poettering committed
999
        /* We assume that the the dependencies are bidirectional, and
Lennart Poettering's avatar
Lennart Poettering committed
1000
1001
         * hence can ignore UNIT_AFTER */
        SET_FOREACH(u, j->unit->meta.dependencies[UNIT_BEFORE], i) {
1002
1003
                Job *o;

Lennart Poettering's avatar
Lennart Poettering committed
1004
1005
                /* Is there a job for this unit? */
                if (!(o = hashmap_get(m->transaction_jobs, u)))
Lennart Poettering's avatar
Lennart Poettering committed
1006
1007
1008
1009

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

1013
                if ((r = transaction_verify_order_one(m, o, j, generation, e)) < 0)
1014
1015
1016
                        return r;
        }

1017
1018
1019
1020
        /* Ok, let's backtrack, and remember that this entry is not on
         * our path anymore. */
        j->marker = NULL;

1021
1022
1023
        return 0;
}

1024
static int transaction_verify_order(Manager *m, unsigned *generation, DBusError *e) {
Lennart Poettering's avatar
Lennart Poettering committed
1025
1026
        Job *j;
        int r;
1027
        Iterator i;
1028
        unsigned g;
Lennart Poettering's avatar
Lennart Poettering committed
1029

1030
1031
1032
        assert(m);
        assert(generation);

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

1036
1037
        g = (*generation)++;

1038
        HASHMAP_FOREACH(j, m->transaction_jobs, i)
1039
                if ((r = transaction_verify_order_one(m, j, NULL, g, e)) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
1040
                        return r;
1041
1042
1043
1044
1045
1046
1047
1048
1049

        return 0;
}

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

        assert(m);

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

1052
        do {
1053
                Iterator i;
1054
1055
1056
1057
                Job *j;

                again = false;

1058
                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1059
1060
1061
                        if (j->object_list)
                                continue;

1062
                        log_debug("Garbage collecting job %s/%s", j->unit->meta.id, job_type_to_string(j->type));
1063
                        transaction_delete_job(m, j, true);
1064
1065
1066
1067
1068
1069
1070
                        again = true;
                        break;
                }

        } while (again);
}

1071
static int transaction_is_destructive(Manager *m, DBusError *e) {
1072
        Iterator i;
1073
        Job *j;
1074
1075
1076

        assert(m);

1077
1078
        /* Checks whether applying this transaction means that
         * existing jobs would be replaced */
1079

1080
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1081
1082
1083
1084
1085

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

Lennart Poettering's avatar
Lennart Poettering committed
1086
1087
                if (j->unit->meta.job &&
                    j->unit->meta.job != j &&
1088
1089
1090
                    !job_type_is_superset(j->type, j->unit->meta.job->type)) {

                        dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
1091
                        return -EEXIST;
1092
                }
1093
        }
1094

1095
1096
1097
        return 0;
}

1098
1099
1100
1101
1102
1103
1104
1105
1106
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;
1107
                Iterator i;
1108
1109
1110

                again = false;

1111
1112
                HASHMAP_FOREACH(j, m->transaction_jobs, i) {
                        LIST_FOREACH(transaction, j, j) {
1113
                                bool stops_running_service, changes_existing_job;
1114
1115
1116
1117
1118
1119
1120
1121

                                /* 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 */
1122
1123
1124
1125
1126

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

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

                                if (!stops_running_service && !changes_existing_job)
1130
1131
                                        continue;

1132
                                if (stops_running_service)
1133
                                        log_info("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type));
1134
1135

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

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

1141
                                transaction_delete_job(m, j, true);
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
                                again = true;
                                break;
                        }

                        if (again)
                                break;
                }

        } while (again);
}

1153
static int transaction_apply(Manager *m) {
1154
        Iterator i;
1155
1156
1157
        Job *j;
        int r;

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

1160
        HASHMAP_FOREACH(j, m->transaction_jobs, i) {
1161
1162
1163
1164
                /* Assume merged */
                assert(!j->transaction_prev);
                assert(!j->transaction_next);

1165
                if (j->installed)
1166
1167
1168
                        continue;

                if ((r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j)) < 0)
1169
1170
1171
                        goto rollback;
        }

1172
        while ((j = hashmap_steal_first(m->transaction_jobs))) {
1173
                if (j->installed)
1174
1175
                        continue;

Lennart Poettering's avatar
Lennart Poettering committed
1176
1177
                if (j->unit->meta.job)
                        job_free(j->unit->meta.job);
1178

Lennart Poettering's avatar
Lennart Poettering committed
1179
                j->unit->meta.job = j;
1180
                j->installed = true;
1181

1182
1183
1184
1185
1186
1187
                /* We're fully installed. Now let's free data we don't
                 * need anymore. */

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

1188
1189
                job_add_to_run_queue(j);
                job_add_to_dbus_queue(j);
1190
                job_start_timer(j);
1191
1192
1193
        }

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

1196
1197
1198
1199
        return 0;

rollback:

1200
        HASHMAP_FOREACH(j, m->transaction_jobs