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"
29 #include "path-lookup.h"
30 #include "path-util.h"
31 #include "string-util.h"
35 int user_config_home(char **config_home
) {
39 e
= getenv("XDG_CONFIG_HOME");
41 r
= strappend(e
, "/systemd/user");
50 home
= getenv("HOME");
52 r
= strappend(home
, "/.config/systemd/user");
64 int user_runtime_dir(char **runtime_dir
) {
68 e
= getenv("XDG_RUNTIME_DIR");
70 r
= strappend(e
, "/systemd/user");
81 static int user_data_home_dir(char **dir
, const char *suffix
) {
85 /* We don't treat /etc/xdg/systemd here as the spec
86 * suggests because we assume that that is a link to
87 * /etc/systemd/ anyway. */
89 e
= getenv("XDG_DATA_HOME");
91 res
= strappend(e
, suffix
);
95 home
= getenv("HOME");
97 res
= strjoin(home
, "/.local/share", suffix
, NULL
);
108 static char** user_dirs(
109 const char *generator
,
110 const char *generator_early
,
111 const char *generator_late
) {
113 const char * const config_unit_paths
[] = {
114 USER_CONFIG_UNIT_PATH
,
119 const char * const runtime_unit_path
= "/run/systemd/user";
121 const char * const data_unit_paths
[] = {
122 "/usr/local/lib/systemd/user",
123 "/usr/local/share/systemd/user",
125 "/usr/lib/systemd/user",
126 "/usr/share/systemd/user",
131 _cleanup_free_
char *config_home
= NULL
, *runtime_dir
= NULL
, *data_home
= NULL
;
132 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
133 _cleanup_free_
char **res
= NULL
;
137 /* Implement the mechanisms defined in
139 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
141 * We look in both the config and the data dirs because we
142 * want to encourage that distributors ship their unit files
143 * as data, and allow overriding as configuration.
146 if (user_config_home(&config_home
) < 0)
149 if (user_runtime_dir(&runtime_dir
) < 0)
152 e
= getenv("XDG_CONFIG_DIRS");
154 config_dirs
= strv_split(e
, ":");
159 r
= user_data_home_dir(&data_home
, "/systemd/user");
163 e
= getenv("XDG_DATA_DIRS");
165 data_dirs
= strv_split(e
, ":");
167 data_dirs
= strv_new("/usr/local/share",
173 /* Now merge everything we found. */
175 if (strv_extend(&res
, generator_early
) < 0)
179 if (strv_extend(&res
, config_home
) < 0)
182 if (!strv_isempty(config_dirs
))
183 if (strv_extend_strv_concat(&res
, config_dirs
, "/systemd/user") < 0)
186 if (strv_extend_strv(&res
, (char**) config_unit_paths
, false) < 0)
190 if (strv_extend(&res
, runtime_dir
) < 0)
193 if (strv_extend(&res
, runtime_unit_path
) < 0)
197 if (strv_extend(&res
, generator
) < 0)
201 if (strv_extend(&res
, data_home
) < 0)
204 if (!strv_isempty(data_dirs
))
205 if (strv_extend_strv_concat(&res
, data_dirs
, "/systemd/user") < 0)
208 if (strv_extend_strv(&res
, (char**) data_unit_paths
, false) < 0)
212 if (strv_extend(&res
, generator_late
) < 0)
215 if (path_strv_make_absolute_cwd(res
) < 0)
223 char **generator_paths(ManagerRunningAs running_as
) {
224 if (running_as
== MANAGER_USER
)
225 return strv_new("/run/systemd/user-generators",
226 "/etc/systemd/user-generators",
227 "/usr/local/lib/systemd/user-generators",
231 return strv_new("/run/systemd/system-generators",
232 "/etc/systemd/system-generators",
233 "/usr/local/lib/systemd/system-generators",
234 SYSTEM_GENERATOR_PATH
,
238 static int acquire_generator_dirs(
239 ManagerRunningAs running_as
,
241 char **generator_early
,
242 char **generator_late
) {
244 _cleanup_free_
char *x
= NULL
, *y
= NULL
, *z
= NULL
;
248 assert(generator_early
);
249 assert(generator_late
);
251 if (running_as
== MANAGER_SYSTEM
)
252 prefix
= "/run/systemd/";
256 assert(running_as
== MANAGER_USER
);
258 e
= getenv("XDG_RUNTIME_DIR");
262 prefix
= strjoina(e
, "/systemd/", NULL
);
265 x
= strappend(prefix
, "generator");
269 y
= strappend(prefix
, "generator.early");
273 z
= strappend(prefix
, "generator.late");
278 *generator_early
= y
;
285 static int patch_root_prefix(char **p
, const char *root_dir
) {
293 if (isempty(root_dir
) || path_equal(root_dir
, "/"))
296 c
= prefix_root(root_dir
, *p
);
306 int lookup_paths_init(
308 ManagerRunningAs running_as
,
310 const char *root_dir
) {
312 _cleanup_free_
char *generator
= NULL
, *generator_early
= NULL
, *generator_late
= NULL
;
313 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
319 assert(running_as
>= 0);
320 assert(running_as
< _MANAGER_RUNNING_AS_MAX
);
322 r
= acquire_generator_dirs(running_as
, &generator
, &generator_early
, &generator_late
);
326 /* First priority is whatever has been passed to us via env
328 e
= getenv("SYSTEMD_UNIT_PATH");
332 k
= endswith(e
, ":");
334 e
= strndupa(e
, k
- e
);
338 /* FIXME: empty components in other places should be
341 r
= path_split_and_make_absolute(e
, &l
);
348 /* Let's figure something out. */
350 _cleanup_strv_free_
char **add
= NULL
;
352 /* For the user units we include share/ in the search
353 * path in order to comply with the XDG basedir spec.
354 * For the system stuff we avoid such nonsense. OTOH
355 * we include /lib in the search path for the system
356 * stuff but avoid it for user stuff. */
358 if (running_as
== MANAGER_USER
) {
360 add
= user_dirs(generator
, generator_early
, generator_late
);
363 /* If you modify this you also want to modify
364 * systemduserunitpath= in systemd.pc.in, and
365 * the arrays in user_dirs() above! */
367 USER_CONFIG_UNIT_PATH
,
371 "/usr/local/lib/systemd/user",
372 "/usr/local/share/systemd/user",
374 "/usr/lib/systemd/user",
375 "/usr/share/systemd/user",
380 /* If you modify this you also want to modify
381 * systemdsystemunitpath= in systemd.pc.in! */
383 SYSTEM_CONFIG_UNIT_PATH
,
384 "/etc/systemd/system",
385 "/run/systemd/system",
387 "/usr/local/lib/systemd/system",
388 SYSTEM_DATA_UNIT_PATH
,
389 "/usr/lib/systemd/system",
390 #ifdef HAVE_SPLIT_USR
391 "/lib/systemd/system",
400 r
= strv_extend_strv(&l
, add
, false);
409 r
= patch_root_prefix(&generator
, root_dir
);
412 r
= patch_root_prefix(&generator_early
, root_dir
);
415 r
= patch_root_prefix(&generator_late
, root_dir
);
419 if (!path_strv_resolve_uniq(l
, root_dir
))
422 if (strv_isempty(l
)) {
423 log_debug("Ignoring unit files.");
426 _cleanup_free_
char *t
;
428 t
= strv_join(l
, "\n\t");
432 log_debug("Looking for unit files in (higher priority first):\n\t%s", t
);
438 p
->generator
= generator
;
439 p
->generator_early
= generator_early
;
440 p
->generator_late
= generator_late
;
441 generator
= generator_early
= generator_late
= NULL
;
446 void lookup_paths_free(LookupPaths
*p
) {
450 p
->search_path
= strv_free(p
->search_path
);
451 p
->generator
= mfree(p
->generator
);
452 p
->generator_early
= mfree(p
->generator_early
);
453 p
->generator_late
= mfree(p
->generator_late
);
456 int lookup_paths_init_from_scope(
459 const char *root_dir
) {
463 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
465 return lookup_paths_init(
467 scope
== UNIT_FILE_SYSTEM
? MANAGER_SYSTEM
: MANAGER_USER
,
468 scope
== UNIT_FILE_USER
,