1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
11 #include "nulstr-util.h"
12 #include "path-lookup.h"
13 #include "path-util.h"
14 #include "stat-util.h"
15 #include "string-util.h"
17 #include "tmpfile-util.h"
18 #include "user-util.h"
20 int xdg_user_runtime_dir(char **ret
, const char *suffix
) {
27 e
= getenv("XDG_RUNTIME_DIR");
31 j
= path_join(e
, suffix
);
39 int xdg_user_config_dir(char **ret
, const char *suffix
) {
40 _cleanup_free_
char *j
= NULL
;
46 e
= getenv("XDG_CONFIG_HOME");
48 j
= path_join(e
, suffix
);
56 if (!path_extend(&j
, "/.config", suffix
))
64 int xdg_user_data_dir(char **ret
, const char *suffix
) {
65 _cleanup_free_
char *j
= NULL
;
72 /* We don't treat /etc/xdg/systemd here as the spec
73 * suggests because we assume that is a link to
74 * /etc/systemd/ anyway. */
76 e
= getenv("XDG_DATA_HOME");
78 j
= path_join(e
, suffix
);
86 if (!path_extend(&j
, "/.local/share", suffix
))
94 int runtime_directory(char **ret
, RuntimeScope scope
, const char *suffix
) {
95 _cleanup_free_
char *d
= NULL
;
100 assert(IN_SET(scope
, RUNTIME_SCOPE_SYSTEM
, RUNTIME_SCOPE_USER
, RUNTIME_SCOPE_GLOBAL
));
102 /* Accept $RUNTIME_DIRECTORY as authoritative
103 * If its missing apply the suffix to /run or $XDG_RUNTIME_DIR
104 * if we are in a user runtime scope.
106 * Return value indicates whether the suffix was applied or not */
108 const char *e
= secure_getenv("RUNTIME_DIRECTORY");
118 if (scope
== RUNTIME_SCOPE_USER
) {
119 r
= xdg_user_runtime_dir(&d
, suffix
);
123 d
= path_join("/run", suffix
);
132 static const char* const user_data_unit_paths
[] = {
133 "/usr/local/lib/systemd/user",
134 "/usr/local/share/systemd/user",
136 "/usr/lib/systemd/user",
137 "/usr/share/systemd/user",
141 static const char* const user_config_unit_paths
[] = {
142 USER_CONFIG_UNIT_DIR
,
147 int xdg_user_dirs(char ***ret_config_dirs
, char ***ret_data_dirs
) {
148 /* Implement the mechanisms defined in
150 * https://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
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.
157 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
159 e
= getenv("XDG_CONFIG_DIRS");
161 config_dirs
= strv_split(e
, ":");
163 config_dirs
= strv_new("/etc/xdg");
167 e
= getenv("XDG_DATA_DIRS");
169 data_dirs
= strv_split(e
, ":");
171 data_dirs
= strv_new("/usr/local/share",
176 *ret_config_dirs
= TAKE_PTR(config_dirs
);
177 *ret_data_dirs
= TAKE_PTR(data_dirs
);
182 static char** user_dirs(
183 const char *persistent_config
,
184 const char *runtime_config
,
185 const char *global_persistent_config
,
186 const char *global_runtime_config
,
187 const char *generator
,
188 const char *generator_early
,
189 const char *generator_late
,
190 const char *transient
,
191 const char *persistent_control
,
192 const char *runtime_control
) {
194 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
195 _cleanup_free_
char *data_home
= NULL
;
196 _cleanup_strv_free_
char **res
= NULL
;
199 r
= xdg_user_dirs(&config_dirs
, &data_dirs
);
203 r
= xdg_user_data_dir(&data_home
, "/systemd/user");
204 if (r
< 0 && r
!= -ENXIO
)
207 /* Now merge everything we found. */
208 if (strv_extend_many(
214 persistent_config
) < 0)
217 if (strv_extend_strv_concat(&res
, config_dirs
, "/systemd/user") < 0)
220 /* global config has lower priority than the user config of the same type */
221 if (strv_extend(&res
, global_persistent_config
) < 0)
224 if (strv_extend_strv(&res
, (char**) user_config_unit_paths
, false) < 0)
227 if (strv_extend_many(
230 global_runtime_config
,
235 if (strv_extend_strv_concat(&res
, data_dirs
, "/systemd/user") < 0)
238 if (strv_extend_strv(&res
, (char**) user_data_unit_paths
, false) < 0)
241 if (strv_extend(&res
, generator_late
) < 0)
244 if (path_strv_make_absolute_cwd(res
) < 0)
247 return TAKE_PTR(res
);
250 bool path_is_user_data_dir(const char *path
) {
253 return strv_contains((char**) user_data_unit_paths
, path
);
256 bool path_is_user_config_dir(const char *path
) {
259 return strv_contains((char**) user_config_unit_paths
, path
);
262 static int acquire_generator_dirs(
266 char **generator_early
,
267 char **generator_late
) {
269 _cleanup_free_
char *x
= NULL
, *y
= NULL
, *z
= NULL
, *p
= NULL
;
273 assert(generator_early
);
274 assert(generator_late
);
275 assert(IN_SET(scope
, RUNTIME_SCOPE_SYSTEM
, RUNTIME_SCOPE_USER
, RUNTIME_SCOPE_GLOBAL
));
277 if (scope
== RUNTIME_SCOPE_GLOBAL
)
282 else if (scope
== RUNTIME_SCOPE_SYSTEM
)
283 prefix
= "/run/systemd";
285 /* RUNTIME_SCOPE_USER */
288 e
= getenv("XDG_RUNTIME_DIR");
292 p
= path_join(e
, "/systemd");
299 x
= path_join(prefix
, "generator");
303 y
= path_join(prefix
, "generator.early");
307 z
= path_join(prefix
, "generator.late");
311 *generator
= TAKE_PTR(x
);
312 *generator_early
= TAKE_PTR(y
);
313 *generator_late
= TAKE_PTR(z
);
318 static int acquire_transient_dir(
326 assert(IN_SET(scope
, RUNTIME_SCOPE_SYSTEM
, RUNTIME_SCOPE_USER
, RUNTIME_SCOPE_GLOBAL
));
328 if (scope
== RUNTIME_SCOPE_GLOBAL
)
332 transient
= path_join(tempdir
, "transient");
333 else if (scope
== RUNTIME_SCOPE_SYSTEM
)
334 transient
= strdup("/run/systemd/transient");
336 return xdg_user_runtime_dir(ret
, "/systemd/transient");
344 static int acquire_config_dirs(RuntimeScope scope
, char **persistent
, char **runtime
) {
345 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
353 case RUNTIME_SCOPE_SYSTEM
:
354 a
= strdup(SYSTEM_CONFIG_UNIT_DIR
);
355 b
= strdup("/run/systemd/system");
358 case RUNTIME_SCOPE_GLOBAL
:
359 a
= strdup(USER_CONFIG_UNIT_DIR
);
360 b
= strdup("/run/systemd/user");
363 case RUNTIME_SCOPE_USER
:
364 r
= xdg_user_config_dir(&a
, "/systemd/user");
365 if (r
< 0 && r
!= -ENXIO
)
368 r
= xdg_user_runtime_dir(runtime
, "/systemd/user");
373 /* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
374 * directory to NULL */
378 *persistent
= TAKE_PTR(a
);
383 assert_not_reached();
389 *persistent
= TAKE_PTR(a
);
390 *runtime
= TAKE_PTR(b
);
395 static int acquire_control_dirs(RuntimeScope scope
, char **persistent
, char **runtime
) {
396 _cleanup_free_
char *a
= NULL
;
404 case RUNTIME_SCOPE_SYSTEM
: {
405 _cleanup_free_
char *b
= NULL
;
407 a
= strdup("/etc/systemd/system.control");
411 b
= strdup("/run/systemd/system.control");
415 *runtime
= TAKE_PTR(b
);
420 case RUNTIME_SCOPE_USER
:
421 r
= xdg_user_config_dir(&a
, "/systemd/user.control");
422 if (r
< 0 && r
!= -ENXIO
)
425 r
= xdg_user_runtime_dir(runtime
, "/systemd/user.control");
430 /* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
437 case RUNTIME_SCOPE_GLOBAL
:
441 assert_not_reached();
444 *persistent
= TAKE_PTR(a
);
449 static int acquire_attached_dirs(
451 char **ret_persistent
,
452 char **ret_runtime
) {
454 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
456 assert(ret_persistent
);
459 /* Portable services are not available to regular users for now. */
460 if (scope
!= RUNTIME_SCOPE_SYSTEM
)
463 a
= strdup("/etc/systemd/system.attached");
467 b
= strdup("/run/systemd/system.attached");
471 *ret_persistent
= TAKE_PTR(a
);
472 *ret_runtime
= TAKE_PTR(b
);
477 static int patch_root_prefix(char **p
, const char *root_dir
) {
485 c
= path_join(root_dir
, *p
);
489 free_and_replace(*p
, c
);
493 static int patch_root_prefix_strv(char **l
, const char *root_dir
) {
500 r
= patch_root_prefix(i
, root_dir
);
508 static int get_paths_from_environ(const char *var
, char ***paths
, bool *append
) {
522 k
= endswith(e
, ":");
524 e
= strndupa_safe(e
, k
- e
);
528 /* FIXME: empty components in other places should be rejected. */
530 r
= path_split_and_make_absolute(e
, paths
);
538 int lookup_paths_init(
541 LookupPathsFlags flags
,
542 const char *root_dir
) {
544 _cleanup_(rmdir_and_freep
) char *tempdir
= NULL
;
547 *persistent_config
= NULL
, *runtime_config
= NULL
,
548 *global_persistent_config
= NULL
, *global_runtime_config
= NULL
,
549 *generator
= NULL
, *generator_early
= NULL
, *generator_late
= NULL
,
551 *persistent_control
= NULL
, *runtime_control
= NULL
,
552 *persistent_attached
= NULL
, *runtime_attached
= NULL
;
553 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
554 _cleanup_strv_free_
char **paths
= NULL
;
559 assert(scope
< _RUNTIME_SCOPE_MAX
);
561 if (!empty_or_root(root_dir
)) {
562 if (scope
== RUNTIME_SCOPE_USER
)
565 r
= is_dir(root_dir
, true);
571 root
= strdup(root_dir
);
576 if (flags
& LOOKUP_PATHS_TEMPORARY_GENERATED
) {
577 r
= mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir
);
579 return log_debug_errno(r
, "Failed to create temporary directory: %m");
582 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
583 r
= acquire_config_dirs(scope
, &persistent_config
, &runtime_config
);
587 if (scope
== RUNTIME_SCOPE_USER
) {
588 r
= acquire_config_dirs(RUNTIME_SCOPE_GLOBAL
, &global_persistent_config
, &global_runtime_config
);
593 if ((flags
& LOOKUP_PATHS_EXCLUDE_GENERATED
) == 0) {
594 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
595 r
= acquire_generator_dirs(scope
, tempdir
,
596 &generator
, &generator_early
, &generator_late
);
597 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
601 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
602 r
= acquire_transient_dir(scope
, tempdir
, &transient
);
603 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
606 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
607 r
= acquire_control_dirs(scope
, &persistent_control
, &runtime_control
);
608 if (r
< 0 && r
!= -EOPNOTSUPP
)
611 r
= acquire_attached_dirs(scope
, &persistent_attached
, &runtime_attached
);
612 if (r
< 0 && r
!= -EOPNOTSUPP
)
615 /* First priority is whatever has been passed to us via env vars */
616 r
= get_paths_from_environ("SYSTEMD_UNIT_PATH", &paths
, &append
);
620 if (!paths
|| append
) {
621 /* Let's figure something out. */
623 _cleanup_strv_free_
char **add
= NULL
;
625 /* For the user units we include share/ in the search
626 * path in order to comply with the XDG basedir spec.
627 * For the system stuff we avoid such nonsense. OTOH
628 * we include /lib in the search path for the system
629 * stuff but avoid it for user stuff. */
633 case RUNTIME_SCOPE_SYSTEM
:
635 /* If you modify this you also want to modify
636 * systemdsystemunitpath= in systemd.pc.in! */
637 STRV_IFNOTNULL(persistent_control
),
638 STRV_IFNOTNULL(runtime_control
),
639 STRV_IFNOTNULL(transient
),
640 STRV_IFNOTNULL(generator_early
),
642 SYSTEM_CONFIG_UNIT_DIR
,
643 "/etc/systemd/system",
644 STRV_IFNOTNULL(persistent_attached
),
646 "/run/systemd/system",
647 STRV_IFNOTNULL(runtime_attached
),
648 STRV_IFNOTNULL(generator
),
649 "/usr/local/lib/systemd/system",
650 SYSTEM_DATA_UNIT_DIR
,
651 "/usr/lib/systemd/system",
652 /* To be used ONLY for images which might be legacy split-usr */
653 STRV_IFNOTNULL(flags
& LOOKUP_PATHS_SPLIT_USR
? "/lib/systemd/system" : NULL
),
654 STRV_IFNOTNULL(generator_late
));
657 case RUNTIME_SCOPE_GLOBAL
:
659 /* If you modify this you also want to modify
660 * systemduserunitpath= in systemd.pc.in, and
661 * the arrays in user_dirs() above! */
662 STRV_IFNOTNULL(persistent_control
),
663 STRV_IFNOTNULL(runtime_control
),
664 STRV_IFNOTNULL(transient
),
665 STRV_IFNOTNULL(generator_early
),
667 USER_CONFIG_UNIT_DIR
,
671 STRV_IFNOTNULL(generator
),
672 "/usr/local/share/systemd/user",
673 "/usr/share/systemd/user",
674 "/usr/local/lib/systemd/user",
676 "/usr/lib/systemd/user",
677 STRV_IFNOTNULL(generator_late
));
680 case RUNTIME_SCOPE_USER
:
681 add
= user_dirs(persistent_config
, runtime_config
,
682 global_persistent_config
, global_runtime_config
,
683 generator
, generator_early
, generator_late
,
685 persistent_control
, runtime_control
);
689 assert_not_reached();
696 r
= strv_extend_strv(&paths
, add
, true);
700 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
701 * and don't have to copy anything */
702 paths
= TAKE_PTR(add
);
705 r
= patch_root_prefix(&persistent_config
, root
);
708 r
= patch_root_prefix(&runtime_config
, root
);
712 r
= patch_root_prefix(&generator
, root
);
715 r
= patch_root_prefix(&generator_early
, root
);
718 r
= patch_root_prefix(&generator_late
, root
);
722 r
= patch_root_prefix(&transient
, root
);
726 r
= patch_root_prefix(&persistent_control
, root
);
729 r
= patch_root_prefix(&runtime_control
, root
);
733 r
= patch_root_prefix(&persistent_attached
, root
);
736 r
= patch_root_prefix(&runtime_attached
, root
);
740 r
= patch_root_prefix_strv(paths
, root
);
744 *lp
= (LookupPaths
) {
745 .search_path
= strv_uniq(TAKE_PTR(paths
)),
747 .persistent_config
= TAKE_PTR(persistent_config
),
748 .runtime_config
= TAKE_PTR(runtime_config
),
750 .generator
= TAKE_PTR(generator
),
751 .generator_early
= TAKE_PTR(generator_early
),
752 .generator_late
= TAKE_PTR(generator_late
),
754 .transient
= TAKE_PTR(transient
),
756 .persistent_control
= TAKE_PTR(persistent_control
),
757 .runtime_control
= TAKE_PTR(runtime_control
),
759 .persistent_attached
= TAKE_PTR(persistent_attached
),
760 .runtime_attached
= TAKE_PTR(runtime_attached
),
762 .root_dir
= TAKE_PTR(root
),
763 .temporary_dir
= TAKE_PTR(tempdir
),
769 int lookup_paths_init_or_warn(LookupPaths
*lp
, RuntimeScope scope
, LookupPathsFlags flags
, const char *root_dir
) {
772 r
= lookup_paths_init(lp
, scope
, flags
, root_dir
);
774 return log_error_errno(r
, "Failed to initialize unit search paths%s%s: %m",
775 isempty(root_dir
) ? "" : " for root directory ", strempty(root_dir
));
779 void lookup_paths_done(LookupPaths
*lp
) {
782 lp
->search_path
= strv_free(lp
->search_path
);
784 lp
->persistent_config
= mfree(lp
->persistent_config
);
785 lp
->runtime_config
= mfree(lp
->runtime_config
);
787 lp
->persistent_attached
= mfree(lp
->persistent_attached
);
788 lp
->runtime_attached
= mfree(lp
->runtime_attached
);
790 lp
->generator
= mfree(lp
->generator
);
791 lp
->generator_early
= mfree(lp
->generator_early
);
792 lp
->generator_late
= mfree(lp
->generator_late
);
794 lp
->transient
= mfree(lp
->transient
);
796 lp
->persistent_control
= mfree(lp
->persistent_control
);
797 lp
->runtime_control
= mfree(lp
->runtime_control
);
799 lp
->root_dir
= mfree(lp
->root_dir
);
800 lp
->temporary_dir
= mfree(lp
->temporary_dir
);
803 void lookup_paths_log(LookupPaths
*lp
) {
806 if (strv_isempty(lp
->search_path
)) {
807 log_debug("Ignoring unit files.");
808 lp
->search_path
= strv_free(lp
->search_path
);
810 _cleanup_free_
char *t
= NULL
;
812 t
= strv_join(lp
->search_path
, "\n\t");
813 log_debug("Looking for unit files in (higher priority first):\n\t%s", strna(t
));
817 char **generator_binary_paths(RuntimeScope scope
) {
818 bool append
= false; /* Add items from SYSTEMD_GENERATOR_PATH before normal directories */
819 _cleanup_strv_free_
char **paths
= NULL
;
822 /* First priority is whatever has been passed to us via env vars */
823 r
= get_paths_from_environ("SYSTEMD_GENERATOR_PATH", &paths
, &append
);
827 if (!paths
|| append
) {
828 _cleanup_strv_free_
char **add
= NULL
;
832 case RUNTIME_SCOPE_SYSTEM
:
833 add
= strv_new("/run/systemd/system-generators",
834 "/etc/systemd/system-generators",
835 "/usr/local/lib/systemd/system-generators",
836 SYSTEM_GENERATOR_DIR
);
839 case RUNTIME_SCOPE_GLOBAL
:
840 case RUNTIME_SCOPE_USER
:
841 add
= strv_new("/run/systemd/user-generators",
842 "/etc/systemd/user-generators",
843 "/usr/local/lib/systemd/user-generators",
848 assert_not_reached();
854 r
= strv_extend_strv(&paths
, add
, true);
858 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
859 * and don't have to copy anything */
860 paths
= TAKE_PTR(add
);
863 return TAKE_PTR(paths
);
866 char **env_generator_binary_paths(RuntimeScope runtime_scope
) {
867 _cleanup_strv_free_
char **paths
= NULL
, **add
= NULL
;
868 bool append
= false; /* Add items from SYSTEMD_ENVIRONMENT_GENERATOR_PATH before normal directories */
871 /* First priority is whatever has been passed to us via env vars */
872 r
= get_paths_from_environ("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", &paths
, &append
);
876 if (!paths
|| append
) {
877 switch (runtime_scope
) {
879 case RUNTIME_SCOPE_SYSTEM
:
880 add
= strv_new("/run/systemd/system-environment-generators",
881 "/etc/systemd/system-environment-generators",
882 "/usr/local/lib/systemd/system-environment-generators",
883 SYSTEM_ENV_GENERATOR_DIR
);
886 case RUNTIME_SCOPE_USER
:
887 add
= strv_new("/run/systemd/user-environment-generators",
888 "/etc/systemd/user-environment-generators",
889 "/usr/local/lib/systemd/user-environment-generators",
890 USER_ENV_GENERATOR_DIR
);
894 assert_not_reached();
901 r
= strv_extend_strv(&paths
, add
, true);
905 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
906 * and don't have to copy anything */
907 paths
= TAKE_PTR(add
);
909 return TAKE_PTR(paths
);
912 int find_portable_profile(const char *name
, const char *unit
, char **ret_path
) {
918 assert_se(dot
= strrchr(unit
, '.'));
920 NULSTR_FOREACH(p
, PORTABLE_PROFILE_DIRS
) {
921 _cleanup_free_
char *joined
= NULL
;
923 joined
= strjoin(p
, "/", name
, "/", dot
+ 1, ".conf");
927 if (laccess(joined
, F_OK
) >= 0) {
928 *ret_path
= TAKE_PTR(joined
);