]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/path-lookup.c
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 *persistent_config
,
110 const char *runtime_config
,
111 const char *generator
,
112 const char *generator_early
,
113 const char *generator_late
) {
115 const char * const config_unit_paths
[] = {
116 USER_CONFIG_UNIT_PATH
,
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(&res
, persistent_config
) < 0)
189 if (strv_extend_strv(&res
, (char**) config_unit_paths
, false) < 0)
193 if (strv_extend(&res
, runtime_dir
) < 0)
196 if (strv_extend(&res
, runtime_config
) < 0)
200 if (strv_extend(&res
, generator
) < 0)
204 if (strv_extend(&res
, data_home
) < 0)
207 if (!strv_isempty(data_dirs
))
208 if (strv_extend_strv_concat(&res
, data_dirs
, "/systemd/user") < 0)
211 if (strv_extend_strv(&res
, (char**) data_unit_paths
, false) < 0)
215 if (strv_extend(&res
, generator_late
) < 0)
218 if (path_strv_make_absolute_cwd(res
) < 0)
226 char **generator_paths(UnitFileScope scope
) {
230 case UNIT_FILE_SYSTEM
:
231 return strv_new("/run/systemd/system-generators",
232 "/etc/systemd/system-generators",
233 "/usr/local/lib/systemd/system-generators",
234 SYSTEM_GENERATOR_PATH
,
237 case UNIT_FILE_GLOBAL
:
239 return strv_new("/run/systemd/user-generators",
240 "/etc/systemd/user-generators",
241 "/usr/local/lib/systemd/user-generators",
246 assert_not_reached("Hmm, unexpected scope.");
250 static int acquire_generator_dirs(
253 char **generator_early
,
254 char **generator_late
) {
256 _cleanup_free_
char *x
= NULL
, *y
= NULL
, *z
= NULL
;
260 assert(generator_early
);
261 assert(generator_late
);
265 case UNIT_FILE_SYSTEM
:
266 prefix
= "/run/systemd/";
269 case UNIT_FILE_USER
: {
272 e
= getenv("XDG_RUNTIME_DIR");
276 prefix
= strjoina(e
, "/systemd/", NULL
);
280 case UNIT_FILE_GLOBAL
:
284 assert_not_reached("Hmm, unexpected scope value.");
287 x
= strappend(prefix
, "generator");
291 y
= strappend(prefix
, "generator.early");
295 z
= strappend(prefix
, "generator.late");
300 *generator_early
= y
;
307 static int acquire_config_dirs(UnitFileScope scope
, char **persistent
, char **runtime
) {
308 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
316 case UNIT_FILE_SYSTEM
:
317 a
= strdup(SYSTEM_CONFIG_UNIT_PATH
);
318 b
= strdup("/run/systemd/system");
321 case UNIT_FILE_GLOBAL
:
322 a
= strdup(USER_CONFIG_UNIT_PATH
);
323 b
= strdup("/run/systemd/user");
327 r
= user_config_home(&a
);
331 r
= user_runtime_dir(runtime
);
341 assert_not_reached("Hmm, unexpected scope value.");
354 static int patch_root_prefix(char **p
, const char *root_dir
) {
362 if (isempty(root_dir
) || path_equal(root_dir
, "/"))
365 c
= prefix_root(root_dir
, *p
);
375 int lookup_paths_init(
378 const char *root_dir
) {
380 _cleanup_free_
char *generator
= NULL
, *generator_early
= NULL
, *generator_late
= NULL
,
381 *persistent_config
= NULL
, *runtime_config
= NULL
;
382 bool append
= false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
389 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
391 r
= acquire_config_dirs(scope
, &persistent_config
, &runtime_config
);
395 r
= acquire_generator_dirs(scope
, &generator
, &generator_early
, &generator_late
);
396 if (r
< 0 && r
!= -EOPNOTSUPP
&& r
!= -ENXIO
)
399 /* First priority is whatever has been passed to us via env
401 e
= getenv("SYSTEMD_UNIT_PATH");
405 k
= endswith(e
, ":");
407 e
= strndupa(e
, k
- e
);
411 /* FIXME: empty components in other places should be
414 r
= path_split_and_make_absolute(e
, &l
);
421 /* Let's figure something out. */
423 _cleanup_strv_free_
char **add
= NULL
;
425 /* For the user units we include share/ in the search
426 * path in order to comply with the XDG basedir spec.
427 * For the system stuff we avoid such nonsense. OTOH
428 * we include /lib in the search path for the system
429 * stuff but avoid it for user stuff. */
433 case UNIT_FILE_SYSTEM
:
435 /* If you modify this you also want to modify
436 * systemdsystemunitpath= in systemd.pc.in! */
437 STRV_IFNOTNULL(generator_early
),
439 "/etc/systemd/system",
441 "/run/systemd/system",
442 STRV_IFNOTNULL(generator
),
443 "/usr/local/lib/systemd/system",
444 SYSTEM_DATA_UNIT_PATH
,
445 "/usr/lib/systemd/system",
446 #ifdef HAVE_SPLIT_USR
447 "/lib/systemd/system",
449 STRV_IFNOTNULL(generator_late
),
453 case UNIT_FILE_GLOBAL
:
455 /* If you modify this you also want to modify
456 * systemduserunitpath= in systemd.pc.in, and
457 * the arrays in user_dirs() above! */
458 STRV_IFNOTNULL(generator_early
),
463 STRV_IFNOTNULL(generator
),
464 "/usr/local/lib/systemd/user",
465 "/usr/local/share/systemd/user",
467 "/usr/lib/systemd/user",
468 "/usr/share/systemd/user",
469 STRV_IFNOTNULL(generator_late
),
474 add
= user_dirs(persistent_config
, runtime_config
,
475 generator
, generator_early
, generator_late
);
479 assert_not_reached("Hmm, unexpected scope?");
486 r
= strv_extend_strv(&l
, add
, false);
495 r
= patch_root_prefix(&persistent_config
, root_dir
);
498 r
= patch_root_prefix(&runtime_config
, root_dir
);
502 r
= patch_root_prefix(&generator
, root_dir
);
505 r
= patch_root_prefix(&generator_early
, root_dir
);
508 r
= patch_root_prefix(&generator_late
, root_dir
);
512 if (!path_strv_resolve_uniq(l
, root_dir
))
515 if (strv_isempty(l
)) {
516 log_debug("Ignoring unit files.");
519 _cleanup_free_
char *t
;
521 t
= strv_join(l
, "\n\t");
525 log_debug("Looking for unit files in (higher priority first):\n\t%s", t
);
531 p
->persistent_config
= persistent_config
;
532 p
->runtime_config
= runtime_config
;
533 persistent_config
= runtime_config
= NULL
;
535 p
->generator
= generator
;
536 p
->generator_early
= generator_early
;
537 p
->generator_late
= generator_late
;
538 generator
= generator_early
= generator_late
= NULL
;
543 void lookup_paths_free(LookupPaths
*p
) {
547 p
->search_path
= strv_free(p
->search_path
);
549 p
->persistent_config
= mfree(p
->persistent_config
);
550 p
->runtime_config
= mfree(p
->runtime_config
);
552 p
->generator
= mfree(p
->generator
);
553 p
->generator_early
= mfree(p
->generator_early
);
554 p
->generator_late
= mfree(p
->generator_late
);