1 /* SPDX-License-Identifier: LGPL-2.1+ */
7 #include "alloc-util.h"
8 #include "architecture.h"
13 #include "path-util.h"
14 #include "string-util.h"
16 #include "user-util.h"
19 static int from_environment(const char *envname
, const char *fallback
, const char **ret
) {
25 e
= secure_getenv(envname
);
26 if (e
&& path_is_absolute(e
)) {
40 static int from_home_dir(const char *envname
, const char *suffix
, char **buffer
, const char **ret
) {
41 _cleanup_free_
char *h
= NULL
;
52 e
= secure_getenv(envname
);
53 if (e
&& path_is_absolute(e
)) {
64 cc
= strappend(h
, suffix
);
66 cc
= strjoin(h
, "/", suffix
);
75 static int from_user_dir(const char *field
, char **buffer
, const char **ret
) {
76 _cleanup_fclose_
FILE *f
= NULL
;
77 _cleanup_free_
char *b
= NULL
;
78 _cleanup_free_
const char *fn
= NULL
;
88 r
= from_home_dir("XDG_CONFIG_HOME", ".config", &b
, &c
);
92 fn
= strappend(c
, "/user-dirs.dirs");
104 /* This is an awful parse, but it follows closely what
105 * xdg-user-dirs does upstream */
108 FOREACH_LINE(line
, f
, return -errno
) {
113 if (!strneq(l
, field
, n
))
117 p
+= strspn(p
, WHITESPACE
);
123 p
+= strspn(p
, WHITESPACE
);
134 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
135 if (startswith(p
, "$HOME/")) {
136 _cleanup_free_
char *h
= NULL
;
139 r
= get_home_dir(&h
);
143 cc
= strappend(h
, p
+5);
150 } else if (streq(p
, "$HOME")) {
152 r
= get_home_dir(buffer
);
158 } else if (path_is_absolute(p
)) {
172 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
173 if (streq(field
, "XDG_DESKTOP_DIR")) {
174 _cleanup_free_
char *h
= NULL
;
177 r
= get_home_dir(&h
);
181 cc
= strappend(h
, "/Desktop");
189 r
= get_home_dir(buffer
);
199 static int get_path(uint64_t type
, char **buffer
, const char **ret
) {
207 case SD_PATH_TEMPORARY
:
210 case SD_PATH_TEMPORARY_LARGE
:
211 return var_tmp_dir(ret
);
213 case SD_PATH_SYSTEM_BINARIES
:
217 case SD_PATH_SYSTEM_INCLUDE
:
218 *ret
= "/usr/include";
221 case SD_PATH_SYSTEM_LIBRARY_PRIVATE
:
225 case SD_PATH_SYSTEM_LIBRARY_ARCH
:
229 case SD_PATH_SYSTEM_SHARED
:
233 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY
:
234 *ret
= "/usr/share/factory/etc";
237 case SD_PATH_SYSTEM_STATE_FACTORY
:
238 *ret
= "/usr/share/factory/var";
241 case SD_PATH_SYSTEM_CONFIGURATION
:
245 case SD_PATH_SYSTEM_RUNTIME
:
249 case SD_PATH_SYSTEM_RUNTIME_LOGS
:
253 case SD_PATH_SYSTEM_STATE_PRIVATE
:
257 case SD_PATH_SYSTEM_STATE_LOGS
:
261 case SD_PATH_SYSTEM_STATE_CACHE
:
265 case SD_PATH_SYSTEM_STATE_SPOOL
:
269 case SD_PATH_USER_BINARIES
:
270 return from_home_dir(NULL
, ".local/bin", buffer
, ret
);
272 case SD_PATH_USER_LIBRARY_PRIVATE
:
273 return from_home_dir(NULL
, ".local/lib", buffer
, ret
);
275 case SD_PATH_USER_LIBRARY_ARCH
:
276 return from_home_dir(NULL
, ".local/lib/" LIB_ARCH_TUPLE
, buffer
, ret
);
278 case SD_PATH_USER_SHARED
:
279 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer
, ret
);
281 case SD_PATH_USER_CONFIGURATION
:
282 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer
, ret
);
284 case SD_PATH_USER_RUNTIME
:
285 return from_environment("XDG_RUNTIME_DIR", NULL
, ret
);
287 case SD_PATH_USER_STATE_CACHE
:
288 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer
, ret
);
291 r
= get_home_dir(buffer
);
298 case SD_PATH_USER_DOCUMENTS
:
299 return from_user_dir("XDG_DOCUMENTS_DIR", buffer
, ret
);
301 case SD_PATH_USER_MUSIC
:
302 return from_user_dir("XDG_MUSIC_DIR", buffer
, ret
);
304 case SD_PATH_USER_PICTURES
:
305 return from_user_dir("XDG_PICTURES_DIR", buffer
, ret
);
307 case SD_PATH_USER_VIDEOS
:
308 return from_user_dir("XDG_VIDEOS_DIR", buffer
, ret
);
310 case SD_PATH_USER_DOWNLOAD
:
311 return from_user_dir("XDG_DOWNLOAD_DIR", buffer
, ret
);
313 case SD_PATH_USER_PUBLIC
:
314 return from_user_dir("XDG_PUBLICSHARE_DIR", buffer
, ret
);
316 case SD_PATH_USER_TEMPLATES
:
317 return from_user_dir("XDG_TEMPLATES_DIR", buffer
, ret
);
319 case SD_PATH_USER_DESKTOP
:
320 return from_user_dir("XDG_DESKTOP_DIR", buffer
, ret
);
326 _public_
int sd_path_home(uint64_t type
, const char *suffix
, char **path
) {
327 char *buffer
= NULL
, *cc
;
331 assert_return(path
, -EINVAL
);
334 SD_PATH_SEARCH_BINARIES
,
335 SD_PATH_SEARCH_BINARIES_DEFAULT
,
336 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
337 SD_PATH_SEARCH_LIBRARY_ARCH
,
338 SD_PATH_SEARCH_SHARED
,
339 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
340 SD_PATH_SEARCH_STATE_FACTORY
,
341 SD_PATH_SEARCH_CONFIGURATION
)) {
343 _cleanup_strv_free_
char **l
= NULL
;
345 r
= sd_path_search(type
, suffix
, &l
);
349 buffer
= strv_join(l
, ":");
357 r
= get_path(type
, &buffer
, &ret
);
363 buffer
= strdup(ret
);
372 suffix
+= strspn(suffix
, "/");
374 if (endswith(ret
, "/"))
375 cc
= strappend(ret
, suffix
);
377 cc
= strjoin(ret
, "/", suffix
);
388 static int search_from_environment(
390 const char *env_home
,
391 const char *home_suffix
,
392 const char *env_search
,
393 bool env_search_sufficient
,
394 const char *first
, ...) {
404 e
= secure_getenv(env_search
);
406 l
= strv_split(e
, ":");
410 if (env_search_sufficient
) {
421 l
= strv_new_ap(first
, ap
);
429 e
= secure_getenv(env_home
);
430 if (e
&& path_is_absolute(e
)) {
439 if (!h
&& home_suffix
) {
440 e
= secure_getenv("HOME");
441 if (e
&& path_is_absolute(e
)) {
442 if (endswith(e
, "/"))
443 h
= strappend(e
, home_suffix
);
445 h
= strjoin(e
, "/", home_suffix
);
455 r
= strv_consume_prepend(&l
, h
);
467 # define ARRAY_SBIN_BIN(x) x "sbin", x "bin"
469 # define ARRAY_SBIN_BIN(x) x "bin"
472 static int get_search(uint64_t type
, char ***list
) {
478 case SD_PATH_SEARCH_BINARIES
:
479 return search_from_environment(list
,
484 ARRAY_SBIN_BIN("/usr/local/"),
485 ARRAY_SBIN_BIN("/usr/"),
491 case SD_PATH_SEARCH_LIBRARY_PRIVATE
:
492 return search_from_environment(list
,
504 case SD_PATH_SEARCH_LIBRARY_ARCH
:
505 return search_from_environment(list
,
507 ".local/lib/" LIB_ARCH_TUPLE
,
516 case SD_PATH_SEARCH_SHARED
:
517 return search_from_environment(list
,
526 case SD_PATH_SEARCH_CONFIGURATION_FACTORY
:
527 return search_from_environment(list
,
532 "/usr/local/share/factory/etc",
533 "/usr/share/factory/etc",
536 case SD_PATH_SEARCH_STATE_FACTORY
:
537 return search_from_environment(list
,
542 "/usr/local/share/factory/var",
543 "/usr/share/factory/var",
546 case SD_PATH_SEARCH_CONFIGURATION
:
547 return search_from_environment(list
,
555 case SD_PATH_SEARCH_BINARIES_DEFAULT
: {
558 t
= strv_split_nulstr(DEFAULT_PATH_NULSTR
);
569 _public_
int sd_path_search(uint64_t type
, const char *suffix
, char ***paths
) {
571 _cleanup_strv_free_
char **l
= NULL
, **n
= NULL
;
574 assert_return(paths
, -EINVAL
);
577 SD_PATH_SEARCH_BINARIES
,
578 SD_PATH_SEARCH_BINARIES_DEFAULT
,
579 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
580 SD_PATH_SEARCH_LIBRARY_ARCH
,
581 SD_PATH_SEARCH_SHARED
,
582 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
583 SD_PATH_SEARCH_STATE_FACTORY
,
584 SD_PATH_SEARCH_CONFIGURATION
)) {
588 r
= sd_path_home(type
, suffix
, &p
);
601 *paths
= TAKE_PTR(l
);
605 r
= get_search(type
, &l
);
610 *paths
= TAKE_PTR(l
);
614 n
= new(char*, strv_length(l
)+1);
621 if (endswith(*i
, "/"))
622 *j
= strappend(*i
, suffix
);
624 *j
= strjoin(*i
, "/", suffix
);
633 *paths
= TAKE_PTR(n
);