unit.c 85.6 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
/***
  This file is part of systemd.

  Copyright 2010 Lennart Poettering

  systemd is free software; you can redistribute it and/or modify it
9
10
  under the terms of the GNU Lesser General Public License as published by
  the Free Software Foundation; either version 2.1 of the License, or
11
12
13
14
15
  (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
16
  Lesser General Public License for more details.
17

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

Lennart Poettering's avatar
Lennart Poettering committed
22
23
24
25
26
27
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <sys/poll.h>
28
29
#include <stdlib.h>
#include <unistd.h>
30
#include <sys/stat.h>
Lennart Poettering's avatar
Lennart Poettering committed
31

32
33
#include "systemd/sd-id128.h"
#include "systemd/sd-messages.h"
Lennart Poettering's avatar
Lennart Poettering committed
34
35
36
37
#include "set.h"
#include "unit.h"
#include "macro.h"
#include "strv.h"
Kay Sievers's avatar
Kay Sievers committed
38
#include "path-util.h"
Lennart Poettering's avatar
Lennart Poettering committed
39
40
41
#include "load-fragment.h"
#include "load-dropin.h"
#include "log.h"
42
43
#include "unit-name.h"
#include "specifier.h"
44
#include "dbus-unit.h"
45
#include "special.h"
46
#include "cgroup-util.h"
47
#include "missing.h"
48
#include "cgroup-attr.h"
Lennart Poettering's avatar
Lennart Poettering committed
49
50
51
52
53
54
55
56
57

const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
        [UNIT_SERVICE] = &service_vtable,
        [UNIT_TIMER] = &timer_vtable,
        [UNIT_SOCKET] = &socket_vtable,
        [UNIT_TARGET] = &target_vtable,
        [UNIT_DEVICE] = &device_vtable,
        [UNIT_MOUNT] = &mount_vtable,
        [UNIT_AUTOMOUNT] = &automount_vtable,
Maarten Lankhorst's avatar
Maarten Lankhorst committed
58
        [UNIT_SNAPSHOT] = &snapshot_vtable,
59
60
        [UNIT_SWAP] = &swap_vtable,
        [UNIT_PATH] = &path_vtable
Lennart Poettering's avatar
Lennart Poettering committed
61
62
};

63
Unit *unit_new(Manager *m, size_t size) {
Lennart Poettering's avatar
Lennart Poettering committed
64
65
66
        Unit *u;

        assert(m);
Michal Schmidt's avatar
Michal Schmidt committed
67
        assert(size >= sizeof(Unit));
Lennart Poettering's avatar
Lennart Poettering committed
68

69
70
        u = malloc0(size);
        if (!u)
Lennart Poettering's avatar
Lennart Poettering committed
71
72
                return NULL;

Michal Schmidt's avatar
Michal Schmidt committed
73
74
        u->names = set_new(string_hash_func, string_compare_func);
        if (!u->names) {
Lennart Poettering's avatar
Lennart Poettering committed
75
76
77
78
                free(u);
                return NULL;
        }

Michal Schmidt's avatar
Michal Schmidt committed
79
80
81
82
83
        u->manager = m;
        u->type = _UNIT_TYPE_INVALID;
        u->deserialized_job = _JOB_TYPE_INVALID;
        u->default_dependencies = true;
        u->unit_file_state = _UNIT_FILE_STATE_INVALID;
Lennart Poettering's avatar
Lennart Poettering committed
84
85
86
87

        return u;
}

88
89
90
91
bool unit_has_name(Unit *u, const char *name) {
        assert(u);
        assert(name);

Michal Schmidt's avatar
Michal Schmidt committed
92
        return !!set_get(u->names, (char*) name);
93
94
}

Lennart Poettering's avatar
Lennart Poettering committed
95
96
int unit_add_name(Unit *u, const char *text) {
        UnitType t;
97
        char *s, *i = NULL;
Lennart Poettering's avatar
Lennart Poettering committed
98
99
100
101
102
        int r;

        assert(u);
        assert(text);

103
        if (unit_name_is_template(text)) {
Michal Schmidt's avatar
Michal Schmidt committed
104
                if (!u->instance)
105
                        return -EINVAL;
Lennart Poettering's avatar
Lennart Poettering committed
106

Michal Schmidt's avatar
Michal Schmidt committed
107
                s = unit_name_replace_instance(text, u->instance);
108
109
        } else
                s = strdup(text);
Lennart Poettering's avatar
Lennart Poettering committed
110

111
112
        if (!s)
                return -ENOMEM;
Lennart Poettering's avatar
Lennart Poettering committed
113

114
        if (!unit_name_is_valid(s, false)) {
115
116
117
                r = -EINVAL;
                goto fail;
        }
118

119
        assert_se((t = unit_name_to_type(s)) >= 0);
Lennart Poettering's avatar
Lennart Poettering committed
120

Michal Schmidt's avatar
Michal Schmidt committed
121
        if (u->type != _UNIT_TYPE_INVALID && t != u->type) {
122
123
124
                r = -EINVAL;
                goto fail;
        }
Lennart Poettering's avatar
Lennart Poettering committed
125

126
127
        if ((r = unit_name_to_instance(s, &i)) < 0)
                goto fail;
Lennart Poettering's avatar
Lennart Poettering committed
128

129
130
        if (i && unit_vtable[t]->no_instances) {
                r = -EINVAL;
131
                goto fail;
132
        }
133

134
135
        /* Ensure that this unit is either instanced or not instanced,
         * but not both. */
Michal Schmidt's avatar
Michal Schmidt committed
136
        if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i) {
137
138
139
140
141
                r = -EINVAL;
                goto fail;
        }

        if (unit_vtable[t]->no_alias &&
Michal Schmidt's avatar
Michal Schmidt committed
142
143
            !set_isempty(u->names) &&
            !set_get(u->names, s)) {
144
145
146
147
                r = -EEXIST;
                goto fail;
        }

Michal Schmidt's avatar
Michal Schmidt committed
148
        if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES) {
149
150
151
152
                r = -E2BIG;
                goto fail;
        }

Michal Schmidt's avatar
Michal Schmidt committed
153
        if ((r = set_put(u->names, s)) < 0) {
154
155
156
                if (r == -EEXIST)
                        r = 0;
                goto fail;
Lennart Poettering's avatar
Lennart Poettering committed
157
158
        }

Michal Schmidt's avatar
Michal Schmidt committed
159
160
        if ((r = hashmap_put(u->manager->units, s, u)) < 0) {
                set_remove(u->names, s);
161
                goto fail;
Lennart Poettering's avatar
Lennart Poettering committed
162
163
        }

Michal Schmidt's avatar
Michal Schmidt committed
164
        if (u->type == _UNIT_TYPE_INVALID) {
Lennart Poettering's avatar
Lennart Poettering committed
165

Michal Schmidt's avatar
Michal Schmidt committed
166
167
168
                u->type = t;
                u->id = s;
                u->instance = i;
169

Michal Schmidt's avatar
Michal Schmidt committed
170
                LIST_PREPEND(Unit, units_by_type, u->manager->units_by_type[t], u);
171
172
173

                if (UNIT_VTABLE(u)->init)
                        UNIT_VTABLE(u)->init(u);
174
175
        } else
                free(i);
Lennart Poettering's avatar
Lennart Poettering committed
176

177
        unit_add_to_dbus_queue(u);
Lennart Poettering's avatar
Lennart Poettering committed
178
        return 0;
179
180
181
182
183
184

fail:
        free(s);
        free(i);

        return r;
Lennart Poettering's avatar
Lennart Poettering committed
185
186
}

187
int unit_choose_id(Unit *u, const char *name) {
188
189
        char *s, *t = NULL, *i;
        int r;
190
191
192
193

        assert(u);
        assert(name);

194
195
        if (unit_name_is_template(name)) {

Michal Schmidt's avatar
Michal Schmidt committed
196
                if (!u->instance)
197
198
                        return -EINVAL;

Michal Schmidt's avatar
Michal Schmidt committed
199
                if (!(t = unit_name_replace_instance(name, u->instance)))
200
201
202
203
204
                        return -ENOMEM;

                name = t;
        }

205
        /* Selects one of the names of this unit as the id */
Michal Schmidt's avatar
Michal Schmidt committed
206
        s = set_get(u->names, (char*) name);
207
        free(t);
208

209
        if (!s)
210
211
                return -ENOENT;

212
213
214
        if ((r = unit_name_to_instance(s, &i)) < 0)
                return r;

Michal Schmidt's avatar
Michal Schmidt committed
215
        u->id = s;
216

Michal Schmidt's avatar
Michal Schmidt committed
217
218
        free(u->instance);
        u->instance = i;
219

220
        unit_add_to_dbus_queue(u);
221

222
223
224
        return 0;
}

Lennart Poettering's avatar
Lennart Poettering committed
225
226
227
228
229
230
231
232
int unit_set_description(Unit *u, const char *description) {
        char *s;

        assert(u);

        if (!(s = strdup(description)))
                return -ENOMEM;

Michal Schmidt's avatar
Michal Schmidt committed
233
234
        free(u->description);
        u->description = s;
235
236

        unit_add_to_dbus_queue(u);
Lennart Poettering's avatar
Lennart Poettering committed
237
238
239
        return 0;
}

240
241
242
bool unit_check_gc(Unit *u) {
        assert(u);

Michal Schmidt's avatar
Michal Schmidt committed
243
        if (u->load_state == UNIT_STUB)
244
245
                return true;

246
247
248
        if (UNIT_VTABLE(u)->no_gc)
                return true;

Michal Schmidt's avatar
Michal Schmidt committed
249
        if (u->no_gc)
250
251
                return true;

Michal Schmidt's avatar
Michal Schmidt committed
252
        if (u->job)
253
254
                return true;

255
256
257
        if (u->nop_job)
                return true;

258
259
260
261
262
263
264
265
266
267
        if (unit_active_state(u) != UNIT_INACTIVE)
                return true;

        if (UNIT_VTABLE(u)->check_gc)
                if (UNIT_VTABLE(u)->check_gc(u))
                        return true;

        return false;
}

Lennart Poettering's avatar
Lennart Poettering committed
268
269
void unit_add_to_load_queue(Unit *u) {
        assert(u);
Michal Schmidt's avatar
Michal Schmidt committed
270
        assert(u->type != _UNIT_TYPE_INVALID);
Lennart Poettering's avatar
Lennart Poettering committed
271

Michal Schmidt's avatar
Michal Schmidt committed
272
        if (u->load_state != UNIT_STUB || u->in_load_queue)
Lennart Poettering's avatar
Lennart Poettering committed
273
274
                return;

Michal Schmidt's avatar
Michal Schmidt committed
275
276
        LIST_PREPEND(Unit, load_queue, u->manager->load_queue, u);
        u->in_load_queue = true;
Lennart Poettering's avatar
Lennart Poettering committed
277
278
}

279
280
281
void unit_add_to_cleanup_queue(Unit *u) {
        assert(u);

Michal Schmidt's avatar
Michal Schmidt committed
282
        if (u->in_cleanup_queue)
283
284
                return;

Michal Schmidt's avatar
Michal Schmidt committed
285
286
        LIST_PREPEND(Unit, cleanup_queue, u->manager->cleanup_queue, u);
        u->in_cleanup_queue = true;
287
288
}

289
290
291
void unit_add_to_gc_queue(Unit *u) {
        assert(u);

Michal Schmidt's avatar
Michal Schmidt committed
292
        if (u->in_gc_queue || u->in_cleanup_queue)
293
294
295
296
297
                return;

        if (unit_check_gc(u))
                return;

Michal Schmidt's avatar
Michal Schmidt committed
298
299
        LIST_PREPEND(Unit, gc_queue, u->manager->gc_queue, u);
        u->in_gc_queue = true;
300

Michal Schmidt's avatar
Michal Schmidt committed
301
        u->manager->n_in_gc_queue ++;
302

Michal Schmidt's avatar
Michal Schmidt committed
303
304
        if (u->manager->gc_queue_timestamp <= 0)
                u->manager->gc_queue_timestamp = now(CLOCK_MONOTONIC);
305
306
}

307
308
void unit_add_to_dbus_queue(Unit *u) {
        assert(u);
Michal Schmidt's avatar
Michal Schmidt committed
309
        assert(u->type != _UNIT_TYPE_INVALID);
310

Michal Schmidt's avatar
Michal Schmidt committed
311
        if (u->load_state == UNIT_STUB || u->in_dbus_queue)
312
313
                return;

314
        /* Shortcut things if nobody cares */
Michal Schmidt's avatar
Michal Schmidt committed
315
316
        if (!bus_has_subscriber(u->manager)) {
                u->sent_dbus_new_signal = true;
317
318
319
                return;
        }

Michal Schmidt's avatar
Michal Schmidt committed
320
321
        LIST_PREPEND(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
        u->in_dbus_queue = true;
322
323
}

Lennart Poettering's avatar
Lennart Poettering committed
324
325
326
327
328
329
330
331
332
333
334
335
336
static void bidi_set_free(Unit *u, Set *s) {
        Iterator i;
        Unit *other;

        assert(u);

        /* Frees the set and makes sure we are dropped from the
         * inverse pointers */

        SET_FOREACH(other, s, i) {
                UnitDependency d;

                for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
Michal Schmidt's avatar
Michal Schmidt committed
337
                        set_remove(other->dependencies[d], u);
338
339

                unit_add_to_gc_queue(other);
Lennart Poettering's avatar
Lennart Poettering committed
340
341
342
343
344
345
346
347
348
349
350
351
        }

        set_free(s);
}

void unit_free(Unit *u) {
        UnitDependency d;
        Iterator i;
        char *t;

        assert(u);

352
353
        bus_unit_send_removed_signal(u);

Michal Schmidt's avatar
Michal Schmidt committed
354
        if (u->load_state != UNIT_STUB)
355
356
357
                if (UNIT_VTABLE(u)->done)
                        UNIT_VTABLE(u)->done(u);

Michal Schmidt's avatar
Michal Schmidt committed
358
359
        SET_FOREACH(t, u->names, i)
                hashmap_remove_value(u->manager->units, t, u);
Lennart Poettering's avatar
Lennart Poettering committed
360

Michal Schmidt's avatar
Michal Schmidt committed
361
362
363
364
365
        if (u->job) {
                Job *j = u->job;
                job_uninstall(j);
                job_free(j);
        }
366

367
368
369
370
371
372
        if (u->nop_job) {
                Job *j = u->nop_job;
                job_uninstall(j);
                job_free(j);
        }

373
        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
Michal Schmidt's avatar
Michal Schmidt committed
374
                bidi_set_free(u, u->dependencies[d]);
375

376
377
378
379
380
        if (u->requires_mounts_for) {
                LIST_REMOVE(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
                strv_free(u->requires_mounts_for);
        }

Michal Schmidt's avatar
Michal Schmidt committed
381
382
        if (u->type != _UNIT_TYPE_INVALID)
                LIST_REMOVE(Unit, units_by_type, u->manager->units_by_type[u->type], u);
Lennart Poettering's avatar
Lennart Poettering committed
383

Michal Schmidt's avatar
Michal Schmidt committed
384
385
        if (u->in_load_queue)
                LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
Lennart Poettering's avatar
Lennart Poettering committed
386

Michal Schmidt's avatar
Michal Schmidt committed
387
388
        if (u->in_dbus_queue)
                LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
389

Michal Schmidt's avatar
Michal Schmidt committed
390
391
        if (u->in_cleanup_queue)
                LIST_REMOVE(Unit, cleanup_queue, u->manager->cleanup_queue, u);
392

Michal Schmidt's avatar
Michal Schmidt committed
393
394
395
        if (u->in_gc_queue) {
                LIST_REMOVE(Unit, gc_queue, u->manager->gc_queue, u);
                u->manager->n_in_gc_queue--;
396
397
        }

Michal Schmidt's avatar
Michal Schmidt committed
398
399
        cgroup_bonding_free_list(u->cgroup_bondings, u->manager->n_reloading <= 0);
        cgroup_attribute_free_list(u->cgroup_attributes);
Lennart Poettering's avatar
Lennart Poettering committed
400

Michal Schmidt's avatar
Michal Schmidt committed
401
        free(u->description);
402
        strv_free(u->documentation);
Michal Schmidt's avatar
Michal Schmidt committed
403
        free(u->fragment_path);
404
        free(u->source_path);
Michal Schmidt's avatar
Michal Schmidt committed
405
        free(u->instance);
Lennart Poettering's avatar
Lennart Poettering committed
406

Michal Schmidt's avatar
Michal Schmidt committed
407
        set_free_free(u->names);
Lennart Poettering's avatar
Lennart Poettering committed
408

Michal Schmidt's avatar
Michal Schmidt committed
409
        condition_free_list(u->conditions);
410

Michal Schmidt's avatar
Michal Schmidt committed
411
412
        while (u->refs)
                unit_ref_unset(u->refs);
413

Lennart Poettering's avatar
Lennart Poettering committed
414
415
416
417
418
419
        free(u);
}

UnitActiveState unit_active_state(Unit *u) {
        assert(u);

Michal Schmidt's avatar
Michal Schmidt committed
420
        if (u->load_state == UNIT_MERGED)
421
422
423
424
                return unit_active_state(unit_follow_merge(u));

        /* After a reload it might happen that a unit is not correctly
         * loaded but still has a process around. That's why we won't
425
         * shortcut failed loading to UNIT_INACTIVE_FAILED. */
Lennart Poettering's avatar
Lennart Poettering committed
426
427
428
429

        return UNIT_VTABLE(u)->active_state(u);
}

430
431
432
433
434
435
const char* unit_sub_state_to_string(Unit *u) {
        assert(u);

        return UNIT_VTABLE(u)->sub_state_to_string(u);
}

436
437
438
static void complete_move(Set **s, Set **other) {
        assert(s);
        assert(other);
Lennart Poettering's avatar
Lennart Poettering committed
439

440
441
        if (!*other)
                return;
Lennart Poettering's avatar
Lennart Poettering committed
442
443

        if (*s)
444
445
446
447
448
449
                set_move(*s, *other);
        else {
                *s = *other;
                *other = NULL;
        }
}
Lennart Poettering's avatar
Lennart Poettering committed
450

451
452
453
static void merge_names(Unit *u, Unit *other) {
        char *t;
        Iterator i;
Lennart Poettering's avatar
Lennart Poettering committed
454

455
456
457
        assert(u);
        assert(other);

Michal Schmidt's avatar
Michal Schmidt committed
458
        complete_move(&u->names, &other->names);
459

Michal Schmidt's avatar
Michal Schmidt committed
460
461
462
        set_free_free(other->names);
        other->names = NULL;
        other->id = NULL;
463

Michal Schmidt's avatar
Michal Schmidt committed
464
465
        SET_FOREACH(t, u->names, i)
                assert_se(hashmap_replace(u->manager->units, t, u) == 0);
Lennart Poettering's avatar
Lennart Poettering committed
466
467
}

468
469
470
static void merge_dependencies(Unit *u, Unit *other, UnitDependency d) {
        Iterator i;
        Unit *back;
Lennart Poettering's avatar
Lennart Poettering committed
471
        int r;
472
473
474
475
476

        assert(u);
        assert(other);
        assert(d < _UNIT_DEPENDENCY_MAX);

477
        /* Fix backwards pointers */
Michal Schmidt's avatar
Michal Schmidt committed
478
        SET_FOREACH(back, other->dependencies[d], i) {
479
480
481
                UnitDependency k;

                for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++)
Michal Schmidt's avatar
Michal Schmidt committed
482
                        if ((r = set_remove_and_put(back->dependencies[k], other, u)) < 0) {
483
484

                                if (r == -EEXIST)
Michal Schmidt's avatar
Michal Schmidt committed
485
                                        set_remove(back->dependencies[k], other);
486
487
488
489
490
                                else
                                        assert(r == -ENOENT);
                        }
        }

Michal Schmidt's avatar
Michal Schmidt committed
491
        complete_move(&u->dependencies[d], &other->dependencies[d]);
492

Michal Schmidt's avatar
Michal Schmidt committed
493
494
        set_free(other->dependencies[d]);
        other->dependencies[d] = NULL;
495
496
497
}

int unit_merge(Unit *u, Unit *other) {
Lennart Poettering's avatar
Lennart Poettering committed
498
499
500
501
        UnitDependency d;

        assert(u);
        assert(other);
Michal Schmidt's avatar
Michal Schmidt committed
502
503
        assert(u->manager == other->manager);
        assert(u->type != _UNIT_TYPE_INVALID);
Lennart Poettering's avatar
Lennart Poettering committed
504

505
506
        other = unit_follow_merge(other);

507
508
509
        if (other == u)
                return 0;

Michal Schmidt's avatar
Michal Schmidt committed
510
        if (u->type != other->type)
511
512
                return -EINVAL;

Michal Schmidt's avatar
Michal Schmidt committed
513
        if (!u->instance != !other->instance)
Lennart Poettering's avatar
Lennart Poettering committed
514
515
                return -EINVAL;

Michal Schmidt's avatar
Michal Schmidt committed
516
517
        if (other->load_state != UNIT_STUB &&
            other->load_state != UNIT_ERROR)
518
                return -EEXIST;
Lennart Poettering's avatar
Lennart Poettering committed
519

Michal Schmidt's avatar
Michal Schmidt committed
520
        if (other->job)
521
522
                return -EEXIST;

523
524
525
        if (other->nop_job)
                return -EEXIST;

526
        if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other)))
527
528
                return -EEXIST;

Lennart Poettering's avatar
Lennart Poettering committed
529
        /* Merge names */
530
        merge_names(u, other);
Lennart Poettering's avatar
Lennart Poettering committed
531

532
        /* Redirect all references */
Michal Schmidt's avatar
Michal Schmidt committed
533
534
        while (other->refs)
                unit_ref_set(other->refs, u);
535

Lennart Poettering's avatar
Lennart Poettering committed
536
537
        /* Merge dependencies */
        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
538
                merge_dependencies(u, other, d);
Lennart Poettering's avatar
Lennart Poettering committed
539

Michal Schmidt's avatar
Michal Schmidt committed
540
541
        other->load_state = UNIT_MERGED;
        other->merged_into = u;
542

543
544
        /* If there is still some data attached to the other node, we
         * don't need it anymore, and can free it. */
Michal Schmidt's avatar
Michal Schmidt committed
545
        if (other->load_state != UNIT_STUB)
546
547
548
549
                if (UNIT_VTABLE(other)->done)
                        UNIT_VTABLE(other)->done(other);

        unit_add_to_dbus_queue(u);
550
551
552
553
554
555
556
        unit_add_to_cleanup_queue(other);

        return 0;
}

int unit_merge_by_name(Unit *u, const char *name) {
        Unit *other;
557
558
        int r;
        char *s = NULL;
559
560
561
562

        assert(u);
        assert(name);

563
        if (unit_name_is_template(name)) {
Michal Schmidt's avatar
Michal Schmidt committed
564
                if (!u->instance)
565
566
                        return -EINVAL;

Michal Schmidt's avatar
Michal Schmidt committed
567
                if (!(s = unit_name_replace_instance(name, u->instance)))
568
569
570
571
572
                        return -ENOMEM;

                name = s;
        }

Michal Schmidt's avatar
Michal Schmidt committed
573
        if (!(other = manager_get_unit(u->manager, name)))
574
575
576
                r = unit_add_name(u, name);
        else
                r = unit_merge(u, other);
577

578
579
        free(s);
        return r;
580
581
582
583
584
}

Unit* unit_follow_merge(Unit *u) {
        assert(u);

Michal Schmidt's avatar
Michal Schmidt committed
585
586
        while (u->load_state == UNIT_MERGED)
                assert_se(u = u->merged_into);
587
588
589
590
591
592
593
594
595
596

        return u;
}

int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
        int r;

        assert(u);
        assert(c);

597
598
        if (c->std_output != EXEC_OUTPUT_KMSG &&
            c->std_output != EXEC_OUTPUT_SYSLOG &&
599
            c->std_output != EXEC_OUTPUT_JOURNAL &&
600
601
            c->std_output != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
            c->std_output != EXEC_OUTPUT_SYSLOG_AND_CONSOLE &&
602
            c->std_output != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
603
            c->std_error != EXEC_OUTPUT_KMSG &&
604
            c->std_error != EXEC_OUTPUT_SYSLOG &&
605
            c->std_error != EXEC_OUTPUT_JOURNAL &&
606
            c->std_error != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
607
            c->std_error != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
608
            c->std_error != EXEC_OUTPUT_SYSLOG_AND_CONSOLE)
609
610
611
612
613
                return 0;

        /* If syslog or kernel logging is requested, make sure our own
         * logging daemon is run first. */

Michal Schmidt's avatar
Michal Schmidt committed
614
        if (u->manager->running_as == MANAGER_SYSTEM)
615
                if ((r = unit_add_two_dependencies_by_name(u, UNIT_REQUIRES, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true)) < 0)
616
617
                        return r;

Lennart Poettering's avatar
Lennart Poettering committed
618
619
620
621
622
623
        return 0;
}

const char *unit_description(Unit *u) {
        assert(u);

Michal Schmidt's avatar
Michal Schmidt committed
624
625
        if (u->description)
                return u->description;
Lennart Poettering's avatar
Lennart Poettering committed
626

Michal Schmidt's avatar
Michal Schmidt committed
627
        return strna(u->id);
Lennart Poettering's avatar
Lennart Poettering committed
628
629
630
}

void unit_dump(Unit *u, FILE *f, const char *prefix) {
631
        char *t, **j;
Lennart Poettering's avatar
Lennart Poettering committed
632
633
        UnitDependency d;
        Iterator i;
634
635
        char *p2;
        const char *prefix2;
636
637
638
639
        char
                timestamp1[FORMAT_TIMESTAMP_MAX],
                timestamp2[FORMAT_TIMESTAMP_MAX],
                timestamp3[FORMAT_TIMESTAMP_MAX],
640
641
                timestamp4[FORMAT_TIMESTAMP_MAX],
                timespan[FORMAT_TIMESPAN_MAX];
642
        Unit *following;
Lennart Poettering's avatar
Lennart Poettering committed
643
644

        assert(u);
Michal Schmidt's avatar
Michal Schmidt committed
645
        assert(u->type >= 0);
Lennart Poettering's avatar
Lennart Poettering committed
646
647
648

        if (!prefix)
                prefix = "";
649
650
        p2 = strappend(prefix, "\t");
        prefix2 = p2 ? p2 : prefix;
Lennart Poettering's avatar
Lennart Poettering committed
651
652

        fprintf(f,
653
                "%s-> Unit %s:\n"
Lennart Poettering's avatar
Lennart Poettering committed
654
                "%s\tDescription: %s\n"
655
                "%s\tInstance: %s\n"
Lennart Poettering's avatar
Lennart Poettering committed
656
                "%s\tUnit Load State: %s\n"
657
                "%s\tUnit Active State: %s\n"
658
                "%s\tInactive Exit Timestamp: %s\n"
659
                "%s\tActive Enter Timestamp: %s\n"
660
                "%s\tActive Exit Timestamp: %s\n"
661
                "%s\tInactive Enter Timestamp: %s\n"
662
663
                "%s\tGC Check Good: %s\n"
                "%s\tNeed Daemon Reload: %s\n",
Michal Schmidt's avatar
Michal Schmidt committed
664
                prefix, u->id,
Lennart Poettering's avatar
Lennart Poettering committed
665
                prefix, unit_description(u),
Michal Schmidt's avatar
Michal Schmidt committed
666
667
                prefix, strna(u->instance),
                prefix, unit_load_state_to_string(u->load_state),
668
                prefix, unit_active_state_to_string(unit_active_state(u)),
Michal Schmidt's avatar
Michal Schmidt committed
669
670
671
672
                prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->inactive_exit_timestamp.realtime)),
                prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)),
                prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)),
                prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->inactive_enter_timestamp.realtime)),
673
674
                prefix, yes_no(unit_check_gc(u)),
                prefix, yes_no(unit_need_daemon_reload(u)));
675

Michal Schmidt's avatar
Michal Schmidt committed
676
        SET_FOREACH(t, u->names, i)
Lennart Poettering's avatar
Lennart Poettering committed
677
678
                fprintf(f, "%s\tName: %s\n", prefix, t);

679
680
681
        STRV_FOREACH(j, u->documentation)
                fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);

682
        if ((following = unit_following(u)))
Michal Schmidt's avatar
Michal Schmidt committed
683
                fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
684

Michal Schmidt's avatar
Michal Schmidt committed
685
686
        if (u->fragment_path)
                fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
687

688
689
690
        if (u->source_path)
                fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);

Michal Schmidt's avatar
Michal Schmidt committed
691
692
        if (u->job_timeout > 0)
                fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout));
693

Michal Schmidt's avatar
Michal Schmidt committed
694
        condition_dump_list(u->conditions, f, prefix);
695

Michal Schmidt's avatar
Michal Schmidt committed
696
        if (dual_timestamp_is_set(&u->condition_timestamp))
697
698
699
                fprintf(f,
                        "%s\tCondition Timestamp: %s\n"
                        "%s\tCondition Result: %s\n",
Michal Schmidt's avatar
Michal Schmidt committed
700
701
                        prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->condition_timestamp.realtime)),
                        prefix, yes_no(u->condition_result));
702

Lennart Poettering's avatar
Lennart Poettering committed
703
704
705
        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
                Unit *other;

Michal Schmidt's avatar
Michal Schmidt committed
706
707
                SET_FOREACH(other, u->dependencies[d], i)
                        fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->id);
Lennart Poettering's avatar
Lennart Poettering committed
708
709
        }

710
711
712
713
714
715
716
717
718
719
        if (!strv_isempty(u->requires_mounts_for)) {
                fprintf(f,
                        "%s\tRequiresMountsFor:", prefix);

                STRV_FOREACH(j, u->requires_mounts_for)
                        fprintf(f, " %s", *j);

                fputs("\n", f);
        }

Michal Schmidt's avatar
Michal Schmidt committed
720
        if (u->load_state == UNIT_LOADED) {
721
722
723
                CGroupBonding *b;
                CGroupAttribute *a;

724
                fprintf(f,
725
                        "%s\tStopWhenUnneeded: %s\n"
726
727
                        "%s\tRefuseManualStart: %s\n"
                        "%s\tRefuseManualStop: %s\n"
728
                        "%s\tDefaultDependencies: %s\n"
729
                        "%s\tOnFailureIsolate: %s\n"
730
731
                        "%s\tIgnoreOnIsolate: %s\n"
                        "%s\tIgnoreOnSnapshot: %s\n",
Michal Schmidt's avatar
Michal Schmidt committed
732
733
734
735
736
737
738
739
740
                        prefix, yes_no(u->stop_when_unneeded),
                        prefix, yes_no(u->refuse_manual_start),
                        prefix, yes_no(u->refuse_manual_stop),
                        prefix, yes_no(u->default_dependencies),
                        prefix, yes_no(u->on_failure_isolate),
                        prefix, yes_no(u->ignore_on_isolate),
                        prefix, yes_no(u->ignore_on_snapshot));

                LIST_FOREACH(by_unit, b, u->cgroup_bondings)
741
742
                        fprintf(f, "%s\tControlGroup: %s:%s\n",
                                prefix, b->controller, b->path);
743

Michal Schmidt's avatar
Michal Schmidt committed
744
                LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
745
746
747
748
749
                        char *v = NULL;

                        if (a->map_callback)
                                a->map_callback(a->controller, a->name, a->value, &v);

750
                        fprintf(f, "%s\tControlGroupAttribute: %s %s \"%s\"\n",
751
752
753
754
                                prefix, a->controller, a->name, v ? v : a->value);

                        free(v);
                }
755

756
757
                if (UNIT_VTABLE(u)->dump)
                        UNIT_VTABLE(u)->dump(u, f, prefix2);
758

Michal Schmidt's avatar
Michal Schmidt committed
759
        } else if (u->load_state == UNIT_MERGED)
760
761
                fprintf(f,
                        "%s\tMerged into: %s\n",
Michal Schmidt's avatar
Michal Schmidt committed
762
763
764
                        prefix, u->merged_into->id);
        else if (u->load_state == UNIT_ERROR)
                fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->load_error));
765

Lennart Poettering's avatar
Lennart Poettering committed
766

Michal Schmidt's avatar
Michal Schmidt committed
767
768
        if (u->job)
                job_dump(u->job, f, prefix2);
Lennart Poettering's avatar
Lennart Poettering committed
769

770
771
772
        if (u->nop_job)
                job_dump(u->nop_job, f, prefix2);

773
        free(p2);
Lennart Poettering's avatar
Lennart Poettering committed
774
775
776
}

/* Common implementation for multiple backends */
777
int unit_load_fragment_and_dropin(Unit *u) {
778
779
780
781
782
        int r;

        assert(u);

        /* Load a .service file */
783
        if ((r = unit_load_fragment(u)) < 0)
784
785
                return r;

Michal Schmidt's avatar
Michal Schmidt committed
786
        if (u->load_state == UNIT_STUB)
787
788
789
790
791
792
793
794
795
796
                return -ENOENT;

        /* Load drop-in directory data */
        if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
                return r;

        return 0;
}

/* Common implementation for multiple backends */
797
int unit_load_fragment_and_dropin_optional(Unit *u) {
798
        int r;
Lennart Poettering's avatar
Lennart Poettering committed
799
800
801

        assert(u);

802
803
804
805
        /* Same as unit_load_fragment_and_dropin(), but whether
         * something can be loaded or not doesn't matter. */

        /* Load a .service file */
806
        if ((r = unit_load_fragment(u)) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
807
808
                return r;

Michal Schmidt's avatar
Michal Schmidt committed
809
810
        if (u->load_state == UNIT_STUB)
                u->load_state = UNIT_LOADED;
811

Lennart Poettering's avatar
Lennart Poettering committed
812
        /* Load drop-in directory data */
813
        if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
814
815
                return r;

816
        return 0;
Lennart Poettering's avatar
Lennart Poettering committed
817
818
}

819
int unit_add_default_target_dependency(Unit *u, Unit *target) {
820
821
822
        assert(u);
        assert(target);

Michal Schmidt's avatar
Michal Schmidt committed
823
        if (target->type != UNIT_TARGET)
824
825
                return 0;

Harald Hoyer's avatar
Harald Hoyer committed
826
        /* Only add the dependency if both units are loaded, so that
827
         * that loop check below is reliable */
Michal Schmidt's avatar
Michal Schmidt committed
828
829
        if (u->load_state != UNIT_LOADED ||
            target->load_state != UNIT_LOADED)
830
831
                return 0;

832
833
        /* If either side wants no automatic dependencies, then let's
         * skip this */
Michal Schmidt's avatar
Michal Schmidt committed
834
835
        if (!u->default_dependencies ||
            !target->default_dependencies)
836
837
                return 0;

838
        /* Don't create loops */
Michal Schmidt's avatar
Michal Schmidt committed
839
        if (set_get(target->dependencies[UNIT_BEFORE], u))
840
841
842
843
844
845
                return 0;

        return unit_add_dependency(target, UNIT_AFTER, u, true);
}

static int unit_add_default_dependencies(Unit *u) {
846
847
848
849
850
851
852
        static const UnitDependency deps[] = {
                UNIT_REQUIRED_BY,
                UNIT_REQUIRED_BY_OVERRIDABLE,
                UNIT_WANTED_BY,
                UNIT_BOUND_BY
        };

853
        Unit *target;
854
855
        Iterator i;
        int r;
856
        unsigned k;
857
858
859

        assert(u);

860
        for (k = 0; k < ELEMENTSOF(deps); k++)
Michal Schmidt's avatar
Michal Schmidt committed
861
                SET_FOREACH(target, u->dependencies[deps[k]], i)
862
863
                        if ((r = unit_add_default_target_dependency(u, target)) < 0)
                                return r;
864

865
866
867
        return 0;
}

Lennart Poettering's avatar
Lennart Poettering committed
868
869
870
871
872
int unit_load(Unit *u) {
        int r;

        assert(u);

Michal Schmidt's avatar
Michal Schmidt committed
873
874
875
        if (u->in_load_queue) {
                LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
                u->in_load_queue = false;
Lennart Poettering's avatar
Lennart Poettering committed
876
877
        }

Michal Schmidt's avatar
Michal Schmidt committed
878
        if (u->type == _UNIT_TYPE_INVALID)
879
880
                return -EINVAL;

Michal Schmidt's avatar
Michal Schmidt committed
881
        if (u->load_state != UNIT_STUB)
Lennart Poettering's avatar
Lennart Poettering committed
882
883
                return 0;

884
885
        if (UNIT_VTABLE(u)->load)
                if ((r = UNIT_VTABLE(u)->load(u)) < 0)
Lennart Poettering's avatar
Lennart Poettering committed
886
                        goto fail;
887

Michal Schmidt's avatar
Michal Schmidt committed
888
        if (u->load_state == UNIT_STUB) {
889
890
891
892
                r = -ENOENT;
                goto fail;
        }

Michal Schmidt's avatar
Michal Schmidt committed
893
894
        if (u->load_state == UNIT_LOADED &&
            u->default_dependencies)
895
896
897
                if ((r = unit_add_default_dependencies(u)) < 0)
                        goto fail;

898
899
900
901
902
903
        if (u->load_state == UNIT_LOADED) {
                r = unit_add_mount_links(u);
                if (r < 0)
                        return r;
        }

Michal Schmidt's avatar
Michal Schmidt committed
904
905
        if (u->on_failure_isolate &&
            set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
906
907

                log_error("More than one OnFailure= dependencies specified for %s but OnFailureIsolate= enabled. Refusing.",
Michal Schmidt's avatar
Michal Schmidt committed
908
                          u->id);
909
910
911
912
913

                r = -EINVAL;
                goto fail;
        }

Michal Schmidt's avatar
Michal Schmidt committed
914
        assert((u->load_state != UNIT_MERGED) == !u->merged_into);
915
916

        unit_add_to_dbus_queue(unit_follow_merge(u));
917
        unit_add_to_gc_queue(u);
Lennart Poettering's avatar
Lennart Poettering committed
918
919
920
921

        return 0;

fail:
Michal Schmidt's avatar
Michal Schmidt committed
922
923
        u->load_state = UNIT_ERROR;
        u->load_error = r;
924
        unit_add_to_dbus_queue(u);
925
        unit_add_to_gc_queue(u);
926

Michal Schmidt's avatar
Michal Schmidt committed
927
        log_debug("Failed to load configuration for %s: %s", u->id, strerror(-r));
928

Lennart Poettering's avatar
Lennart Poettering committed
929
930
931
        return r;
}

932
933
934
bool unit_condition_test(Unit *u) {
        assert(u);

Michal Schmidt's avatar
Michal Schmidt committed
935
936
        dual_timestamp_get(&u->condition_timestamp);
        u->condition_result = condition_test_list(u->conditions);
937

Michal Schmidt's avatar
Michal Schmidt committed
938
        return u->condition_result;
939
940
}

941
static const char* unit_get_status_message_format(Unit *u, JobType t) {
942
        const UnitStatusMessageFormats *format_table;
943
944
945
946
947
948
949

        assert(u);
        assert(t >= 0);
        assert(t < _JOB_TYPE_MAX);

        if (t != JOB_START && t != JOB_STOP)
                return NULL;
950
951
952

        format_table = &UNIT_VTABLE(u)->status_message_formats;
        if (!format_table)
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
                return NULL;

        return format_table->starting_stopping[t == JOB_STOP];
}

static const char *unit_get_status_message_format_try_harder(Unit *u, JobType t) {
        const char *format;

        assert(u);
        assert(t >= 0);
        assert(t < _JOB_TYPE_MAX);

        format = unit_get_status_message_format(u, t);
        if (format)
                return format;

        /* Return generic strings */
        if (t == JOB_START)
                return "Starting %s.";
        else if (t == JOB_STOP)
                return "Stopping %s.";
        else if (t == JOB_RELOAD)
                return "Reloading %s.";

        return NULL;
}

static void unit_status_print_starting_stopping(Unit *u,