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