1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
13 #include "alloc-util.h"
20 #include "path-lookup.h"
21 #include "path-util.h"
23 #include "stat-util.h"
24 #include "string-util.h"
26 #include "user-util.h"
29 int xdg_user_runtime_dir(char **ret
, const char *suffix
) {
36 e
= getenv("XDG_RUNTIME_DIR");
40 j
= strappend(e
, suffix
);
48 int xdg_user_config_dir(char **ret
, const char *suffix
) {
55 e
= getenv("XDG_CONFIG_HOME");
57 j
= strappend(e
, suffix
);
59 _cleanup_free_
char *home
= NULL
;
61 r
= get_home_dir(&home
);
65 j
= strjoin(home
, "/.config", suffix
);
75 int xdg_user_data_dir(char **ret
, const char *suffix
) {
83 /* We don't treat /etc/xdg/systemd here as the spec
84 * suggests because we assume that is a link to
85 * /etc/systemd/ anyway. */
87 e
= getenv("XDG_DATA_HOME");
89 j
= strappend(e
, suffix
);
91 _cleanup_free_
char *home
= NULL
;
93 r
= get_home_dir(&home
);
97 j
= strjoin(home
, "/.local/share", suffix
);
106 static const char* const user_data_unit_paths
[] = {
107 "/usr/local/lib/systemd/user",
108 "/usr/local/share/systemd/user",
110 "/usr/lib/systemd/user",
111 "/usr/share/systemd/user",
115 static const char* const user_config_unit_paths
[] = {
116 USER_CONFIG_UNIT_PATH
,
121 int xdg_user_dirs(char ***ret_config_dirs
, char ***ret_data_dirs
) {
122 /* Implement the mechanisms defined in
124 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
126 * We look in both the config and the data dirs because we
127 * want to encourage that distributors ship their unit files
128 * as data, and allow overriding as configuration.
131 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
133 e
= getenv("XDG_CONFIG_DIRS");
135 config_dirs
= strv_split(e
, ":");
140 e
= getenv("XDG_DATA_DIRS");
142 data_dirs
= strv_split(e
, ":");
144 data_dirs
= strv_new("/usr/local/share",
150 *ret_config_dirs
= config_dirs
;
151 *ret_data_dirs
= data_dirs
;
152 config_dirs
= data_dirs
= NULL
;
156 static char** user_dirs(
157 const char *persistent_config
,
158 const char *runtime_config
,
159 const char *global_persistent_config
,
160 const char *global_runtime_config
,
161 const char *generator
,
162 const char *generator_early
,
163 const char *generator_late
,
164 const char *transient
,
165 const char *persistent_control
,
166 const char *runtime_control
) {
168 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
169 _cleanup_free_
char *data_home
= NULL
;
170 _cleanup_strv_free_
char **res
= NULL
;
173 r
= xdg_user_dirs(&config_dirs
, &data_dirs
);
177 r
= xdg_user_data_dir(&data_home
, "/systemd/user");
178 if (r
< 0 && r
!= -ENXIO
)
181 /* Now merge everything we found. */
182 if (strv_extend(&res
, persistent_control
) < 0)
185 if (strv_extend(&res
, runtime_control
) < 0)
188 if (strv_extend(&res
, transient
) < 0)
191 if (strv_extend(&res
, generator_early
) < 0)
194 if (strv_extend_strv_concat(&res
, config_dirs
, "/systemd/user") < 0)
197 if (strv_extend(&res
, persistent_config
) < 0)
200 /* global config has lower priority than the user config of the same type */
201 if (strv_extend(&res
, global_persistent_config
) < 0)
204 if (strv_extend_strv(&res
, (char**) user_config_unit_paths
, false) < 0)
207 if (strv_extend(&res
, runtime_config
) < 0)
210 if (strv_extend(&res
, global_runtime_config
) < 0)
213 if (strv_extend(&res
, generator
) < 0)
216 if (strv_extend(&res
, data_home
) < 0)
219 if (strv_extend_strv_concat(&res
, data_dirs
, "/systemd/user") < 0)
222 if (strv_extend_strv(&res
, (char**) user_data_unit_paths
, false) < 0)
225 if (strv_extend(&res
, generator_late
) < 0)
228 if (path_strv_make_absolute_cwd(res
) < 0)
231 return TAKE_PTR(res
);
234 bool path_is_user_data_dir(const char *path
) {
237 return strv_contains((char**) user_data_unit_paths
, path
);
240 bool path_is_user_config_dir(const char *path
) {
243 return strv_contains((char**) user_config_unit_paths
, path
);
246 static int acquire_generator_dirs(
250 char **generator_early
,
251 char **generator_late
) {
253 _cleanup_free_
char *x
= NULL
, *y
= NULL
, *z
= NULL
;
257 assert(generator_early
);
258 assert(generator_late
);
259 assert(IN_SET(scope
, UNIT_FILE_SYSTEM
, UNIT_FILE_USER
, UNIT_FILE_GLOBAL
));
261 if (scope
== UNIT_FILE_GLOBAL
)
267 else if (scope
== UNIT_FILE_SYSTEM
)
268 prefix
= "/run/systemd";
270 else if (scope
== UNIT_FILE_USER
) {
273 e
= getenv("XDG_RUNTIME_DIR");
277 prefix
= strjoina(e
, "/systemd");
280 x
= strappend(prefix
, "/generator");
284 y
= strappend(prefix
, "/generator.early");
288 z
= strappend(prefix
, "/generator.late");
292 *generator
= TAKE_PTR(x
);
293 *generator_early
= TAKE_PTR(y
);
294 *generator_late
= TAKE_PTR(z
);
299 static int acquire_transient_dir(
307 assert(IN_SET(scope
, UNIT_FILE_SYSTEM
, UNIT_FILE_USER
, UNIT_FILE_GLOBAL
));
309 if (scope
== UNIT_FILE_GLOBAL
)
313 transient
= strjoin(tempdir
, "/transient");
314 else if (scope
== UNIT_FILE_SYSTEM
)
315 transient
= strdup("/run/systemd/transient");
317 return xdg_user_runtime_dir(ret
, "/systemd/transient");
325 static int acquire_config_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
326 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
334 case UNIT_FILE_SYSTEM
:
335 a
= strdup(SYSTEM_CONFIG_UNIT_PATH
);
336 b
= strdup("/run/systemd/system");
339 case UNIT_FILE_GLOBAL
:
340 a
= strdup(USER_CONFIG_UNIT_PATH
);
341 b
= strdup("/run/systemd/user");
345 r
= xdg_user_config_dir(&a
, "/systemd/user");
346 if (r
< 0 && r
!= -ENXIO
)
349 r
= xdg_user_runtime_dir(runtime
, "/systemd/user");
354 /* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
355 * directory to NULL */
359 *persistent
= TAKE_PTR(a
);
364 assert_not_reached("Hmm, unexpected scope value.");
370 *persistent
= TAKE_PTR(a
);
371 *runtime
= TAKE_PTR(b
);
376 static int acquire_control_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
377 _cleanup_free_
char *a
= NULL
;
385 case UNIT_FILE_SYSTEM
: {
386 _cleanup_free_
char *b
= NULL
;
388 a
= strdup("/etc/systemd/system.control");
392 b
= strdup("/run/systemd/system.control");
396 *runtime
= TAKE_PTR(b
);
402 r
= xdg_user_config_dir(&a
, "/systemd/user.control");
403 if (r
< 0 && r
!= -ENXIO
)
406 r
= xdg_user_runtime_dir(runtime
, "/systemd/user.control");
411 /* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
418 case UNIT_FILE_GLOBAL
:
422 assert_not_reached("Hmm, unexpected scope value.");
425 *persistent
= TAKE_PTR(a
);
430 static int patch_root_prefix(char **p
, const char *root_dir
) {
438 c
= prefix_root(root_dir
, *p
);
448 static int patch_root_prefix_strv(char **l
, const char *root_dir
) {
456 r
= patch_root_prefix(i
, root_dir
);
464 int lookup_paths_init(
467 LookupPathsFlags flags
,
468 const char *root_dir
) {
470 _cleanup_(rmdir_and_freep
) char *tempdir
= NULL
;
473 *persistent_config
= NULL
, *runtime_config
= NULL
,
474 *global_persistent_config
= NULL
, *global_runtime_config
= NULL
,
475 *generator
= NULL
, *generator_early
= NULL
, *generator_late
= NULL
,
477 *persistent_control
= NULL
, *runtime_control
= NULL
;
478 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
479 _cleanup_strv_free_
char **paths
= NULL
;
485 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
487 if (!isempty(root_dir
) && !path_equal(root_dir
, "/")) {
488 if (scope
== UNIT_FILE_USER
)
491 r
= is_dir(root_dir
, true);
497 root
= strdup(root_dir
);
502 if (flags
& LOOKUP_PATHS_TEMPORARY_GENERATED
) {
503 r
= mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir
);
505 return log_error_errno(r
, "Failed to create temporary directory: %m");
508 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
509 r
= acquire_config_dirs(scope
, &persistent_config
, &runtime_config
);
513 if (scope
== UNIT_FILE_USER
) {
514 r
= acquire_config_dirs(UNIT_FILE_GLOBAL
, &global_persistent_config
, &global_runtime_config
);
519 if ((flags
& LOOKUP_PATHS_EXCLUDE_GENERATED
) == 0) {
520 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
521 r
= acquire_generator_dirs(scope
, tempdir
,
522 &generator
, &generator_early
, &generator_late
);
523 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
527 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
528 r
= acquire_transient_dir(scope
, tempdir
, &transient
);
529 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
532 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
533 r
= acquire_control_dirs(scope
, &persistent_control
, &runtime_control
);
534 if (r
< 0 && r
!= -EOPNOTSUPP
)
537 /* First priority is whatever has been passed to us via env vars */
538 e
= getenv("SYSTEMD_UNIT_PATH");
542 k
= endswith(e
, ":");
544 e
= strndupa(e
, k
- e
);
548 /* FIXME: empty components in other places should be rejected. */
550 r
= path_split_and_make_absolute(e
, &paths
);
555 if (!paths
|| append
) {
556 /* Let's figure something out. */
558 _cleanup_strv_free_
char **add
= NULL
;
560 /* For the user units we include share/ in the search
561 * path in order to comply with the XDG basedir spec.
562 * For the system stuff we avoid such nonsense. OTOH
563 * we include /lib in the search path for the system
564 * stuff but avoid it for user stuff. */
568 case UNIT_FILE_SYSTEM
:
570 /* If you modify this you also want to modify
571 * systemdsystemunitpath= in systemd.pc.in! */
572 STRV_IFNOTNULL(persistent_control
),
573 STRV_IFNOTNULL(runtime_control
),
574 STRV_IFNOTNULL(transient
),
575 STRV_IFNOTNULL(generator_early
),
577 SYSTEM_CONFIG_UNIT_PATH
,
578 "/etc/systemd/system",
580 "/run/systemd/system",
581 STRV_IFNOTNULL(generator
),
582 "/usr/local/lib/systemd/system",
583 SYSTEM_DATA_UNIT_PATH
,
584 "/usr/lib/systemd/system",
586 "/lib/systemd/system",
588 STRV_IFNOTNULL(generator_late
),
592 case UNIT_FILE_GLOBAL
:
594 /* If you modify this you also want to modify
595 * systemduserunitpath= in systemd.pc.in, and
596 * the arrays in user_dirs() above! */
597 STRV_IFNOTNULL(persistent_control
),
598 STRV_IFNOTNULL(runtime_control
),
599 STRV_IFNOTNULL(transient
),
600 STRV_IFNOTNULL(generator_early
),
602 USER_CONFIG_UNIT_PATH
,
606 STRV_IFNOTNULL(generator
),
607 "/usr/local/share/systemd/user",
608 "/usr/share/systemd/user",
609 "/usr/local/lib/systemd/user",
611 "/usr/lib/systemd/user",
612 STRV_IFNOTNULL(generator_late
),
617 add
= user_dirs(persistent_config
, runtime_config
,
618 global_persistent_config
, global_runtime_config
,
619 generator
, generator_early
, generator_late
,
621 persistent_control
, runtime_control
);
625 assert_not_reached("Hmm, unexpected scope?");
632 r
= strv_extend_strv(&paths
, add
, true);
636 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
637 * and don't have to copy anything */
638 paths
= TAKE_PTR(add
);
641 r
= patch_root_prefix(&persistent_config
, root
);
644 r
= patch_root_prefix(&runtime_config
, root
);
648 r
= patch_root_prefix(&generator
, root
);
651 r
= patch_root_prefix(&generator_early
, root
);
654 r
= patch_root_prefix(&generator_late
, root
);
658 r
= patch_root_prefix(&transient
, root
);
662 r
= patch_root_prefix(&persistent_control
, root
);
666 r
= patch_root_prefix(&runtime_control
, root
);
670 r
= patch_root_prefix_strv(paths
, root
);
674 p
->search_path
= strv_uniq(paths
);
677 p
->persistent_config
= TAKE_PTR(persistent_config
);
678 p
->runtime_config
= TAKE_PTR(runtime_config
);
680 p
->generator
= TAKE_PTR(generator
);
681 p
->generator_early
= TAKE_PTR(generator_early
);
682 p
->generator_late
= TAKE_PTR(generator_late
);
684 p
->transient
= TAKE_PTR(transient
);
686 p
->persistent_control
= TAKE_PTR(persistent_control
);
687 p
->runtime_control
= TAKE_PTR(runtime_control
);
689 p
->root_dir
= TAKE_PTR(root
);
690 p
->temporary_dir
= TAKE_PTR(tempdir
);
695 void lookup_paths_free(LookupPaths
*p
) {
699 p
->search_path
= strv_free(p
->search_path
);
701 p
->persistent_config
= mfree(p
->persistent_config
);
702 p
->runtime_config
= mfree(p
->runtime_config
);
704 p
->generator
= mfree(p
->generator
);
705 p
->generator_early
= mfree(p
->generator_early
);
706 p
->generator_late
= mfree(p
->generator_late
);
708 p
->transient
= mfree(p
->transient
);
710 p
->persistent_control
= mfree(p
->persistent_control
);
711 p
->runtime_control
= mfree(p
->runtime_control
);
713 p
->root_dir
= mfree(p
->root_dir
);
714 p
->temporary_dir
= mfree(p
->temporary_dir
);
717 int lookup_paths_reduce(LookupPaths
*p
) {
718 _cleanup_free_
struct stat
*stats
= NULL
;
719 size_t n_stats
= 0, allocated
= 0;
725 /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
726 * the same by comparing their device and inode numbers. Note one special tweak: when we have a root path set,
727 * we do not follow symlinks when retrieving them, because the kernel wouldn't take the root prefix into
728 * account when following symlinks. When we have no root path set this restriction does not apply however. */
733 while (p
->search_path
[c
]) {
737 /* Never strip the transient and control directories from the path */
738 if (path_equal_ptr(p
->search_path
[c
], p
->transient
) ||
739 path_equal_ptr(p
->search_path
[c
], p
->persistent_control
) ||
740 path_equal_ptr(p
->search_path
[c
], p
->runtime_control
)) {
746 r
= lstat(p
->search_path
[c
], &st
);
748 r
= stat(p
->search_path
[c
], &st
);
753 /* If something we don't grok happened, let's better leave it in. */
754 log_debug_errno(errno
, "Failed to stat %s: %m", p
->search_path
[c
]);
759 for (k
= 0; k
< n_stats
; k
++) {
760 if (stats
[k
].st_dev
== st
.st_dev
&&
761 stats
[k
].st_ino
== st
.st_ino
)
765 if (k
< n_stats
) /* Is there already an entry with the same device/inode? */
768 if (!GREEDY_REALLOC(stats
, allocated
, n_stats
+1))
771 stats
[n_stats
++] = st
;
776 free(p
->search_path
[c
]);
777 memmove(p
->search_path
+ c
,
778 p
->search_path
+ c
+ 1,
779 (strv_length(p
->search_path
+ c
+ 1) + 1) * sizeof(char*));
782 if (strv_isempty(p
->search_path
)) {
783 log_debug("Ignoring unit files.");
784 p
->search_path
= strv_free(p
->search_path
);
786 _cleanup_free_
char *t
;
788 t
= strv_join(p
->search_path
, "\n\t");
792 log_debug("Looking for unit files in (higher priority first):\n\t%s", t
);
798 int lookup_paths_mkdir_generator(LookupPaths
*p
) {
803 if (!p
->generator
|| !p
->generator_early
|| !p
->generator_late
)
806 r
= mkdir_p_label(p
->generator
, 0755);
808 q
= mkdir_p_label(p
->generator_early
, 0755);
812 q
= mkdir_p_label(p
->generator_late
, 0755);
819 void lookup_paths_trim_generator(LookupPaths
*p
) {
822 /* Trim empty dirs */
825 (void) rmdir(p
->generator
);
826 if (p
->generator_early
)
827 (void) rmdir(p
->generator_early
);
828 if (p
->generator_late
)
829 (void) rmdir(p
->generator_late
);
832 void lookup_paths_flush_generator(LookupPaths
*p
) {
835 /* Flush the generated unit files in full */
838 (void) rm_rf(p
->generator
, REMOVE_ROOT
);
839 if (p
->generator_early
)
840 (void) rm_rf(p
->generator_early
, REMOVE_ROOT
);
841 if (p
->generator_late
)
842 (void) rm_rf(p
->generator_late
, REMOVE_ROOT
);
844 if (p
->temporary_dir
)
845 (void) rm_rf(p
->temporary_dir
, REMOVE_ROOT
);
848 char **generator_binary_paths(UnitFileScope scope
) {
852 case UNIT_FILE_SYSTEM
:
853 return strv_new("/run/systemd/system-generators",
854 "/etc/systemd/system-generators",
855 "/usr/local/lib/systemd/system-generators",
856 SYSTEM_GENERATOR_PATH
,
859 case UNIT_FILE_GLOBAL
:
861 return strv_new("/run/systemd/user-generators",
862 "/etc/systemd/user-generators",
863 "/usr/local/lib/systemd/user-generators",
868 assert_not_reached("Hmm, unexpected scope.");