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/>.
32 #include "path-util.h"
33 #include "path-lookup.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 char** user_dirs(
82 const char *generator,
83 const char *generator_early,
84 const char *generator_late) {
86 const char * const config_unit_paths[] = {
87 USER_CONFIG_UNIT_PATH,
92 const char * const runtime_unit_path = "/run/systemd/user";
94 const char * const data_unit_paths[] = {
95 "/usr/local/lib/systemd/user",
96 "/usr/local/share/systemd/user",
98 "/usr/lib/systemd/user",
99 "/usr/share/systemd/user",
103 const char *home, *e;
104 _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL;
105 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
108 /* Implement the mechanisms defined in
110 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
112 * We look in both the config and the data dirs because we
113 * want to encourage that distributors ship their unit files
114 * as data, and allow overriding as configuration.
117 if (user_config_home(&config_home) < 0)
120 if (user_runtime_dir(&runtime_dir) < 0)
123 home = getenv("HOME");
125 e = getenv("XDG_CONFIG_DIRS");
127 config_dirs = strv_split(e, ":");
132 /* We don't treat /etc/xdg/systemd here as the spec
133 * suggests because we assume that that is a link to
134 * /etc/systemd/ anyway. */
136 e = getenv("XDG_DATA_HOME");
138 if (asprintf(&data_home, "%s/systemd/user", e) < 0)
142 if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0)
146 e = getenv("XDG_DATA_DIRS");
148 data_dirs = strv_split(e, ":");
150 data_dirs = strv_new("/usr/local/share",
156 /* Now merge everything we found. */
158 if (strv_extend(&r, generator_early) < 0)
162 if (strv_extend(&r, config_home) < 0)
165 if (!strv_isempty(config_dirs))
166 if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0)
169 if (strv_extend_strv(&r, (char**) config_unit_paths) < 0)
173 if (strv_extend(&r, runtime_dir) < 0)
176 if (strv_extend(&r, runtime_unit_path) < 0)
180 if (strv_extend(&r, generator) < 0)
184 if (strv_extend(&r, data_home) < 0)
187 if (!strv_isempty(data_dirs))
188 if (strv_extend_strv_concat(&r, data_dirs, "/systemd/user") < 0)
191 if (strv_extend_strv(&r, (char**) data_unit_paths) < 0)
195 if (strv_extend(&r, generator_late) < 0)
198 if (!path_strv_make_absolute_cwd(r))
208 int lookup_paths_init(
210 SystemdRunningAs running_as,
212 const char *root_dir,
213 const char *generator,
214 const char *generator_early,
215 const char *generator_late) {
218 bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
222 /* First priority is whatever has been passed to us via env
224 e = getenv("SYSTEMD_UNIT_PATH");
226 if (endswith(e, ":")) {
227 e = strndupa(e, strlen(e) - 1);
231 /* FIXME: empty components in other places should be
234 p->unit_path = path_split_and_make_absolute(e);
240 if (!p->unit_path || append) {
241 /* Let's figure something out. */
243 _cleanup_strv_free_ char **unit_path;
246 /* For the user units we include share/ in the search
247 * path in order to comply with the XDG basedir spec.
248 * For the system stuff we avoid such nonsense. OTOH
249 * we include /lib in the search path for the system
250 * stuff but avoid it for user stuff. */
252 if (running_as == SYSTEMD_USER) {
254 unit_path = user_dirs(generator, generator_early, generator_late);
256 unit_path = strv_new(
257 /* If you modify this you also want to modify
258 * systemduserunitpath= in systemd.pc.in, and
259 * the arrays in user_dirs() above! */
260 STRV_IFNOTNULL(generator_early),
261 USER_CONFIG_UNIT_PATH,
264 STRV_IFNOTNULL(generator),
265 "/usr/local/lib/systemd/user",
266 "/usr/local/share/systemd/user",
268 "/usr/lib/systemd/user",
269 "/usr/share/systemd/user",
270 STRV_IFNOTNULL(generator_late),
273 unit_path = strv_new(
274 /* If you modify this you also want to modify
275 * systemdsystemunitpath= in systemd.pc.in! */
276 STRV_IFNOTNULL(generator_early),
277 SYSTEM_CONFIG_UNIT_PATH,
278 "/etc/systemd/system",
279 "/run/systemd/system",
280 STRV_IFNOTNULL(generator),
281 "/usr/local/lib/systemd/system",
282 SYSTEM_DATA_UNIT_PATH,
283 "/usr/lib/systemd/system",
284 #ifdef HAVE_SPLIT_USR
285 "/lib/systemd/system",
287 STRV_IFNOTNULL(generator_late),
293 r = strv_extend_strv(&p->unit_path, unit_path);
298 if (!path_strv_resolve_uniq(p->unit_path, root_dir))
301 if (!strv_isempty(p->unit_path)) {
302 _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
305 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
307 log_debug("Ignoring unit files.");
308 strv_free(p->unit_path);
312 if (running_as == SYSTEMD_SYSTEM) {
313 #ifdef HAVE_SYSV_COMPAT
314 /* /etc/init.d/ compatibility does not matter to users */
316 e = getenv("SYSTEMD_SYSVINIT_PATH");
318 p->sysvinit_path = path_split_and_make_absolute(e);
319 if (!p->sysvinit_path)
322 p->sysvinit_path = NULL;
324 if (strv_isempty(p->sysvinit_path)) {
325 strv_free(p->sysvinit_path);
327 p->sysvinit_path = strv_new(
328 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
330 if (!p->sysvinit_path)
334 e = getenv("SYSTEMD_SYSVRCND_PATH");
336 p->sysvrcnd_path = path_split_and_make_absolute(e);
337 if (!p->sysvrcnd_path)
340 p->sysvrcnd_path = NULL;
342 if (strv_isempty(p->sysvrcnd_path)) {
343 strv_free(p->sysvrcnd_path);
345 p->sysvrcnd_path = strv_new(
346 SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
348 if (!p->sysvrcnd_path)
352 if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir))
355 if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir))
358 if (!strv_isempty(p->sysvinit_path)) {
359 _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
362 log_debug("Looking for SysV init scripts in:\n\t%s", t);
364 log_debug("Ignoring SysV init scripts.");
365 strv_free(p->sysvinit_path);
366 p->sysvinit_path = NULL;
369 if (!strv_isempty(p->sysvrcnd_path)) {
370 _cleanup_free_ char *t =
371 strv_join(p->sysvrcnd_path, "\n\t");
375 log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
377 log_debug("Ignoring SysV rcN.d links.");
378 strv_free(p->sysvrcnd_path);
379 p->sysvrcnd_path = NULL;
382 log_debug("SysV init scripts and rcN.d links support disabled");
389 void lookup_paths_free(LookupPaths *p) {
392 strv_free(p->unit_path);
395 #ifdef HAVE_SYSV_COMPAT
396 strv_free(p->sysvinit_path);
397 strv_free(p->sysvrcnd_path);
398 p->sysvinit_path = p->sysvrcnd_path = NULL;