1 /* SPDX-License-Identifier: LGPL-2.1+ */
7 #include "alloc-util.h"
11 #include "path-lookup.h"
12 #include "path-util.h"
13 #include "stat-util.h"
14 #include "string-util.h"
16 #include "tmpfile-util.h"
17 #include "user-util.h"
19 int xdg_user_runtime_dir(char **ret
, const char *suffix
) {
26 e
= getenv("XDG_RUNTIME_DIR");
30 j
= path_join(e
, suffix
);
38 int xdg_user_config_dir(char **ret
, const char *suffix
) {
45 e
= getenv("XDG_CONFIG_HOME");
47 j
= path_join(e
, suffix
);
49 _cleanup_free_
char *home
= NULL
;
51 r
= get_home_dir(&home
);
55 j
= path_join(home
, "/.config", suffix
);
65 int xdg_user_data_dir(char **ret
, const char *suffix
) {
73 /* We don't treat /etc/xdg/systemd here as the spec
74 * suggests because we assume that is a link to
75 * /etc/systemd/ anyway. */
77 e
= getenv("XDG_DATA_HOME");
79 j
= path_join(e
, suffix
);
81 _cleanup_free_
char *home
= NULL
;
83 r
= get_home_dir(&home
);
87 j
= path_join(home
, "/.local/share", suffix
);
96 static const char* const user_data_unit_paths
[] = {
97 "/usr/local/lib/systemd/user",
98 "/usr/local/share/systemd/user",
100 "/usr/lib/systemd/user",
101 "/usr/share/systemd/user",
105 static const char* const user_config_unit_paths
[] = {
106 USER_CONFIG_UNIT_DIR
,
111 int xdg_user_dirs(char ***ret_config_dirs
, char ***ret_data_dirs
) {
112 /* Implement the mechanisms defined in
114 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
116 * We look in both the config and the data dirs because we
117 * want to encourage that distributors ship their unit files
118 * as data, and allow overriding as configuration.
121 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
123 e
= getenv("XDG_CONFIG_DIRS");
125 config_dirs
= strv_split(e
, ":");
127 config_dirs
= strv_new("/etc/xdg");
131 e
= getenv("XDG_DATA_DIRS");
133 data_dirs
= strv_split(e
, ":");
135 data_dirs
= strv_new("/usr/local/share",
140 *ret_config_dirs
= TAKE_PTR(config_dirs
);
141 *ret_data_dirs
= TAKE_PTR(data_dirs
);
146 static char** user_dirs(
147 const char *persistent_config
,
148 const char *runtime_config
,
149 const char *global_persistent_config
,
150 const char *global_runtime_config
,
151 const char *generator
,
152 const char *generator_early
,
153 const char *generator_late
,
154 const char *transient
,
155 const char *persistent_control
,
156 const char *runtime_control
) {
158 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
159 _cleanup_free_
char *data_home
= NULL
;
160 _cleanup_strv_free_
char **res
= NULL
;
163 r
= xdg_user_dirs(&config_dirs
, &data_dirs
);
167 r
= xdg_user_data_dir(&data_home
, "/systemd/user");
168 if (r
< 0 && r
!= -ENXIO
)
171 /* Now merge everything we found. */
172 if (strv_extend(&res
, persistent_control
) < 0)
175 if (strv_extend(&res
, runtime_control
) < 0)
178 if (strv_extend(&res
, transient
) < 0)
181 if (strv_extend(&res
, generator_early
) < 0)
184 if (strv_extend(&res
, persistent_config
) < 0)
187 if (strv_extend_strv_concat(&res
, config_dirs
, "/systemd/user") < 0)
190 /* global config has lower priority than the user config of the same type */
191 if (strv_extend(&res
, global_persistent_config
) < 0)
194 if (strv_extend_strv(&res
, (char**) user_config_unit_paths
, false) < 0)
197 if (strv_extend(&res
, runtime_config
) < 0)
200 if (strv_extend(&res
, global_runtime_config
) < 0)
203 if (strv_extend(&res
, generator
) < 0)
206 if (strv_extend(&res
, data_home
) < 0)
209 if (strv_extend_strv_concat(&res
, data_dirs
, "/systemd/user") < 0)
212 if (strv_extend_strv(&res
, (char**) user_data_unit_paths
, false) < 0)
215 if (strv_extend(&res
, generator_late
) < 0)
218 if (path_strv_make_absolute_cwd(res
) < 0)
221 return TAKE_PTR(res
);
224 bool path_is_user_data_dir(const char *path
) {
227 return strv_contains((char**) user_data_unit_paths
, path
);
230 bool path_is_user_config_dir(const char *path
) {
233 return strv_contains((char**) user_config_unit_paths
, path
);
236 static int acquire_generator_dirs(
240 char **generator_early
,
241 char **generator_late
) {
243 _cleanup_free_
char *x
= NULL
, *y
= NULL
, *z
= NULL
;
247 assert(generator_early
);
248 assert(generator_late
);
249 assert(IN_SET(scope
, UNIT_FILE_SYSTEM
, UNIT_FILE_USER
, UNIT_FILE_GLOBAL
));
251 if (scope
== UNIT_FILE_GLOBAL
)
256 else if (scope
== UNIT_FILE_SYSTEM
)
257 prefix
= "/run/systemd";
262 e
= getenv("XDG_RUNTIME_DIR");
266 prefix
= strjoina(e
, "/systemd");
269 x
= path_join(prefix
, "generator");
273 y
= path_join(prefix
, "generator.early");
277 z
= path_join(prefix
, "generator.late");
281 *generator
= TAKE_PTR(x
);
282 *generator_early
= TAKE_PTR(y
);
283 *generator_late
= TAKE_PTR(z
);
288 static int acquire_transient_dir(
296 assert(IN_SET(scope
, UNIT_FILE_SYSTEM
, UNIT_FILE_USER
, UNIT_FILE_GLOBAL
));
298 if (scope
== UNIT_FILE_GLOBAL
)
302 transient
= path_join(tempdir
, "transient");
303 else if (scope
== UNIT_FILE_SYSTEM
)
304 transient
= strdup("/run/systemd/transient");
306 return xdg_user_runtime_dir(ret
, "/systemd/transient");
314 static int acquire_config_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
315 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
323 case UNIT_FILE_SYSTEM
:
324 a
= strdup(SYSTEM_CONFIG_UNIT_DIR
);
325 b
= strdup("/run/systemd/system");
328 case UNIT_FILE_GLOBAL
:
329 a
= strdup(USER_CONFIG_UNIT_DIR
);
330 b
= strdup("/run/systemd/user");
334 r
= xdg_user_config_dir(&a
, "/systemd/user");
335 if (r
< 0 && r
!= -ENXIO
)
338 r
= xdg_user_runtime_dir(runtime
, "/systemd/user");
343 /* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
344 * directory to NULL */
348 *persistent
= TAKE_PTR(a
);
353 assert_not_reached("Hmm, unexpected scope value.");
359 *persistent
= TAKE_PTR(a
);
360 *runtime
= TAKE_PTR(b
);
365 static int acquire_control_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
366 _cleanup_free_
char *a
= NULL
;
374 case UNIT_FILE_SYSTEM
: {
375 _cleanup_free_
char *b
= NULL
;
377 a
= strdup("/etc/systemd/system.control");
381 b
= strdup("/run/systemd/system.control");
385 *runtime
= TAKE_PTR(b
);
391 r
= xdg_user_config_dir(&a
, "/systemd/user.control");
392 if (r
< 0 && r
!= -ENXIO
)
395 r
= xdg_user_runtime_dir(runtime
, "/systemd/user.control");
400 /* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
407 case UNIT_FILE_GLOBAL
:
411 assert_not_reached("Hmm, unexpected scope value.");
414 *persistent
= TAKE_PTR(a
);
419 static int acquire_attached_dirs(
421 char **ret_persistent
,
422 char **ret_runtime
) {
424 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
426 assert(ret_persistent
);
429 /* Portable services are not available to regular users for now. */
430 if (scope
!= UNIT_FILE_SYSTEM
)
433 a
= strdup("/etc/systemd/system.attached");
437 b
= strdup("/run/systemd/system.attached");
441 *ret_persistent
= TAKE_PTR(a
);
442 *ret_runtime
= TAKE_PTR(b
);
447 static int patch_root_prefix(char **p
, const char *root_dir
) {
455 c
= path_join(root_dir
, *p
);
459 free_and_replace(*p
, c
);
463 static int patch_root_prefix_strv(char **l
, const char *root_dir
) {
471 r
= patch_root_prefix(i
, root_dir
);
479 static int get_paths_from_environ(const char *var
, char ***paths
, bool *append
) {
493 k
= endswith(e
, ":");
495 e
= strndupa(e
, k
- e
);
499 /* FIXME: empty components in other places should be rejected. */
501 r
= path_split_and_make_absolute(e
, paths
);
509 int lookup_paths_init(
512 LookupPathsFlags flags
,
513 const char *root_dir
) {
515 _cleanup_(rmdir_and_freep
) char *tempdir
= NULL
;
518 *persistent_config
= NULL
, *runtime_config
= NULL
,
519 *global_persistent_config
= NULL
, *global_runtime_config
= NULL
,
520 *generator
= NULL
, *generator_early
= NULL
, *generator_late
= NULL
,
522 *persistent_control
= NULL
, *runtime_control
= NULL
,
523 *persistent_attached
= NULL
, *runtime_attached
= NULL
;
524 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
525 _cleanup_strv_free_
char **paths
= NULL
;
530 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
533 flags
|= LOOKUP_PATHS_SPLIT_USR
;
536 if (!empty_or_root(root_dir
)) {
537 if (scope
== UNIT_FILE_USER
)
540 r
= is_dir(root_dir
, true);
546 root
= strdup(root_dir
);
551 if (flags
& LOOKUP_PATHS_TEMPORARY_GENERATED
) {
552 r
= mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir
);
554 return log_debug_errno(r
, "Failed to create temporary directory: %m");
557 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
558 r
= acquire_config_dirs(scope
, &persistent_config
, &runtime_config
);
562 if (scope
== UNIT_FILE_USER
) {
563 r
= acquire_config_dirs(UNIT_FILE_GLOBAL
, &global_persistent_config
, &global_runtime_config
);
568 if ((flags
& LOOKUP_PATHS_EXCLUDE_GENERATED
) == 0) {
569 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
570 r
= acquire_generator_dirs(scope
, tempdir
,
571 &generator
, &generator_early
, &generator_late
);
572 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
576 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
577 r
= acquire_transient_dir(scope
, tempdir
, &transient
);
578 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
581 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
582 r
= acquire_control_dirs(scope
, &persistent_control
, &runtime_control
);
583 if (r
< 0 && r
!= -EOPNOTSUPP
)
586 r
= acquire_attached_dirs(scope
, &persistent_attached
, &runtime_attached
);
587 if (r
< 0 && r
!= -EOPNOTSUPP
)
590 /* First priority is whatever has been passed to us via env vars */
591 r
= get_paths_from_environ("SYSTEMD_UNIT_PATH", &paths
, &append
);
595 if (!paths
|| append
) {
596 /* Let's figure something out. */
598 _cleanup_strv_free_
char **add
= NULL
;
600 /* For the user units we include share/ in the search
601 * path in order to comply with the XDG basedir spec.
602 * For the system stuff we avoid such nonsense. OTOH
603 * we include /lib in the search path for the system
604 * stuff but avoid it for user stuff. */
608 case UNIT_FILE_SYSTEM
:
610 /* If you modify this you also want to modify
611 * systemdsystemunitpath= in systemd.pc.in! */
612 STRV_IFNOTNULL(persistent_control
),
613 STRV_IFNOTNULL(runtime_control
),
614 STRV_IFNOTNULL(transient
),
615 STRV_IFNOTNULL(generator_early
),
617 SYSTEM_CONFIG_UNIT_DIR
,
618 "/etc/systemd/system",
619 STRV_IFNOTNULL(persistent_attached
),
621 "/run/systemd/system",
622 STRV_IFNOTNULL(runtime_attached
),
623 STRV_IFNOTNULL(generator
),
624 "/usr/local/lib/systemd/system",
625 SYSTEM_DATA_UNIT_PATH
,
626 "/usr/lib/systemd/system",
627 STRV_IFNOTNULL(flags
& LOOKUP_PATHS_SPLIT_USR
? "/lib/systemd/system" : NULL
),
628 STRV_IFNOTNULL(generator_late
));
631 case UNIT_FILE_GLOBAL
:
633 /* If you modify this you also want to modify
634 * systemduserunitpath= in systemd.pc.in, and
635 * the arrays in user_dirs() above! */
636 STRV_IFNOTNULL(persistent_control
),
637 STRV_IFNOTNULL(runtime_control
),
638 STRV_IFNOTNULL(transient
),
639 STRV_IFNOTNULL(generator_early
),
641 USER_CONFIG_UNIT_DIR
,
645 STRV_IFNOTNULL(generator
),
646 "/usr/local/share/systemd/user",
647 "/usr/share/systemd/user",
648 "/usr/local/lib/systemd/user",
650 "/usr/lib/systemd/user",
651 STRV_IFNOTNULL(generator_late
));
655 add
= user_dirs(persistent_config
, runtime_config
,
656 global_persistent_config
, global_runtime_config
,
657 generator
, generator_early
, generator_late
,
659 persistent_control
, runtime_control
);
663 assert_not_reached("Hmm, unexpected scope?");
670 r
= strv_extend_strv(&paths
, add
, true);
674 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
675 * and don't have to copy anything */
676 paths
= TAKE_PTR(add
);
679 r
= patch_root_prefix(&persistent_config
, root
);
682 r
= patch_root_prefix(&runtime_config
, root
);
686 r
= patch_root_prefix(&generator
, root
);
689 r
= patch_root_prefix(&generator_early
, root
);
692 r
= patch_root_prefix(&generator_late
, root
);
696 r
= patch_root_prefix(&transient
, root
);
700 r
= patch_root_prefix(&persistent_control
, root
);
703 r
= patch_root_prefix(&runtime_control
, root
);
707 r
= patch_root_prefix(&persistent_attached
, root
);
710 r
= patch_root_prefix(&runtime_attached
, root
);
714 r
= patch_root_prefix_strv(paths
, root
);
719 .search_path
= strv_uniq(TAKE_PTR(paths
)),
721 .persistent_config
= TAKE_PTR(persistent_config
),
722 .runtime_config
= TAKE_PTR(runtime_config
),
724 .generator
= TAKE_PTR(generator
),
725 .generator_early
= TAKE_PTR(generator_early
),
726 .generator_late
= TAKE_PTR(generator_late
),
728 .transient
= TAKE_PTR(transient
),
730 .persistent_control
= TAKE_PTR(persistent_control
),
731 .runtime_control
= TAKE_PTR(runtime_control
),
733 .persistent_attached
= TAKE_PTR(persistent_attached
),
734 .runtime_attached
= TAKE_PTR(runtime_attached
),
736 .root_dir
= TAKE_PTR(root
),
737 .temporary_dir
= TAKE_PTR(tempdir
),
743 void lookup_paths_free(LookupPaths
*p
) {
747 p
->search_path
= strv_free(p
->search_path
);
749 p
->persistent_config
= mfree(p
->persistent_config
);
750 p
->runtime_config
= mfree(p
->runtime_config
);
752 p
->persistent_attached
= mfree(p
->persistent_attached
);
753 p
->runtime_attached
= mfree(p
->runtime_attached
);
755 p
->generator
= mfree(p
->generator
);
756 p
->generator_early
= mfree(p
->generator_early
);
757 p
->generator_late
= mfree(p
->generator_late
);
759 p
->transient
= mfree(p
->transient
);
761 p
->persistent_control
= mfree(p
->persistent_control
);
762 p
->runtime_control
= mfree(p
->runtime_control
);
764 p
->root_dir
= mfree(p
->root_dir
);
765 p
->temporary_dir
= mfree(p
->temporary_dir
);
768 void lookup_paths_log(LookupPaths
*p
) {
771 if (strv_isempty(p
->search_path
)) {
772 log_debug("Ignoring unit files.");
773 p
->search_path
= strv_free(p
->search_path
);
775 _cleanup_free_
char *t
;
777 t
= strv_join(p
->search_path
, "\n\t");
778 log_debug("Looking for unit files in (higher priority first):\n\t%s", strna(t
));
782 char **generator_binary_paths(UnitFileScope scope
) {
783 bool append
= false; /* Add items from SYSTEMD_GENERATOR_PATH before normal directories */
784 _cleanup_strv_free_
char **paths
= NULL
;
787 /* First priority is whatever has been passed to us via env vars */
788 r
= get_paths_from_environ("SYSTEMD_GENERATOR_PATH", &paths
, &append
);
792 if (!paths
|| append
) {
793 _cleanup_strv_free_
char **add
= NULL
;
797 case UNIT_FILE_SYSTEM
:
798 add
= strv_new("/run/systemd/system-generators",
799 "/etc/systemd/system-generators",
800 "/usr/local/lib/systemd/system-generators",
801 SYSTEM_GENERATOR_DIR
);
804 case UNIT_FILE_GLOBAL
:
806 add
= strv_new("/run/systemd/user-generators",
807 "/etc/systemd/user-generators",
808 "/usr/local/lib/systemd/user-generators",
813 assert_not_reached("Hmm, unexpected scope.");
820 r
= strv_extend_strv(&paths
, add
, true);
824 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
825 * and don't have to copy anything */
826 paths
= TAKE_PTR(add
);
829 return TAKE_PTR(paths
);
832 char **env_generator_binary_paths(bool is_system
) {
833 bool append
= false; /* Add items from SYSTEMD_ENVIRONMENT_GENERATOR_PATH before normal directories */
834 _cleanup_strv_free_
char **paths
= NULL
;
835 _cleanup_strv_free_
char **add
= NULL
;
838 /* First priority is whatever has been passed to us via env vars */
839 r
= get_paths_from_environ("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", &paths
, &append
);
843 if (!paths
|| append
) {
845 add
= strv_new("/run/systemd/system-environment-generators",
846 "/etc/systemd/system-environment-generators",
847 "/usr/local/lib/systemd/system-environment-generators",
848 SYSTEM_ENV_GENERATOR_DIR
);
850 add
= strv_new("/run/systemd/user-environment-generators",
851 "/etc/systemd/user-environment-generators",
852 "/usr/local/lib/systemd/user-environment-generators",
853 USER_ENV_GENERATOR_DIR
);
860 r
= strv_extend_strv(&paths
, add
, true);
864 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
865 * and don't have to copy anything */
866 paths
= TAKE_PTR(add
);
868 return TAKE_PTR(paths
);