Coverage Report

Created: 2019-06-19 13:33

/src/systemd/src/shared/path-lookup.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1+ */
2
3
#include <errno.h>
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <string.h>
7
8
#include "alloc-util.h"
9
#include "fs-util.h"
10
#include "install.h"
11
#include "log.h"
12
#include "macro.h"
13
#include "mkdir.h"
14
#include "path-lookup.h"
15
#include "path-util.h"
16
#include "rm-rf.h"
17
#include "stat-util.h"
18
#include "string-util.h"
19
#include "strv.h"
20
#include "tmpfile-util.h"
21
#include "user-util.h"
22
#include "util.h"
23
24
0
int xdg_user_runtime_dir(char **ret, const char *suffix) {
25
0
        const char *e;
26
0
        char *j;
27
0
28
0
        assert(ret);
29
0
        assert(suffix);
30
0
31
0
        e = getenv("XDG_RUNTIME_DIR");
32
0
        if (!e)
33
0
                return -ENXIO;
34
0
35
0
        j = strappend(e, suffix);
36
0
        if (!j)
37
0
                return -ENOMEM;
38
0
39
0
        *ret = j;
40
0
        return 0;
41
0
}
42
43
0
int xdg_user_config_dir(char **ret, const char *suffix) {
44
0
        const char *e;
45
0
        char *j;
46
0
        int r;
47
0
48
0
        assert(ret);
49
0
50
0
        e = getenv("XDG_CONFIG_HOME");
51
0
        if (e)
52
0
                j = strappend(e, suffix);
53
0
        else {
54
0
                _cleanup_free_ char *home = NULL;
55
0
56
0
                r = get_home_dir(&home);
57
0
                if (r < 0)
58
0
                        return r;
59
0
60
0
                j = strjoin(home, "/.config", suffix);
61
0
        }
62
0
63
0
        if (!j)
64
0
                return -ENOMEM;
65
0
66
0
        *ret = j;
67
0
        return 0;
68
0
}
69
70
0
int xdg_user_data_dir(char **ret, const char *suffix) {
71
0
        const char *e;
72
0
        char *j;
73
0
        int r;
74
0
75
0
        assert(ret);
76
0
        assert(suffix);
77
0
78
0
        /* We don't treat /etc/xdg/systemd here as the spec
79
0
         * suggests because we assume that is a link to
80
0
         * /etc/systemd/ anyway. */
81
0
82
0
        e = getenv("XDG_DATA_HOME");
83
0
        if (e)
84
0
                j = strappend(e, suffix);
85
0
        else {
86
0
                _cleanup_free_ char *home = NULL;
87
0
88
0
                r = get_home_dir(&home);
89
0
                if (r < 0)
90
0
                        return r;
91
0
92
0
                j = strjoin(home, "/.local/share", suffix);
93
0
        }
94
0
        if (!j)
95
0
                return -ENOMEM;
96
0
97
0
        *ret = j;
98
0
        return 1;
99
0
}
100
101
static const char* const user_data_unit_paths[] = {
102
        "/usr/local/lib/systemd/user",
103
        "/usr/local/share/systemd/user",
104
        USER_DATA_UNIT_PATH,
105
        "/usr/lib/systemd/user",
106
        "/usr/share/systemd/user",
107
        NULL
108
};
109
110
static const char* const user_config_unit_paths[] = {
111
        USER_CONFIG_UNIT_PATH,
112
        "/etc/systemd/user",
113
        NULL
114
};
115
116
0
int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs) {
117
0
        /* Implement the mechanisms defined in
118
0
         *
119
0
         * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
120
0
         *
121
0
         * We look in both the config and the data dirs because we
122
0
         * want to encourage that distributors ship their unit files
123
0
         * as data, and allow overriding as configuration.
124
0
         */
125
0
        const char *e;
126
0
        _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
127
0
128
0
        e = getenv("XDG_CONFIG_DIRS");
129
0
        if (e) {
130
0
                config_dirs = strv_split(e, ":");
131
0
                if (!config_dirs)
132
0
                        return -ENOMEM;
133
0
        }
134
0
135
0
        e = getenv("XDG_DATA_DIRS");
136
0
        if (e)
137
0
                data_dirs = strv_split(e, ":");
138
0
        else
139
0
                data_dirs = strv_new("/usr/local/share",
140
0
                                     "/usr/share");
141
0
        if (!data_dirs)
142
0
                return -ENOMEM;
143
0
144
0
        *ret_config_dirs = TAKE_PTR(config_dirs);
145
0
        *ret_data_dirs = TAKE_PTR(data_dirs);
146
0
147
0
        return 0;
148
0
}
149
150
static char** user_dirs(
151
                const char *persistent_config,
152
                const char *runtime_config,
153
                const char *global_persistent_config,
154
                const char *global_runtime_config,
155
                const char *generator,
156
                const char *generator_early,
157
                const char *generator_late,
158
                const char *transient,
159
                const char *persistent_control,
160
0
                const char *runtime_control) {
161
0
162
0
        _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
163
0
        _cleanup_free_ char *data_home = NULL;
164
0
        _cleanup_strv_free_ char **res = NULL;
165
0
        int r;
166
0
167
0
        r = xdg_user_dirs(&config_dirs, &data_dirs);
168
0
        if (r < 0)
169
0
                return NULL;
170
0
171
0
        r = xdg_user_data_dir(&data_home, "/systemd/user");
172
0
        if (r < 0 && r != -ENXIO)
173
0
                return NULL;
174
0
175
0
        /* Now merge everything we found. */
176
0
        if (strv_extend(&res, persistent_control) < 0)
177
0
                return NULL;
178
0
179
0
        if (strv_extend(&res, runtime_control) < 0)
180
0
                return NULL;
181
0
182
0
        if (strv_extend(&res, transient) < 0)
183
0
                return NULL;
184
0
185
0
        if (strv_extend(&res, generator_early) < 0)
186
0
                return NULL;
187
0
188
0
        if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
189
0
                return NULL;
190
0
191
0
        if (strv_extend(&res, persistent_config) < 0)
192
0
                return NULL;
193
0
194
0
        /* global config has lower priority than the user config of the same type */
195
0
        if (strv_extend(&res, global_persistent_config) < 0)
196
0
                return NULL;
197
0
198
0
        if (strv_extend_strv(&res, (char**) user_config_unit_paths, false) < 0)
199
0
                return NULL;
200
0
201
0
        if (strv_extend(&res, runtime_config) < 0)
202
0
                return NULL;
203
0
204
0
        if (strv_extend(&res, global_runtime_config) < 0)
205
0
                return NULL;
206
0
207
0
        if (strv_extend(&res, generator) < 0)
208
0
                return NULL;
209
0
210
0
        if (strv_extend(&res, data_home) < 0)
211
0
                return NULL;
212
0
213
0
        if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
214
0
                return NULL;
215
0
216
0
        if (strv_extend_strv(&res, (char**) user_data_unit_paths, false) < 0)
217
0
                return NULL;
218
0
219
0
        if (strv_extend(&res, generator_late) < 0)
220
0
                return NULL;
221
0
222
0
        if (path_strv_make_absolute_cwd(res) < 0)
223
0
                return NULL;
224
0
225
0
        return TAKE_PTR(res);
226
0
}
227
228
0
bool path_is_user_data_dir(const char *path) {
229
0
        assert(path);
230
0
231
0
        return strv_contains((char**) user_data_unit_paths, path);
232
0
}
233
234
0
bool path_is_user_config_dir(const char *path) {
235
0
        assert(path);
236
0
237
0
        return strv_contains((char**) user_config_unit_paths, path);
238
0
}
239
240
static int acquire_generator_dirs(
241
                UnitFileScope scope,
242
                const char *tempdir,
243
                char **generator,
244
                char **generator_early,
245
0
                char **generator_late) {
246
0
247
0
        _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
248
0
        const char *prefix;
249
0
250
0
        assert(generator);
251
0
        assert(generator_early);
252
0
        assert(generator_late);
253
0
        assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
254
0
255
0
        if (scope == UNIT_FILE_GLOBAL)
256
0
                return -EOPNOTSUPP;
257
0
258
0
        if (tempdir)
259
0
                prefix = tempdir;
260
0
        else if (scope == UNIT_FILE_SYSTEM)
261
0
                prefix = "/run/systemd";
262
0
        else {
263
0
                /* UNIT_FILE_USER */
264
0
                const char *e;
265
0
266
0
                e = getenv("XDG_RUNTIME_DIR");
267
0
                if (!e)
268
0
                        return -ENXIO;
269
0
270
0
                prefix = strjoina(e, "/systemd");
271
0
        }
272
0
273
0
        x = strappend(prefix, "/generator");
274
0
        if (!x)
275
0
                return -ENOMEM;
276
0
277
0
        y = strappend(prefix, "/generator.early");
278
0
        if (!y)
279
0
                return -ENOMEM;
280
0
281
0
        z = strappend(prefix, "/generator.late");
282
0
        if (!z)
283
0
                return -ENOMEM;
284
0
285
0
        *generator = TAKE_PTR(x);
286
0
        *generator_early = TAKE_PTR(y);
287
0
        *generator_late = TAKE_PTR(z);
288
0
289
0
        return 0;
290
0
}
291
292
static int acquire_transient_dir(
293
                UnitFileScope scope,
294
                const char *tempdir,
295
0
                char **ret) {
296
0
297
0
        char *transient;
298
0
299
0
        assert(ret);
300
0
        assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
301
0
302
0
        if (scope == UNIT_FILE_GLOBAL)
303
0
                return -EOPNOTSUPP;
304
0
305
0
        if (tempdir)
306
0
                transient = strjoin(tempdir, "/transient");
307
0
        else if (scope == UNIT_FILE_SYSTEM)
308
0
                transient = strdup("/run/systemd/transient");
309
0
        else
310
0
                return xdg_user_runtime_dir(ret, "/systemd/transient");
311
0
312
0
        if (!transient)
313
0
                return -ENOMEM;
314
0
        *ret = transient;
315
0
        return 0;
316
0
}
317
318
0
static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
319
0
        _cleanup_free_ char *a = NULL, *b = NULL;
320
0
        int r;
321
0
322
0
        assert(persistent);
323
0
        assert(runtime);
324
0
325
0
        switch (scope) {
326
0
327
0
        case UNIT_FILE_SYSTEM:
328
0
                a = strdup(SYSTEM_CONFIG_UNIT_PATH);
329
0
                b = strdup("/run/systemd/system");
330
0
                break;
331
0
332
0
        case UNIT_FILE_GLOBAL:
333
0
                a = strdup(USER_CONFIG_UNIT_PATH);
334
0
                b = strdup("/run/systemd/user");
335
0
                break;
336
0
337
0
        case UNIT_FILE_USER:
338
0
                r = xdg_user_config_dir(&a, "/systemd/user");
339
0
                if (r < 0 && r != -ENXIO)
340
0
                        return r;
341
0
342
0
                r = xdg_user_runtime_dir(runtime, "/systemd/user");
343
0
                if (r < 0) {
344
0
                        if (r != -ENXIO)
345
0
                                return r;
346
0
347
0
                        /* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
348
0
                         * directory to NULL */
349
0
                        *runtime = NULL;
350
0
                }
351
0
352
0
                *persistent = TAKE_PTR(a);
353
0
354
0
                return 0;
355
0
356
0
        default:
357
0
                assert_not_reached("Hmm, unexpected scope value.");
358
0
        }
359
0
360
0
        if (!a || !b)
361
0
                return -ENOMEM;
362
0
363
0
        *persistent = TAKE_PTR(a);
364
0
        *runtime = TAKE_PTR(b);
365
0
366
0
        return 0;
367
0
}
368
369
0
static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
370
0
        _cleanup_free_ char *a = NULL;
371
0
        int r;
372
0
373
0
        assert(persistent);
374
0
        assert(runtime);
375
0
376
0
        switch (scope) {
377
0
378
0
        case UNIT_FILE_SYSTEM:  {
379
0
                _cleanup_free_ char *b = NULL;
380
0
381
0
                a = strdup("/etc/systemd/system.control");
382
0
                if (!a)
383
0
                        return -ENOMEM;
384
0
385
0
                b = strdup("/run/systemd/system.control");
386
0
                if (!b)
387
0
                        return -ENOMEM;
388
0
389
0
                *runtime = TAKE_PTR(b);
390
0
391
0
                break;
392
0
        }
393
0
394
0
        case UNIT_FILE_USER:
395
0
                r = xdg_user_config_dir(&a, "/systemd/user.control");
396
0
                if (r < 0 && r != -ENXIO)
397
0
                        return r;
398
0
399
0
                r = xdg_user_runtime_dir(runtime, "/systemd/user.control");
400
0
                if (r < 0) {
401
0
                        if (r != -ENXIO)
402
0
                                return r;
403
0
404
0
                        /* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
405
0
                         * NULL */
406
0
                        *runtime = NULL;
407
0
                }
408
0
409
0
                break;
410
0
411
0
        case UNIT_FILE_GLOBAL:
412
0
                return -EOPNOTSUPP;
413
0
414
0
        default:
415
0
                assert_not_reached("Hmm, unexpected scope value.");
416
0
        }
417
0
418
0
        *persistent = TAKE_PTR(a);
419
0
420
0
        return 0;
421
0
}
422
423
static int acquire_attached_dirs(
424
                UnitFileScope scope,
425
                char **ret_persistent,
426
0
                char **ret_runtime) {
427
0
428
0
        _cleanup_free_ char *a = NULL, *b = NULL;
429
0
430
0
        assert(ret_persistent);
431
0
        assert(ret_runtime);
432
0
433
0
        /* Portable services are not available to regular users for now. */
434
0
        if (scope != UNIT_FILE_SYSTEM)
435
0
                return -EOPNOTSUPP;
436
0
437
0
        a = strdup("/etc/systemd/system.attached");
438
0
        if (!a)
439
0
                return -ENOMEM;
440
0
441
0
        b = strdup("/run/systemd/system.attached");
442
0
        if (!b)
443
0
                return -ENOMEM;
444
0
445
0
        *ret_persistent = TAKE_PTR(a);
446
0
        *ret_runtime = TAKE_PTR(b);
447
0
448
0
        return 0;
449
0
}
450
451
0
static int patch_root_prefix(char **p, const char *root_dir) {
452
0
        char *c;
453
0
454
0
        assert(p);
455
0
456
0
        if (!*p)
457
0
                return 0;
458
0
459
0
        c = prefix_root(root_dir, *p);
460
0
        if (!c)
461
0
                return -ENOMEM;
462
0
463
0
        free(*p);
464
0
        *p = c;
465
0
466
0
        return 0;
467
0
}
468
469
0
static int patch_root_prefix_strv(char **l, const char *root_dir) {
470
0
        char **i;
471
0
        int r;
472
0
473
0
        if (!root_dir)
474
0
                return 0;
475
0
476
0
        STRV_FOREACH(i, l) {
477
0
                r = patch_root_prefix(i, root_dir);
478
0
                if (r < 0)
479
0
                        return r;
480
0
        }
481
0
482
0
        return 0;
483
0
}
484
485
int lookup_paths_init(
486
                LookupPaths *p,
487
                UnitFileScope scope,
488
                LookupPathsFlags flags,
489
0
                const char *root_dir) {
490
0
491
0
        _cleanup_(rmdir_and_freep) char *tempdir = NULL;
492
0
        _cleanup_free_ char
493
0
                *root = NULL,
494
0
                *persistent_config = NULL, *runtime_config = NULL,
495
0
                *global_persistent_config = NULL, *global_runtime_config = NULL,
496
0
                *generator = NULL, *generator_early = NULL, *generator_late = NULL,
497
0
                *transient = NULL,
498
0
                *persistent_control = NULL, *runtime_control = NULL,
499
0
                *persistent_attached = NULL, *runtime_attached = NULL;
500
0
        bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
501
0
        _cleanup_strv_free_ char **paths = NULL;
502
0
        const char *e;
503
0
        int r;
504
0
505
0
        assert(p);
506
0
        assert(scope >= 0);
507
0
        assert(scope < _UNIT_FILE_SCOPE_MAX);
508
0
509
0
#if HAVE_SPLIT_USR
510
0
        flags |= LOOKUP_PATHS_SPLIT_USR;
511
0
#endif
512
0
513
0
        if (!empty_or_root(root_dir)) {
514
0
                if (scope == UNIT_FILE_USER)
515
0
                        return -EINVAL;
516
0
517
0
                r = is_dir(root_dir, true);
518
0
                if (r < 0)
519
0
                        return r;
520
0
                if (r == 0)
521
0
                        return -ENOTDIR;
522
0
523
0
                root = strdup(root_dir);
524
0
                if (!root)
525
0
                        return -ENOMEM;
526
0
        }
527
0
528
0
        if (flags & LOOKUP_PATHS_TEMPORARY_GENERATED) {
529
0
                r = mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir);
530
0
                if (r < 0)
531
0
                        return log_debug_errno(r, "Failed to create temporary directory: %m");
532
0
        }
533
0
534
0
        /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
535
0
        r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
536
0
        if (r < 0)
537
0
                return r;
538
0
539
0
        if (scope == UNIT_FILE_USER) {
540
0
                r = acquire_config_dirs(UNIT_FILE_GLOBAL, &global_persistent_config, &global_runtime_config);
541
0
                if (r < 0)
542
0
                        return r;
543
0
        }
544
0
545
0
        if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
546
0
                /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
547
0
                r = acquire_generator_dirs(scope, tempdir,
548
0
                                           &generator, &generator_early, &generator_late);
549
0
                if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
550
0
                        return r;
551
0
        }
552
0
553
0
        /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
554
0
        r = acquire_transient_dir(scope, tempdir, &transient);
555
0
        if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
556
0
                return r;
557
0
558
0
        /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
559
0
        r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
560
0
        if (r < 0 && r != -EOPNOTSUPP)
561
0
                return r;
562
0
563
0
        r = acquire_attached_dirs(scope, &persistent_attached, &runtime_attached);
564
0
        if (r < 0 && r != -EOPNOTSUPP)
565
0
                return r;
566
0
567
0
        /* First priority is whatever has been passed to us via env vars */
568
0
        e = getenv("SYSTEMD_UNIT_PATH");
569
0
        if (e) {
570
0
                const char *k;
571
0
572
0
                k = endswith(e, ":");
573
0
                if (k) {
574
0
                        e = strndupa(e, k - e);
575
0
                        append = true;
576
0
                }
577
0
578
0
                /* FIXME: empty components in other places should be rejected. */
579
0
580
0
                r = path_split_and_make_absolute(e, &paths);
581
0
                if (r < 0)
582
0
                        return r;
583
0
        }
584
0
585
0
        if (!paths || append) {
586
0
                /* Let's figure something out. */
587
0
588
0
                _cleanup_strv_free_ char **add = NULL;
589
0
590
0
                /* For the user units we include share/ in the search
591
0
                 * path in order to comply with the XDG basedir spec.
592
0
                 * For the system stuff we avoid such nonsense. OTOH
593
0
                 * we include /lib in the search path for the system
594
0
                 * stuff but avoid it for user stuff. */
595
0
596
0
                switch (scope) {
597
0
598
0
                case UNIT_FILE_SYSTEM:
599
0
                        add = strv_new(
600
0
                                        /* If you modify this you also want to modify
601
0
                                         * systemdsystemunitpath= in systemd.pc.in! */
602
0
                                        STRV_IFNOTNULL(persistent_control),
603
0
                                        STRV_IFNOTNULL(runtime_control),
604
0
                                        STRV_IFNOTNULL(transient),
605
0
                                        STRV_IFNOTNULL(generator_early),
606
0
                                        persistent_config,
607
0
                                        SYSTEM_CONFIG_UNIT_PATH,
608
0
                                        "/etc/systemd/system",
609
0
                                        STRV_IFNOTNULL(persistent_attached),
610
0
                                        runtime_config,
611
0
                                        "/run/systemd/system",
612
0
                                        STRV_IFNOTNULL(runtime_attached),
613
0
                                        STRV_IFNOTNULL(generator),
614
0
                                        "/usr/local/lib/systemd/system",
615
0
                                        SYSTEM_DATA_UNIT_PATH,
616
0
                                        "/usr/lib/systemd/system",
617
0
                                        STRV_IFNOTNULL(flags & LOOKUP_PATHS_SPLIT_USR ? "/lib/systemd/system" : NULL),
618
0
                                        STRV_IFNOTNULL(generator_late));
619
0
                        break;
620
0
621
0
                case UNIT_FILE_GLOBAL:
622
0
                        add = strv_new(
623
0
                                        /* If you modify this you also want to modify
624
0
                                         * systemduserunitpath= in systemd.pc.in, and
625
0
                                         * the arrays in user_dirs() above! */
626
0
                                        STRV_IFNOTNULL(persistent_control),
627
0
                                        STRV_IFNOTNULL(runtime_control),
628
0
                                        STRV_IFNOTNULL(transient),
629
0
                                        STRV_IFNOTNULL(generator_early),
630
0
                                        persistent_config,
631
0
                                        USER_CONFIG_UNIT_PATH,
632
0
                                        "/etc/systemd/user",
633
0
                                        runtime_config,
634
0
                                        "/run/systemd/user",
635
0
                                        STRV_IFNOTNULL(generator),
636
0
                                        "/usr/local/share/systemd/user",
637
0
                                        "/usr/share/systemd/user",
638
0
                                        "/usr/local/lib/systemd/user",
639
0
                                        USER_DATA_UNIT_PATH,
640
0
                                        "/usr/lib/systemd/user",
641
0
                                        STRV_IFNOTNULL(generator_late));
642
0
                        break;
643
0
644
0
                case UNIT_FILE_USER:
645
0
                        add = user_dirs(persistent_config, runtime_config,
646
0
                                        global_persistent_config, global_runtime_config,
647
0
                                        generator, generator_early, generator_late,
648
0
                                        transient,
649
0
                                        persistent_control, runtime_control);
650
0
                        break;
651
0
652
0
                default:
653
0
                        assert_not_reached("Hmm, unexpected scope?");
654
0
                }
655
0
656
0
                if (!add)
657
0
                        return -ENOMEM;
658
0
659
0
                if (paths) {
660
0
                        r = strv_extend_strv(&paths, add, true);
661
0
                        if (r < 0)
662
0
                                return r;
663
0
                } else
664
0
                        /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
665
0
                         * and don't have to copy anything */
666
0
                        paths = TAKE_PTR(add);
667
0
        }
668
0
669
0
        r = patch_root_prefix(&persistent_config, root);
670
0
        if (r < 0)
671
0
                return r;
672
0
        r = patch_root_prefix(&runtime_config, root);
673
0
        if (r < 0)
674
0
                return r;
675
0
676
0
        r = patch_root_prefix(&generator, root);
677
0
        if (r < 0)
678
0
                return r;
679
0
        r = patch_root_prefix(&generator_early, root);
680
0
        if (r < 0)
681
0
                return r;
682
0
        r = patch_root_prefix(&generator_late, root);
683
0
        if (r < 0)
684
0
                return r;
685
0
686
0
        r = patch_root_prefix(&transient, root);
687
0
        if (r < 0)
688
0
                return r;
689
0
690
0
        r = patch_root_prefix(&persistent_control, root);
691
0
        if (r < 0)
692
0
                return r;
693
0
        r = patch_root_prefix(&runtime_control, root);
694
0
        if (r < 0)
695
0
                return r;
696
0
697
0
        r = patch_root_prefix(&persistent_attached, root);
698
0
        if (r < 0)
699
0
                return r;
700
0
        r = patch_root_prefix(&runtime_attached, root);
701
0
        if (r < 0)
702
0
                return r;
703
0
704
0
        r = patch_root_prefix_strv(paths, root);
705
0
        if (r < 0)
706
0
                return -ENOMEM;
707
0
708
0
        *p = (LookupPaths) {
709
0
                .search_path = strv_uniq(paths),
710
0
711
0
                .persistent_config = TAKE_PTR(persistent_config),
712
0
                .runtime_config = TAKE_PTR(runtime_config),
713
0
714
0
                .generator = TAKE_PTR(generator),
715
0
                .generator_early = TAKE_PTR(generator_early),
716
0
                .generator_late = TAKE_PTR(generator_late),
717
0
718
0
                .transient = TAKE_PTR(transient),
719
0
720
0
                .persistent_control = TAKE_PTR(persistent_control),
721
0
                .runtime_control = TAKE_PTR(runtime_control),
722
0
723
0
                .persistent_attached = TAKE_PTR(persistent_attached),
724
0
                .runtime_attached = TAKE_PTR(runtime_attached),
725
0
726
0
                .root_dir = TAKE_PTR(root),
727
0
                .temporary_dir = TAKE_PTR(tempdir),
728
0
        };
729
0
730
0
        paths = NULL;
731
0
        return 0;
732
0
}
733
734
18.0k
void lookup_paths_free(LookupPaths *p) {
735
18.0k
        if (!p)
736
0
                return;
737
18.0k
738
18.0k
        p->search_path = strv_free(p->search_path);
739
18.0k
740
18.0k
        p->persistent_config = mfree(p->persistent_config);
741
18.0k
        p->runtime_config = mfree(p->runtime_config);
742
18.0k
743
18.0k
        p->persistent_attached = mfree(p->persistent_attached);
744
18.0k
        p->runtime_attached = mfree(p->runtime_attached);
745
18.0k
746
18.0k
        p->generator = mfree(p->generator);
747
18.0k
        p->generator_early = mfree(p->generator_early);
748
18.0k
        p->generator_late = mfree(p->generator_late);
749
18.0k
750
18.0k
        p->transient = mfree(p->transient);
751
18.0k
752
18.0k
        p->persistent_control = mfree(p->persistent_control);
753
18.0k
        p->runtime_control = mfree(p->runtime_control);
754
18.0k
755
18.0k
        p->root_dir = mfree(p->root_dir);
756
18.0k
        p->temporary_dir = mfree(p->temporary_dir);
757
18.0k
}
758
759
0
int lookup_paths_reduce(LookupPaths *p) {
760
0
        _cleanup_free_ struct stat *stats = NULL;
761
0
        size_t n_stats = 0, allocated = 0;
762
0
        size_t c = 0;
763
0
        int r;
764
0
765
0
        assert(p);
766
0
767
0
        /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
768
0
         * the same by comparing their device and inode numbers. */
769
0
770
0
        if (!p->search_path)
771
0
                return 0;
772
0
773
0
        while (p->search_path[c]) {
774
0
                struct stat st;
775
0
                size_t k;
776
0
777
0
                /* Never strip the transient and control directories from the path */
778
0
                if (path_equal_ptr(p->search_path[c], p->transient) ||
779
0
                    path_equal_ptr(p->search_path[c], p->persistent_control) ||
780
0
                    path_equal_ptr(p->search_path[c], p->runtime_control)) {
781
0
                        c++;
782
0
                        continue;
783
0
                }
784
0
785
0
                r = chase_symlinks_and_stat(p->search_path[c], p->root_dir, 0, NULL, &st);
786
0
                if (r == -ENOENT)
787
0
                        goto remove_item;
788
0
                if (r < 0) {
789
0
                        /* If something we don't grok happened, let's better leave it in. */
790
0
                        log_debug_errno(r, "Failed to chase and stat %s: %m", p->search_path[c]);
791
0
                        c++;
792
0
                        continue;
793
0
                }
794
0
795
0
                for (k = 0; k < n_stats; k++)
796
0
                        if (stats[k].st_dev == st.st_dev &&
797
0
                            stats[k].st_ino == st.st_ino)
798
0
                                break;
799
0
800
0
                if (k < n_stats) /* Is there already an entry with the same device/inode? */
801
0
                        goto remove_item;
802
0
803
0
                if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
804
0
                        return -ENOMEM;
805
0
806
0
                stats[n_stats++] = st;
807
0
                c++;
808
0
                continue;
809
0
810
0
        remove_item:
811
0
                free(p->search_path[c]);
812
0
                memmove(p->search_path + c,
813
0
                        p->search_path + c + 1,
814
0
                        (strv_length(p->search_path + c + 1) + 1) * sizeof(char*));
815
0
        }
816
0
817
0
        if (strv_isempty(p->search_path)) {
818
0
                log_debug("Ignoring unit files.");
819
0
                p->search_path = strv_free(p->search_path);
820
0
        } else {
821
0
                _cleanup_free_ char *t;
822
0
823
0
                t = strv_join(p->search_path, "\n\t");
824
0
                if (!t)
825
0
                        return -ENOMEM;
826
0
827
0
                log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
828
0
        }
829
0
830
0
        return 0;
831
0
}
832
833
0
int lookup_paths_mkdir_generator(LookupPaths *p) {
834
0
        int r, q;
835
0
836
0
        assert(p);
837
0
838
0
        if (!p->generator || !p->generator_early || !p->generator_late)
839
0
                return -EINVAL;
840
0
841
0
        r = mkdir_p_label(p->generator, 0755);
842
0
843
0
        q = mkdir_p_label(p->generator_early, 0755);
844
0
        if (q < 0 && r >= 0)
845
0
                r = q;
846
0
847
0
        q = mkdir_p_label(p->generator_late, 0755);
848
0
        if (q < 0 && r >= 0)
849
0
                r = q;
850
0
851
0
        return r;
852
0
}
853
854
0
void lookup_paths_trim_generator(LookupPaths *p) {
855
0
        assert(p);
856
0
857
0
        /* Trim empty dirs */
858
0
859
0
        if (p->generator)
860
0
                (void) rmdir(p->generator);
861
0
        if (p->generator_early)
862
0
                (void) rmdir(p->generator_early);
863
0
        if (p->generator_late)
864
0
                (void) rmdir(p->generator_late);
865
0
}
866
867
18.0k
void lookup_paths_flush_generator(LookupPaths *p) {
868
18.0k
        assert(p);
869
18.0k
870
18.0k
        /* Flush the generated unit files in full */
871
18.0k
872
18.0k
        if (p->generator)
873
0
                (void) rm_rf(p->generator, REMOVE_ROOT|REMOVE_PHYSICAL);
874
18.0k
        if (p->generator_early)
875
0
                (void) rm_rf(p->generator_early, REMOVE_ROOT|REMOVE_PHYSICAL);
876
18.0k
        if (p->generator_late)
877
0
                (void) rm_rf(p->generator_late, REMOVE_ROOT|REMOVE_PHYSICAL);
878
18.0k
879
18.0k
        if (p->temporary_dir)
880
0
                (void) rm_rf(p->temporary_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
881
18.0k
}
882
883
0
char **generator_binary_paths(UnitFileScope scope) {
884
0
885
0
        switch (scope) {
886
0
887
0
        case UNIT_FILE_SYSTEM:
888
0
                return strv_new("/run/systemd/system-generators",
889
0
                                "/etc/systemd/system-generators",
890
0
                                "/usr/local/lib/systemd/system-generators",
891
0
                                SYSTEM_GENERATOR_PATH);
892
0
893
0
        case UNIT_FILE_GLOBAL:
894
0
        case UNIT_FILE_USER:
895
0
                return strv_new("/run/systemd/user-generators",
896
0
                                "/etc/systemd/user-generators",
897
0
                                "/usr/local/lib/systemd/user-generators",
898
0
                                USER_GENERATOR_PATH);
899
0
900
0
        default:
901
0
                assert_not_reached("Hmm, unexpected scope.");
902
0
        }
903
0
}