1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
10 #include "alloc-util.h"
11 #include "architecture.h"
16 #include "path-util.h"
17 #include "string-util.h"
19 #include "user-util.h"
22 static int from_environment(const char *envname
, const char *fallback
, const char **ret
) {
28 e
= secure_getenv(envname
);
29 if (e
&& path_is_absolute(e
)) {
43 static int from_home_dir(const char *envname
, const char *suffix
, char **buffer
, const char **ret
) {
44 _cleanup_free_
char *h
= NULL
;
55 e
= secure_getenv(envname
);
56 if (e
&& path_is_absolute(e
)) {
67 cc
= strappend(h
, suffix
);
69 cc
= strjoin(h
, "/", suffix
);
78 static int from_user_dir(const char *field
, char **buffer
, const char **ret
) {
79 _cleanup_fclose_
FILE *f
= NULL
;
80 _cleanup_free_
char *b
= NULL
;
81 _cleanup_free_
const char *fn
= NULL
;
91 r
= from_home_dir("XDG_CONFIG_HOME", ".config", &b
, &c
);
95 fn
= strappend(c
, "/user-dirs.dirs");
107 /* This is an awful parse, but it follows closely what
108 * xdg-user-dirs does upstream */
111 FOREACH_LINE(line
, f
, return -errno
) {
116 if (!strneq(l
, field
, n
))
120 p
+= strspn(p
, WHITESPACE
);
126 p
+= strspn(p
, WHITESPACE
);
137 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
138 if (startswith(p
, "$HOME/")) {
139 _cleanup_free_
char *h
= NULL
;
142 r
= get_home_dir(&h
);
146 cc
= strappend(h
, p
+5);
153 } else if (streq(p
, "$HOME")) {
155 r
= get_home_dir(buffer
);
161 } else if (path_is_absolute(p
)) {
175 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
176 if (streq(field
, "XDG_DESKTOP_DIR")) {
177 _cleanup_free_
char *h
= NULL
;
180 r
= get_home_dir(&h
);
184 cc
= strappend(h
, "/Desktop");
192 r
= get_home_dir(buffer
);
202 static int get_path(uint64_t type
, char **buffer
, const char **ret
) {
210 case SD_PATH_TEMPORARY
:
213 case SD_PATH_TEMPORARY_LARGE
:
214 return var_tmp_dir(ret
);
216 case SD_PATH_SYSTEM_BINARIES
:
220 case SD_PATH_SYSTEM_INCLUDE
:
221 *ret
= "/usr/include";
224 case SD_PATH_SYSTEM_LIBRARY_PRIVATE
:
228 case SD_PATH_SYSTEM_LIBRARY_ARCH
:
232 case SD_PATH_SYSTEM_SHARED
:
236 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY
:
237 *ret
= "/usr/share/factory/etc";
240 case SD_PATH_SYSTEM_STATE_FACTORY
:
241 *ret
= "/usr/share/factory/var";
244 case SD_PATH_SYSTEM_CONFIGURATION
:
248 case SD_PATH_SYSTEM_RUNTIME
:
252 case SD_PATH_SYSTEM_RUNTIME_LOGS
:
256 case SD_PATH_SYSTEM_STATE_PRIVATE
:
260 case SD_PATH_SYSTEM_STATE_LOGS
:
264 case SD_PATH_SYSTEM_STATE_CACHE
:
268 case SD_PATH_SYSTEM_STATE_SPOOL
:
272 case SD_PATH_USER_BINARIES
:
273 return from_home_dir(NULL
, ".local/bin", buffer
, ret
);
275 case SD_PATH_USER_LIBRARY_PRIVATE
:
276 return from_home_dir(NULL
, ".local/lib", buffer
, ret
);
278 case SD_PATH_USER_LIBRARY_ARCH
:
279 return from_home_dir(NULL
, ".local/lib/" LIB_ARCH_TUPLE
, buffer
, ret
);
281 case SD_PATH_USER_SHARED
:
282 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer
, ret
);
284 case SD_PATH_USER_CONFIGURATION
:
285 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer
, ret
);
287 case SD_PATH_USER_RUNTIME
:
288 return from_environment("XDG_RUNTIME_DIR", NULL
, ret
);
290 case SD_PATH_USER_STATE_CACHE
:
291 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer
, ret
);
294 r
= get_home_dir(buffer
);
301 case SD_PATH_USER_DOCUMENTS
:
302 return from_user_dir("XDG_DOCUMENTS_DIR", buffer
, ret
);
304 case SD_PATH_USER_MUSIC
:
305 return from_user_dir("XDG_MUSIC_DIR", buffer
, ret
);
307 case SD_PATH_USER_PICTURES
:
308 return from_user_dir("XDG_PICTURES_DIR", buffer
, ret
);
310 case SD_PATH_USER_VIDEOS
:
311 return from_user_dir("XDG_VIDEOS_DIR", buffer
, ret
);
313 case SD_PATH_USER_DOWNLOAD
:
314 return from_user_dir("XDG_DOWNLOAD_DIR", buffer
, ret
);
316 case SD_PATH_USER_PUBLIC
:
317 return from_user_dir("XDG_PUBLICSHARE_DIR", buffer
, ret
);
319 case SD_PATH_USER_TEMPLATES
:
320 return from_user_dir("XDG_TEMPLATES_DIR", buffer
, ret
);
322 case SD_PATH_USER_DESKTOP
:
323 return from_user_dir("XDG_DESKTOP_DIR", buffer
, ret
);
329 _public_
int sd_path_home(uint64_t type
, const char *suffix
, char **path
) {
330 char *buffer
= NULL
, *cc
;
334 assert_return(path
, -EINVAL
);
337 SD_PATH_SEARCH_BINARIES
,
338 SD_PATH_SEARCH_BINARIES_DEFAULT
,
339 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
340 SD_PATH_SEARCH_LIBRARY_ARCH
,
341 SD_PATH_SEARCH_SHARED
,
342 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
343 SD_PATH_SEARCH_STATE_FACTORY
,
344 SD_PATH_SEARCH_CONFIGURATION
)) {
346 _cleanup_strv_free_
char **l
= NULL
;
348 r
= sd_path_search(type
, suffix
, &l
);
352 buffer
= strv_join(l
, ":");
360 r
= get_path(type
, &buffer
, &ret
);
366 buffer
= strdup(ret
);
375 suffix
+= strspn(suffix
, "/");
377 if (endswith(ret
, "/"))
378 cc
= strappend(ret
, suffix
);
380 cc
= strjoin(ret
, "/", suffix
);
391 static int search_from_environment(
393 const char *env_home
,
394 const char *home_suffix
,
395 const char *env_search
,
396 bool env_search_sufficient
,
397 const char *first
, ...) {
407 e
= secure_getenv(env_search
);
409 l
= strv_split(e
, ":");
413 if (env_search_sufficient
) {
424 l
= strv_new_ap(first
, ap
);
432 e
= secure_getenv(env_home
);
433 if (e
&& path_is_absolute(e
)) {
442 if (!h
&& home_suffix
) {
443 e
= secure_getenv("HOME");
444 if (e
&& path_is_absolute(e
)) {
445 if (endswith(e
, "/"))
446 h
= strappend(e
, home_suffix
);
448 h
= strjoin(e
, "/", home_suffix
);
458 r
= strv_consume_prepend(&l
, h
);
470 # define ARRAY_SBIN_BIN(x) x "sbin", x "bin"
472 # define ARRAY_SBIN_BIN(x) x "bin"
475 static int get_search(uint64_t type
, char ***list
) {
481 case SD_PATH_SEARCH_BINARIES
:
482 return search_from_environment(list
,
487 ARRAY_SBIN_BIN("/usr/local/"),
488 ARRAY_SBIN_BIN("/usr/"),
494 case SD_PATH_SEARCH_LIBRARY_PRIVATE
:
495 return search_from_environment(list
,
507 case SD_PATH_SEARCH_LIBRARY_ARCH
:
508 return search_from_environment(list
,
510 ".local/lib/" LIB_ARCH_TUPLE
,
519 case SD_PATH_SEARCH_SHARED
:
520 return search_from_environment(list
,
529 case SD_PATH_SEARCH_CONFIGURATION_FACTORY
:
530 return search_from_environment(list
,
535 "/usr/local/share/factory/etc",
536 "/usr/share/factory/etc",
539 case SD_PATH_SEARCH_STATE_FACTORY
:
540 return search_from_environment(list
,
545 "/usr/local/share/factory/var",
546 "/usr/share/factory/var",
549 case SD_PATH_SEARCH_CONFIGURATION
:
550 return search_from_environment(list
,
558 case SD_PATH_SEARCH_BINARIES_DEFAULT
: {
561 t
= strv_split_nulstr(DEFAULT_PATH_NULSTR
);
572 _public_
int sd_path_search(uint64_t type
, const char *suffix
, char ***paths
) {
574 _cleanup_strv_free_
char **l
= NULL
, **n
= NULL
;
577 assert_return(paths
, -EINVAL
);
580 SD_PATH_SEARCH_BINARIES
,
581 SD_PATH_SEARCH_BINARIES_DEFAULT
,
582 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
583 SD_PATH_SEARCH_LIBRARY_ARCH
,
584 SD_PATH_SEARCH_SHARED
,
585 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
586 SD_PATH_SEARCH_STATE_FACTORY
,
587 SD_PATH_SEARCH_CONFIGURATION
)) {
591 r
= sd_path_home(type
, suffix
, &p
);
604 *paths
= TAKE_PTR(l
);
608 r
= get_search(type
, &l
);
613 *paths
= TAKE_PTR(l
);
617 n
= new(char*, strv_length(l
)+1);
624 if (endswith(*i
, "/"))
625 *j
= strappend(*i
, suffix
);
627 *j
= strjoin(*i
, "/", suffix
);
636 *paths
= TAKE_PTR(n
);