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
= strappend(e
, suffix
);
43 int xdg_user_config_dir(char **ret
, const char *suffix
) {
50 e
= getenv("XDG_CONFIG_HOME");
52 j
= strappend(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
= strappend(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
= strappend(prefix
, "/generator");
277 y
= strappend(prefix
, "/generator.early");
281 z
= strappend(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
= strjoin(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
= prefix_root(root_dir
, *p
);
469 static int patch_root_prefix_strv(char **l
, const char *root_dir
) {
477 r
= patch_root_prefix(i
, root_dir
);
485 int lookup_paths_init(
488 LookupPathsFlags flags
,
489 const char *root_dir
) {
491 _cleanup_(rmdir_and_freep
) char *tempdir
= NULL
;
494 *persistent_config
= NULL
, *runtime_config
= NULL
,
495 *global_persistent_config
= NULL
, *global_runtime_config
= NULL
,
496 *generator
= NULL
, *generator_early
= NULL
, *generator_late
= NULL
,
498 *persistent_control
= NULL
, *runtime_control
= NULL
,
499 *persistent_attached
= NULL
, *runtime_attached
= NULL
;
500 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
501 _cleanup_strv_free_
char **paths
= NULL
;
507 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
510 flags
|= LOOKUP_PATHS_SPLIT_USR
;
513 if (!empty_or_root(root_dir
)) {
514 if (scope
== UNIT_FILE_USER
)
517 r
= is_dir(root_dir
, true);
523 root
= strdup(root_dir
);
528 if (flags
& LOOKUP_PATHS_TEMPORARY_GENERATED
) {
529 r
= mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir
);
531 return log_debug_errno(r
, "Failed to create temporary directory: %m");
534 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
535 r
= acquire_config_dirs(scope
, &persistent_config
, &runtime_config
);
539 if (scope
== UNIT_FILE_USER
) {
540 r
= acquire_config_dirs(UNIT_FILE_GLOBAL
, &global_persistent_config
, &global_runtime_config
);
545 if ((flags
& LOOKUP_PATHS_EXCLUDE_GENERATED
) == 0) {
546 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
547 r
= acquire_generator_dirs(scope
, tempdir
,
548 &generator
, &generator_early
, &generator_late
);
549 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
553 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
554 r
= acquire_transient_dir(scope
, tempdir
, &transient
);
555 if (r
< 0 && !IN_SET(r
, -EOPNOTSUPP
, -ENXIO
))
558 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
559 r
= acquire_control_dirs(scope
, &persistent_control
, &runtime_control
);
560 if (r
< 0 && r
!= -EOPNOTSUPP
)
563 r
= acquire_attached_dirs(scope
, &persistent_attached
, &runtime_attached
);
564 if (r
< 0 && r
!= -EOPNOTSUPP
)
567 /* First priority is whatever has been passed to us via env vars */
568 e
= getenv("SYSTEMD_UNIT_PATH");
572 k
= endswith(e
, ":");
574 e
= strndupa(e
, k
- e
);
578 /* FIXME: empty components in other places should be rejected. */
580 r
= path_split_and_make_absolute(e
, &paths
);
585 if (!paths
|| append
) {
586 /* Let's figure something out. */
588 _cleanup_strv_free_
char **add
= NULL
;
590 /* For the user units we include share/ in the search
591 * path in order to comply with the XDG basedir spec.
592 * For the system stuff we avoid such nonsense. OTOH
593 * we include /lib in the search path for the system
594 * stuff but avoid it for user stuff. */
598 case UNIT_FILE_SYSTEM
:
600 /* If you modify this you also want to modify
601 * systemdsystemunitpath= in systemd.pc.in! */
602 STRV_IFNOTNULL(persistent_control
),
603 STRV_IFNOTNULL(runtime_control
),
604 STRV_IFNOTNULL(transient
),
605 STRV_IFNOTNULL(generator_early
),
607 SYSTEM_CONFIG_UNIT_PATH
,
608 "/etc/systemd/system",
609 STRV_IFNOTNULL(persistent_attached
),
611 "/run/systemd/system",
612 STRV_IFNOTNULL(runtime_attached
),
613 STRV_IFNOTNULL(generator
),
614 "/usr/local/lib/systemd/system",
615 SYSTEM_DATA_UNIT_PATH
,
616 "/usr/lib/systemd/system",
617 STRV_IFNOTNULL(flags
& LOOKUP_PATHS_SPLIT_USR
? "/lib/systemd/system" : NULL
),
618 STRV_IFNOTNULL(generator_late
));
621 case UNIT_FILE_GLOBAL
:
623 /* If you modify this you also want to modify
624 * systemduserunitpath= in systemd.pc.in, and
625 * the arrays in user_dirs() above! */
626 STRV_IFNOTNULL(persistent_control
),
627 STRV_IFNOTNULL(runtime_control
),
628 STRV_IFNOTNULL(transient
),
629 STRV_IFNOTNULL(generator_early
),
631 USER_CONFIG_UNIT_PATH
,
635 STRV_IFNOTNULL(generator
),
636 "/usr/local/share/systemd/user",
637 "/usr/share/systemd/user",
638 "/usr/local/lib/systemd/user",
640 "/usr/lib/systemd/user",
641 STRV_IFNOTNULL(generator_late
));
645 add
= user_dirs(persistent_config
, runtime_config
,
646 global_persistent_config
, global_runtime_config
,
647 generator
, generator_early
, generator_late
,
649 persistent_control
, runtime_control
);
653 assert_not_reached("Hmm, unexpected scope?");
660 r
= strv_extend_strv(&paths
, add
, true);
664 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
665 * and don't have to copy anything */
666 paths
= TAKE_PTR(add
);
669 r
= patch_root_prefix(&persistent_config
, root
);
672 r
= patch_root_prefix(&runtime_config
, root
);
676 r
= patch_root_prefix(&generator
, root
);
679 r
= patch_root_prefix(&generator_early
, root
);
682 r
= patch_root_prefix(&generator_late
, root
);
686 r
= patch_root_prefix(&transient
, root
);
690 r
= patch_root_prefix(&persistent_control
, root
);
693 r
= patch_root_prefix(&runtime_control
, root
);
697 r
= patch_root_prefix(&persistent_attached
, root
);
700 r
= patch_root_prefix(&runtime_attached
, root
);
704 r
= patch_root_prefix_strv(paths
, root
);
709 .search_path
= strv_uniq(paths
),
711 .persistent_config
= TAKE_PTR(persistent_config
),
712 .runtime_config
= TAKE_PTR(runtime_config
),
714 .generator
= TAKE_PTR(generator
),
715 .generator_early
= TAKE_PTR(generator_early
),
716 .generator_late
= TAKE_PTR(generator_late
),
718 .transient
= TAKE_PTR(transient
),
720 .persistent_control
= TAKE_PTR(persistent_control
),
721 .runtime_control
= TAKE_PTR(runtime_control
),
723 .persistent_attached
= TAKE_PTR(persistent_attached
),
724 .runtime_attached
= TAKE_PTR(runtime_attached
),
726 .root_dir
= TAKE_PTR(root
),
727 .temporary_dir
= TAKE_PTR(tempdir
),
734 void lookup_paths_free(LookupPaths
*p
) {
738 p
->search_path
= strv_free(p
->search_path
);
740 p
->persistent_config
= mfree(p
->persistent_config
);
741 p
->runtime_config
= mfree(p
->runtime_config
);
743 p
->persistent_attached
= mfree(p
->persistent_attached
);
744 p
->runtime_attached
= mfree(p
->runtime_attached
);
746 p
->generator
= mfree(p
->generator
);
747 p
->generator_early
= mfree(p
->generator_early
);
748 p
->generator_late
= mfree(p
->generator_late
);
750 p
->transient
= mfree(p
->transient
);
752 p
->persistent_control
= mfree(p
->persistent_control
);
753 p
->runtime_control
= mfree(p
->runtime_control
);
755 p
->root_dir
= mfree(p
->root_dir
);
756 p
->temporary_dir
= mfree(p
->temporary_dir
);
759 int lookup_paths_reduce(LookupPaths
*p
) {
760 _cleanup_free_
struct stat
*stats
= NULL
;
761 size_t n_stats
= 0, allocated
= 0;
767 /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
768 * the same by comparing their device and inode numbers. */
773 while (p
->search_path
[c
]) {
777 /* Never strip the transient and control directories from the path */
778 if (path_equal_ptr(p
->search_path
[c
], p
->transient
) ||
779 path_equal_ptr(p
->search_path
[c
], p
->persistent_control
) ||
780 path_equal_ptr(p
->search_path
[c
], p
->runtime_control
)) {
785 r
= chase_symlinks_and_stat(p
->search_path
[c
], p
->root_dir
, 0, NULL
, &st
);
789 /* If something we don't grok happened, let's better leave it in. */
790 log_debug_errno(r
, "Failed to chase and stat %s: %m", p
->search_path
[c
]);
795 for (k
= 0; k
< n_stats
; k
++)
796 if (stats
[k
].st_dev
== st
.st_dev
&&
797 stats
[k
].st_ino
== st
.st_ino
)
800 if (k
< n_stats
) /* Is there already an entry with the same device/inode? */
803 if (!GREEDY_REALLOC(stats
, allocated
, n_stats
+1))
806 stats
[n_stats
++] = st
;
811 free(p
->search_path
[c
]);
812 memmove(p
->search_path
+ c
,
813 p
->search_path
+ c
+ 1,
814 (strv_length(p
->search_path
+ c
+ 1) + 1) * sizeof(char*));
817 if (strv_isempty(p
->search_path
)) {
818 log_debug("Ignoring unit files.");
819 p
->search_path
= strv_free(p
->search_path
);
821 _cleanup_free_
char *t
;
823 t
= strv_join(p
->search_path
, "\n\t");
827 log_debug("Looking for unit files in (higher priority first):\n\t%s", t
);
833 int lookup_paths_mkdir_generator(LookupPaths
*p
) {
838 if (!p
->generator
|| !p
->generator_early
|| !p
->generator_late
)
841 r
= mkdir_p_label(p
->generator
, 0755);
843 q
= mkdir_p_label(p
->generator_early
, 0755);
847 q
= mkdir_p_label(p
->generator_late
, 0755);
854 void lookup_paths_trim_generator(LookupPaths
*p
) {
857 /* Trim empty dirs */
860 (void) rmdir(p
->generator
);
861 if (p
->generator_early
)
862 (void) rmdir(p
->generator_early
);
863 if (p
->generator_late
)
864 (void) rmdir(p
->generator_late
);
867 void lookup_paths_flush_generator(LookupPaths
*p
) {
870 /* Flush the generated unit files in full */
873 (void) rm_rf(p
->generator
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
874 if (p
->generator_early
)
875 (void) rm_rf(p
->generator_early
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
876 if (p
->generator_late
)
877 (void) rm_rf(p
->generator_late
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
879 if (p
->temporary_dir
)
880 (void) rm_rf(p
->temporary_dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
883 char **generator_binary_paths(UnitFileScope scope
) {
887 case UNIT_FILE_SYSTEM
:
888 return strv_new("/run/systemd/system-generators",
889 "/etc/systemd/system-generators",
890 "/usr/local/lib/systemd/system-generators",
891 SYSTEM_GENERATOR_PATH
);
893 case UNIT_FILE_GLOBAL
:
895 return strv_new("/run/systemd/user-generators",
896 "/etc/systemd/user-generators",
897 "/usr/local/lib/systemd/user-generators",
898 USER_GENERATOR_PATH
);
901 assert_not_reached("Hmm, unexpected scope.");