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 int lookup_paths_init(
223 SystemdRunningAs running_as,
225 const char *root_dir,
226 const char *generator,
227 const char *generator_early,
228 const char *generator_late) {
231 bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
235 /* First priority is whatever has been passed to us via env
237 e = getenv("SYSTEMD_UNIT_PATH");
239 if (endswith(e, ":")) {
240 e = strndupa(e, strlen(e) - 1);
244 /* FIXME: empty components in other places should be
247 p->unit_path = path_split_and_make_absolute(e);
253 if (!p->unit_path || append) {
254 /* Let's figure something out. */
256 _cleanup_strv_free_ char **unit_path;
259 /* For the user units we include share/ in the search
260 * path in order to comply with the XDG basedir spec.
261 * For the system stuff we avoid such nonsense. OTOH
262 * we include /lib in the search path for the system
263 * stuff but avoid it for user stuff. */
265 if (running_as == SYSTEMD_USER) {
267 unit_path = user_dirs(generator, generator_early, generator_late);
269 unit_path = strv_new(
270 /* If you modify this you also want to modify
271 * systemduserunitpath= in systemd.pc.in, and
272 * the arrays in user_dirs() above! */
273 STRV_IFNOTNULL(generator_early),
274 USER_CONFIG_UNIT_PATH,
277 STRV_IFNOTNULL(generator),
278 "/usr/local/lib/systemd/user",
279 "/usr/local/share/systemd/user",
281 "/usr/lib/systemd/user",
282 "/usr/share/systemd/user",
283 STRV_IFNOTNULL(generator_late),
286 unit_path = strv_new(
287 /* If you modify this you also want to modify
288 * systemdsystemunitpath= in systemd.pc.in! */
289 STRV_IFNOTNULL(generator_early),
290 SYSTEM_CONFIG_UNIT_PATH,
291 "/etc/systemd/system",
292 "/run/systemd/system",
293 STRV_IFNOTNULL(generator),
294 "/usr/local/lib/systemd/system",
295 SYSTEM_DATA_UNIT_PATH,
296 "/usr/lib/systemd/system",
297 #ifdef HAVE_SPLIT_USR
298 "/lib/systemd/system",
300 STRV_IFNOTNULL(generator_late),
306 r = strv_extend_strv(&p->unit_path, unit_path);
311 if (!path_strv_resolve_uniq(p->unit_path, root_dir))
314 if (!strv_isempty(p->unit_path)) {
315 _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
318 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
320 log_debug("Ignoring unit files.");
321 strv_free(p->unit_path);
325 if (running_as == SYSTEMD_SYSTEM) {
326 log_debug("SysV init scripts and rcN.d links support disabled");
332 void lookup_paths_free(LookupPaths *p) {
335 strv_free(p->unit_path);
339 int lookup_paths_init_from_scope(LookupPaths *paths,
341 const char *root_dir) {
344 assert(scope < _UNIT_FILE_SCOPE_MAX);
348 return lookup_paths_init(paths,
349 scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
350 scope == UNIT_FILE_USER,