1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "alloc-util.h"
14 #include "path-lookup.h"
15 #include "path-util.h"
17 #include "stat-util.h"
18 #include "string-util.h"
20 #include "tmpfile-util.h"
21 #include "user-util.h"
24 int xdg_user_runtime_dir(char **ret
, const char *suffix
) {
31 e
= getenv("XDG_RUNTIME_DIR");
35 j
= strjoin(e
, suffix
);
43 int xdg_user_config_dir(char **ret
, const char *suffix
) {
50 e
= getenv("XDG_CONFIG_HOME");
52 j
= strjoin(e
, suffix
);
54 _cleanup_free_
char *home
= NULL
;
56 r
= get_home_dir(&home
);
60 j
= strjoin(home
, "/.config", suffix
);
70 int xdg_user_data_dir(char **ret
, const char *suffix
) {
78 /* We don't treat /etc/xdg/systemd here as the spec
79 * suggests because we assume that is a link to
80 * /etc/systemd/ anyway. */
82 e
= getenv("XDG_DATA_HOME");
84 j
= strjoin(e
, suffix
);
86 _cleanup_free_
char *home
= NULL
;
88 r
= get_home_dir(&home
);
92 j
= strjoin(home
, "/.local/share", suffix
);
101 static const char* const user_data_unit_paths
[] = {
102 "/usr/local/lib/systemd/user",
103 "/usr/local/share/systemd/user",
105 "/usr/lib/systemd/user",
106 "/usr/share/systemd/user",
110 static const char* const user_config_unit_paths
[] = {
111 USER_CONFIG_UNIT_PATH
,
116 int xdg_user_dirs(char ***ret_config_dirs
, char ***ret_data_dirs
) {
117 /* Implement the mechanisms defined in
119 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
121 * We look in both the config and the data dirs because we
122 * want to encourage that distributors ship their unit files
123 * as data, and allow overriding as configuration.
126 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
128 e
= getenv("XDG_CONFIG_DIRS");
130 config_dirs
= strv_split(e
, ":");
135 e
= getenv("XDG_DATA_DIRS");
137 data_dirs
= strv_split(e
, ":");
139 data_dirs
= strv_new("/usr/local/share",
144 *ret_config_dirs
= TAKE_PTR(config_dirs
);
145 *ret_data_dirs
= TAKE_PTR(data_dirs
);
150 static char** user_dirs(
151 const char *persistent_config
,
152 const char *runtime_config
,
153 const char *global_persistent_config
,
154 const char *global_runtime_config
,
155 const char *generator
,
156 const char *generator_early
,
157 const char *generator_late
,
158 const char *transient
,
159 const char *persistent_control
,
160 const char *runtime_control
) {
162 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
163 _cleanup_free_
char *data_home
= NULL
;
164 _cleanup_strv_free_
char **res
= NULL
;
167 r
= xdg_user_dirs(&config_dirs
, &data_dirs
);
171 r
= xdg_user_data_dir(&data_home
, "/systemd/user");
172 if (r
< 0 && r
!= -ENXIO
)
175 /* Now merge everything we found. */
176 if (strv_extend(&res
, persistent_control
) < 0)
179 if (strv_extend(&res
, runtime_control
) < 0)
182 if (strv_extend(&res
, transient
) < 0)
185 if (strv_extend(&res
, generator_early
) < 0)
188 if (strv_extend_strv_concat(&res
, config_dirs
, "/systemd/user") < 0)
191 if (strv_extend(&res
, persistent_config
) < 0)
194 /* global config has lower priority than the user config of the same type */
195 if (strv_extend(&res
, global_persistent_config
) < 0)
198 if (strv_extend_strv(&res
, (char**) user_config_unit_paths
, false) < 0)
201 if (strv_extend(&res
, runtime_config
) < 0)
204 if (strv_extend(&res
, global_runtime_config
) < 0)
207 if (strv_extend(&res
, generator
) < 0)
210 if (strv_extend(&res
, data_home
) < 0)
213 if (strv_extend_strv_concat(&res
, data_dirs
, "/systemd/user") < 0)
216 if (strv_extend_strv(&res
, (char**) user_data_unit_paths
, false) < 0)
219 if (strv_extend(&res
, generator_late
) < 0)
222 if (path_strv_make_absolute_cwd(res
) < 0)
225 return TAKE_PTR(res
);
228 bool path_is_user_data_dir(const char *path
) {
231 return strv_contains((char**) user_data_unit_paths
, path
);
234 bool path_is_user_config_dir(const char *path
) {
237 return strv_contains((char**) user_config_unit_paths
, path
);
240 static int acquire_generator_dirs(
244 char **generator_early
,
245 char **generator_late
) {
247 _cleanup_free_
char *x
= NULL
, *y
= NULL
, *z
= NULL
;
251 assert(generator_early
);
252 assert(generator_late
);
253 assert(IN_SET(scope
, UNIT_FILE_SYSTEM
, UNIT_FILE_USER
, UNIT_FILE_GLOBAL
));
255 if (scope
== UNIT_FILE_GLOBAL
)
260 else if (scope
== UNIT_FILE_SYSTEM
)
261 prefix
= "/run/systemd";
266 e
= getenv("XDG_RUNTIME_DIR");
270 prefix
= strjoina(e
, "/systemd");
273 x
= path_join(prefix
, "generator");
277 y
= path_join(prefix
, "generator.early");
281 z
= path_join(prefix
, "generator.late");
285 *generator
= TAKE_PTR(x
);
286 *generator_early
= TAKE_PTR(y
);
287 *generator_late
= TAKE_PTR(z
);
292 static int acquire_transient_dir(
300 assert(IN_SET(scope
, UNIT_FILE_SYSTEM
, UNIT_FILE_USER
, UNIT_FILE_GLOBAL
));
302 if (scope
== UNIT_FILE_GLOBAL
)
306 transient
= path_join(tempdir
, "transient");
307 else if (scope
== UNIT_FILE_SYSTEM
)
308 transient
= strdup("/run/systemd/transient");
310 return xdg_user_runtime_dir(ret
, "/systemd/transient");
318 static int acquire_config_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
319 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
327 case UNIT_FILE_SYSTEM
:
328 a
= strdup(SYSTEM_CONFIG_UNIT_PATH
);
329 b
= strdup("/run/systemd/system");
332 case UNIT_FILE_GLOBAL
:
333 a
= strdup(USER_CONFIG_UNIT_PATH
);
334 b
= strdup("/run/systemd/user");
338 r
= xdg_user_config_dir(&a
, "/systemd/user");
339 if (r
< 0 && r
!= -ENXIO
)
342 r
= xdg_user_runtime_dir(runtime
, "/systemd/user");
347 /* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
348 * directory to NULL */
352 *persistent
= TAKE_PTR(a
);
357 assert_not_reached("Hmm, unexpected scope value.");
363 *persistent
= TAKE_PTR(a
);
364 *runtime
= TAKE_PTR(b
);
369 static int acquire_control_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
370 _cleanup_free_
char *a
= NULL
;
378 case UNIT_FILE_SYSTEM
: {
379 _cleanup_free_
char *b
= NULL
;
381 a
= strdup("/etc/systemd/system.control");
385 b
= strdup("/run/systemd/system.control");
389 *runtime
= TAKE_PTR(b
);
395 r
= xdg_user_config_dir(&a
, "/systemd/user.control");
396 if (r
< 0 && r
!= -ENXIO
)
399 r
= xdg_user_runtime_dir(runtime
, "/systemd/user.control");
404 /* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
411 case UNIT_FILE_GLOBAL
:
415 assert_not_reached("Hmm, unexpected scope value.");
418 *persistent
= TAKE_PTR(a
);
423 static int acquire_attached_dirs(
425 char **ret_persistent
,
426 char **ret_runtime
) {
428 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
430 assert(ret_persistent
);
433 /* Portable services are not available to regular users for now. */
434 if (scope
!= UNIT_FILE_SYSTEM
)
437 a
= strdup("/etc/systemd/system.attached");
441 b
= strdup("/run/systemd/system.attached");
445 *ret_persistent
= TAKE_PTR(a
);
446 *ret_runtime
= TAKE_PTR(b
);
451 static int patch_root_prefix(char **p
, const char *root_dir
) {
459 c
= path_join(root_dir
, *p
);
463 free_and_replace(*p
, c
);
467 static int patch_root_prefix_strv(char **l
, const char *root_dir
) {
475 r
= patch_root_prefix(i
, root_dir
);
483 int lookup_paths_init(
486 LookupPathsFlags flags
,
487 const char *root_dir
) {
489 _cleanup_(rmdir_and_freep
) char *tempdir
= NULL
;
492 *persistent_config
= NULL
, *runtime_config
= NULL
,
493 *global_persistent_config
= NULL
, *global_runtime_config
= NULL
,
494 *generator
= NULL
, *generator_early
= NULL
, *generator_late
= NULL
,
496 *persistent_control
= NULL
, *runtime_control
= NULL
,
497 *persistent_attached
= NULL
, *runtime_attached
= NULL
;
498 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
499 _cleanup_strv_free_
char **paths
= NULL
;
505 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
508 flags
|= LOOKUP_PATHS_SPLIT_USR
;
511 if (!empty_or_root(root_dir
)) {
512 if (scope
== UNIT_FILE_USER
)
515 r
= is_dir(root_dir
, true);
521 root
= strdup(root_dir
);
526 if (flags
& LOOKUP_PATHS_TEMPORARY_GENERATED
) {
527 r
= mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir
);
529 return log_debug_errno(r
, "Failed to create temporary directory: %m");
532 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
533 r
= acquire_config_dirs(scope
, &persistent_config
, &runtime_config
);
537 if (scope
== UNIT_FILE_USER
) {
538 r
= acquire_config_dirs(UNIT_FILE_GLOBAL
, &global_persistent_config
, &global_runtime_config
);
543 if ((flags
& LOOKUP_PATHS_EXCLUDE_GENERATED
) == 0) {
544 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
545 r
= acquire_generator_dirs(scope
, tempdir
,
546 &generator
, &generator_early
, &generator_late
);
547 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
551 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
552 r
= acquire_transient_dir(scope
, tempdir
, &transient
);
553 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
556 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
557 r
= acquire_control_dirs(scope
, &persistent_control
, &runtime_control
);
558 if (r
< 0 && r
!= -EOPNOTSUPP
)
561 r
= acquire_attached_dirs(scope
, &persistent_attached
, &runtime_attached
);
562 if (r
< 0 && r
!= -EOPNOTSUPP
)
565 /* First priority is whatever has been passed to us via env vars */
566 e
= getenv("SYSTEMD_UNIT_PATH");
570 k
= endswith(e
, ":");
572 e
= strndupa(e
, k
- e
);
576 /* FIXME: empty components in other places should be rejected. */
578 r
= path_split_and_make_absolute(e
, &paths
);
583 if (!paths
|| append
) {
584 /* Let's figure something out. */
586 _cleanup_strv_free_
char **add
= NULL
;
588 /* For the user units we include share/ in the search
589 * path in order to comply with the XDG basedir spec.
590 * For the system stuff we avoid such nonsense. OTOH
591 * we include /lib in the search path for the system
592 * stuff but avoid it for user stuff. */
596 case UNIT_FILE_SYSTEM
:
598 /* If you modify this you also want to modify
599 * systemdsystemunitpath= in systemd.pc.in! */
600 STRV_IFNOTNULL(persistent_control
),
601 STRV_IFNOTNULL(runtime_control
),
602 STRV_IFNOTNULL(transient
),
603 STRV_IFNOTNULL(generator_early
),
605 SYSTEM_CONFIG_UNIT_PATH
,
606 "/etc/systemd/system",
607 STRV_IFNOTNULL(persistent_attached
),
609 "/run/systemd/system",
610 STRV_IFNOTNULL(runtime_attached
),
611 STRV_IFNOTNULL(generator
),
612 "/usr/local/lib/systemd/system",
613 SYSTEM_DATA_UNIT_PATH
,
614 "/usr/lib/systemd/system",
615 STRV_IFNOTNULL(flags
& LOOKUP_PATHS_SPLIT_USR
? "/lib/systemd/system" : NULL
),
616 STRV_IFNOTNULL(generator_late
));
619 case UNIT_FILE_GLOBAL
:
621 /* If you modify this you also want to modify
622 * systemduserunitpath= in systemd.pc.in, and
623 * the arrays in user_dirs() above! */
624 STRV_IFNOTNULL(persistent_control
),
625 STRV_IFNOTNULL(runtime_control
),
626 STRV_IFNOTNULL(transient
),
627 STRV_IFNOTNULL(generator_early
),
629 USER_CONFIG_UNIT_PATH
,
633 STRV_IFNOTNULL(generator
),
634 "/usr/local/share/systemd/user",
635 "/usr/share/systemd/user",
636 "/usr/local/lib/systemd/user",
638 "/usr/lib/systemd/user",
639 STRV_IFNOTNULL(generator_late
));
643 add
= user_dirs(persistent_config
, runtime_config
,
644 global_persistent_config
, global_runtime_config
,
645 generator
, generator_early
, generator_late
,
647 persistent_control
, runtime_control
);
651 assert_not_reached("Hmm, unexpected scope?");
658 r
= strv_extend_strv(&paths
, add
, true);
662 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
663 * and don't have to copy anything */
664 paths
= TAKE_PTR(add
);
667 r
= patch_root_prefix(&persistent_config
, root
);
670 r
= patch_root_prefix(&runtime_config
, root
);
674 r
= patch_root_prefix(&generator
, root
);
677 r
= patch_root_prefix(&generator_early
, root
);
680 r
= patch_root_prefix(&generator_late
, root
);
684 r
= patch_root_prefix(&transient
, root
);
688 r
= patch_root_prefix(&persistent_control
, root
);
691 r
= patch_root_prefix(&runtime_control
, root
);
695 r
= patch_root_prefix(&persistent_attached
, root
);
698 r
= patch_root_prefix(&runtime_attached
, root
);
702 r
= patch_root_prefix_strv(paths
, root
);
707 .search_path
= strv_uniq(TAKE_PTR(paths
)),
709 .persistent_config
= TAKE_PTR(persistent_config
),
710 .runtime_config
= TAKE_PTR(runtime_config
),
712 .generator
= TAKE_PTR(generator
),
713 .generator_early
= TAKE_PTR(generator_early
),
714 .generator_late
= TAKE_PTR(generator_late
),
716 .transient
= TAKE_PTR(transient
),
718 .persistent_control
= TAKE_PTR(persistent_control
),
719 .runtime_control
= TAKE_PTR(runtime_control
),
721 .persistent_attached
= TAKE_PTR(persistent_attached
),
722 .runtime_attached
= TAKE_PTR(runtime_attached
),
724 .root_dir
= TAKE_PTR(root
),
725 .temporary_dir
= TAKE_PTR(tempdir
),
731 void lookup_paths_free(LookupPaths
*p
) {
735 p
->search_path
= strv_free(p
->search_path
);
737 p
->persistent_config
= mfree(p
->persistent_config
);
738 p
->runtime_config
= mfree(p
->runtime_config
);
740 p
->persistent_attached
= mfree(p
->persistent_attached
);
741 p
->runtime_attached
= mfree(p
->runtime_attached
);
743 p
->generator
= mfree(p
->generator
);
744 p
->generator_early
= mfree(p
->generator_early
);
745 p
->generator_late
= mfree(p
->generator_late
);
747 p
->transient
= mfree(p
->transient
);
749 p
->persistent_control
= mfree(p
->persistent_control
);
750 p
->runtime_control
= mfree(p
->runtime_control
);
752 p
->root_dir
= mfree(p
->root_dir
);
753 p
->temporary_dir
= mfree(p
->temporary_dir
);
756 void lookup_paths_log(LookupPaths
*p
) {
759 if (strv_isempty(p
->search_path
)) {
760 log_debug("Ignoring unit files.");
761 p
->search_path
= strv_free(p
->search_path
);
763 _cleanup_free_
char *t
;
765 t
= strv_join(p
->search_path
, "\n\t");
766 log_debug("Looking for unit files in (higher priority first):\n\t%s", strna(t
));
770 int lookup_paths_mkdir_generator(LookupPaths
*p
) {
775 if (!p
->generator
|| !p
->generator_early
|| !p
->generator_late
)
778 r
= mkdir_p_label(p
->generator
, 0755);
780 q
= mkdir_p_label(p
->generator_early
, 0755);
784 q
= mkdir_p_label(p
->generator_late
, 0755);
791 void lookup_paths_trim_generator(LookupPaths
*p
) {
794 /* Trim empty dirs */
797 (void) rmdir(p
->generator
);
798 if (p
->generator_early
)
799 (void) rmdir(p
->generator_early
);
800 if (p
->generator_late
)
801 (void) rmdir(p
->generator_late
);
804 void lookup_paths_flush_generator(LookupPaths
*p
) {
807 /* Flush the generated unit files in full */
810 (void) rm_rf(p
->generator
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
811 if (p
->generator_early
)
812 (void) rm_rf(p
->generator_early
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
813 if (p
->generator_late
)
814 (void) rm_rf(p
->generator_late
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
816 if (p
->temporary_dir
)
817 (void) rm_rf(p
->temporary_dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
820 char **generator_binary_paths(UnitFileScope scope
) {
824 case UNIT_FILE_SYSTEM
:
825 return strv_new("/run/systemd/system-generators",
826 "/etc/systemd/system-generators",
827 "/usr/local/lib/systemd/system-generators",
828 SYSTEM_GENERATOR_PATH
);
830 case UNIT_FILE_GLOBAL
:
832 return strv_new("/run/systemd/user-generators",
833 "/etc/systemd/user-generators",
834 "/usr/local/lib/systemd/user-generators",
835 USER_GENERATOR_PATH
);
838 assert_not_reached("Hmm, unexpected scope.");