]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/path-lookup.c
path-lookup: try harder acquiring them $HOME of a user
[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 const char *e;
142 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
143 _cleanup_free_ char *data_home = NULL;
144 _cleanup_strv_free_ char **res = NULL;
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_isempty(config_dirs))
192 if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
193 return NULL;
194
195 if (strv_extend(&res, persistent_config) < 0)
196 return NULL;
197
198 if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
199 return NULL;
200
201 if (strv_extend(&res, runtime_config) < 0)
202 return NULL;
203
204 if (strv_extend(&res, generator) < 0)
205 return NULL;
206
207 if (strv_extend(&res, data_home) < 0)
208 return NULL;
209
210 if (!strv_isempty(data_dirs))
211 if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
212 return NULL;
213
214 if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
215 return NULL;
216
217 if (strv_extend(&res, generator_late) < 0)
218 return NULL;
219
220 if (path_strv_make_absolute_cwd(res) < 0)
221 return NULL;
222
223 tmp = res;
224 res = NULL;
225 return tmp;
226 }
227
228 static int acquire_generator_dirs(
229 UnitFileScope scope,
230 char **generator,
231 char **generator_early,
232 char **generator_late) {
233
234 _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
235 const char *prefix;
236
237 assert(generator);
238 assert(generator_early);
239 assert(generator_late);
240
241 switch (scope) {
242
243 case UNIT_FILE_SYSTEM:
244 prefix = "/run/systemd/";
245 break;
246
247 case UNIT_FILE_USER: {
248 const char *e;
249
250 e = getenv("XDG_RUNTIME_DIR");
251 if (!e)
252 return -ENXIO;
253
254 prefix = strjoina(e, "/systemd/");
255 break;
256 }
257
258 case UNIT_FILE_GLOBAL:
259 return -EOPNOTSUPP;
260
261 default:
262 assert_not_reached("Hmm, unexpected scope value.");
263 }
264
265 x = strappend(prefix, "generator");
266 if (!x)
267 return -ENOMEM;
268
269 y = strappend(prefix, "generator.early");
270 if (!y)
271 return -ENOMEM;
272
273 z = strappend(prefix, "generator.late");
274 if (!z)
275 return -ENOMEM;
276
277 *generator = x;
278 *generator_early = y;
279 *generator_late = z;
280
281 x = y = z = NULL;
282 return 0;
283 }
284
285 static int acquire_transient_dir(UnitFileScope scope, char **ret) {
286 assert(ret);
287
288 switch (scope) {
289
290 case UNIT_FILE_SYSTEM: {
291 char *transient;
292
293 transient = strdup("/run/systemd/transient");
294 if (!transient)
295 return -ENOMEM;
296
297 *ret = transient;
298 return 0;
299 }
300
301 case UNIT_FILE_USER:
302 return user_runtime_dir(ret, "/systemd/transient");
303
304 case UNIT_FILE_GLOBAL:
305 return -EOPNOTSUPP;
306
307 default:
308 assert_not_reached("Hmm, unexpected scope value.");
309 }
310 }
311
312 static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
313 _cleanup_free_ char *a = NULL, *b = NULL;
314 int r;
315
316 assert(persistent);
317 assert(runtime);
318
319 switch (scope) {
320
321 case UNIT_FILE_SYSTEM:
322 a = strdup(SYSTEM_CONFIG_UNIT_PATH);
323 b = strdup("/run/systemd/system");
324 break;
325
326 case UNIT_FILE_GLOBAL:
327 a = strdup(USER_CONFIG_UNIT_PATH);
328 b = strdup("/run/systemd/user");
329 break;
330
331 case UNIT_FILE_USER:
332 r = user_config_dir(&a, "/systemd/user");
333 if (r < 0)
334 return r;
335
336 r = user_runtime_dir(runtime, "/systemd/user");
337 if (r < 0)
338 return r;
339
340 *persistent = a;
341 a = NULL;
342
343 return 0;
344
345 default:
346 assert_not_reached("Hmm, unexpected scope value.");
347 }
348
349 if (!a || !b)
350 return -ENOMEM;
351
352 *persistent = a;
353 *runtime = b;
354 a = b = NULL;
355
356 return 0;
357 }
358
359 static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
360 _cleanup_free_ char *a = NULL;
361 int r;
362
363 assert(persistent);
364 assert(runtime);
365
366 switch (scope) {
367
368 case UNIT_FILE_SYSTEM: {
369 _cleanup_free_ char *b = NULL;
370
371 a = strdup("/etc/systemd/system.control");
372 if (!a)
373 return -ENOMEM;
374
375 b = strdup("/run/systemd/system.control");
376 if (!b)
377 return -ENOMEM;
378
379 *runtime = b;
380 b = NULL;
381
382 break;
383 }
384
385 case UNIT_FILE_USER:
386 r = user_config_dir(&a, "/systemd/system.control");
387 if (r < 0)
388 return r;
389
390 r = user_runtime_dir(runtime, "/systemd/system.control");
391 if (r < 0)
392 return r;
393
394 break;
395
396 case UNIT_FILE_GLOBAL:
397 return -EOPNOTSUPP;
398
399 default:
400 assert_not_reached("Hmm, unexpected scope value.");
401 }
402
403 *persistent = a;
404 a = NULL;
405
406 return 0;
407 }
408
409 static int patch_root_prefix(char **p, const char *root_dir) {
410 char *c;
411
412 assert(p);
413
414 if (!*p)
415 return 0;
416
417 c = prefix_root(root_dir, *p);
418 if (!c)
419 return -ENOMEM;
420
421 free(*p);
422 *p = c;
423
424 return 0;
425 }
426
427 static int patch_root_prefix_strv(char **l, const char *root_dir) {
428 char **i;
429 int r;
430
431 if (!root_dir)
432 return 0;
433
434 STRV_FOREACH(i, l) {
435 r = patch_root_prefix(i, root_dir);
436 if (r < 0)
437 return r;
438 }
439
440 return 0;
441 }
442
443 int lookup_paths_init(
444 LookupPaths *p,
445 UnitFileScope scope,
446 LookupPathsFlags flags,
447 const char *root_dir) {
448
449 _cleanup_free_ char
450 *root = NULL,
451 *persistent_config = NULL, *runtime_config = NULL,
452 *generator = NULL, *generator_early = NULL, *generator_late = NULL,
453 *transient = NULL,
454 *persistent_control = NULL, *runtime_control = NULL;
455 bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
456 _cleanup_strv_free_ char **paths = NULL;
457 const char *e;
458 int r;
459
460 assert(p);
461 assert(scope >= 0);
462 assert(scope < _UNIT_FILE_SCOPE_MAX);
463
464 if (!isempty(root_dir) && !path_equal(root_dir, "/")) {
465 if (scope == UNIT_FILE_USER)
466 return -EINVAL;
467
468 r = is_dir(root_dir, true);
469 if (r < 0)
470 return r;
471 if (r == 0)
472 return -ENOTDIR;
473
474 root = strdup(root_dir);
475 if (!root)
476 return -ENOMEM;
477 }
478
479 r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
480 if (r < 0 && r != -ENXIO)
481 return r;
482
483 if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
484 r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late);
485 if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
486 return r;
487 }
488
489 r = acquire_transient_dir(scope, &transient);
490 if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
491 return r;
492
493 r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
494 if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
495 return r;
496
497 /* First priority is whatever has been passed to us via env vars */
498 e = getenv("SYSTEMD_UNIT_PATH");
499 if (e) {
500 const char *k;
501
502 k = endswith(e, ":");
503 if (k) {
504 e = strndupa(e, k - e);
505 append = true;
506 }
507
508 /* FIXME: empty components in other places should be
509 * rejected. */
510
511 r = path_split_and_make_absolute(e, &paths);
512 if (r < 0)
513 return r;
514 }
515
516 if (!paths || append) {
517 /* Let's figure something out. */
518
519 _cleanup_strv_free_ char **add = NULL;
520
521 /* For the user units we include share/ in the search
522 * path in order to comply with the XDG basedir spec.
523 * For the system stuff we avoid such nonsense. OTOH
524 * we include /lib in the search path for the system
525 * stuff but avoid it for user stuff. */
526
527 switch (scope) {
528
529 case UNIT_FILE_SYSTEM:
530 add = strv_new(
531 /* If you modify this you also want to modify
532 * systemdsystemunitpath= in systemd.pc.in! */
533 STRV_IFNOTNULL(persistent_control),
534 STRV_IFNOTNULL(runtime_control),
535 STRV_IFNOTNULL(transient),
536 STRV_IFNOTNULL(generator_early),
537 persistent_config,
538 SYSTEM_CONFIG_UNIT_PATH,
539 "/etc/systemd/system",
540 runtime_config,
541 "/run/systemd/system",
542 STRV_IFNOTNULL(generator),
543 "/usr/local/lib/systemd/system",
544 SYSTEM_DATA_UNIT_PATH,
545 "/usr/lib/systemd/system",
546 #ifdef HAVE_SPLIT_USR
547 "/lib/systemd/system",
548 #endif
549 STRV_IFNOTNULL(generator_late),
550 NULL);
551 break;
552
553 case UNIT_FILE_GLOBAL:
554 add = strv_new(
555 /* If you modify this you also want to modify
556 * systemduserunitpath= in systemd.pc.in, and
557 * the arrays in user_dirs() above! */
558 STRV_IFNOTNULL(persistent_control),
559 STRV_IFNOTNULL(runtime_control),
560 STRV_IFNOTNULL(transient),
561 STRV_IFNOTNULL(generator_early),
562 persistent_config,
563 USER_CONFIG_UNIT_PATH,
564 "/etc/systemd/user",
565 runtime_config,
566 "/run/systemd/user",
567 STRV_IFNOTNULL(generator),
568 "/usr/local/lib/systemd/user",
569 "/usr/local/share/systemd/user",
570 USER_DATA_UNIT_PATH,
571 "/usr/lib/systemd/user",
572 "/usr/share/systemd/user",
573 STRV_IFNOTNULL(generator_late),
574 NULL);
575 break;
576
577 case UNIT_FILE_USER:
578 add = user_dirs(persistent_config, runtime_config,
579 generator, generator_early, generator_late,
580 transient,
581 persistent_config, runtime_control);
582 break;
583
584 default:
585 assert_not_reached("Hmm, unexpected scope?");
586 }
587
588 if (!add)
589 return -ENOMEM;
590
591 if (paths) {
592 r = strv_extend_strv(&paths, add, true);
593 if (r < 0)
594 return r;
595 } else {
596 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
597 * and don't have to copy anything */
598 paths = add;
599 add = NULL;
600 }
601 }
602
603 r = patch_root_prefix(&persistent_config, root);
604 if (r < 0)
605 return r;
606 r = patch_root_prefix(&runtime_config, root);
607 if (r < 0)
608 return r;
609
610 r = patch_root_prefix(&generator, root);
611 if (r < 0)
612 return r;
613 r = patch_root_prefix(&generator_early, root);
614 if (r < 0)
615 return r;
616 r = patch_root_prefix(&generator_late, root);
617 if (r < 0)
618 return r;
619
620 r = patch_root_prefix(&transient, root);
621 if (r < 0)
622 return r;
623
624 r = patch_root_prefix(&persistent_control, root);
625 if (r < 0)
626 return r;
627
628 r = patch_root_prefix(&runtime_control, root);
629 if (r < 0)
630 return r;
631
632 r = patch_root_prefix_strv(paths, root);
633 if (r < 0)
634 return -ENOMEM;
635
636 p->search_path = strv_uniq(paths);
637 paths = NULL;
638
639 p->persistent_config = persistent_config;
640 p->runtime_config = runtime_config;
641 persistent_config = runtime_config = NULL;
642
643 p->generator = generator;
644 p->generator_early = generator_early;
645 p->generator_late = generator_late;
646 generator = generator_early = generator_late = NULL;
647
648 p->transient = transient;
649 transient = NULL;
650
651 p->persistent_control = persistent_control;
652 p->runtime_control = runtime_control;
653 persistent_control = runtime_control = NULL;
654
655 p->root_dir = root;
656 root = NULL;
657
658 return 0;
659 }
660
661 void lookup_paths_free(LookupPaths *p) {
662 if (!p)
663 return;
664
665 p->search_path = strv_free(p->search_path);
666
667 p->persistent_config = mfree(p->persistent_config);
668 p->runtime_config = mfree(p->runtime_config);
669
670 p->generator = mfree(p->generator);
671 p->generator_early = mfree(p->generator_early);
672 p->generator_late = mfree(p->generator_late);
673
674 p->transient = mfree(p->transient);
675
676 p->persistent_control = mfree(p->persistent_control);
677 p->runtime_control = mfree(p->runtime_control);
678
679 p->root_dir = mfree(p->root_dir);
680 }
681
682 int lookup_paths_reduce(LookupPaths *p) {
683 _cleanup_free_ struct stat *stats = NULL;
684 size_t n_stats = 0, allocated = 0;
685 unsigned c = 0;
686 int r;
687
688 assert(p);
689
690 /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
691 * the same by comparing their device and inode numbers. Note one special tweak: when we have a root path set,
692 * we do not follow symlinks when retrieving them, because the kernel wouldn't take the root prefix into
693 * account when following symlinks. When we have no root path set this restriction does not apply however. */
694
695 if (!p->search_path)
696 return 0;
697
698 while (p->search_path[c]) {
699 struct stat st;
700 unsigned k;
701
702 if (p->root_dir)
703 r = lstat(p->search_path[c], &st);
704 else
705 r = stat(p->search_path[c], &st);
706 if (r < 0) {
707 if (errno == ENOENT)
708 goto remove_item;
709
710 /* If something we don't grok happened, let's better leave it in. */
711 log_debug_errno(errno, "Failed to stat %s: %m", p->search_path[c]);
712 c++;
713 continue;
714 }
715
716 for (k = 0; k < n_stats; k++) {
717 if (stats[k].st_dev == st.st_dev &&
718 stats[k].st_ino == st.st_ino)
719 break;
720 }
721
722 if (k < n_stats) /* Is there already an entry with the same device/inode? */
723 goto remove_item;
724
725 if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
726 return -ENOMEM;
727
728 stats[n_stats++] = st;
729 c++;
730 continue;
731
732 remove_item:
733 free(p->search_path[c]);
734 memmove(p->search_path + c,
735 p->search_path + c + 1,
736 (strv_length(p->search_path + c + 1) + 1) * sizeof(char*));
737 }
738
739 if (strv_isempty(p->search_path)) {
740 log_debug("Ignoring unit files.");
741 p->search_path = strv_free(p->search_path);
742 } else {
743 _cleanup_free_ char *t;
744
745 t = strv_join(p->search_path, "\n\t");
746 if (!t)
747 return -ENOMEM;
748
749 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
750 }
751
752 return 0;
753 }
754
755 int lookup_paths_mkdir_generator(LookupPaths *p) {
756 int r, q;
757
758 assert(p);
759
760 if (!p->generator || !p->generator_early || !p->generator_late)
761 return -EINVAL;
762
763 r = mkdir_p_label(p->generator, 0755);
764
765 q = mkdir_p_label(p->generator_early, 0755);
766 if (q < 0 && r >= 0)
767 r = q;
768
769 q = mkdir_p_label(p->generator_late, 0755);
770 if (q < 0 && r >= 0)
771 r = q;
772
773 return r;
774 }
775
776 void lookup_paths_trim_generator(LookupPaths *p) {
777 assert(p);
778
779 /* Trim empty dirs */
780
781 if (p->generator)
782 (void) rmdir(p->generator);
783 if (p->generator_early)
784 (void) rmdir(p->generator_early);
785 if (p->generator_late)
786 (void) rmdir(p->generator_late);
787 }
788
789 void lookup_paths_flush_generator(LookupPaths *p) {
790 assert(p);
791
792 /* Flush the generated unit files in full */
793
794 if (p->generator)
795 (void) rm_rf(p->generator, REMOVE_ROOT);
796 if (p->generator_early)
797 (void) rm_rf(p->generator_early, REMOVE_ROOT);
798 if (p->generator_late)
799 (void) rm_rf(p->generator_late, REMOVE_ROOT);
800 }
801
802 char **generator_binary_paths(UnitFileScope scope) {
803
804 switch (scope) {
805
806 case UNIT_FILE_SYSTEM:
807 return strv_new("/run/systemd/system-generators",
808 "/etc/systemd/system-generators",
809 "/usr/local/lib/systemd/system-generators",
810 SYSTEM_GENERATOR_PATH,
811 NULL);
812
813 case UNIT_FILE_GLOBAL:
814 case UNIT_FILE_USER:
815 return strv_new("/run/systemd/user-generators",
816 "/etc/systemd/user-generators",
817 "/usr/local/lib/systemd/user-generators",
818 USER_GENERATOR_PATH,
819 NULL);
820
821 default:
822 assert_not_reached("Hmm, unexpected scope.");
823 }
824 }