2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "alloc-util.h"
32 #include "path-lookup.h"
33 #include "path-util.h"
35 #include "stat-util.h"
36 #include "string-util.h"
38 #include "user-util.h"
41 static int user_runtime_dir(char **ret
, const char *suffix
) {
48 e
= getenv("XDG_RUNTIME_DIR");
52 j
= strappend(e
, suffix
);
60 static int user_config_dir(char **ret
, const char *suffix
) {
67 e
= getenv("XDG_CONFIG_HOME");
69 j
= strappend(e
, suffix
);
71 _cleanup_free_
char *home
= NULL
;
73 r
= get_home_dir(&home
);
77 j
= strjoin(home
, "/.config", suffix
);
87 static int user_data_dir(char **ret
, const char *suffix
) {
95 /* We don't treat /etc/xdg/systemd here as the spec
96 * suggests because we assume that is a link to
97 * /etc/systemd/ anyway. */
99 e
= getenv("XDG_DATA_HOME");
101 j
= strappend(e
, suffix
);
103 _cleanup_free_
char *home
= NULL
;
105 r
= get_home_dir(&home
);
109 j
= strjoin(home
, "/.local/share", suffix
);
118 static const char* const user_data_unit_paths
[] = {
119 "/usr/local/lib/systemd/user",
120 "/usr/local/share/systemd/user",
122 "/usr/lib/systemd/user",
123 "/usr/share/systemd/user",
127 static const char* const user_config_unit_paths
[] = {
128 USER_CONFIG_UNIT_PATH
,
133 static char** user_dirs(
134 const char *persistent_config
,
135 const char *runtime_config
,
136 const char *generator
,
137 const char *generator_early
,
138 const char *generator_late
,
139 const char *transient
,
140 const char *persistent_control
,
141 const char *runtime_control
) {
143 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
144 _cleanup_free_
char *data_home
= NULL
;
145 _cleanup_strv_free_
char **res
= NULL
;
150 /* Implement the mechanisms defined in
152 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
154 * We look in both the config and the data dirs because we
155 * want to encourage that distributors ship their unit files
156 * as data, and allow overriding as configuration.
159 e
= getenv("XDG_CONFIG_DIRS");
161 config_dirs
= strv_split(e
, ":");
166 r
= user_data_dir(&data_home
, "/systemd/user");
167 if (r
< 0 && r
!= -ENXIO
)
170 e
= getenv("XDG_DATA_DIRS");
172 data_dirs
= strv_split(e
, ":");
174 data_dirs
= strv_new("/usr/local/share",
180 /* Now merge everything we found. */
181 if (strv_extend(&res
, persistent_control
) < 0)
184 if (strv_extend(&res
, runtime_control
) < 0)
187 if (strv_extend(&res
, transient
) < 0)
190 if (strv_extend(&res
, generator_early
) < 0)
193 if (strv_extend_strv_concat(&res
, config_dirs
, "/systemd/user") < 0)
196 if (strv_extend(&res
, persistent_config
) < 0)
199 if (strv_extend_strv(&res
, (char**) user_config_unit_paths
, false) < 0)
202 if (strv_extend(&res
, runtime_config
) < 0)
205 if (strv_extend(&res
, generator
) < 0)
208 if (strv_extend(&res
, data_home
) < 0)
211 if (strv_extend_strv_concat(&res
, data_dirs
, "/systemd/user") < 0)
214 if (strv_extend_strv(&res
, (char**) user_data_unit_paths
, false) < 0)
217 if (strv_extend(&res
, generator_late
) < 0)
220 if (path_strv_make_absolute_cwd(res
) < 0)
229 bool path_is_user_data_dir(const char *path
) {
232 return strv_contains((char**) user_data_unit_paths
, path
);
235 bool path_is_user_config_dir(const char *path
) {
238 return strv_contains((char**) user_config_unit_paths
, path
);
241 static int acquire_generator_dirs(
245 char **generator_early
,
246 char **generator_late
) {
248 _cleanup_(rmdir_and_freep
) char *t
= NULL
;
249 _cleanup_free_
char *x
= NULL
, *y
= NULL
, *z
= NULL
;
253 assert(generator_early
);
254 assert(generator_late
);
255 assert(IN_SET(scope
, UNIT_FILE_SYSTEM
, UNIT_FILE_USER
, UNIT_FILE_GLOBAL
));
257 if (scope
== UNIT_FILE_GLOBAL
)
263 else if (scope
== UNIT_FILE_SYSTEM
)
264 prefix
= "/run/systemd";
266 else if (scope
== UNIT_FILE_USER
) {
269 e
= getenv("XDG_RUNTIME_DIR");
273 prefix
= strjoina(e
, "/systemd");
276 x
= strappend(prefix
, "/generator");
280 y
= strappend(prefix
, "/generator.early");
284 z
= strappend(prefix
, "/generator.late");
289 *generator_early
= y
;
296 static int acquire_transient_dir(
304 assert(IN_SET(scope
, UNIT_FILE_SYSTEM
, UNIT_FILE_USER
, UNIT_FILE_GLOBAL
));
306 if (scope
== UNIT_FILE_GLOBAL
)
310 transient
= strjoin(tempdir
, "/transient");
311 else if (scope
== UNIT_FILE_SYSTEM
)
312 transient
= strdup("/run/systemd/transient");
314 return user_runtime_dir(ret
, "/systemd/transient");
322 static int acquire_config_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
323 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
331 case UNIT_FILE_SYSTEM
:
332 a
= strdup(SYSTEM_CONFIG_UNIT_PATH
);
333 b
= strdup("/run/systemd/system");
336 case UNIT_FILE_GLOBAL
:
337 a
= strdup(USER_CONFIG_UNIT_PATH
);
338 b
= strdup("/run/systemd/user");
342 r
= user_config_dir(&a
, "/systemd/user");
343 if (r
< 0 && r
!= -ENXIO
)
346 r
= user_runtime_dir(runtime
, "/systemd/user");
351 /* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
352 * directory to NULL */
362 assert_not_reached("Hmm, unexpected scope value.");
375 static int acquire_control_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
376 _cleanup_free_
char *a
= NULL
;
384 case UNIT_FILE_SYSTEM
: {
385 _cleanup_free_
char *b
= NULL
;
387 a
= strdup("/etc/systemd/system.control");
391 b
= strdup("/run/systemd/system.control");
402 r
= user_config_dir(&a
, "/systemd/system.control");
403 if (r
< 0 && r
!= -ENXIO
)
406 r
= user_runtime_dir(runtime
, "/systemd/system.control");
411 /* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
418 case UNIT_FILE_GLOBAL
:
422 assert_not_reached("Hmm, unexpected scope value.");
431 static int patch_root_prefix(char **p
, const char *root_dir
) {
439 c
= prefix_root(root_dir
, *p
);
449 static int patch_root_prefix_strv(char **l
, const char *root_dir
) {
457 r
= patch_root_prefix(i
, root_dir
);
465 int lookup_paths_init(
468 LookupPathsFlags flags
,
469 const char *root_dir
) {
471 _cleanup_(rmdir_and_freep
) char *tempdir
= NULL
;
474 *persistent_config
= NULL
, *runtime_config
= NULL
,
475 *generator
= NULL
, *generator_early
= NULL
, *generator_late
= NULL
,
477 *persistent_control
= NULL
, *runtime_control
= NULL
;
478 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
479 _cleanup_strv_free_
char **paths
= NULL
;
485 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
487 if (!isempty(root_dir
) && !path_equal(root_dir
, "/")) {
488 if (scope
== UNIT_FILE_USER
)
491 r
= is_dir(root_dir
, true);
497 root
= strdup(root_dir
);
502 if (flags
& LOOKUP_PATHS_TEMPORARY_GENERATED
) {
503 r
= mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir
);
505 return log_error_errno(r
, "Failed to create temporary directory: %m");
508 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
509 r
= acquire_config_dirs(scope
, &persistent_config
, &runtime_config
);
513 if ((flags
& LOOKUP_PATHS_EXCLUDE_GENERATED
) == 0) {
514 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
515 r
= acquire_generator_dirs(scope
, tempdir
,
516 &generator
, &generator_early
, &generator_late
);
517 if (r
< 0 && r
!= -EOPNOTSUPP
&& r
!= -ENXIO
)
521 /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
522 r
= acquire_transient_dir(scope
, tempdir
, &transient
);
523 if (r
< 0 && r
!= -EOPNOTSUPP
&& r
!= -ENXIO
)
526 /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
527 r
= acquire_control_dirs(scope
, &persistent_control
, &runtime_control
);
528 if (r
< 0 && r
!= -EOPNOTSUPP
)
531 /* First priority is whatever has been passed to us via env vars */
532 e
= getenv("SYSTEMD_UNIT_PATH");
536 k
= endswith(e
, ":");
538 e
= strndupa(e
, k
- e
);
542 /* FIXME: empty components in other places should be rejected. */
544 r
= path_split_and_make_absolute(e
, &paths
);
549 if (!paths
|| append
) {
550 /* Let's figure something out. */
552 _cleanup_strv_free_
char **add
= NULL
;
554 /* For the user units we include share/ in the search
555 * path in order to comply with the XDG basedir spec.
556 * For the system stuff we avoid such nonsense. OTOH
557 * we include /lib in the search path for the system
558 * stuff but avoid it for user stuff. */
562 case UNIT_FILE_SYSTEM
:
564 /* If you modify this you also want to modify
565 * systemdsystemunitpath= in systemd.pc.in! */
566 STRV_IFNOTNULL(persistent_control
),
567 STRV_IFNOTNULL(runtime_control
),
568 STRV_IFNOTNULL(transient
),
569 STRV_IFNOTNULL(generator_early
),
571 SYSTEM_CONFIG_UNIT_PATH
,
572 "/etc/systemd/system",
574 "/run/systemd/system",
575 STRV_IFNOTNULL(generator
),
576 "/usr/local/lib/systemd/system",
577 SYSTEM_DATA_UNIT_PATH
,
578 "/usr/lib/systemd/system",
579 #ifdef HAVE_SPLIT_USR
580 "/lib/systemd/system",
582 STRV_IFNOTNULL(generator_late
),
586 case UNIT_FILE_GLOBAL
:
588 /* If you modify this you also want to modify
589 * systemduserunitpath= in systemd.pc.in, and
590 * the arrays in user_dirs() above! */
591 STRV_IFNOTNULL(persistent_control
),
592 STRV_IFNOTNULL(runtime_control
),
593 STRV_IFNOTNULL(transient
),
594 STRV_IFNOTNULL(generator_early
),
596 USER_CONFIG_UNIT_PATH
,
600 STRV_IFNOTNULL(generator
),
601 "/usr/local/lib/systemd/user",
602 "/usr/local/share/systemd/user",
604 "/usr/lib/systemd/user",
605 "/usr/share/systemd/user",
606 STRV_IFNOTNULL(generator_late
),
611 add
= user_dirs(persistent_config
, runtime_config
,
612 generator
, generator_early
, generator_late
,
614 persistent_config
, runtime_control
);
618 assert_not_reached("Hmm, unexpected scope?");
625 r
= strv_extend_strv(&paths
, add
, true);
629 /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
630 * and don't have to copy anything */
636 r
= patch_root_prefix(&persistent_config
, root
);
639 r
= patch_root_prefix(&runtime_config
, root
);
643 r
= patch_root_prefix(&generator
, root
);
646 r
= patch_root_prefix(&generator_early
, root
);
649 r
= patch_root_prefix(&generator_late
, root
);
653 r
= patch_root_prefix(&transient
, root
);
657 r
= patch_root_prefix(&persistent_control
, root
);
661 r
= patch_root_prefix(&runtime_control
, root
);
665 r
= patch_root_prefix_strv(paths
, root
);
669 p
->search_path
= strv_uniq(paths
);
672 p
->persistent_config
= persistent_config
;
673 p
->runtime_config
= runtime_config
;
674 persistent_config
= runtime_config
= NULL
;
676 p
->generator
= generator
;
677 p
->generator_early
= generator_early
;
678 p
->generator_late
= generator_late
;
679 generator
= generator_early
= generator_late
= NULL
;
681 p
->transient
= transient
;
684 p
->persistent_control
= persistent_control
;
685 p
->runtime_control
= runtime_control
;
686 persistent_control
= runtime_control
= NULL
;
691 p
->temporary_dir
= tempdir
;
697 void lookup_paths_free(LookupPaths
*p
) {
701 p
->search_path
= strv_free(p
->search_path
);
703 p
->persistent_config
= mfree(p
->persistent_config
);
704 p
->runtime_config
= mfree(p
->runtime_config
);
706 p
->generator
= mfree(p
->generator
);
707 p
->generator_early
= mfree(p
->generator_early
);
708 p
->generator_late
= mfree(p
->generator_late
);
710 p
->transient
= mfree(p
->transient
);
712 p
->persistent_control
= mfree(p
->persistent_control
);
713 p
->runtime_control
= mfree(p
->runtime_control
);
715 p
->root_dir
= mfree(p
->root_dir
);
716 p
->temporary_dir
= mfree(p
->temporary_dir
);
719 int lookup_paths_reduce(LookupPaths
*p
) {
720 _cleanup_free_
struct stat
*stats
= NULL
;
721 size_t n_stats
= 0, allocated
= 0;
727 /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
728 * the same by comparing their device and inode numbers. Note one special tweak: when we have a root path set,
729 * we do not follow symlinks when retrieving them, because the kernel wouldn't take the root prefix into
730 * account when following symlinks. When we have no root path set this restriction does not apply however. */
735 while (p
->search_path
[c
]) {
740 r
= lstat(p
->search_path
[c
], &st
);
742 r
= stat(p
->search_path
[c
], &st
);
747 /* If something we don't grok happened, let's better leave it in. */
748 log_debug_errno(errno
, "Failed to stat %s: %m", p
->search_path
[c
]);
753 for (k
= 0; k
< n_stats
; k
++) {
754 if (stats
[k
].st_dev
== st
.st_dev
&&
755 stats
[k
].st_ino
== st
.st_ino
)
759 if (k
< n_stats
) /* Is there already an entry with the same device/inode? */
762 if (!GREEDY_REALLOC(stats
, allocated
, n_stats
+1))
765 stats
[n_stats
++] = st
;
770 free(p
->search_path
[c
]);
771 memmove(p
->search_path
+ c
,
772 p
->search_path
+ c
+ 1,
773 (strv_length(p
->search_path
+ c
+ 1) + 1) * sizeof(char*));
776 if (strv_isempty(p
->search_path
)) {
777 log_debug("Ignoring unit files.");
778 p
->search_path
= strv_free(p
->search_path
);
780 _cleanup_free_
char *t
;
782 t
= strv_join(p
->search_path
, "\n\t");
786 log_debug("Looking for unit files in (higher priority first):\n\t%s", t
);
792 int lookup_paths_mkdir_generator(LookupPaths
*p
) {
797 if (!p
->generator
|| !p
->generator_early
|| !p
->generator_late
)
800 r
= mkdir_p_label(p
->generator
, 0755);
802 q
= mkdir_p_label(p
->generator_early
, 0755);
806 q
= mkdir_p_label(p
->generator_late
, 0755);
813 void lookup_paths_trim_generator(LookupPaths
*p
) {
816 /* Trim empty dirs */
819 (void) rmdir(p
->generator
);
820 if (p
->generator_early
)
821 (void) rmdir(p
->generator_early
);
822 if (p
->generator_late
)
823 (void) rmdir(p
->generator_late
);
826 void lookup_paths_flush_generator(LookupPaths
*p
) {
829 /* Flush the generated unit files in full */
832 (void) rm_rf(p
->generator
, REMOVE_ROOT
);
833 if (p
->generator_early
)
834 (void) rm_rf(p
->generator_early
, REMOVE_ROOT
);
835 if (p
->generator_late
)
836 (void) rm_rf(p
->generator_late
, REMOVE_ROOT
);
838 if (p
->temporary_dir
)
839 (void) rm_rf(p
->temporary_dir
, REMOVE_ROOT
);
842 char **generator_binary_paths(UnitFileScope scope
) {
846 case UNIT_FILE_SYSTEM
:
847 return strv_new("/run/systemd/system-generators",
848 "/etc/systemd/system-generators",
849 "/usr/local/lib/systemd/system-generators",
850 SYSTEM_GENERATOR_PATH
,
853 case UNIT_FILE_GLOBAL
:
855 return strv_new("/run/systemd/user-generators",
856 "/etc/systemd/user-generators",
857 "/usr/local/lib/systemd/user-generators",
862 assert_not_reached("Hmm, unexpected scope.");