1 /* SPDX-License-Identifier: LGPL-2.1+ */
5 #include "alloc-util.h"
6 #include "architecture.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
)) {
62 cc
= strappend(h
, suffix
);
64 cc
= strjoin(h
, "/", suffix
);
73 static int from_user_dir(const char *field
, char **buffer
, const char **ret
) {
74 _cleanup_fclose_
FILE *f
= NULL
;
75 _cleanup_free_
char *b
= NULL
;
76 _cleanup_free_
const char *fn
= NULL
;
86 r
= from_home_dir("XDG_CONFIG_HOME", ".config", &b
, &c
);
90 fn
= strappend(c
, "/user-dirs.dirs");
102 /* This is an awful parse, but it follows closely what
103 * xdg-user-dirs does upstream */
106 FOREACH_LINE(line
, f
, return -errno
) {
111 if (!strneq(l
, field
, n
))
115 p
+= strspn(p
, WHITESPACE
);
121 p
+= strspn(p
, WHITESPACE
);
132 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
133 if (startswith(p
, "$HOME/")) {
134 _cleanup_free_
char *h
= NULL
;
137 r
= get_home_dir(&h
);
141 cc
= strappend(h
, p
+5);
148 } else if (streq(p
, "$HOME")) {
150 r
= get_home_dir(buffer
);
156 } else if (path_is_absolute(p
)) {
170 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
171 if (streq(field
, "XDG_DESKTOP_DIR")) {
172 _cleanup_free_
char *h
= NULL
;
175 r
= get_home_dir(&h
);
179 cc
= strappend(h
, "/Desktop");
187 r
= get_home_dir(buffer
);
197 static int get_path(uint64_t type
, char **buffer
, const char **ret
) {
205 case SD_PATH_TEMPORARY
:
208 case SD_PATH_TEMPORARY_LARGE
:
209 return var_tmp_dir(ret
);
211 case SD_PATH_SYSTEM_BINARIES
:
215 case SD_PATH_SYSTEM_INCLUDE
:
216 *ret
= "/usr/include";
219 case SD_PATH_SYSTEM_LIBRARY_PRIVATE
:
223 case SD_PATH_SYSTEM_LIBRARY_ARCH
:
227 case SD_PATH_SYSTEM_SHARED
:
231 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY
:
232 *ret
= "/usr/share/factory/etc";
235 case SD_PATH_SYSTEM_STATE_FACTORY
:
236 *ret
= "/usr/share/factory/var";
239 case SD_PATH_SYSTEM_CONFIGURATION
:
243 case SD_PATH_SYSTEM_RUNTIME
:
247 case SD_PATH_SYSTEM_RUNTIME_LOGS
:
251 case SD_PATH_SYSTEM_STATE_PRIVATE
:
255 case SD_PATH_SYSTEM_STATE_LOGS
:
259 case SD_PATH_SYSTEM_STATE_CACHE
:
263 case SD_PATH_SYSTEM_STATE_SPOOL
:
267 case SD_PATH_USER_BINARIES
:
268 return from_home_dir(NULL
, ".local/bin", buffer
, ret
);
270 case SD_PATH_USER_LIBRARY_PRIVATE
:
271 return from_home_dir(NULL
, ".local/lib", buffer
, ret
);
273 case SD_PATH_USER_LIBRARY_ARCH
:
274 return from_home_dir(NULL
, ".local/lib/" LIB_ARCH_TUPLE
, buffer
, ret
);
276 case SD_PATH_USER_SHARED
:
277 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer
, ret
);
279 case SD_PATH_USER_CONFIGURATION
:
280 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer
, ret
);
282 case SD_PATH_USER_RUNTIME
:
283 return from_environment("XDG_RUNTIME_DIR", NULL
, ret
);
285 case SD_PATH_USER_STATE_CACHE
:
286 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer
, ret
);
289 r
= get_home_dir(buffer
);
296 case SD_PATH_USER_DOCUMENTS
:
297 return from_user_dir("XDG_DOCUMENTS_DIR", buffer
, ret
);
299 case SD_PATH_USER_MUSIC
:
300 return from_user_dir("XDG_MUSIC_DIR", buffer
, ret
);
302 case SD_PATH_USER_PICTURES
:
303 return from_user_dir("XDG_PICTURES_DIR", buffer
, ret
);
305 case SD_PATH_USER_VIDEOS
:
306 return from_user_dir("XDG_VIDEOS_DIR", buffer
, ret
);
308 case SD_PATH_USER_DOWNLOAD
:
309 return from_user_dir("XDG_DOWNLOAD_DIR", buffer
, ret
);
311 case SD_PATH_USER_PUBLIC
:
312 return from_user_dir("XDG_PUBLICSHARE_DIR", buffer
, ret
);
314 case SD_PATH_USER_TEMPLATES
:
315 return from_user_dir("XDG_TEMPLATES_DIR", buffer
, ret
);
317 case SD_PATH_USER_DESKTOP
:
318 return from_user_dir("XDG_DESKTOP_DIR", buffer
, ret
);
324 _public_
int sd_path_home(uint64_t type
, const char *suffix
, char **path
) {
325 char *buffer
= NULL
, *cc
;
329 assert_return(path
, -EINVAL
);
332 SD_PATH_SEARCH_BINARIES
,
333 SD_PATH_SEARCH_BINARIES_DEFAULT
,
334 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
335 SD_PATH_SEARCH_LIBRARY_ARCH
,
336 SD_PATH_SEARCH_SHARED
,
337 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
338 SD_PATH_SEARCH_STATE_FACTORY
,
339 SD_PATH_SEARCH_CONFIGURATION
)) {
341 _cleanup_strv_free_
char **l
= NULL
;
343 r
= sd_path_search(type
, suffix
, &l
);
347 buffer
= strv_join(l
, ":");
355 r
= get_path(type
, &buffer
, &ret
);
361 buffer
= strdup(ret
);
370 suffix
+= strspn(suffix
, "/");
372 if (endswith(ret
, "/"))
373 cc
= strappend(ret
, suffix
);
375 cc
= strjoin(ret
, "/", suffix
);
386 static int search_from_environment(
388 const char *env_home
,
389 const char *home_suffix
,
390 const char *env_search
,
391 bool env_search_sufficient
,
392 const char *first
, ...) {
402 e
= secure_getenv(env_search
);
404 l
= strv_split(e
, ":");
408 if (env_search_sufficient
) {
419 l
= strv_new_ap(first
, ap
);
427 e
= secure_getenv(env_home
);
428 if (e
&& path_is_absolute(e
)) {
437 if (!h
&& home_suffix
) {
438 e
= secure_getenv("HOME");
439 if (e
&& path_is_absolute(e
)) {
440 if (endswith(e
, "/"))
441 h
= strappend(e
, home_suffix
);
443 h
= strjoin(e
, "/", home_suffix
);
453 r
= strv_consume_prepend(&l
, h
);
465 # define ARRAY_SBIN_BIN(x) x "sbin", x "bin"
467 # define ARRAY_SBIN_BIN(x) x "bin"
470 static int get_search(uint64_t type
, char ***list
) {
476 case SD_PATH_SEARCH_BINARIES
:
477 return search_from_environment(list
,
482 ARRAY_SBIN_BIN("/usr/local/"),
483 ARRAY_SBIN_BIN("/usr/"),
489 case SD_PATH_SEARCH_LIBRARY_PRIVATE
:
490 return search_from_environment(list
,
502 case SD_PATH_SEARCH_LIBRARY_ARCH
:
503 return search_from_environment(list
,
505 ".local/lib/" LIB_ARCH_TUPLE
,
514 case SD_PATH_SEARCH_SHARED
:
515 return search_from_environment(list
,
524 case SD_PATH_SEARCH_CONFIGURATION_FACTORY
:
525 return search_from_environment(list
,
530 "/usr/local/share/factory/etc",
531 "/usr/share/factory/etc",
534 case SD_PATH_SEARCH_STATE_FACTORY
:
535 return search_from_environment(list
,
540 "/usr/local/share/factory/var",
541 "/usr/share/factory/var",
544 case SD_PATH_SEARCH_CONFIGURATION
:
545 return search_from_environment(list
,
553 case SD_PATH_SEARCH_BINARIES_DEFAULT
: {
556 t
= strv_split_nulstr(DEFAULT_PATH_NULSTR
);
567 _public_
int sd_path_search(uint64_t type
, const char *suffix
, char ***paths
) {
569 _cleanup_strv_free_
char **l
= NULL
, **n
= NULL
;
572 assert_return(paths
, -EINVAL
);
575 SD_PATH_SEARCH_BINARIES
,
576 SD_PATH_SEARCH_BINARIES_DEFAULT
,
577 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
578 SD_PATH_SEARCH_LIBRARY_ARCH
,
579 SD_PATH_SEARCH_SHARED
,
580 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
581 SD_PATH_SEARCH_STATE_FACTORY
,
582 SD_PATH_SEARCH_CONFIGURATION
)) {
586 r
= sd_path_home(type
, suffix
, &p
);
599 *paths
= TAKE_PTR(l
);
603 r
= get_search(type
, &l
);
608 *paths
= TAKE_PTR(l
);
612 n
= new(char*, strv_length(l
)+1);
619 if (endswith(*i
, "/"))
620 *j
= strappend(*i
, suffix
);
622 *j
= strjoin(*i
, "/", suffix
);
631 *paths
= TAKE_PTR(n
);