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