]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/path-lookup.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / shared / path-lookup.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
84e3543e
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
84e3543e
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
84e3543e 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
84e3543e
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
cf0fbc49 21#include <errno.h>
84e3543e 22#include <stdio.h>
cf0fbc49 23#include <stdlib.h>
67445f4e 24#include <string.h>
84e3543e 25
b5efdb8a 26#include "alloc-util.h"
a1f31f47
ZJS
27#include "fileio.h"
28#include "fs-util.h"
a8ffe6fb 29#include "install.h"
a8fbdf54
TA
30#include "log.h"
31#include "macro.h"
cd64fd56 32#include "mkdir.h"
07630cea 33#include "path-lookup.h"
cf0fbc49 34#include "path-util.h"
80b1ae32 35#include "rm-rf.h"
e4bb56c7 36#include "stat-util.h"
cf0fbc49
TA
37#include "string-util.h"
38#include "strv.h"
c4997074 39#include "user-util.h"
cf0fbc49 40#include "util.h"
84e3543e 41
80b1ae32 42static int user_runtime_dir(char **ret, const char *suffix) {
10e87ee7 43 const char *e;
205dd21e
LP
44 char *j;
45
46 assert(ret);
80b1ae32 47 assert(suffix);
10e87ee7 48
80b1ae32
LP
49 e = getenv("XDG_RUNTIME_DIR");
50 if (!e)
51 return -ENXIO;
205dd21e 52
80b1ae32
LP
53 j = strappend(e, suffix);
54 if (!j)
55 return -ENOMEM;
10e87ee7 56
205dd21e 57 *ret = j;
10e87ee7
LP
58 return 0;
59}
60
80b1ae32 61static int user_config_dir(char **ret, const char *suffix) {
718880ba 62 const char *e;
205dd21e 63 char *j;
c4997074 64 int r;
205dd21e
LP
65
66 assert(ret);
718880ba 67
80b1ae32
LP
68 e = getenv("XDG_CONFIG_HOME");
69 if (e)
70 j = strappend(e, suffix);
71 else {
c4997074 72 _cleanup_free_ char *home = NULL;
80b1ae32 73
c4997074
LP
74 r = get_home_dir(&home);
75 if (r < 0)
76 return r;
80b1ae32 77
605405c6 78 j = strjoin(home, "/.config", suffix);
80b1ae32 79 }
718880ba 80
205dd21e
LP
81 if (!j)
82 return -ENOMEM;
718880ba 83
205dd21e 84 *ret = j;
718880ba
SA
85 return 0;
86}
87
80b1ae32 88static int user_data_dir(char **ret, const char *suffix) {
e801700e 89 const char *e;
205dd21e 90 char *j;
c4997074 91 int r;
205dd21e
LP
92
93 assert(ret);
a7527131 94 assert(suffix);
e801700e
ZJS
95
96 /* We don't treat /etc/xdg/systemd here as the spec
61233823 97 * suggests because we assume that is a link to
e801700e
ZJS
98 * /etc/systemd/ anyway. */
99
100 e = getenv("XDG_DATA_HOME");
101 if (e)
205dd21e 102 j = strappend(e, suffix);
e801700e 103 else {
c4997074 104 _cleanup_free_ char *home = NULL;
205dd21e 105
c4997074
LP
106 r = get_home_dir(&home);
107 if (r < 0)
108 return r;
205dd21e 109
605405c6 110 j = strjoin(home, "/.local/share", suffix);
e801700e 111 }
205dd21e 112 if (!j)
e801700e
ZJS
113 return -ENOMEM;
114
205dd21e 115 *ret = j;
463d0d15 116 return 1;
e801700e
ZJS
117}
118
d2561cfd
ZJS
119static const char* const user_data_unit_paths[] = {
120 "/usr/local/lib/systemd/user",
121 "/usr/local/share/systemd/user",
122 USER_DATA_UNIT_PATH,
123 "/usr/lib/systemd/user",
124 "/usr/share/systemd/user",
125 NULL
126};
127
128static const char* const user_config_unit_paths[] = {
129 USER_CONFIG_UNIT_PATH,
130 "/etc/systemd/user",
131 NULL
132};
133
07719a21 134static char** user_dirs(
a0f84a10
LP
135 const char *persistent_config,
136 const char *runtime_config,
07719a21
LP
137 const char *generator,
138 const char *generator_early,
39591351 139 const char *generator_late,
80b1ae32
LP
140 const char *transient,
141 const char *persistent_control,
142 const char *runtime_control) {
07719a21 143
e3e45d4f 144 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
205dd21e 145 _cleanup_free_ char *data_home = NULL;
fcd574d4 146 _cleanup_strv_free_ char **res = NULL;
b9418b05 147 const char *e;
e801700e
ZJS
148 char **tmp;
149 int r;
84e3543e
LP
150
151 /* Implement the mechanisms defined in
152 *
153 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
154 *
155 * We look in both the config and the data dirs because we
156 * want to encourage that distributors ship their unit files
157 * as data, and allow overriding as configuration.
158 */
159
07719a21
LP
160 e = getenv("XDG_CONFIG_DIRS");
161 if (e) {
162 config_dirs = strv_split(e, ":");
163 if (!config_dirs)
e801700e 164 return NULL;
07719a21 165 }
84e3543e 166
80b1ae32 167 r = user_data_dir(&data_home, "/systemd/user");
205dd21e 168 if (r < 0 && r != -ENXIO)
e801700e 169 return NULL;
84e3543e 170
07719a21
LP
171 e = getenv("XDG_DATA_DIRS");
172 if (e)
84e3543e
LP
173 data_dirs = strv_split(e, ":");
174 else
ef3102bf 175 data_dirs = strv_new("/usr/local/share",
ef3102bf 176 "/usr/share",
ef3102bf 177 NULL);
84e3543e 178 if (!data_dirs)
e801700e 179 return NULL;
84e3543e
LP
180
181 /* Now merge everything we found. */
80b1ae32
LP
182 if (strv_extend(&res, persistent_control) < 0)
183 return NULL;
39591351 184
80b1ae32
LP
185 if (strv_extend(&res, runtime_control) < 0)
186 return NULL;
187
188 if (strv_extend(&res, transient) < 0)
189 return NULL;
190
191 if (strv_extend(&res, generator_early) < 0)
192 return NULL;
07719a21 193
b9418b05
LP
194 if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
195 return NULL;
718880ba 196
a0f84a10
LP
197 if (strv_extend(&res, persistent_config) < 0)
198 return NULL;
199
d2561cfd 200 if (strv_extend_strv(&res, (char**) user_config_unit_paths, false) < 0)
e801700e 201 return NULL;
718880ba 202
a0f84a10 203 if (strv_extend(&res, runtime_config) < 0)
e801700e 204 return NULL;
84e3543e 205
80b1ae32
LP
206 if (strv_extend(&res, generator) < 0)
207 return NULL;
07719a21 208
80b1ae32
LP
209 if (strv_extend(&res, data_home) < 0)
210 return NULL;
84e3543e 211
b9418b05
LP
212 if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
213 return NULL;
84e3543e 214
d2561cfd 215 if (strv_extend_strv(&res, (char**) user_data_unit_paths, false) < 0)
e801700e 216 return NULL;
84e3543e 217
80b1ae32
LP
218 if (strv_extend(&res, generator_late) < 0)
219 return NULL;
07719a21 220
0f474365 221 if (path_strv_make_absolute_cwd(res) < 0)
e801700e 222 return NULL;
84e3543e 223
e801700e
ZJS
224 tmp = res;
225 res = NULL;
b9418b05 226
e801700e
ZJS
227 return tmp;
228}
84e3543e 229
d2561cfd
ZJS
230bool path_is_user_data_dir(const char *path) {
231 assert(path);
232
233 return strv_contains((char**) user_data_unit_paths, path);
234}
235
236bool path_is_user_config_dir(const char *path) {
237 assert(path);
238
239 return strv_contains((char**) user_config_unit_paths, path);
240}
241
a3c4eb07 242static int acquire_generator_dirs(
463d0d15 243 UnitFileScope scope,
a1f31f47 244 const char *tempdir,
a3c4eb07
LP
245 char **generator,
246 char **generator_early,
247 char **generator_late) {
248
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);
4c701096 517 if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
4943d143
LP
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);
4c701096 523 if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
39591351
LP
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}