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