1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "alloc-util.h"
33 #include "path-lookup.h"
34 #include "path-util.h"
36 #include "stat-util.h"
37 #include "string-util.h"
39 #include "user-util.h"
42 int xdg_user_runtime_dir(char **ret
, const char *suffix
) {
49 e
= getenv("XDG_RUNTIME_DIR");
53 j
= strappend(e
, suffix
);
61 int xdg_user_config_dir(char **ret
, const char *suffix
) {
68 e
= getenv("XDG_CONFIG_HOME");
70 j
= strappend(e
, suffix
);
72 _cleanup_free_
char *home
= NULL
;
74 r
= get_home_dir(&home
);
78 j
= strjoin(home
, "/.config", suffix
);
88 int xdg_user_data_dir(char **ret
, const char *suffix
) {
96 /* We don't treat /etc/xdg/systemd here as the spec
97 * suggests because we assume that is a link to
98 * /etc/systemd/ anyway. */
100 e
= getenv("XDG_DATA_HOME");
102 j
= strappend(e
, suffix
);
104 _cleanup_free_
char *home
= NULL
;
106 r
= get_home_dir(&home
);
110 j
= strjoin(home
, "/.local/share", suffix
);
119 static const char* const user_data_unit_paths
[] = {
120 "/usr/local/lib/systemd/user",
121 "/usr/local/share/systemd/user",
123 "/usr/lib/systemd/user",
124 "/usr/share/systemd/user",
128 static const char* const user_config_unit_paths
[] = {
129 USER_CONFIG_UNIT_PATH
,
134 int xdg_user_dirs(char ***ret_config_dirs
, char ***ret_data_dirs
) {
135 /* Implement the mechanisms defined in
137 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
139 * We look in both the config and the data dirs because we
140 * want to encourage that distributors ship their unit files
141 * as data, and allow overriding as configuration.
144 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
146 e
= getenv("XDG_CONFIG_DIRS");
148 config_dirs
= strv_split(e
, ":");
153 e
= getenv("XDG_DATA_DIRS");
155 data_dirs
= strv_split(e
, ":");
157 data_dirs
= strv_new("/usr/local/share",
163 *ret_config_dirs
= config_dirs
;
164 *ret_data_dirs
= data_dirs
;
165 config_dirs
= data_dirs
= NULL
;
169 static char** user_dirs(
170 const char *persistent_config
,
171 const char *runtime_config
,
172 const char *global_persistent_config
,
173 const char *global_runtime_config
,
174 const char *generator
,
175 const char *generator_early
,
176 const char *generator_late
,
177 const char *transient
,
178 const char *persistent_control
,
179 const char *runtime_control
) {
181 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
182 _cleanup_free_
char *data_home
= NULL
;
183 _cleanup_strv_free_
char **res
= NULL
;
186 r
= xdg_user_dirs(&config_dirs
, &data_dirs
);
190 r
= xdg_user_data_dir(&data_home
, "/systemd/user");
191 if (r
< 0 && r
!= -ENXIO
)
194 /* Now merge everything we found. */
195 if (strv_extend(&res
, persistent_control
) < 0)
198 if (strv_extend(&res
, runtime_control
) < 0)
201 if (strv_extend(&res
, transient
) < 0)
204 if (strv_extend(&res
, generator_early
) < 0)
207 if (strv_extend_strv_concat(&res
, config_dirs
, "/systemd/user") < 0)
210 if (strv_extend(&res
, persistent_config
) < 0)
213 /* global config has lower priority than the user config of the same type */
214 if (strv_extend(&res
, global_persistent_config
) < 0)
217 if (strv_extend_strv(&res
, (char**) user_config_unit_paths
, false) < 0)
220 if (strv_extend(&res
, runtime_config
) < 0)
223 if (strv_extend(&res
, global_runtime_config
) < 0)
226 if (strv_extend(&res
, generator
) < 0)
229 if (strv_extend(&res
, data_home
) < 0)
232 if (strv_extend_strv_concat(&res
, data_dirs
, "/systemd/user") < 0)
235 if (strv_extend_strv(&res
, (char**) user_data_unit_paths
, false) < 0)
238 if (strv_extend(&res
, generator_late
) < 0)
241 if (path_strv_make_absolute_cwd(res
) < 0)
244 return TAKE_PTR(res
);
247 bool path_is_user_data_dir(const char *path
) {
250 return strv_contains((char**) user_data_unit_paths
, path
);
253 bool path_is_user_config_dir(const char *path
) {
256 return strv_contains((char**) user_config_unit_paths
, path
);
259 static int acquire_generator_dirs(
263 char **generator_early
,
264 char **generator_late
) {
266 _cleanup_free_
char *x
= NULL
, *y
= NULL
, *z
= NULL
;
270 assert(generator_early
);
271 assert(generator_late
);
272 assert(IN_SET(scope
, UNIT_FILE_SYSTEM
, UNIT_FILE_USER
, UNIT_FILE_GLOBAL
));
274 if (scope
== UNIT_FILE_GLOBAL
)
280 else if (scope
== UNIT_FILE_SYSTEM
)
281 prefix
= "/run/systemd";
283 else if (scope
== UNIT_FILE_USER
) {
286 e
= getenv("XDG_RUNTIME_DIR");
290 prefix
= strjoina(e
, "/systemd");
293 x
= strappend(prefix
, "/generator");
297 y
= strappend(prefix
, "/generator.early");
301 z
= strappend(prefix
, "/generator.late");
305 *generator
= TAKE_PTR(x
);
306 *generator_early
= TAKE_PTR(y
);
307 *generator_late
= TAKE_PTR(z
);
312 static int acquire_transient_dir(
320 assert(IN_SET(scope
, UNIT_FILE_SYSTEM
, UNIT_FILE_USER
, UNIT_FILE_GLOBAL
));
322 if (scope
== UNIT_FILE_GLOBAL
)
326 transient
= strjoin(tempdir
, "/transient");
327 else if (scope
== UNIT_FILE_SYSTEM
)
328 transient
= strdup("/run/systemd/transient");
330 return xdg_user_runtime_dir(ret
, "/systemd/transient");
338 static int acquire_config_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
339 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
347 case UNIT_FILE_SYSTEM
:
348 a
= strdup(SYSTEM_CONFIG_UNIT_PATH
);
349 b
= strdup("/run/systemd/system");
352 case UNIT_FILE_GLOBAL
:
353 a
= strdup(USER_CONFIG_UNIT_PATH
);
354 b
= strdup("/run/systemd/user");
358 r
= xdg_user_config_dir(&a
, "/systemd/user");
359 if (r
< 0 && r
!= -ENXIO
)
362 r
= xdg_user_runtime_dir(runtime
, "/systemd/user");
367 /* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
368 * directory to NULL */
372 *persistent
= TAKE_PTR(a
);
377 assert_not_reached("Hmm, unexpected scope value.");
383 *persistent
= TAKE_PTR(a
);
384 *runtime
= TAKE_PTR(b
);
389 static int acquire_control_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
390 _cleanup_free_
char *a
= NULL
;
398 case UNIT_FILE_SYSTEM
: {
399 _cleanup_free_
char *b
= NULL
;
401 a
= strdup("/etc/systemd/system.control");
405 b
= strdup("/run/systemd/system.control");
409 *runtime
= TAKE_PTR(b
);
415 r
= xdg_user_config_dir(&a
, "/systemd/user.control");
416 if (r
< 0 && r
!= -ENXIO
)
419 r
= xdg_user_runtime_dir(runtime
, "/systemd/user.control");
424 /* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
431 case UNIT_FILE_GLOBAL
:
435 assert_not_reached("Hmm, unexpected scope value.");
438 *persistent
= TAKE_PTR(a
);
443 static int patch_root_prefix(char **p
, const char *root_dir
) {
451 c
= prefix_root(root_dir
, *p
);
461 static int patch_root_prefix_strv(char **l
, const char *root_dir
) {
469 r
= patch_root_prefix(i
, root_dir
);
477 int lookup_paths_init(
480 LookupPathsFlags flags
,
481 const char *root_dir
) {
483 _cleanup_(rmdir_and_freep
) char *tempdir
= NULL
;
486 *persistent_config
= NULL
, *runtime_config
= NULL
,
487 *global_persistent_config
= NULL
, *global_runtime_config
= NULL
,
488 *generator
= NULL
, *generator_early
= NULL
, *generator_late
= NULL
,
490 *persistent_control
= NULL
, *runtime_control
= NULL
;
491 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
492 _cleanup_strv_free_
char **paths
= NULL
;
498 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
500 if (!isempty(root_dir
) && !path_equal(root_dir
, "/")) {
501 if (scope
== UNIT_FILE_USER
)
504 r
= is_dir(root_dir
, true);
510 root
= strdup(root_dir
);
515 if (flags
& LOOKUP_PATHS_TEMPORARY_GENERATED
) {
516 r
= mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir
);
518 return log_error_errno(r
, "Failed to create temporary directory: %m");
521 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
522 r
= acquire_config_dirs(scope
, &persistent_config
, &runtime_config
);
526 if (scope
== UNIT_FILE_USER
) {
527 r
= acquire_config_dirs(UNIT_FILE_GLOBAL
, &global_persistent_config
, &global_runtime_config
);
532 if ((flags
& LOOKUP_PATHS_EXCLUDE_GENERATED
) == 0) {
533 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
534 r
= acquire_generator_dirs(scope
, tempdir
,
535 &generator
, &generator_early
, &generator_late
);
536 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
540 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
541 r
= acquire_transient_dir(scope
, tempdir
, &transient
);
542 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
545 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
546 r
= acquire_control_dirs(scope
, &persistent_control
, &runtime_control
);
547 if (r
< 0 && r
!= -EOPNOTSUPP
)
550 /* First priority is whatever has been passed to us via env vars */
551 e
= getenv("SYSTEMD_UNIT_PATH");
555 k
= endswith(e
, ":");
557 e
= strndupa(e
, k
- e
);
561 /* FIXME: empty components in other places should be rejected. */
563 r
= path_split_and_make_absolute(e
, &paths
);
568 if (!paths
|| append
) {
569 /* Let's figure something out. */
571 _cleanup_strv_free_
char **add
= NULL
;
573 /* For the user units we include share/ in the search
574 * path in order to comply with the XDG basedir spec.
575 * For the system stuff we avoid such nonsense. OTOH
576 * we include /lib in the search path for the system
577 * stuff but avoid it for user stuff. */
581 case UNIT_FILE_SYSTEM
:
583 /* If you modify this you also want to modify
584 * systemdsystemunitpath= in systemd.pc.in! */
585 STRV_IFNOTNULL(persistent_control
),
586 STRV_IFNOTNULL(runtime_control
),
587 STRV_IFNOTNULL(transient
),
588 STRV_IFNOTNULL(generator_early
),
590 SYSTEM_CONFIG_UNIT_PATH
,
591 "/etc/systemd/system",
593 "/run/systemd/system",
594 STRV_IFNOTNULL(generator
),
595 "/usr/local/lib/systemd/system",
596 SYSTEM_DATA_UNIT_PATH
,
597 "/usr/lib/systemd/system",
599 "/lib/systemd/system",
601 STRV_IFNOTNULL(generator_late
),
605 case UNIT_FILE_GLOBAL
:
607 /* If you modify this you also want to modify
608 * systemduserunitpath= in systemd.pc.in, and
609 * the arrays in user_dirs() above! */
610 STRV_IFNOTNULL(persistent_control
),
611 STRV_IFNOTNULL(runtime_control
),
612 STRV_IFNOTNULL(transient
),
613 STRV_IFNOTNULL(generator_early
),
615 USER_CONFIG_UNIT_PATH
,
619 STRV_IFNOTNULL(generator
),
620 "/usr/local/share/systemd/user",
621 "/usr/share/systemd/user",
622 "/usr/local/lib/systemd/user",
624 "/usr/lib/systemd/user",
625 STRV_IFNOTNULL(generator_late
),
630 add
= user_dirs(persistent_config
, runtime_config
,
631 global_persistent_config
, global_runtime_config
,
632 generator
, generator_early
, generator_late
,
634 persistent_control
, runtime_control
);
638 assert_not_reached("Hmm, unexpected scope?");
645 r
= strv_extend_strv(&paths
, add
, true);
649 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
650 * and don't have to copy anything */
651 paths
= TAKE_PTR(add
);
654 r
= patch_root_prefix(&persistent_config
, root
);
657 r
= patch_root_prefix(&runtime_config
, root
);
661 r
= patch_root_prefix(&generator
, root
);
664 r
= patch_root_prefix(&generator_early
, root
);
667 r
= patch_root_prefix(&generator_late
, root
);
671 r
= patch_root_prefix(&transient
, root
);
675 r
= patch_root_prefix(&persistent_control
, root
);
679 r
= patch_root_prefix(&runtime_control
, root
);
683 r
= patch_root_prefix_strv(paths
, root
);
687 p
->search_path
= strv_uniq(paths
);
690 p
->persistent_config
= TAKE_PTR(persistent_config
);
691 p
->runtime_config
= TAKE_PTR(runtime_config
);
693 p
->generator
= TAKE_PTR(generator
);
694 p
->generator_early
= TAKE_PTR(generator_early
);
695 p
->generator_late
= TAKE_PTR(generator_late
);
697 p
->transient
= TAKE_PTR(transient
);
699 p
->persistent_control
= TAKE_PTR(persistent_control
);
700 p
->runtime_control
= TAKE_PTR(runtime_control
);
702 p
->root_dir
= TAKE_PTR(root
);
703 p
->temporary_dir
= TAKE_PTR(tempdir
);
708 void lookup_paths_free(LookupPaths
*p
) {
712 p
->search_path
= strv_free(p
->search_path
);
714 p
->persistent_config
= mfree(p
->persistent_config
);
715 p
->runtime_config
= mfree(p
->runtime_config
);
717 p
->generator
= mfree(p
->generator
);
718 p
->generator_early
= mfree(p
->generator_early
);
719 p
->generator_late
= mfree(p
->generator_late
);
721 p
->transient
= mfree(p
->transient
);
723 p
->persistent_control
= mfree(p
->persistent_control
);
724 p
->runtime_control
= mfree(p
->runtime_control
);
726 p
->root_dir
= mfree(p
->root_dir
);
727 p
->temporary_dir
= mfree(p
->temporary_dir
);
730 int lookup_paths_reduce(LookupPaths
*p
) {
731 _cleanup_free_
struct stat
*stats
= NULL
;
732 size_t n_stats
= 0, allocated
= 0;
738 /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
739 * the same by comparing their device and inode numbers. Note one special tweak: when we have a root path set,
740 * we do not follow symlinks when retrieving them, because the kernel wouldn't take the root prefix into
741 * account when following symlinks. When we have no root path set this restriction does not apply however. */
746 while (p
->search_path
[c
]) {
750 /* Never strip the transient and control directories from the path */
751 if (path_equal_ptr(p
->search_path
[c
], p
->transient
) ||
752 path_equal_ptr(p
->search_path
[c
], p
->persistent_control
) ||
753 path_equal_ptr(p
->search_path
[c
], p
->runtime_control
)) {
759 r
= lstat(p
->search_path
[c
], &st
);
761 r
= stat(p
->search_path
[c
], &st
);
766 /* If something we don't grok happened, let's better leave it in. */
767 log_debug_errno(errno
, "Failed to stat %s: %m", p
->search_path
[c
]);
772 for (k
= 0; k
< n_stats
; k
++) {
773 if (stats
[k
].st_dev
== st
.st_dev
&&
774 stats
[k
].st_ino
== st
.st_ino
)
778 if (k
< n_stats
) /* Is there already an entry with the same device/inode? */
781 if (!GREEDY_REALLOC(stats
, allocated
, n_stats
+1))
784 stats
[n_stats
++] = st
;
789 free(p
->search_path
[c
]);
790 memmove(p
->search_path
+ c
,
791 p
->search_path
+ c
+ 1,
792 (strv_length(p
->search_path
+ c
+ 1) + 1) * sizeof(char*));
795 if (strv_isempty(p
->search_path
)) {
796 log_debug("Ignoring unit files.");
797 p
->search_path
= strv_free(p
->search_path
);
799 _cleanup_free_
char *t
;
801 t
= strv_join(p
->search_path
, "\n\t");
805 log_debug("Looking for unit files in (higher priority first):\n\t%s", t
);
811 int lookup_paths_mkdir_generator(LookupPaths
*p
) {
816 if (!p
->generator
|| !p
->generator_early
|| !p
->generator_late
)
819 r
= mkdir_p_label(p
->generator
, 0755);
821 q
= mkdir_p_label(p
->generator_early
, 0755);
825 q
= mkdir_p_label(p
->generator_late
, 0755);
832 void lookup_paths_trim_generator(LookupPaths
*p
) {
835 /* Trim empty dirs */
838 (void) rmdir(p
->generator
);
839 if (p
->generator_early
)
840 (void) rmdir(p
->generator_early
);
841 if (p
->generator_late
)
842 (void) rmdir(p
->generator_late
);
845 void lookup_paths_flush_generator(LookupPaths
*p
) {
848 /* Flush the generated unit files in full */
851 (void) rm_rf(p
->generator
, REMOVE_ROOT
);
852 if (p
->generator_early
)
853 (void) rm_rf(p
->generator_early
, REMOVE_ROOT
);
854 if (p
->generator_late
)
855 (void) rm_rf(p
->generator_late
, REMOVE_ROOT
);
857 if (p
->temporary_dir
)
858 (void) rm_rf(p
->temporary_dir
, REMOVE_ROOT
);
861 char **generator_binary_paths(UnitFileScope scope
) {
865 case UNIT_FILE_SYSTEM
:
866 return strv_new("/run/systemd/system-generators",
867 "/etc/systemd/system-generators",
868 "/usr/local/lib/systemd/system-generators",
869 SYSTEM_GENERATOR_PATH
,
872 case UNIT_FILE_GLOBAL
:
874 return strv_new("/run/systemd/user-generators",
875 "/etc/systemd/user-generators",
876 "/usr/local/lib/systemd/user-generators",
881 assert_not_reached("Hmm, unexpected scope.");