]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/path-lookup.c
Merge pull request #3589 from brauner/cgroup_namespace
[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 "util.h"
37
38 static int user_runtime_dir(char **ret, const char *suffix) {
39 const char *e;
40 char *j;
41
42 assert(ret);
43 assert(suffix);
44
45 e = getenv("XDG_RUNTIME_DIR");
46 if (!e)
47 return -ENXIO;
48
49 j = strappend(e, suffix);
50 if (!j)
51 return -ENOMEM;
52
53 *ret = j;
54 return 0;
55 }
56
57 static int user_config_dir(char **ret, const char *suffix) {
58 const char *e;
59 char *j;
60
61 assert(ret);
62
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
73 j = strjoin(home, "/.config", suffix, NULL);
74 }
75
76 if (!j)
77 return -ENOMEM;
78
79 *ret = j;
80 return 0;
81 }
82
83 static int user_data_dir(char **ret, const char *suffix) {
84 const char *e;
85 char *j;
86
87 assert(ret);
88 assert(suffix);
89
90 /* We don't treat /etc/xdg/systemd here as the spec
91 * suggests because we assume that is a link to
92 * /etc/systemd/ anyway. */
93
94 e = getenv("XDG_DATA_HOME");
95 if (e)
96 j = strappend(e, suffix);
97 else {
98 const char *home;
99
100 home = getenv("HOME");
101 if (!home)
102 return -ENXIO;
103
104
105 j = strjoin(home, "/.local/share", suffix, NULL);
106 }
107 if (!j)
108 return -ENOMEM;
109
110 *ret = j;
111 return 1;
112 }
113
114 static char** user_dirs(
115 const char *persistent_config,
116 const char *runtime_config,
117 const char *generator,
118 const char *generator_early,
119 const char *generator_late,
120 const char *transient,
121 const char *persistent_control,
122 const char *runtime_control) {
123
124 const char * const config_unit_paths[] = {
125 USER_CONFIG_UNIT_PATH,
126 "/etc/systemd/user",
127 NULL
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",
135 "/usr/share/systemd/user",
136 NULL
137 };
138
139 const char *e;
140 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
141 _cleanup_free_ char *data_home = NULL;
142 _cleanup_free_ char **res = NULL;
143 char **tmp;
144 int r;
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
155 e = getenv("XDG_CONFIG_DIRS");
156 if (e) {
157 config_dirs = strv_split(e, ":");
158 if (!config_dirs)
159 return NULL;
160 }
161
162 r = user_data_dir(&data_home, "/systemd/user");
163 if (r < 0 && r != -ENXIO)
164 return NULL;
165
166 e = getenv("XDG_DATA_DIRS");
167 if (e)
168 data_dirs = strv_split(e, ":");
169 else
170 data_dirs = strv_new("/usr/local/share",
171 "/usr/share",
172 NULL);
173 if (!data_dirs)
174 return NULL;
175
176 /* Now merge everything we found. */
177 if (strv_extend(&res, persistent_control) < 0)
178 return NULL;
179
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;
188
189 if (!strv_isempty(config_dirs))
190 if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
191 return NULL;
192
193 if (strv_extend(&res, persistent_config) < 0)
194 return NULL;
195
196 if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
197 return NULL;
198
199 if (strv_extend(&res, runtime_config) < 0)
200 return NULL;
201
202 if (strv_extend(&res, generator) < 0)
203 return NULL;
204
205 if (strv_extend(&res, data_home) < 0)
206 return NULL;
207
208 if (!strv_isempty(data_dirs))
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 return tmp;
224 }
225
226 static int acquire_generator_dirs(
227 UnitFileScope scope,
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
239 switch (scope) {
240
241 case UNIT_FILE_SYSTEM:
242 prefix = "/run/systemd/";
243 break;
244
245 case UNIT_FILE_USER: {
246 const char *e;
247
248 e = getenv("XDG_RUNTIME_DIR");
249 if (!e)
250 return -ENXIO;
251
252 prefix = strjoina(e, "/systemd/");
253 break;
254 }
255
256 case UNIT_FILE_GLOBAL:
257 return -EOPNOTSUPP;
258
259 default:
260 assert_not_reached("Hmm, unexpected scope value.");
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
283 static int acquire_transient_dir(UnitFileScope scope, char **ret) {
284 assert(ret);
285
286 switch (scope) {
287
288 case UNIT_FILE_SYSTEM: {
289 char *transient;
290
291 transient = strdup("/run/systemd/transient");
292 if (!transient)
293 return -ENOMEM;
294
295 *ret = transient;
296 return 0;
297 }
298
299 case UNIT_FILE_USER:
300 return user_runtime_dir(ret, "/systemd/transient");
301
302 case UNIT_FILE_GLOBAL:
303 return -EOPNOTSUPP;
304
305 default:
306 assert_not_reached("Hmm, unexpected scope value.");
307 }
308 }
309
310 static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
311 _cleanup_free_ char *a = NULL, *b = NULL;
312 int r;
313
314 assert(persistent);
315 assert(runtime);
316
317 switch (scope) {
318
319 case UNIT_FILE_SYSTEM:
320 a = strdup(SYSTEM_CONFIG_UNIT_PATH);
321 b = strdup("/run/systemd/system");
322 break;
323
324 case UNIT_FILE_GLOBAL:
325 a = strdup(USER_CONFIG_UNIT_PATH);
326 b = strdup("/run/systemd/user");
327 break;
328
329 case UNIT_FILE_USER:
330 r = user_config_dir(&a, "/systemd/user");
331 if (r < 0)
332 return r;
333
334 r = user_runtime_dir(runtime, "/systemd/user");
335 if (r < 0)
336 return r;
337
338 *persistent = a;
339 a = NULL;
340
341 return 0;
342
343 default:
344 assert_not_reached("Hmm, unexpected scope value.");
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
357 static 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
407 static 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
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
425 static 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
441 int lookup_paths_init(
442 LookupPaths *p,
443 UnitFileScope scope,
444 LookupPathsFlags flags,
445 const char *root_dir) {
446
447 _cleanup_free_ char
448 *root = NULL,
449 *persistent_config = NULL, *runtime_config = NULL,
450 *generator = NULL, *generator_early = NULL, *generator_late = NULL,
451 *transient = NULL,
452 *persistent_control = NULL, *runtime_control = NULL;
453 bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
454 _cleanup_strv_free_ char **paths = NULL;
455 const char *e;
456 int r;
457
458 assert(p);
459 assert(scope >= 0);
460 assert(scope < _UNIT_FILE_SCOPE_MAX);
461
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
477 r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
478 if (r < 0 && r != -ENXIO)
479 return r;
480
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 }
486
487 r = acquire_transient_dir(scope, &transient);
488 if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
489 return r;
490
491 r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
492 if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
493 return r;
494
495 /* First priority is whatever has been passed to us via env vars */
496 e = getenv("SYSTEMD_UNIT_PATH");
497 if (e) {
498 const char *k;
499
500 k = endswith(e, ":");
501 if (k) {
502 e = strndupa(e, k - e);
503 append = true;
504 }
505
506 /* FIXME: empty components in other places should be
507 * rejected. */
508
509 r = path_split_and_make_absolute(e, &paths);
510 if (r < 0)
511 return r;
512 }
513
514 if (!paths || append) {
515 /* Let's figure something out. */
516
517 _cleanup_strv_free_ char **add = NULL;
518
519 /* For the user units we include share/ in the search
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. */
524
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! */
531 STRV_IFNOTNULL(persistent_control),
532 STRV_IFNOTNULL(runtime_control),
533 STRV_IFNOTNULL(transient),
534 STRV_IFNOTNULL(generator_early),
535 persistent_config,
536 SYSTEM_CONFIG_UNIT_PATH,
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(
553 /* If you modify this you also want to modify
554 * systemduserunitpath= in systemd.pc.in, and
555 * the arrays in user_dirs() above! */
556 STRV_IFNOTNULL(persistent_control),
557 STRV_IFNOTNULL(runtime_control),
558 STRV_IFNOTNULL(transient),
559 STRV_IFNOTNULL(generator_early),
560 persistent_config,
561 USER_CONFIG_UNIT_PATH,
562 "/etc/systemd/user",
563 runtime_config,
564 "/run/systemd/user",
565 STRV_IFNOTNULL(generator),
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",
571 STRV_IFNOTNULL(generator_late),
572 NULL);
573 break;
574
575 case UNIT_FILE_USER:
576 add = user_dirs(persistent_config, runtime_config,
577 generator, generator_early, generator_late,
578 transient,
579 persistent_config, runtime_control);
580 break;
581
582 default:
583 assert_not_reached("Hmm, unexpected scope?");
584 }
585
586 if (!add)
587 return -ENOMEM;
588
589 if (paths) {
590 r = strv_extend_strv(&paths, add, true);
591 if (r < 0)
592 return r;
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 }
599 }
600
601 r = patch_root_prefix(&persistent_config, root);
602 if (r < 0)
603 return r;
604 r = patch_root_prefix(&runtime_config, root);
605 if (r < 0)
606 return r;
607
608 r = patch_root_prefix(&generator, root);
609 if (r < 0)
610 return r;
611 r = patch_root_prefix(&generator_early, root);
612 if (r < 0)
613 return r;
614 r = patch_root_prefix(&generator_late, root);
615 if (r < 0)
616 return r;
617
618 r = patch_root_prefix(&transient, root);
619 if (r < 0)
620 return r;
621
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
630 r = patch_root_prefix_strv(paths, root);
631 if (r < 0)
632 return -ENOMEM;
633
634 p->search_path = strv_uniq(paths);
635 paths = NULL;
636
637 p->persistent_config = persistent_config;
638 p->runtime_config = runtime_config;
639 persistent_config = runtime_config = NULL;
640
641 p->generator = generator;
642 p->generator_early = generator_early;
643 p->generator_late = generator_late;
644 generator = generator_early = generator_late = NULL;
645
646 p->transient = transient;
647 transient = NULL;
648
649 p->persistent_control = persistent_control;
650 p->runtime_control = runtime_control;
651 persistent_control = runtime_control = NULL;
652
653 p->root_dir = root;
654 root = NULL;
655
656 return 0;
657 }
658
659 void lookup_paths_free(LookupPaths *p) {
660 if (!p)
661 return;
662
663 p->search_path = strv_free(p->search_path);
664
665 p->persistent_config = mfree(p->persistent_config);
666 p->runtime_config = mfree(p->runtime_config);
667
668 p->generator = mfree(p->generator);
669 p->generator_early = mfree(p->generator_early);
670 p->generator_late = mfree(p->generator_late);
671
672 p->transient = mfree(p->transient);
673
674 p->persistent_control = mfree(p->persistent_control);
675 p->runtime_control = mfree(p->runtime_control);
676
677 p->root_dir = mfree(p->root_dir);
678 }
679
680 int 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
753 int lookup_paths_mkdir_generator(LookupPaths *p) {
754 int r, q;
755
756 assert(p);
757
758 if (!p->generator || !p->generator_early || !p->generator_late)
759 return -EINVAL;
760
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
774 void lookup_paths_trim_generator(LookupPaths *p) {
775 assert(p);
776
777 /* Trim empty dirs */
778
779 if (p->generator)
780 (void) rmdir(p->generator);
781 if (p->generator_early)
782 (void) rmdir(p->generator_early);
783 if (p->generator_late)
784 (void) rmdir(p->generator_late);
785 }
786
787 void lookup_paths_flush_generator(LookupPaths *p) {
788 assert(p);
789
790 /* Flush the generated unit files in full */
791
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 }
799
800 char **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 }