2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "alloc-util.h"
29 #include "path-lookup.h"
30 #include "path-util.h"
31 #include "string-util.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 int user_runtime_dir(char **runtime_dir
) {
68 e
= getenv("XDG_RUNTIME_DIR");
70 r
= strappend(e
, "/systemd/user");
81 static int user_data_home_dir(char **dir
, const char *suffix
) {
85 /* We don't treat /etc/xdg/systemd here as the spec
86 * suggests because we assume that that is a link to
87 * /etc/systemd/ anyway. */
89 e
= getenv("XDG_DATA_HOME");
91 res
= strappend(e
, suffix
);
95 home
= getenv("HOME");
97 res
= strjoin(home
, "/.local/share", suffix
, NULL
);
108 static char** user_dirs(
109 const char *generator
,
110 const char *generator_early
,
111 const char *generator_late
) {
113 const char * const config_unit_paths
[] = {
114 USER_CONFIG_UNIT_PATH
,
119 const char * const runtime_unit_path
= "/run/systemd/user";
121 const char * const data_unit_paths
[] = {
122 "/usr/local/lib/systemd/user",
123 "/usr/local/share/systemd/user",
125 "/usr/lib/systemd/user",
126 "/usr/share/systemd/user",
131 _cleanup_free_
char *config_home
= NULL
, *runtime_dir
= NULL
, *data_home
= NULL
;
132 _cleanup_strv_free_
char **config_dirs
= NULL
, **data_dirs
= NULL
;
133 _cleanup_free_
char **res
= NULL
;
137 /* Implement the mechanisms defined in
139 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
141 * We look in both the config and the data dirs because we
142 * want to encourage that distributors ship their unit files
143 * as data, and allow overriding as configuration.
146 if (user_config_home(&config_home
) < 0)
149 if (user_runtime_dir(&runtime_dir
) < 0)
152 e
= getenv("XDG_CONFIG_DIRS");
154 config_dirs
= strv_split(e
, ":");
159 r
= user_data_home_dir(&data_home
, "/systemd/user");
163 e
= getenv("XDG_DATA_DIRS");
165 data_dirs
= strv_split(e
, ":");
167 data_dirs
= strv_new("/usr/local/share",
173 /* Now merge everything we found. */
175 if (strv_extend(&res
, generator_early
) < 0)
179 if (strv_extend(&res
, config_home
) < 0)
182 if (!strv_isempty(config_dirs
))
183 if (strv_extend_strv_concat(&res
, config_dirs
, "/systemd/user") < 0)
186 if (strv_extend_strv(&res
, (char**) config_unit_paths
, false) < 0)
190 if (strv_extend(&res
, runtime_dir
) < 0)
193 if (strv_extend(&res
, runtime_unit_path
) < 0)
197 if (strv_extend(&res
, generator
) < 0)
201 if (strv_extend(&res
, data_home
) < 0)
204 if (!strv_isempty(data_dirs
))
205 if (strv_extend_strv_concat(&res
, data_dirs
, "/systemd/user") < 0)
208 if (strv_extend_strv(&res
, (char**) data_unit_paths
, false) < 0)
212 if (strv_extend(&res
, generator_late
) < 0)
215 if (path_strv_make_absolute_cwd(res
) < 0)
223 char **generator_paths(ManagerRunningAs running_as
) {
224 if (running_as
== MANAGER_USER
)
225 return strv_new("/run/systemd/user-generators",
226 "/etc/systemd/user-generators",
227 "/usr/local/lib/systemd/user-generators",
231 return strv_new("/run/systemd/system-generators",
232 "/etc/systemd/system-generators",
233 "/usr/local/lib/systemd/system-generators",
234 SYSTEM_GENERATOR_PATH
,
238 int lookup_paths_init(
240 ManagerRunningAs running_as
,
242 const char *root_dir
,
243 const char *generator
,
244 const char *generator_early
,
245 const char *generator_late
) {
248 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
253 /* First priority is whatever has been passed to us via env
255 e
= getenv("SYSTEMD_UNIT_PATH");
257 if (endswith(e
, ":")) {
258 e
= strndupa(e
, strlen(e
) - 1);
262 /* FIXME: empty components in other places should be
265 r
= path_split_and_make_absolute(e
, &p
->unit_path
);
271 if (!p
->unit_path
|| append
) {
272 /* Let's figure something out. */
274 _cleanup_strv_free_
char **unit_path
;
276 /* For the user units we include share/ in the search
277 * path in order to comply with the XDG basedir spec.
278 * For the system stuff we avoid such nonsense. OTOH
279 * we include /lib in the search path for the system
280 * stuff but avoid it for user stuff. */
282 if (running_as
== MANAGER_USER
) {
284 unit_path
= user_dirs(generator
, generator_early
, generator_late
);
286 unit_path
= strv_new(
287 /* If you modify this you also want to modify
288 * systemduserunitpath= in systemd.pc.in, and
289 * the arrays in user_dirs() above! */
290 STRV_IFNOTNULL(generator_early
),
291 USER_CONFIG_UNIT_PATH
,
294 STRV_IFNOTNULL(generator
),
295 "/usr/local/lib/systemd/user",
296 "/usr/local/share/systemd/user",
298 "/usr/lib/systemd/user",
299 "/usr/share/systemd/user",
300 STRV_IFNOTNULL(generator_late
),
303 unit_path
= strv_new(
304 /* If you modify this you also want to modify
305 * systemdsystemunitpath= in systemd.pc.in! */
306 STRV_IFNOTNULL(generator_early
),
307 SYSTEM_CONFIG_UNIT_PATH
,
308 "/etc/systemd/system",
309 "/run/systemd/system",
310 STRV_IFNOTNULL(generator
),
311 "/usr/local/lib/systemd/system",
312 SYSTEM_DATA_UNIT_PATH
,
313 "/usr/lib/systemd/system",
314 #ifdef HAVE_SPLIT_USR
315 "/lib/systemd/system",
317 STRV_IFNOTNULL(generator_late
),
323 r
= strv_extend_strv(&p
->unit_path
, unit_path
, false);
328 if (!path_strv_resolve_uniq(p
->unit_path
, root_dir
))
331 if (!strv_isempty(p
->unit_path
)) {
332 _cleanup_free_
char *t
= strv_join(p
->unit_path
, "\n\t");
335 log_debug("Looking for unit files in (higher priority first):\n\t%s", t
);
337 log_debug("Ignoring unit files.");
338 p
->unit_path
= strv_free(p
->unit_path
);
345 void lookup_paths_free(LookupPaths
*p
) {
348 p
->unit_path
= strv_free(p
->unit_path
);
351 int lookup_paths_init_from_scope(LookupPaths
*paths
,
353 const char *root_dir
) {
356 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
360 return lookup_paths_init(paths
,
361 scope
== UNIT_FILE_SYSTEM
? MANAGER_SYSTEM
: MANAGER_USER
,
362 scope
== UNIT_FILE_USER
,