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 char *config_home = NULL, *data_home = NULL;
94 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)
131 /* There is really no need for two unit dirs in $HOME,
132 * except to be fully compliant with the XDG spec. We
133 * now try to link the two dirs, so that we can
134 * minimize disk seeks a little. Further down we'll
135 * then filter out this link, if it is actually is
138 mkdir_parents_label(data_home, 0777);
139 (void) symlink("../../../.config/systemd/user", data_home);
142 e = getenv("XDG_DATA_DIRS");
144 data_dirs = strv_split(e, ":");
146 data_dirs = strv_new("/usr/local/share",
152 /* Now merge everything we found. */
153 if (generator_early) {
154 t = strv_append(r, generator_early);
162 t = strv_append(r, config_home);
169 if (!strv_isempty(config_dirs)) {
170 t = strv_merge_concat(r, config_dirs, "/systemd/user");
177 t = strv_merge(r, (char**) config_unit_paths);
184 t = strv_append(r, generator);
192 t = strv_append(r, data_home);
199 if (!strv_isempty(data_dirs)) {
200 t = strv_merge_concat(r, data_dirs, "/systemd/user");
207 t = strv_merge(r, (char**) data_unit_paths);
213 if (generator_late) {
214 t = strv_append(r, generator_late);
221 if (!path_strv_make_absolute_cwd(r))
226 strv_free(config_dirs);
228 strv_free(data_dirs);
238 int lookup_paths_init(
240 SystemdRunningAs running_as,
242 const char *generator,
243 const char *generator_early,
244 const char *generator_late) {
250 /* First priority is whatever has been passed to us via env
252 e = getenv("SYSTEMD_UNIT_PATH");
254 p->unit_path = path_split_and_make_absolute(e);
260 if (strv_isempty(p->unit_path)) {
261 /* Nothing is set, so let's figure something out. */
262 strv_free(p->unit_path);
264 /* For the user units we include share/ in the search
265 * path in order to comply with the XDG basedir
266 * spec. For the system stuff we avoid such
267 * nonsense. OTOH we include /lib in the search path
268 * for the system stuff but avoid it for user
271 if (running_as == SYSTEMD_USER) {
274 p->unit_path = user_dirs(generator, generator_early, generator_late);
276 p->unit_path = strv_new(
277 /* If you modify this you also want to modify
278 * systemduserunitpath= in systemd.pc.in, and
279 * the arrays in user_dirs() above! */
280 STRV_IFNOTNULL(generator_early),
281 USER_CONFIG_UNIT_PATH,
284 STRV_IFNOTNULL(generator),
285 "/usr/local/lib/systemd/user",
286 "/usr/local/share/systemd/user",
288 "/usr/lib/systemd/user",
289 "/usr/share/systemd/user",
290 STRV_IFNOTNULL(generator_late),
297 p->unit_path = strv_new(
298 /* If you modify this you also want to modify
299 * systemdsystemunitpath= in systemd.pc.in! */
300 STRV_IFNOTNULL(generator_early),
301 SYSTEM_CONFIG_UNIT_PATH,
302 "/etc/systemd/system",
303 "/run/systemd/system",
304 STRV_IFNOTNULL(generator),
305 "/usr/local/lib/systemd/system",
306 SYSTEM_DATA_UNIT_PATH,
307 "/usr/lib/systemd/system",
308 #ifdef HAVE_SPLIT_USR
309 "/lib/systemd/system",
311 STRV_IFNOTNULL(generator_late),
319 if (!path_strv_canonicalize(p->unit_path))
322 strv_uniq(p->unit_path);
324 if (!strv_isempty(p->unit_path)) {
325 _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
328 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
330 log_debug("Ignoring unit files.");
331 strv_free(p->unit_path);
335 if (running_as == SYSTEMD_SYSTEM) {
336 #ifdef HAVE_SYSV_COMPAT
337 /* /etc/init.d/ compatibility does not matter to users */
339 e = getenv("SYSTEMD_SYSVINIT_PATH");
341 p->sysvinit_path = path_split_and_make_absolute(e);
342 if (!p->sysvinit_path)
345 p->sysvinit_path = NULL;
347 if (strv_isempty(p->sysvinit_path)) {
348 strv_free(p->sysvinit_path);
350 p->sysvinit_path = strv_new(
351 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
353 if (!p->sysvinit_path)
357 e = getenv("SYSTEMD_SYSVRCND_PATH");
359 p->sysvrcnd_path = path_split_and_make_absolute(e);
360 if (!p->sysvrcnd_path)
363 p->sysvrcnd_path = NULL;
365 if (strv_isempty(p->sysvrcnd_path)) {
366 strv_free(p->sysvrcnd_path);
368 p->sysvrcnd_path = strv_new(
369 SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
371 if (!p->sysvrcnd_path)
375 if (!path_strv_canonicalize(p->sysvinit_path))
378 if (!path_strv_canonicalize(p->sysvrcnd_path))
381 strv_uniq(p->sysvinit_path);
382 strv_uniq(p->sysvrcnd_path);
384 if (!strv_isempty(p->sysvinit_path)) {
385 _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
388 log_debug("Looking for SysV init scripts in:\n\t%s", t);
390 log_debug("Ignoring SysV init scripts.");
391 strv_free(p->sysvinit_path);
392 p->sysvinit_path = NULL;
395 if (!strv_isempty(p->sysvrcnd_path)) {
396 _cleanup_free_ char *t =
397 strv_join(p->sysvrcnd_path, "\n\t");
401 log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
403 log_debug("Ignoring SysV rcN.d links.");
404 strv_free(p->sysvrcnd_path);
405 p->sysvrcnd_path = NULL;
408 log_debug("SysV init scripts and rcN.d links support disabled");
415 void lookup_paths_free(LookupPaths *p) {
418 strv_free(p->unit_path);
421 #ifdef HAVE_SYSV_COMPAT
422 strv_free(p->sysvinit_path);
423 strv_free(p->sysvrcnd_path);
424 p->sysvinit_path = p->sysvrcnd_path = NULL;