1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "alloc-util.h"
31 #include "path-lookup.h"
32 #include "path-util.h"
33 #include "string-util.h"
37 int user_config_home(char **config_home
) {
41 e
= getenv("XDG_CONFIG_HOME");
43 r
= strappend(e
, "/systemd/user");
52 home
= getenv("HOME");
54 r
= strappend(home
, "/.config/systemd/user");
66 int user_runtime_dir(char **runtime_dir
) {
70 e
= getenv("XDG_RUNTIME_DIR");
72 r
= strappend(e
, "/systemd/user");
83 static int user_data_home_dir(char **dir
, const char *suffix
) {
87 /* We don't treat /etc/xdg/systemd here as the spec
88 * suggests because we assume that that is a link to
89 * /etc/systemd/ anyway. */
91 e
= getenv("XDG_DATA_HOME");
93 res
= strappend(e
, suffix
);
97 home
= getenv("HOME");
99 res
= strjoin(home
, "/.local/share", suffix
, NULL
);
110 static char** user_dirs(
111 const char *generator
,
112 const char *generator_early
,
113 const char *generator_late
) {
115 const char * const config_unit_paths
[] = {
116 USER_CONFIG_UNIT_PATH
,
121 const char * const runtime_unit_path
= "/run/systemd/user";
123 const char * const data_unit_paths
[] = {
124 "/usr/local/lib/systemd/user",
125 "/usr/local/share/systemd/user",
127 "/usr/lib/systemd/user",
128 "/usr/share/systemd/user",
133 _cleanup_free_
char *config_home
= NULL
, *runtime_dir
= NULL
, *data_home
= NULL
;
134 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
135 _cleanup_free_
char **res
= NULL
;
139 /* Implement the mechanisms defined in
141 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
143 * We look in both the config and the data dirs because we
144 * want to encourage that distributors ship their unit files
145 * as data, and allow overriding as configuration.
148 if (user_config_home(&config_home
) < 0)
151 if (user_runtime_dir(&runtime_dir
) < 0)
154 e
= getenv("XDG_CONFIG_DIRS");
156 config_dirs
= strv_split(e
, ":");
161 r
= user_data_home_dir(&data_home
, "/systemd/user");
165 e
= getenv("XDG_DATA_DIRS");
167 data_dirs
= strv_split(e
, ":");
169 data_dirs
= strv_new("/usr/local/share",
175 /* Now merge everything we found. */
177 if (strv_extend(&res
, generator_early
) < 0)
181 if (strv_extend(&res
, config_home
) < 0)
184 if (!strv_isempty(config_dirs
))
185 if (strv_extend_strv_concat(&res
, config_dirs
, "/systemd/user") < 0)
188 if (strv_extend_strv(&res
, (char**) config_unit_paths
, false) < 0)
192 if (strv_extend(&res
, runtime_dir
) < 0)
195 if (strv_extend(&res
, runtime_unit_path
) < 0)
199 if (strv_extend(&res
, generator
) < 0)
203 if (strv_extend(&res
, data_home
) < 0)
206 if (!strv_isempty(data_dirs
))
207 if (strv_extend_strv_concat(&res
, data_dirs
, "/systemd/user") < 0)
210 if (strv_extend_strv(&res
, (char**) data_unit_paths
, false) < 0)
214 if (strv_extend(&res
, generator_late
) < 0)
217 if (path_strv_make_absolute_cwd(res
) < 0)
225 char **generator_paths(ManagerRunningAs running_as
) {
226 if (running_as
== MANAGER_USER
)
227 return strv_new("/run/systemd/user-generators",
228 "/etc/systemd/user-generators",
229 "/usr/local/lib/systemd/user-generators",
233 return strv_new("/run/systemd/system-generators",
234 "/etc/systemd/system-generators",
235 "/usr/local/lib/systemd/system-generators",
236 SYSTEM_GENERATOR_PATH
,
240 int lookup_paths_init(
242 ManagerRunningAs running_as
,
244 const char *root_dir
,
245 const char *generator
,
246 const char *generator_early
,
247 const char *generator_late
) {
250 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
255 /* First priority is whatever has been passed to us via env
257 e
= getenv("SYSTEMD_UNIT_PATH");
259 if (endswith(e
, ":")) {
260 e
= strndupa(e
, strlen(e
) - 1);
264 /* FIXME: empty components in other places should be
267 r
= path_split_and_make_absolute(e
, &p
->unit_path
);
273 if (!p
->unit_path
|| append
) {
274 /* Let's figure something out. */
276 _cleanup_strv_free_
char **unit_path
;
278 /* For the user units we include share/ in the search
279 * path in order to comply with the XDG basedir spec.
280 * For the system stuff we avoid such nonsense. OTOH
281 * we include /lib in the search path for the system
282 * stuff but avoid it for user stuff. */
284 if (running_as
== MANAGER_USER
) {
286 unit_path
= user_dirs(generator
, generator_early
, generator_late
);
288 unit_path
= strv_new(
289 /* If you modify this you also want to modify
290 * systemduserunitpath= in systemd.pc.in, and
291 * the arrays in user_dirs() above! */
292 STRV_IFNOTNULL(generator_early
),
293 USER_CONFIG_UNIT_PATH
,
296 STRV_IFNOTNULL(generator
),
297 "/usr/local/lib/systemd/user",
298 "/usr/local/share/systemd/user",
300 "/usr/lib/systemd/user",
301 "/usr/share/systemd/user",
302 STRV_IFNOTNULL(generator_late
),
305 unit_path
= strv_new(
306 /* If you modify this you also want to modify
307 * systemdsystemunitpath= in systemd.pc.in! */
308 STRV_IFNOTNULL(generator_early
),
309 SYSTEM_CONFIG_UNIT_PATH
,
310 "/etc/systemd/system",
311 "/run/systemd/system",
312 STRV_IFNOTNULL(generator
),
313 "/usr/local/lib/systemd/system",
314 SYSTEM_DATA_UNIT_PATH
,
315 "/usr/lib/systemd/system",
316 #ifdef HAVE_SPLIT_USR
317 "/lib/systemd/system",
319 STRV_IFNOTNULL(generator_late
),
325 r
= strv_extend_strv(&p
->unit_path
, unit_path
, false);
330 if (!path_strv_resolve_uniq(p
->unit_path
, root_dir
))
333 if (!strv_isempty(p
->unit_path
)) {
334 _cleanup_free_
char *t
= strv_join(p
->unit_path
, "\n\t");
337 log_debug("Looking for unit files in (higher priority first):\n\t%s", t
);
339 log_debug("Ignoring unit files.");
340 p
->unit_path
= strv_free(p
->unit_path
);
343 if (running_as
== MANAGER_SYSTEM
) {
344 #ifdef HAVE_SYSV_COMPAT
345 /* /etc/init.d/ compatibility does not matter to users */
347 e
= getenv("SYSTEMD_SYSVINIT_PATH");
349 r
= path_split_and_make_absolute(e
, &p
->sysvinit_path
);
353 p
->sysvinit_path
= NULL
;
355 if (strv_isempty(p
->sysvinit_path
)) {
356 strv_free(p
->sysvinit_path
);
358 p
->sysvinit_path
= strv_new(
359 SYSTEM_SYSVINIT_PATH
, /* /etc/init.d/ */
361 if (!p
->sysvinit_path
)
365 e
= getenv("SYSTEMD_SYSVRCND_PATH");
367 r
= path_split_and_make_absolute(e
, &p
->sysvrcnd_path
);
371 p
->sysvrcnd_path
= NULL
;
373 if (strv_isempty(p
->sysvrcnd_path
)) {
374 strv_free(p
->sysvrcnd_path
);
376 p
->sysvrcnd_path
= strv_new(
377 SYSTEM_SYSVRCND_PATH
, /* /etc/rcN.d/ */
379 if (!p
->sysvrcnd_path
)
383 if (!path_strv_resolve_uniq(p
->sysvinit_path
, root_dir
))
386 if (!path_strv_resolve_uniq(p
->sysvrcnd_path
, root_dir
))
389 if (!strv_isempty(p
->sysvinit_path
)) {
390 _cleanup_free_
char *t
= strv_join(p
->sysvinit_path
, "\n\t");
393 log_debug("Looking for SysV init scripts in:\n\t%s", t
);
395 log_debug("Ignoring SysV init scripts.");
396 p
->sysvinit_path
= strv_free(p
->sysvinit_path
);
399 if (!strv_isempty(p
->sysvrcnd_path
)) {
400 _cleanup_free_
char *t
=
401 strv_join(p
->sysvrcnd_path
, "\n\t");
405 log_debug("Looking for SysV rcN.d links in:\n\t%s", t
);
407 log_debug("Ignoring SysV rcN.d links.");
408 p
->sysvrcnd_path
= strv_free(p
->sysvrcnd_path
);
411 log_debug("SysV init scripts and rcN.d links support disabled");
418 void lookup_paths_free(LookupPaths
*p
) {
421 p
->unit_path
= strv_free(p
->unit_path
);
423 #ifdef HAVE_SYSV_COMPAT
424 p
->sysvinit_path
= strv_free(p
->sysvinit_path
);
425 p
->sysvrcnd_path
= strv_free(p
->sysvrcnd_path
);
429 int lookup_paths_init_from_scope(LookupPaths
*paths
,
431 const char *root_dir
) {
434 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
438 return lookup_paths_init(paths
,
439 scope
== UNIT_FILE_SYSTEM
? MANAGER_SYSTEM
: MANAGER_USER
,
440 scope
== UNIT_FILE_USER
,