1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
6 #include "architecture.h"
10 #include "path-lookup.h"
11 #include "path-util.h"
12 #include "string-util.h"
14 #include "user-util.h"
17 static int from_environment(const char *envname
, const char *fallback
, const char **ret
) {
23 e
= secure_getenv(envname
);
24 if (e
&& path_is_absolute(e
)) {
38 static int from_home_dir(const char *envname
, const char *suffix
, char **buffer
, const char **ret
) {
39 _cleanup_free_
char *h
= NULL
;
50 e
= secure_getenv(envname
);
51 if (e
&& path_is_absolute(e
)) {
61 cc
= path_join(h
, suffix
);
70 static int from_user_dir(const char *field
, char **buffer
, const char **ret
) {
71 _cleanup_fclose_
FILE *f
= NULL
;
72 _cleanup_free_
char *b
= NULL
;
73 _cleanup_free_
const char *fn
= NULL
;
82 r
= from_home_dir("XDG_CONFIG_HOME", ".config", &b
, &c
);
86 fn
= path_join(c
, "user-dirs.dirs");
98 /* This is an awful parse, but it follows closely what
99 * xdg-user-dirs does upstream */
103 _cleanup_free_
char *line
= NULL
;
106 r
= read_line(f
, LONG_LINE_MAX
, &line
);
114 if (!strneq(l
, field
, n
))
118 p
+= strspn(p
, WHITESPACE
);
124 p
+= strspn(p
, WHITESPACE
);
135 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
136 if (startswith(p
, "$HOME/")) {
137 _cleanup_free_
char *h
= NULL
;
140 r
= get_home_dir(&h
);
144 cc
= path_join(h
, p
+5);
151 } else if (streq(p
, "$HOME")) {
153 r
= get_home_dir(buffer
);
159 } else if (path_is_absolute(p
)) {
173 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
174 if (streq(field
, "XDG_DESKTOP_DIR")) {
175 _cleanup_free_
char *h
= NULL
;
178 r
= get_home_dir(&h
);
182 cc
= path_join(h
, "Desktop");
190 r
= get_home_dir(buffer
);
200 static int get_path(uint64_t type
, char **buffer
, const char **ret
) {
208 case SD_PATH_TEMPORARY
:
211 case SD_PATH_TEMPORARY_LARGE
:
212 return var_tmp_dir(ret
);
214 case SD_PATH_SYSTEM_BINARIES
:
218 case SD_PATH_SYSTEM_INCLUDE
:
219 *ret
= "/usr/include";
222 case SD_PATH_SYSTEM_LIBRARY_PRIVATE
:
226 case SD_PATH_SYSTEM_LIBRARY_ARCH
:
230 case SD_PATH_SYSTEM_SHARED
:
234 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY
:
235 *ret
= "/usr/share/factory/etc";
238 case SD_PATH_SYSTEM_STATE_FACTORY
:
239 *ret
= "/usr/share/factory/var";
242 case SD_PATH_SYSTEM_CONFIGURATION
:
246 case SD_PATH_SYSTEM_RUNTIME
:
250 case SD_PATH_SYSTEM_RUNTIME_LOGS
:
254 case SD_PATH_SYSTEM_STATE_PRIVATE
:
258 case SD_PATH_SYSTEM_STATE_LOGS
:
262 case SD_PATH_SYSTEM_STATE_CACHE
:
266 case SD_PATH_SYSTEM_STATE_SPOOL
:
270 case SD_PATH_USER_BINARIES
:
271 return from_home_dir(NULL
, ".local/bin", buffer
, ret
);
273 case SD_PATH_USER_LIBRARY_PRIVATE
:
274 return from_home_dir(NULL
, ".local/lib", buffer
, ret
);
276 case SD_PATH_USER_LIBRARY_ARCH
:
277 return from_home_dir(NULL
, ".local/lib/" LIB_ARCH_TUPLE
, buffer
, ret
);
279 case SD_PATH_USER_SHARED
:
280 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer
, ret
);
282 case SD_PATH_USER_CONFIGURATION
:
283 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer
, ret
);
285 case SD_PATH_USER_RUNTIME
:
286 return from_environment("XDG_RUNTIME_DIR", NULL
, ret
);
288 case SD_PATH_USER_STATE_CACHE
:
289 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer
, ret
);
292 r
= get_home_dir(buffer
);
299 case SD_PATH_USER_DOCUMENTS
:
300 return from_user_dir("XDG_DOCUMENTS_DIR", buffer
, ret
);
302 case SD_PATH_USER_MUSIC
:
303 return from_user_dir("XDG_MUSIC_DIR", buffer
, ret
);
305 case SD_PATH_USER_PICTURES
:
306 return from_user_dir("XDG_PICTURES_DIR", buffer
, ret
);
308 case SD_PATH_USER_VIDEOS
:
309 return from_user_dir("XDG_VIDEOS_DIR", buffer
, ret
);
311 case SD_PATH_USER_DOWNLOAD
:
312 return from_user_dir("XDG_DOWNLOAD_DIR", buffer
, ret
);
314 case SD_PATH_USER_PUBLIC
:
315 return from_user_dir("XDG_PUBLICSHARE_DIR", buffer
, ret
);
317 case SD_PATH_USER_TEMPLATES
:
318 return from_user_dir("XDG_TEMPLATES_DIR", buffer
, ret
);
320 case SD_PATH_USER_DESKTOP
:
321 return from_user_dir("XDG_DESKTOP_DIR", buffer
, ret
);
323 case SD_PATH_SYSTEMD_UTIL
:
324 *ret
= ROOTPREFIX_NOSLASH
"/lib/systemd";
327 case SD_PATH_SYSTEMD_SYSTEM_UNIT
:
328 *ret
= SYSTEM_DATA_UNIT_PATH
;
331 case SD_PATH_SYSTEMD_SYSTEM_PRESET
:
332 *ret
= ROOTPREFIX_NOSLASH
"/lib/systemd/system-preset";
335 case SD_PATH_SYSTEMD_USER_UNIT
:
336 *ret
= USER_DATA_UNIT_DIR
;
339 case SD_PATH_SYSTEMD_USER_PRESET
:
340 *ret
= ROOTPREFIX_NOSLASH
"/lib/systemd/user-preset";
343 case SD_PATH_SYSTEMD_SYSTEM_CONF
:
344 *ret
= SYSTEM_CONFIG_UNIT_DIR
;
347 case SD_PATH_SYSTEMD_USER_CONF
:
348 *ret
= USER_CONFIG_UNIT_DIR
;
351 case SD_PATH_SYSTEMD_SYSTEM_GENERATOR
:
352 *ret
= SYSTEM_GENERATOR_DIR
;
355 case SD_PATH_SYSTEMD_USER_GENERATOR
:
356 *ret
= USER_GENERATOR_DIR
;
359 case SD_PATH_SYSTEMD_SLEEP
:
360 *ret
= ROOTPREFIX_NOSLASH
"/lib/systemd/system-sleep";
363 case SD_PATH_SYSTEMD_SHUTDOWN
:
364 *ret
= ROOTPREFIX_NOSLASH
"/lib/systemd/system-shutdown";
367 case SD_PATH_TMPFILES
:
368 *ret
= "/usr/lib/tmpfiles.d";
371 case SD_PATH_SYSUSERS
:
372 *ret
= ROOTPREFIX_NOSLASH
"/lib/sysusers.d";
376 *ret
= ROOTPREFIX_NOSLASH
"/lib/sysctl.d";
380 *ret
= ROOTPREFIX_NOSLASH
"/lib/binfmt.d";
383 case SD_PATH_MODULES_LOAD
:
384 *ret
= ROOTPREFIX_NOSLASH
"/lib/modules-load.d";
387 case SD_PATH_CATALOG
:
388 *ret
= "/usr/lib/systemd/catalog";
395 static int get_path_alloc(uint64_t type
, const char *suffix
, char **path
) {
396 _cleanup_free_
char *buffer
= NULL
;
397 char *buffer2
= NULL
;
403 r
= get_path(type
, &buffer
, &ret
);
408 suffix
+= strspn(suffix
, "/");
409 buffer2
= path_join(ret
, suffix
);
412 } else if (!buffer
) {
413 buffer
= strdup(ret
);
418 *path
= buffer2
?: TAKE_PTR(buffer
);
422 _public_
int sd_path_lookup(uint64_t type
, const char *suffix
, char **path
) {
425 assert_return(path
, -EINVAL
);
427 r
= get_path_alloc(type
, suffix
, path
);
428 if (r
!= -EOPNOTSUPP
)
431 /* Fall back to sd_path_lookup_strv */
432 _cleanup_strv_free_
char **l
= NULL
;
435 r
= sd_path_lookup_strv(type
, suffix
, &l
);
439 buffer
= strv_join(l
, ":");
447 static int search_from_environment(
449 const char *env_home
,
450 const char *home_suffix
,
451 const char *env_search
,
452 bool env_search_sufficient
,
453 const char *first
, ...) {
455 _cleanup_strv_free_
char **l
= NULL
;
463 e
= secure_getenv(env_search
);
465 l
= strv_split(e
, ":");
469 if (env_search_sufficient
) {
480 l
= strv_new_ap(first
, ap
);
488 e
= secure_getenv(env_home
);
489 if (e
&& path_is_absolute(e
)) {
496 if (!h
&& home_suffix
) {
497 e
= secure_getenv("HOME");
498 if (e
&& path_is_absolute(e
)) {
499 h
= path_join(e
, home_suffix
);
506 r
= strv_consume_prepend(&l
, h
);
516 # define ARRAY_SBIN_BIN(x) x "sbin", x "bin"
518 # define ARRAY_SBIN_BIN(x) x "bin"
521 static int get_search(uint64_t type
, char ***list
) {
528 case SD_PATH_SEARCH_BINARIES
:
529 return search_from_environment(list
,
534 ARRAY_SBIN_BIN("/usr/local/"),
535 ARRAY_SBIN_BIN("/usr/"),
541 case SD_PATH_SEARCH_LIBRARY_PRIVATE
:
542 return search_from_environment(list
,
554 case SD_PATH_SEARCH_LIBRARY_ARCH
:
555 return search_from_environment(list
,
557 ".local/lib/" LIB_ARCH_TUPLE
,
566 case SD_PATH_SEARCH_SHARED
:
567 return search_from_environment(list
,
576 case SD_PATH_SEARCH_CONFIGURATION_FACTORY
:
577 return search_from_environment(list
,
582 "/usr/local/share/factory/etc",
583 "/usr/share/factory/etc",
586 case SD_PATH_SEARCH_STATE_FACTORY
:
587 return search_from_environment(list
,
592 "/usr/local/share/factory/var",
593 "/usr/share/factory/var",
596 case SD_PATH_SEARCH_CONFIGURATION
:
597 return search_from_environment(list
,
605 case SD_PATH_SEARCH_BINARIES_DEFAULT
:
606 return strv_from_nulstr(list
, DEFAULT_PATH_NULSTR
);
608 case SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT
:
609 case SD_PATH_SYSTEMD_SEARCH_USER_UNIT
: {
610 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
611 const UnitFileScope scope
= type
== SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT
?
612 UNIT_FILE_SYSTEM
: UNIT_FILE_USER
;
614 r
= lookup_paths_init(&lp
, scope
, 0, NULL
);
618 *list
= TAKE_PTR(lp
.search_path
);
622 case SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR
:
623 case SD_PATH_SYSTEMD_SEARCH_USER_GENERATOR
: {
625 const UnitFileScope scope
= type
== SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR
?
626 UNIT_FILE_SYSTEM
: UNIT_FILE_USER
;
628 t
= generator_binary_paths(scope
);
636 case SD_PATH_SYSTEMD_SEARCH_NETWORK
:
637 return strv_from_nulstr(list
, NETWORK_DIRS_NULSTR
);
644 _public_
int sd_path_lookup_strv(uint64_t type
, const char *suffix
, char ***paths
) {
645 _cleanup_strv_free_
char **l
= NULL
, **n
= NULL
;
648 assert_return(paths
, -EINVAL
);
650 r
= get_search(type
, &l
);
651 if (r
== -EOPNOTSUPP
) {
652 _cleanup_free_
char *t
= NULL
;
654 r
= get_path_alloc(type
, suffix
, &t
);
664 *paths
= TAKE_PTR(l
);
671 *paths
= TAKE_PTR(l
);
675 n
= new(char*, strv_length(l
)+1);
681 *j
= path_join(*i
, suffix
);
689 *paths
= TAKE_PTR(n
);