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)
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. */
154 if (strv_extend(&r, generator_early) < 0)
158 if (strv_extend(&r, config_home) < 0)
161 if (!strv_isempty(config_dirs))
162 if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0)
165 if (strv_extend_strv(&r, (char**) config_unit_paths) < 0)
169 if (strv_extend(&r, generator) < 0)
173 if (strv_extend(&r, data_home) < 0)
176 if (!strv_isempty(data_dirs))
177 if (strv_extend_strv_concat(&r, data_dirs, "/systemd/user") < 0)
180 if (strv_extend_strv(&r, (char**) data_unit_paths) < 0)
184 if (strv_extend(&r, generator_late) < 0)
187 if (!path_strv_make_absolute_cwd(r))
197 int lookup_paths_init(
199 SystemdRunningAs running_as,
201 const char *root_dir,
202 const char *generator,
203 const char *generator_early,
204 const char *generator_late) {
210 /* First priority is whatever has been passed to us via env
212 e = getenv("SYSTEMD_UNIT_PATH");
214 p->unit_path = path_split_and_make_absolute(e);
220 if (strv_isempty(p->unit_path)) {
221 /* Nothing is set, so let's figure something out. */
222 strv_free(p->unit_path);
224 /* For the user units we include share/ in the search
225 * path in order to comply with the XDG basedir
226 * spec. For the system stuff we avoid such
227 * nonsense. OTOH we include /lib in the search path
228 * for the system stuff but avoid it for user
231 if (running_as == SYSTEMD_USER) {
234 p->unit_path = user_dirs(generator, generator_early, generator_late);
236 p->unit_path = strv_new(
237 /* If you modify this you also want to modify
238 * systemduserunitpath= in systemd.pc.in, and
239 * the arrays in user_dirs() above! */
240 STRV_IFNOTNULL(generator_early),
241 USER_CONFIG_UNIT_PATH,
244 STRV_IFNOTNULL(generator),
245 "/usr/local/lib/systemd/user",
246 "/usr/local/share/systemd/user",
248 "/usr/lib/systemd/user",
249 "/usr/share/systemd/user",
250 STRV_IFNOTNULL(generator_late),
257 p->unit_path = strv_new(
258 /* If you modify this you also want to modify
259 * systemdsystemunitpath= in systemd.pc.in! */
260 STRV_IFNOTNULL(generator_early),
261 SYSTEM_CONFIG_UNIT_PATH,
262 "/etc/systemd/system",
263 "/run/systemd/system",
264 STRV_IFNOTNULL(generator),
265 "/usr/local/lib/systemd/system",
266 SYSTEM_DATA_UNIT_PATH,
267 "/usr/lib/systemd/system",
268 #ifdef HAVE_SPLIT_USR
269 "/lib/systemd/system",
271 STRV_IFNOTNULL(generator_late),
279 if (!path_strv_canonicalize_absolute_uniq(p->unit_path, root_dir))
282 if (!strv_isempty(p->unit_path)) {
283 _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
286 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
288 log_debug("Ignoring unit files.");
289 strv_free(p->unit_path);
293 if (running_as == SYSTEMD_SYSTEM) {
294 #ifdef HAVE_SYSV_COMPAT
295 /* /etc/init.d/ compatibility does not matter to users */
297 e = getenv("SYSTEMD_SYSVINIT_PATH");
299 p->sysvinit_path = path_split_and_make_absolute(e);
300 if (!p->sysvinit_path)
303 p->sysvinit_path = NULL;
305 if (strv_isempty(p->sysvinit_path)) {
306 strv_free(p->sysvinit_path);
308 p->sysvinit_path = strv_new(
309 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
311 if (!p->sysvinit_path)
315 e = getenv("SYSTEMD_SYSVRCND_PATH");
317 p->sysvrcnd_path = path_split_and_make_absolute(e);
318 if (!p->sysvrcnd_path)
321 p->sysvrcnd_path = NULL;
323 if (strv_isempty(p->sysvrcnd_path)) {
324 strv_free(p->sysvrcnd_path);
326 p->sysvrcnd_path = strv_new(
327 SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
329 if (!p->sysvrcnd_path)
333 if (!path_strv_canonicalize_absolute_uniq(p->sysvinit_path, root_dir))
336 if (!path_strv_canonicalize_absolute_uniq(p->sysvrcnd_path, root_dir))
339 if (!strv_isempty(p->sysvinit_path)) {
340 _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
343 log_debug("Looking for SysV init scripts in:\n\t%s", t);
345 log_debug("Ignoring SysV init scripts.");
346 strv_free(p->sysvinit_path);
347 p->sysvinit_path = NULL;
350 if (!strv_isempty(p->sysvrcnd_path)) {
351 _cleanup_free_ char *t =
352 strv_join(p->sysvrcnd_path, "\n\t");
356 log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
358 log_debug("Ignoring SysV rcN.d links.");
359 strv_free(p->sysvrcnd_path);
360 p->sysvrcnd_path = NULL;
363 log_debug("SysV init scripts and rcN.d links support disabled");
370 void lookup_paths_free(LookupPaths *p) {
373 strv_free(p->unit_path);
376 #ifdef HAVE_SYSV_COMPAT
377 strv_free(p->sysvinit_path);
378 strv_free(p->sysvrcnd_path);
379 p->sysvinit_path = p->sysvrcnd_path = NULL;