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-lookup.h"
34 int user_config_home(char **config_home) {
37 if ((e = getenv("XDG_CONFIG_HOME"))) {
38 if (asprintf(config_home, "%s/systemd/user", e) < 0)
45 if ((home = getenv("HOME"))) {
46 if (asprintf(config_home, "%s/.config/systemd/user", home) < 0)
56 static char** user_dirs(void) {
57 const char * const config_unit_paths[] = {
58 USER_CONFIG_UNIT_PATH,
64 const char * const data_unit_paths[] = {
65 "/usr/local/lib/systemd/user",
66 "/usr/local/share/systemd/user",
68 "/usr/lib/systemd/user",
69 "/usr/share/systemd/user",
74 char *config_home = NULL, *data_home = NULL;
75 char **config_dirs = NULL, **data_dirs = NULL;
78 /* Implement the mechanisms defined in
80 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
82 * We look in both the config and the data dirs because we
83 * want to encourage that distributors ship their unit files
84 * as data, and allow overriding as configuration.
87 if (user_config_home(&config_home) < 0)
90 home = getenv("HOME");
92 if ((e = getenv("XDG_CONFIG_DIRS")))
93 if (!(config_dirs = strv_split(e, ":")))
96 /* We don't treat /etc/xdg/systemd here as the spec
97 * suggests because we assume that that is a link to
98 * /etc/systemd/ anyway. */
100 if ((e = getenv("XDG_DATA_HOME"))) {
101 if (asprintf(&data_home, "%s/systemd/user", e) < 0)
105 if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0)
108 /* There is really no need for two unit dirs in $HOME,
109 * except to be fully compliant with the XDG spec. We
110 * now try to link the two dirs, so that we can
111 * minimize disk seeks a little. Further down we'll
112 * then filter out this link, if it is actually is
115 mkdir_parents(data_home, 0777);
116 (void) symlink("../../../.config/systemd/user", data_home);
119 if ((e = getenv("XDG_DATA_DIRS")))
120 data_dirs = strv_split(e, ":");
122 data_dirs = strv_new("/usr/local/share",
129 /* Now merge everything we found. */
131 if (!(t = strv_append(r, config_home)))
137 if (!strv_isempty(config_dirs)) {
138 if (!(t = strv_merge_concat(r, config_dirs, "/systemd/user")))
144 if (!(t = strv_merge(r, (char**) config_unit_paths)))
150 if (!(t = strv_append(r, data_home)))
156 if (!strv_isempty(data_dirs)) {
157 if (!(t = strv_merge_concat(r, data_dirs, "/systemd/user")))
163 if (!(t = strv_merge(r, (char**) data_unit_paths)))
168 if (!strv_path_make_absolute_cwd(r))
173 strv_free(config_dirs);
175 strv_free(data_dirs);
185 int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal) {
191 /* First priority is whatever has been passed to us via env
193 if ((e = getenv("SYSTEMD_UNIT_PATH")))
194 if (!(p->unit_path = split_path_and_make_absolute(e)))
197 if (strv_isempty(p->unit_path)) {
199 /* Nothing is set, so let's figure something out. */
200 strv_free(p->unit_path);
202 if (running_as == MANAGER_USER) {
205 p->unit_path = user_dirs();
207 p->unit_path = strv_new(
208 /* If you modify this you also want to modify
209 * systemduserunitpath= in systemd.pc.in, and
210 * the arrays in user_dirs() above! */
211 USER_CONFIG_UNIT_PATH,
214 "/usr/local/lib/systemd/user",
215 "/usr/local/share/systemd/user",
217 "/usr/lib/systemd/user",
218 "/usr/share/systemd/user",
225 if (!(p->unit_path = strv_new(
226 /* If you modify this you also want to modify
227 * systemdsystemunitpath= in systemd.pc.in! */
228 SYSTEM_CONFIG_UNIT_PATH,
229 "/etc/systemd/system",
230 "/run/systemd/system",
231 "/usr/local/lib/systemd/system",
232 SYSTEM_DATA_UNIT_PATH,
233 "/usr/lib/systemd/system",
234 #ifdef HAVE_SPLIT_USR
235 "/lib/systemd/system",
242 if (!strv_path_canonicalize(p->unit_path))
245 strv_uniq(p->unit_path);
246 strv_path_remove_empty(p->unit_path);
248 if (!strv_isempty(p->unit_path)) {
250 if (!(t = strv_join(p->unit_path, "\n\t")))
252 log_debug("Looking for unit files in:\n\t%s", t);
255 log_debug("Ignoring unit files.");
256 strv_free(p->unit_path);
260 if (running_as == MANAGER_SYSTEM) {
261 #ifdef HAVE_SYSV_COMPAT
262 /* /etc/init.d/ compatibility does not matter to users */
264 if ((e = getenv("SYSTEMD_SYSVINIT_PATH")))
265 if (!(p->sysvinit_path = split_path_and_make_absolute(e)))
268 if (strv_isempty(p->sysvinit_path)) {
269 strv_free(p->sysvinit_path);
271 if (!(p->sysvinit_path = strv_new(
272 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
277 if ((e = getenv("SYSTEMD_SYSVRCND_PATH")))
278 if (!(p->sysvrcnd_path = split_path_and_make_absolute(e)))
281 if (strv_isempty(p->sysvrcnd_path)) {
282 strv_free(p->sysvrcnd_path);
284 if (!(p->sysvrcnd_path = strv_new(
285 SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
290 if (p->sysvinit_path)
291 if (!strv_path_canonicalize(p->sysvinit_path))
294 if (p->sysvrcnd_path)
295 if (!strv_path_canonicalize(p->sysvrcnd_path))
298 strv_uniq(p->sysvinit_path);
299 strv_uniq(p->sysvrcnd_path);
301 strv_path_remove_empty(p->sysvinit_path);
302 strv_path_remove_empty(p->sysvrcnd_path);
304 if (!strv_isempty(p->sysvinit_path)) {
306 if (!(t = strv_join(p->sysvinit_path, "\n\t")))
309 log_debug("Looking for SysV init scripts in:\n\t%s", t);
312 log_debug("Ignoring SysV init scripts.");
313 strv_free(p->sysvinit_path);
314 p->sysvinit_path = NULL;
317 if (!strv_isempty(p->sysvrcnd_path)) {
319 if (!(t = strv_join(p->sysvrcnd_path, "\n\t")))
322 log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
325 log_debug("Ignoring SysV rcN.d links.");
326 strv_free(p->sysvrcnd_path);
327 p->sysvrcnd_path = NULL;
330 log_debug("Disabled SysV init scripts and rcN.d links support");
337 void lookup_paths_free(LookupPaths *p) {
340 strv_free(p->unit_path);
343 #ifdef HAVE_SYSV_COMPAT
344 strv_free(p->sysvinit_path);
345 strv_free(p->sysvrcnd_path);
346 p->sysvinit_path = p->sysvrcnd_path = NULL;