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 static char** user_dirs(
65 const char *generator,
66 const char *generator_early,
67 const char *generator_late) {
69 const char * const config_unit_paths[] = {
70 USER_CONFIG_UNIT_PATH,
76 const char * const data_unit_paths[] = {
77 "/usr/local/lib/systemd/user",
78 "/usr/local/share/systemd/user",
80 "/usr/lib/systemd/user",
81 "/usr/share/systemd/user",
86 _cleanup_free_ char *config_home = NULL, *data_home = NULL;
87 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
90 /* Implement the mechanisms defined in
92 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
94 * We look in both the config and the data dirs because we
95 * want to encourage that distributors ship their unit files
96 * as data, and allow overriding as configuration.
99 if (user_config_home(&config_home) < 0)
102 home = getenv("HOME");
104 e = getenv("XDG_CONFIG_DIRS");
106 config_dirs = strv_split(e, ":");
111 /* We don't treat /etc/xdg/systemd here as the spec
112 * suggests because we assume that that is a link to
113 * /etc/systemd/ anyway. */
115 e = getenv("XDG_DATA_HOME");
117 if (asprintf(&data_home, "%s/systemd/user", e) < 0)
121 if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0)
125 e = getenv("XDG_DATA_DIRS");
127 data_dirs = strv_split(e, ":");
129 data_dirs = strv_new("/usr/local/share",
135 /* Now merge everything we found. */
137 if (strv_extend(&r, generator_early) < 0)
141 if (strv_extend(&r, config_home) < 0)
144 if (!strv_isempty(config_dirs))
145 if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0)
148 if (strv_extend_strv(&r, (char**) config_unit_paths) < 0)
152 if (strv_extend(&r, generator) < 0)
156 if (strv_extend(&r, data_home) < 0)
159 if (!strv_isempty(data_dirs))
160 if (strv_extend_strv_concat(&r, data_dirs, "/systemd/user") < 0)
163 if (strv_extend_strv(&r, (char**) data_unit_paths) < 0)
167 if (strv_extend(&r, generator_late) < 0)
170 if (!path_strv_make_absolute_cwd(r))
180 int lookup_paths_init(
182 SystemdRunningAs running_as,
184 const char *root_dir,
185 const char *generator,
186 const char *generator_early,
187 const char *generator_late) {
193 /* First priority is whatever has been passed to us via env
195 e = getenv("SYSTEMD_UNIT_PATH");
197 p->unit_path = path_split_and_make_absolute(e);
203 if (strv_isempty(p->unit_path)) {
204 /* Nothing is set, so let's figure something out. */
205 strv_free(p->unit_path);
207 /* For the user units we include share/ in the search
208 * path in order to comply with the XDG basedir
209 * spec. For the system stuff we avoid such
210 * nonsense. OTOH we include /lib in the search path
211 * for the system stuff but avoid it for user
214 if (running_as == SYSTEMD_USER) {
217 p->unit_path = user_dirs(generator, generator_early, generator_late);
219 p->unit_path = strv_new(
220 /* If you modify this you also want to modify
221 * systemduserunitpath= in systemd.pc.in, and
222 * the arrays in user_dirs() above! */
223 STRV_IFNOTNULL(generator_early),
224 USER_CONFIG_UNIT_PATH,
227 STRV_IFNOTNULL(generator),
228 "/usr/local/lib/systemd/user",
229 "/usr/local/share/systemd/user",
231 "/usr/lib/systemd/user",
232 "/usr/share/systemd/user",
233 STRV_IFNOTNULL(generator_late),
240 p->unit_path = strv_new(
241 /* If you modify this you also want to modify
242 * systemdsystemunitpath= in systemd.pc.in! */
243 STRV_IFNOTNULL(generator_early),
244 SYSTEM_CONFIG_UNIT_PATH,
245 "/etc/systemd/system",
246 "/run/systemd/system",
247 STRV_IFNOTNULL(generator),
248 "/usr/local/lib/systemd/system",
249 SYSTEM_DATA_UNIT_PATH,
250 "/usr/lib/systemd/system",
251 #ifdef HAVE_SPLIT_USR
252 "/lib/systemd/system",
254 STRV_IFNOTNULL(generator_late),
262 if (!path_strv_resolve_uniq(p->unit_path, root_dir))
265 if (!strv_isempty(p->unit_path)) {
266 _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
269 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
271 log_debug("Ignoring unit files.");
272 strv_free(p->unit_path);
276 if (running_as == SYSTEMD_SYSTEM) {
277 #ifdef HAVE_SYSV_COMPAT
278 /* /etc/init.d/ compatibility does not matter to users */
280 e = getenv("SYSTEMD_SYSVINIT_PATH");
282 p->sysvinit_path = path_split_and_make_absolute(e);
283 if (!p->sysvinit_path)
286 p->sysvinit_path = NULL;
288 if (strv_isempty(p->sysvinit_path)) {
289 strv_free(p->sysvinit_path);
291 p->sysvinit_path = strv_new(
292 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
294 if (!p->sysvinit_path)
298 e = getenv("SYSTEMD_SYSVRCND_PATH");
300 p->sysvrcnd_path = path_split_and_make_absolute(e);
301 if (!p->sysvrcnd_path)
304 p->sysvrcnd_path = NULL;
306 if (strv_isempty(p->sysvrcnd_path)) {
307 strv_free(p->sysvrcnd_path);
309 p->sysvrcnd_path = strv_new(
310 SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
312 if (!p->sysvrcnd_path)
316 if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir))
319 if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir))
322 if (!strv_isempty(p->sysvinit_path)) {
323 _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
326 log_debug("Looking for SysV init scripts in:\n\t%s", t);
328 log_debug("Ignoring SysV init scripts.");
329 strv_free(p->sysvinit_path);
330 p->sysvinit_path = NULL;
333 if (!strv_isempty(p->sysvrcnd_path)) {
334 _cleanup_free_ char *t =
335 strv_join(p->sysvrcnd_path, "\n\t");
339 log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
341 log_debug("Ignoring SysV rcN.d links.");
342 strv_free(p->sysvrcnd_path);
343 p->sysvrcnd_path = NULL;
346 log_debug("SysV init scripts and rcN.d links support disabled");
353 void lookup_paths_free(LookupPaths *p) {
356 strv_free(p->unit_path);
359 #ifdef HAVE_SYSV_COMPAT
360 strv_free(p->sysvinit_path);
361 strv_free(p->sysvrcnd_path);
362 p->sysvinit_path = p->sysvrcnd_path = NULL;