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/>.
29 #include "path-util.h"
30 #include "path-lookup.h"
33 int user_config_home(char **config_home) {
37 e = getenv("XDG_CONFIG_HOME");
39 r = strappend(e, "/systemd/user");
48 home = getenv("HOME");
50 r = strappend(home, "/.config/systemd/user");
62 int user_runtime_dir(char **runtime_dir) {
66 e = getenv("XDG_RUNTIME_DIR");
68 r = strappend(e, "/systemd/user");
79 static int user_data_home_dir(char **dir, const char *suffix) {
83 /* We don't treat /etc/xdg/systemd here as the spec
84 * suggests because we assume that that is a link to
85 * /etc/systemd/ anyway. */
87 e = getenv("XDG_DATA_HOME");
89 res = strappend(e, suffix);
93 home = getenv("HOME");
95 res = strjoin(home, "/.local/share", suffix, NULL);
106 static char** user_dirs(
107 const char *generator,
108 const char *generator_early,
109 const char *generator_late) {
111 const char * const config_unit_paths[] = {
112 USER_CONFIG_UNIT_PATH,
117 const char * const runtime_unit_path = "/run/systemd/user";
119 const char * const data_unit_paths[] = {
120 "/usr/local/lib/systemd/user",
121 "/usr/local/share/systemd/user",
123 "/usr/lib/systemd/user",
124 "/usr/share/systemd/user",
129 _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL;
130 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
131 _cleanup_free_ char **res = NULL;
135 /* Implement the mechanisms defined in
137 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
139 * We look in both the config and the data dirs because we
140 * want to encourage that distributors ship their unit files
141 * as data, and allow overriding as configuration.
144 if (user_config_home(&config_home) < 0)
147 if (user_runtime_dir(&runtime_dir) < 0)
150 e = getenv("XDG_CONFIG_DIRS");
152 config_dirs = strv_split(e, ":");
157 r = user_data_home_dir(&data_home, "/systemd/user");
161 e = getenv("XDG_DATA_DIRS");
163 data_dirs = strv_split(e, ":");
165 data_dirs = strv_new("/usr/local/share",
171 /* Now merge everything we found. */
173 if (strv_extend(&res, generator_early) < 0)
177 if (strv_extend(&res, config_home) < 0)
180 if (!strv_isempty(config_dirs))
181 if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
184 if (strv_extend_strv(&res, (char**) config_unit_paths) < 0)
188 if (strv_extend(&res, runtime_dir) < 0)
191 if (strv_extend(&res, runtime_unit_path) < 0)
195 if (strv_extend(&res, generator) < 0)
199 if (strv_extend(&res, data_home) < 0)
202 if (!strv_isempty(data_dirs))
203 if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
206 if (strv_extend_strv(&res, (char**) data_unit_paths) < 0)
210 if (strv_extend(&res, generator_late) < 0)
213 if (!path_strv_make_absolute_cwd(res))
221 char **generator_paths(SystemdRunningAs running_as) {
222 if (running_as == SYSTEMD_USER)
223 return strv_new("/run/systemd/user-generators",
224 "/etc/systemd/user-generators",
225 "/usr/local/lib/systemd/user-generators",
229 return strv_new("/run/systemd/system-generators",
230 "/etc/systemd/system-generators",
231 "/usr/local/lib/systemd/system-generators",
232 SYSTEM_GENERATOR_PATH,
236 int lookup_paths_init(
238 SystemdRunningAs running_as,
240 const char *root_dir,
241 const char *generator,
242 const char *generator_early,
243 const char *generator_late) {
246 bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
250 /* First priority is whatever has been passed to us via env
252 e = getenv("SYSTEMD_UNIT_PATH");
254 if (endswith(e, ":")) {
255 e = strndupa(e, strlen(e) - 1);
259 /* FIXME: empty components in other places should be
262 p->unit_path = path_split_and_make_absolute(e);
268 if (!p->unit_path || append) {
269 /* Let's figure something out. */
271 _cleanup_strv_free_ char **unit_path;
274 /* For the user units we include share/ in the search
275 * path in order to comply with the XDG basedir spec.
276 * For the system stuff we avoid such nonsense. OTOH
277 * we include /lib in the search path for the system
278 * stuff but avoid it for user stuff. */
280 if (running_as == SYSTEMD_USER) {
282 unit_path = user_dirs(generator, generator_early, generator_late);
284 unit_path = strv_new(
285 /* If you modify this you also want to modify
286 * systemduserunitpath= in systemd.pc.in, and
287 * the arrays in user_dirs() above! */
288 STRV_IFNOTNULL(generator_early),
289 USER_CONFIG_UNIT_PATH,
292 STRV_IFNOTNULL(generator),
293 "/usr/local/lib/systemd/user",
294 "/usr/local/share/systemd/user",
296 "/usr/lib/systemd/user",
297 "/usr/share/systemd/user",
298 STRV_IFNOTNULL(generator_late),
301 unit_path = strv_new(
302 /* If you modify this you also want to modify
303 * systemdsystemunitpath= in systemd.pc.in! */
304 STRV_IFNOTNULL(generator_early),
305 SYSTEM_CONFIG_UNIT_PATH,
306 "/etc/systemd/system",
307 "/run/systemd/system",
308 STRV_IFNOTNULL(generator),
309 "/usr/local/lib/systemd/system",
310 SYSTEM_DATA_UNIT_PATH,
311 "/usr/lib/systemd/system",
312 #ifdef HAVE_SPLIT_USR
313 "/lib/systemd/system",
315 STRV_IFNOTNULL(generator_late),
321 r = strv_extend_strv(&p->unit_path, unit_path);
326 if (!path_strv_resolve_uniq(p->unit_path, root_dir))
329 if (!strv_isempty(p->unit_path)) {
330 _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
333 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
335 log_debug("Ignoring unit files.");
336 strv_free(p->unit_path);
340 if (running_as == SYSTEMD_SYSTEM) {
341 log_debug("SysV init scripts and rcN.d links support disabled");
347 void lookup_paths_free(LookupPaths *p) {
350 strv_free(p->unit_path);
354 int lookup_paths_init_from_scope(LookupPaths *paths,
356 const char *root_dir) {
359 assert(scope < _UNIT_FILE_SCOPE_MAX);
363 return lookup_paths_init(paths,
364 scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
365 scope == UNIT_FILE_USER,