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"
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 int lookup_paths_init(
240 ManagerRunningAs running_as
,
242 const char *root_dir
,
243 const char *generator
,
244 const char *generator_early
,
245 const char *generator_late
) {
248 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
253 /* First priority is whatever has been passed to us via env
255 e
= getenv("SYSTEMD_UNIT_PATH");
257 if (endswith(e
, ":")) {
258 e
= strndupa(e
, strlen(e
) - 1);
262 /* FIXME: empty components in other places should be
265 r
= path_split_and_make_absolute(e
, &p
->unit_path
);
271 if (!p
->unit_path
|| append
) {
272 /* Let's figure something out. */
274 _cleanup_strv_free_
char **unit_path
;
276 /* For the user units we include share/ in the search
277 * path in order to comply with the XDG basedir spec.
278 * For the system stuff we avoid such nonsense. OTOH
279 * we include /lib in the search path for the system
280 * stuff but avoid it for user stuff. */
282 if (running_as
== MANAGER_USER
) {
284 unit_path
= user_dirs(generator
, generator_early
, generator_late
);
286 unit_path
= strv_new(
287 /* If you modify this you also want to modify
288 * systemduserunitpath= in systemd.pc.in, and
289 * the arrays in user_dirs() above! */
290 STRV_IFNOTNULL(generator_early
),
291 USER_CONFIG_UNIT_PATH
,
294 STRV_IFNOTNULL(generator
),
295 "/usr/local/lib/systemd/user",
296 "/usr/local/share/systemd/user",
298 "/usr/lib/systemd/user",
299 "/usr/share/systemd/user",
300 STRV_IFNOTNULL(generator_late
),
303 unit_path
= strv_new(
304 /* If you modify this you also want to modify
305 * systemdsystemunitpath= in systemd.pc.in! */
306 STRV_IFNOTNULL(generator_early
),
307 SYSTEM_CONFIG_UNIT_PATH
,
308 "/etc/systemd/system",
309 "/run/systemd/system",
310 STRV_IFNOTNULL(generator
),
311 "/usr/local/lib/systemd/system",
312 SYSTEM_DATA_UNIT_PATH
,
313 "/usr/lib/systemd/system",
314 #ifdef HAVE_SPLIT_USR
315 "/lib/systemd/system",
317 STRV_IFNOTNULL(generator_late
),
323 r
= strv_extend_strv(&p
->unit_path
, unit_path
, false);
328 if (!path_strv_resolve_uniq(p
->unit_path
, root_dir
))
331 if (!strv_isempty(p
->unit_path
)) {
332 _cleanup_free_
char *t
= strv_join(p
->unit_path
, "\n\t");
335 log_debug("Looking for unit files in (higher priority first):\n\t%s", t
);
337 log_debug("Ignoring unit files.");
338 p
->unit_path
= strv_free(p
->unit_path
);
341 if (running_as
== MANAGER_SYSTEM
) {
342 #ifdef HAVE_SYSV_COMPAT
343 /* /etc/init.d/ compatibility does not matter to users */
345 e
= getenv("SYSTEMD_SYSVINIT_PATH");
347 r
= path_split_and_make_absolute(e
, &p
->sysvinit_path
);
351 p
->sysvinit_path
= NULL
;
353 if (strv_isempty(p
->sysvinit_path
)) {
354 strv_free(p
->sysvinit_path
);
356 p
->sysvinit_path
= strv_new(
357 SYSTEM_SYSVINIT_PATH
, /* /etc/init.d/ */
359 if (!p
->sysvinit_path
)
363 e
= getenv("SYSTEMD_SYSVRCND_PATH");
365 r
= path_split_and_make_absolute(e
, &p
->sysvrcnd_path
);
369 p
->sysvrcnd_path
= NULL
;
371 if (strv_isempty(p
->sysvrcnd_path
)) {
372 strv_free(p
->sysvrcnd_path
);
374 p
->sysvrcnd_path
= strv_new(
375 SYSTEM_SYSVRCND_PATH
, /* /etc/rcN.d/ */
377 if (!p
->sysvrcnd_path
)
381 if (!path_strv_resolve_uniq(p
->sysvinit_path
, root_dir
))
384 if (!path_strv_resolve_uniq(p
->sysvrcnd_path
, root_dir
))
387 if (!strv_isempty(p
->sysvinit_path
)) {
388 _cleanup_free_
char *t
= strv_join(p
->sysvinit_path
, "\n\t");
391 log_debug("Looking for SysV init scripts in:\n\t%s", t
);
393 log_debug("Ignoring SysV init scripts.");
394 p
->sysvinit_path
= strv_free(p
->sysvinit_path
);
397 if (!strv_isempty(p
->sysvrcnd_path
)) {
398 _cleanup_free_
char *t
=
399 strv_join(p
->sysvrcnd_path
, "\n\t");
403 log_debug("Looking for SysV rcN.d links in:\n\t%s", t
);
405 log_debug("Ignoring SysV rcN.d links.");
406 p
->sysvrcnd_path
= strv_free(p
->sysvrcnd_path
);
409 log_debug("SysV init scripts and rcN.d links support disabled");
416 void lookup_paths_free(LookupPaths
*p
) {
419 p
->unit_path
= strv_free(p
->unit_path
);
421 #ifdef HAVE_SYSV_COMPAT
422 p
->sysvinit_path
= strv_free(p
->sysvinit_path
);
423 p
->sysvrcnd_path
= strv_free(p
->sysvrcnd_path
);
427 int lookup_paths_init_from_scope(LookupPaths
*paths
,
429 const char *root_dir
) {
432 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
436 return lookup_paths_init(paths
,
437 scope
== UNIT_FILE_SYSTEM
? MANAGER_SYSTEM
: MANAGER_USER
,
438 scope
== UNIT_FILE_USER
,