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 static const char* const systemd_running_as_table[_SYSTEMD_RUNNING_AS_MAX] = {
36 [SYSTEMD_SYSTEM] = "system",
37 [SYSTEMD_USER] = "user"
40 DEFINE_STRING_TABLE_LOOKUP(systemd_running_as, SystemdRunningAs);
42 int user_config_home(char **config_home) {
46 e = getenv("XDG_CONFIG_HOME");
48 r = strappend(e, "/systemd/user");
57 home = getenv("HOME");
59 r = strappend(home, "/.config/systemd/user");
71 static char** user_dirs(
72 const char *generator,
73 const char *generator_early,
74 const char *generator_late) {
76 const char * const config_unit_paths[] = {
77 USER_CONFIG_UNIT_PATH,
83 const char * const data_unit_paths[] = {
84 "/usr/local/lib/systemd/user",
85 "/usr/local/share/systemd/user",
87 "/usr/lib/systemd/user",
88 "/usr/share/systemd/user",
93 _cleanup_free_ char *config_home = NULL, *data_home = NULL;
94 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
97 /* Implement the mechanisms defined in
99 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
101 * We look in both the config and the data dirs because we
102 * want to encourage that distributors ship their unit files
103 * as data, and allow overriding as configuration.
106 if (user_config_home(&config_home) < 0)
109 home = getenv("HOME");
111 e = getenv("XDG_CONFIG_DIRS");
113 config_dirs = strv_split(e, ":");
118 /* We don't treat /etc/xdg/systemd here as the spec
119 * suggests because we assume that that is a link to
120 * /etc/systemd/ anyway. */
122 e = getenv("XDG_DATA_HOME");
124 if (asprintf(&data_home, "%s/systemd/user", e) < 0)
128 if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0)
132 e = getenv("XDG_DATA_DIRS");
134 data_dirs = strv_split(e, ":");
136 data_dirs = strv_new("/usr/local/share",
142 /* Now merge everything we found. */
144 if (strv_extend(&r, generator_early) < 0)
148 if (strv_extend(&r, config_home) < 0)
151 if (!strv_isempty(config_dirs))
152 if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0)
155 if (strv_extend_strv(&r, (char**) config_unit_paths) < 0)
159 if (strv_extend(&r, generator) < 0)
163 if (strv_extend(&r, data_home) < 0)
166 if (!strv_isempty(data_dirs))
167 if (strv_extend_strv_concat(&r, data_dirs, "/systemd/user") < 0)
170 if (strv_extend_strv(&r, (char**) data_unit_paths) < 0)
174 if (strv_extend(&r, generator_late) < 0)
177 if (!path_strv_make_absolute_cwd(r))
187 int lookup_paths_init(
189 SystemdRunningAs running_as,
191 const char *root_dir,
192 const char *generator,
193 const char *generator_early,
194 const char *generator_late) {
200 /* First priority is whatever has been passed to us via env
202 e = getenv("SYSTEMD_UNIT_PATH");
204 p->unit_path = path_split_and_make_absolute(e);
210 if (strv_isempty(p->unit_path)) {
211 /* Nothing is set, so let's figure something out. */
212 strv_free(p->unit_path);
214 /* For the user units we include share/ in the search
215 * path in order to comply with the XDG basedir
216 * spec. For the system stuff we avoid such
217 * nonsense. OTOH we include /lib in the search path
218 * for the system stuff but avoid it for user
221 if (running_as == SYSTEMD_USER) {
224 p->unit_path = user_dirs(generator, generator_early, generator_late);
226 p->unit_path = strv_new(
227 /* If you modify this you also want to modify
228 * systemduserunitpath= in systemd.pc.in, and
229 * the arrays in user_dirs() above! */
230 STRV_IFNOTNULL(generator_early),
231 USER_CONFIG_UNIT_PATH,
234 STRV_IFNOTNULL(generator),
235 "/usr/local/lib/systemd/user",
236 "/usr/local/share/systemd/user",
238 "/usr/lib/systemd/user",
239 "/usr/share/systemd/user",
240 STRV_IFNOTNULL(generator_late),
247 p->unit_path = strv_new(
248 /* If you modify this you also want to modify
249 * systemdsystemunitpath= in systemd.pc.in! */
250 STRV_IFNOTNULL(generator_early),
251 SYSTEM_CONFIG_UNIT_PATH,
252 "/etc/systemd/system",
253 "/run/systemd/system",
254 STRV_IFNOTNULL(generator),
255 "/usr/local/lib/systemd/system",
256 SYSTEM_DATA_UNIT_PATH,
257 "/usr/lib/systemd/system",
258 #ifdef HAVE_SPLIT_USR
259 "/lib/systemd/system",
261 STRV_IFNOTNULL(generator_late),
269 if (!path_strv_resolve_uniq(p->unit_path, root_dir))
272 if (!strv_isempty(p->unit_path)) {
273 _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
276 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
278 log_debug("Ignoring unit files.");
279 strv_free(p->unit_path);
283 if (running_as == SYSTEMD_SYSTEM) {
284 #ifdef HAVE_SYSV_COMPAT
285 /* /etc/init.d/ compatibility does not matter to users */
287 e = getenv("SYSTEMD_SYSVINIT_PATH");
289 p->sysvinit_path = path_split_and_make_absolute(e);
290 if (!p->sysvinit_path)
293 p->sysvinit_path = NULL;
295 if (strv_isempty(p->sysvinit_path)) {
296 strv_free(p->sysvinit_path);
298 p->sysvinit_path = strv_new(
299 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
301 if (!p->sysvinit_path)
305 e = getenv("SYSTEMD_SYSVRCND_PATH");
307 p->sysvrcnd_path = path_split_and_make_absolute(e);
308 if (!p->sysvrcnd_path)
311 p->sysvrcnd_path = NULL;
313 if (strv_isempty(p->sysvrcnd_path)) {
314 strv_free(p->sysvrcnd_path);
316 p->sysvrcnd_path = strv_new(
317 SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
319 if (!p->sysvrcnd_path)
323 if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir))
326 if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir))
329 if (!strv_isempty(p->sysvinit_path)) {
330 _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
333 log_debug("Looking for SysV init scripts in:\n\t%s", t);
335 log_debug("Ignoring SysV init scripts.");
336 strv_free(p->sysvinit_path);
337 p->sysvinit_path = NULL;
340 if (!strv_isempty(p->sysvrcnd_path)) {
341 _cleanup_free_ char *t =
342 strv_join(p->sysvrcnd_path, "\n\t");
346 log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
348 log_debug("Ignoring SysV rcN.d links.");
349 strv_free(p->sysvrcnd_path);
350 p->sysvrcnd_path = NULL;
353 log_debug("SysV init scripts and rcN.d links support disabled");
360 void lookup_paths_free(LookupPaths *p) {
363 strv_free(p->unit_path);
366 #ifdef HAVE_SYSV_COMPAT
367 strv_free(p->sysvinit_path);
368 strv_free(p->sysvrcnd_path);
369 p->sysvinit_path = p->sysvrcnd_path = NULL;