1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
8 #include "architecture.h"
12 #include "network-util.h"
13 #include "nulstr-util.h"
14 #include "path-lookup.h"
15 #include "path-util.h"
16 #include "string-util.h"
18 #include "user-util.h"
20 static int from_environment(const char *envname
, const char *fallback
, const char **ret
) {
26 e
= secure_getenv(envname
);
27 if (e
&& path_is_absolute(e
)) {
41 static int from_home_dir(
47 _cleanup_free_
char *h
= NULL
;
57 e
= secure_getenv(envname
);
58 if (e
&& path_is_absolute(e
)) {
68 if (!path_extend(&h
, suffix
))
76 static int from_xdg_user_dir(const char *field
, char **buffer
, const char **ret
) {
77 _cleanup_free_
char *user_dirs
= NULL
;
78 _cleanup_fclose_
FILE *f
= NULL
;
85 r
= sd_path_lookup(SD_PATH_USER_CONFIGURATION
, "user-dirs.dirs", &user_dirs
);
89 f
= fopen(user_dirs
, "re");
97 /* This is an awful parse, but it follows closely what xdg-user-dirs does upstream */
99 _cleanup_free_
char *line
= NULL
;
102 r
= read_stripped_line(f
, LONG_LINE_MAX
, &line
);
108 p
= startswith(line
, field
);
112 p
= skip_leading_chars(p
, WHITESPACE
);
117 p
= skip_leading_chars(p
, WHITESPACE
);
127 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
128 if (streq(p
, "$HOME"))
131 const char *s
= startswith(p
, "$HOME/");
133 return from_home_dir(/* envname = */ NULL
, s
, buffer
, ret
);
135 if (path_is_absolute(p
)) {
146 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
147 if (streq(field
, "XDG_DESKTOP_DIR"))
148 return from_home_dir(/* envname = */ NULL
, "Desktop", buffer
, ret
);
151 r
= get_home_dir(buffer
);
159 static int get_path(uint64_t type
, char **buffer
, const char **ret
) {
167 case SD_PATH_TEMPORARY
:
170 case SD_PATH_TEMPORARY_LARGE
:
171 return var_tmp_dir(ret
);
173 case SD_PATH_SYSTEM_BINARIES
:
177 case SD_PATH_SYSTEM_INCLUDE
:
178 *ret
= "/usr/include";
181 case SD_PATH_SYSTEM_LIBRARY_PRIVATE
:
185 case SD_PATH_SYSTEM_LIBRARY_ARCH
:
189 case SD_PATH_SYSTEM_SHARED
:
193 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY
:
194 *ret
= "/usr/share/factory/etc";
197 case SD_PATH_SYSTEM_STATE_FACTORY
:
198 *ret
= "/usr/share/factory/var";
201 case SD_PATH_SYSTEM_CONFIGURATION
:
205 case SD_PATH_SYSTEM_RUNTIME
:
209 case SD_PATH_SYSTEM_RUNTIME_LOGS
:
213 case SD_PATH_SYSTEM_STATE_PRIVATE
:
217 case SD_PATH_SYSTEM_STATE_LOGS
:
221 case SD_PATH_SYSTEM_STATE_CACHE
:
225 case SD_PATH_SYSTEM_STATE_SPOOL
:
229 case SD_PATH_USER_BINARIES
:
230 return from_home_dir(NULL
, ".local/bin", buffer
, ret
);
232 case SD_PATH_USER_LIBRARY_PRIVATE
:
233 return from_home_dir(NULL
, ".local/lib", buffer
, ret
);
235 case SD_PATH_USER_LIBRARY_ARCH
:
236 return from_home_dir(NULL
, ".local/lib/" LIB_ARCH_TUPLE
, buffer
, ret
);
238 case SD_PATH_USER_SHARED
:
239 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer
, ret
);
241 case SD_PATH_USER_CONFIGURATION
:
242 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer
, ret
);
244 case SD_PATH_USER_RUNTIME
:
245 return from_environment("XDG_RUNTIME_DIR", NULL
, ret
);
247 case SD_PATH_USER_STATE_CACHE
:
248 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer
, ret
);
250 case SD_PATH_USER_STATE_PRIVATE
:
251 return from_home_dir("XDG_STATE_HOME", ".local/state", buffer
, ret
);
254 r
= get_home_dir(buffer
);
261 case SD_PATH_USER_DOCUMENTS
:
262 return from_xdg_user_dir("XDG_DOCUMENTS_DIR", buffer
, ret
);
264 case SD_PATH_USER_MUSIC
:
265 return from_xdg_user_dir("XDG_MUSIC_DIR", buffer
, ret
);
267 case SD_PATH_USER_PICTURES
:
268 return from_xdg_user_dir("XDG_PICTURES_DIR", buffer
, ret
);
270 case SD_PATH_USER_VIDEOS
:
271 return from_xdg_user_dir("XDG_VIDEOS_DIR", buffer
, ret
);
273 case SD_PATH_USER_DOWNLOAD
:
274 return from_xdg_user_dir("XDG_DOWNLOAD_DIR", buffer
, ret
);
276 case SD_PATH_USER_PUBLIC
:
277 return from_xdg_user_dir("XDG_PUBLICSHARE_DIR", buffer
, ret
);
279 case SD_PATH_USER_TEMPLATES
:
280 return from_xdg_user_dir("XDG_TEMPLATES_DIR", buffer
, ret
);
282 case SD_PATH_USER_DESKTOP
:
283 return from_xdg_user_dir("XDG_DESKTOP_DIR", buffer
, ret
);
285 case SD_PATH_SYSTEMD_UTIL
:
286 *ret
= PREFIX_NOSLASH
"/lib/systemd";
289 case SD_PATH_SYSTEMD_SYSTEM_UNIT
:
290 *ret
= SYSTEM_DATA_UNIT_DIR
;
293 case SD_PATH_SYSTEMD_SYSTEM_PRESET
:
294 *ret
= PREFIX_NOSLASH
"/lib/systemd/system-preset";
297 case SD_PATH_SYSTEMD_USER_UNIT
:
298 *ret
= USER_DATA_UNIT_DIR
;
301 case SD_PATH_SYSTEMD_USER_PRESET
:
302 *ret
= PREFIX_NOSLASH
"/lib/systemd/user-preset";
305 case SD_PATH_SYSTEMD_INITRD_PRESET
:
306 *ret
= PREFIX_NOSLASH
"/lib/systemd/initrd-preset";
309 case SD_PATH_SYSTEMD_SYSTEM_CONF
:
310 *ret
= SYSTEM_CONFIG_UNIT_DIR
;
313 case SD_PATH_SYSTEMD_USER_CONF
:
314 *ret
= USER_CONFIG_UNIT_DIR
;
317 case SD_PATH_SYSTEMD_SYSTEM_GENERATOR
:
318 *ret
= SYSTEM_GENERATOR_DIR
;
321 case SD_PATH_SYSTEMD_USER_GENERATOR
:
322 *ret
= USER_GENERATOR_DIR
;
325 case SD_PATH_SYSTEMD_SLEEP
:
326 *ret
= PREFIX_NOSLASH
"/lib/systemd/system-sleep";
329 case SD_PATH_SYSTEMD_SHUTDOWN
:
330 *ret
= PREFIX_NOSLASH
"/lib/systemd/system-shutdown";
333 case SD_PATH_TMPFILES
:
334 *ret
= "/usr/lib/tmpfiles.d";
337 case SD_PATH_SYSUSERS
:
338 *ret
= PREFIX_NOSLASH
"/lib/sysusers.d";
342 *ret
= PREFIX_NOSLASH
"/lib/sysctl.d";
346 *ret
= PREFIX_NOSLASH
"/lib/binfmt.d";
349 case SD_PATH_MODULES_LOAD
:
350 *ret
= PREFIX_NOSLASH
"/lib/modules-load.d";
353 case SD_PATH_CATALOG
:
354 *ret
= "/usr/lib/systemd/catalog";
357 case SD_PATH_SYSTEMD_SYSTEM_ENVIRONMENT_GENERATOR
:
358 *ret
= SYSTEM_ENV_GENERATOR_DIR
;
361 case SD_PATH_SYSTEMD_USER_ENVIRONMENT_GENERATOR
:
362 *ret
= USER_ENV_GENERATOR_DIR
;
365 case SD_PATH_SYSTEM_CREDENTIAL_STORE
:
366 *ret
= "/etc/credstore";
369 case SD_PATH_SYSTEM_CREDENTIAL_STORE_ENCRYPTED
:
370 *ret
= "/etc/credstore.encrypted";
373 case SD_PATH_USER_CREDENTIAL_STORE
:
374 r
= xdg_user_config_dir("credstore", buffer
);
381 case SD_PATH_USER_CREDENTIAL_STORE_ENCRYPTED
:
382 r
= xdg_user_config_dir("credstore.encrypted", buffer
);
393 static int get_path_alloc(uint64_t type
, const char *suffix
, char **ret
) {
394 _cleanup_free_
char *buffer
= NULL
;
400 r
= get_path(type
, &buffer
, &p
);
404 if (!isempty(suffix
)) {
405 char *suffixed
= path_join(p
, suffix
);
409 path_simplify_full(suffixed
, PATH_SIMPLIFY_KEEP_TRAILING_SLASH
);
411 free_and_replace(buffer
, suffixed
);
412 } else if (!buffer
) {
418 *ret
= TAKE_PTR(buffer
);
422 _public_
int sd_path_lookup(uint64_t type
, const char *suffix
, char **ret
) {
425 assert_return(ret
, -EINVAL
);
427 r
= get_path_alloc(type
, suffix
, ret
);
428 if (r
!= -EOPNOTSUPP
)
431 /* Fall back to sd_path_lookup_strv */
432 _cleanup_strv_free_
char **l
= NULL
;
434 r
= sd_path_lookup_strv(type
, suffix
, &l
);
438 char *joined
= strv_join(l
, ":");
446 static int search_from_environment(
448 const char *env_home
,
449 const char *home_suffix
,
450 const char *env_search
,
451 bool env_search_sufficient
,
452 const char *first
, ...) {
454 _cleanup_strv_free_
char **l
= NULL
;
462 e
= secure_getenv(env_search
);
464 l
= strv_split(e
, ":");
468 if (env_search_sufficient
) {
479 l
= strv_new_ap(first
, ap
);
487 e
= secure_getenv(env_home
);
488 if (e
&& path_is_absolute(e
)) {
495 if (!h
&& home_suffix
) {
496 e
= secure_getenv("HOME");
497 if (e
&& path_is_absolute(e
)) {
498 h
= path_join(e
, home_suffix
);
505 r
= strv_consume_prepend(&l
, h
);
515 # define ARRAY_SBIN_BIN(x) x "sbin", x "bin"
517 # define ARRAY_SBIN_BIN(x) x "bin"
520 static int get_search(uint64_t type
, char ***ret
) {
527 case SD_PATH_SEARCH_BINARIES
:
528 return search_from_environment(ret
,
533 ARRAY_SBIN_BIN("/usr/local/"),
534 ARRAY_SBIN_BIN("/usr/"),
537 case SD_PATH_SEARCH_LIBRARY_PRIVATE
:
538 return search_from_environment(ret
,
547 case SD_PATH_SEARCH_LIBRARY_ARCH
:
548 return search_from_environment(ret
,
550 ".local/lib/" LIB_ARCH_TUPLE
,
556 case SD_PATH_SEARCH_SHARED
:
557 return search_from_environment(ret
,
566 case SD_PATH_SEARCH_CONFIGURATION_FACTORY
:
567 return search_from_environment(ret
,
572 "/usr/local/share/factory/etc",
573 "/usr/share/factory/etc",
576 case SD_PATH_SEARCH_STATE_FACTORY
:
577 return search_from_environment(ret
,
582 "/usr/local/share/factory/var",
583 "/usr/share/factory/var",
586 case SD_PATH_SEARCH_CONFIGURATION
:
587 return search_from_environment(ret
,
595 case SD_PATH_SEARCH_BINARIES_DEFAULT
: {
596 char **t
= strv_split(default_PATH(), ":");
604 case SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT
:
605 case SD_PATH_SYSTEMD_SEARCH_USER_UNIT
: {
606 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
607 RuntimeScope scope
= type
== SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT
?
608 RUNTIME_SCOPE_SYSTEM
: RUNTIME_SCOPE_USER
;
610 r
= lookup_paths_init(&lp
, scope
, 0, NULL
);
614 *ret
= TAKE_PTR(lp
.search_path
);
618 case SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR
:
619 case SD_PATH_SYSTEMD_SEARCH_USER_GENERATOR
:
620 case SD_PATH_SYSTEMD_SEARCH_SYSTEM_ENVIRONMENT_GENERATOR
:
621 case SD_PATH_SYSTEMD_SEARCH_USER_ENVIRONMENT_GENERATOR
: {
622 RuntimeScope scope
= IN_SET(type
, SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR
,
623 SD_PATH_SYSTEMD_SEARCH_SYSTEM_ENVIRONMENT_GENERATOR
) ?
624 RUNTIME_SCOPE_SYSTEM
: RUNTIME_SCOPE_USER
;
625 bool env_generator
= IN_SET(type
, SD_PATH_SYSTEMD_SEARCH_SYSTEM_ENVIRONMENT_GENERATOR
,
626 SD_PATH_SYSTEMD_SEARCH_USER_ENVIRONMENT_GENERATOR
);
628 char **t
= generator_binary_paths_internal(scope
, env_generator
);
636 case SD_PATH_SYSTEMD_SEARCH_NETWORK
:
637 return strv_from_nulstr(ret
, NETWORK_DIRS_NULSTR
);
639 case SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE
:
640 case SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED
: {
642 type
== SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED
? "credstore.encrypted" : "credstore";
644 _cleanup_strv_free_
char **l
= NULL
;
645 FOREACH_STRING(d
, CONF_PATHS("")) {
646 char *j
= path_join(d
, suffix
);
650 r
= strv_consume(&l
, TAKE_PTR(j
));
659 case SD_PATH_USER_SEARCH_CREDENTIAL_STORE
:
660 case SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED
: {
662 type
== SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED
? "credstore.encrypted" : "credstore";
664 static const uint64_t dirs
[] = {
665 SD_PATH_USER_CONFIGURATION
,
666 SD_PATH_USER_RUNTIME
,
667 SD_PATH_USER_LIBRARY_PRIVATE
,
670 _cleanup_strv_free_
char **l
= NULL
;
671 FOREACH_ELEMENT(d
, dirs
) {
672 _cleanup_free_
char *p
= NULL
;
673 r
= sd_path_lookup(*d
, suffix
, &p
);
679 r
= strv_consume(&l
, TAKE_PTR(p
));
691 _public_
int sd_path_lookup_strv(uint64_t type
, const char *suffix
, char ***ret
) {
692 _cleanup_strv_free_
char **l
= NULL
;
695 assert_return(ret
, -EINVAL
);
697 r
= get_search(type
, &l
);
698 if (r
== -EOPNOTSUPP
) {
699 _cleanup_free_
char *t
= NULL
;
701 r
= get_path_alloc(type
, suffix
, &t
);
719 if (!path_extend(i
, suffix
))
722 path_simplify_full(*i
, PATH_SIMPLIFY_KEEP_TRAILING_SLASH
);