1 /* SPDX-License-Identifier: LGPL-2.1+ */
5 #include "alloc-util.h"
6 #include "architecture.h"
12 #include "path-util.h"
13 #include "string-util.h"
15 #include "user-util.h"
18 static int from_environment(const char *envname
, const char *fallback
, const char **ret
) {
24 e
= secure_getenv(envname
);
25 if (e
&& path_is_absolute(e
)) {
39 static int from_home_dir(const char *envname
, const char *suffix
, char **buffer
, const char **ret
) {
40 _cleanup_free_
char *h
= NULL
;
51 e
= secure_getenv(envname
);
52 if (e
&& path_is_absolute(e
)) {
63 cc
= strappend(h
, suffix
);
65 cc
= strjoin(h
, "/", suffix
);
74 static int from_user_dir(const char *field
, char **buffer
, const char **ret
) {
75 _cleanup_fclose_
FILE *f
= NULL
;
76 _cleanup_free_
char *b
= NULL
;
77 _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 */
107 _cleanup_free_
char *line
= NULL
;
110 r
= read_line(f
, LONG_LINE_MAX
, &line
);
118 if (!strneq(l
, field
, n
))
122 p
+= strspn(p
, WHITESPACE
);
128 p
+= strspn(p
, WHITESPACE
);
139 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
140 if (startswith(p
, "$HOME/")) {
141 _cleanup_free_
char *h
= NULL
;
144 r
= get_home_dir(&h
);
148 cc
= strappend(h
, p
+5);
155 } else if (streq(p
, "$HOME")) {
157 r
= get_home_dir(buffer
);
163 } else if (path_is_absolute(p
)) {
177 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
178 if (streq(field
, "XDG_DESKTOP_DIR")) {
179 _cleanup_free_
char *h
= NULL
;
182 r
= get_home_dir(&h
);
186 cc
= strappend(h
, "/Desktop");
194 r
= get_home_dir(buffer
);
204 static int get_path(uint64_t type
, char **buffer
, const char **ret
) {
212 case SD_PATH_TEMPORARY
:
215 case SD_PATH_TEMPORARY_LARGE
:
216 return var_tmp_dir(ret
);
218 case SD_PATH_SYSTEM_BINARIES
:
222 case SD_PATH_SYSTEM_INCLUDE
:
223 *ret
= "/usr/include";
226 case SD_PATH_SYSTEM_LIBRARY_PRIVATE
:
230 case SD_PATH_SYSTEM_LIBRARY_ARCH
:
234 case SD_PATH_SYSTEM_SHARED
:
238 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY
:
239 *ret
= "/usr/share/factory/etc";
242 case SD_PATH_SYSTEM_STATE_FACTORY
:
243 *ret
= "/usr/share/factory/var";
246 case SD_PATH_SYSTEM_CONFIGURATION
:
250 case SD_PATH_SYSTEM_RUNTIME
:
254 case SD_PATH_SYSTEM_RUNTIME_LOGS
:
258 case SD_PATH_SYSTEM_STATE_PRIVATE
:
262 case SD_PATH_SYSTEM_STATE_LOGS
:
266 case SD_PATH_SYSTEM_STATE_CACHE
:
270 case SD_PATH_SYSTEM_STATE_SPOOL
:
274 case SD_PATH_USER_BINARIES
:
275 return from_home_dir(NULL
, ".local/bin", buffer
, ret
);
277 case SD_PATH_USER_LIBRARY_PRIVATE
:
278 return from_home_dir(NULL
, ".local/lib", buffer
, ret
);
280 case SD_PATH_USER_LIBRARY_ARCH
:
281 return from_home_dir(NULL
, ".local/lib/" LIB_ARCH_TUPLE
, buffer
, ret
);
283 case SD_PATH_USER_SHARED
:
284 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer
, ret
);
286 case SD_PATH_USER_CONFIGURATION
:
287 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer
, ret
);
289 case SD_PATH_USER_RUNTIME
:
290 return from_environment("XDG_RUNTIME_DIR", NULL
, ret
);
292 case SD_PATH_USER_STATE_CACHE
:
293 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer
, ret
);
296 r
= get_home_dir(buffer
);
303 case SD_PATH_USER_DOCUMENTS
:
304 return from_user_dir("XDG_DOCUMENTS_DIR", buffer
, ret
);
306 case SD_PATH_USER_MUSIC
:
307 return from_user_dir("XDG_MUSIC_DIR", buffer
, ret
);
309 case SD_PATH_USER_PICTURES
:
310 return from_user_dir("XDG_PICTURES_DIR", buffer
, ret
);
312 case SD_PATH_USER_VIDEOS
:
313 return from_user_dir("XDG_VIDEOS_DIR", buffer
, ret
);
315 case SD_PATH_USER_DOWNLOAD
:
316 return from_user_dir("XDG_DOWNLOAD_DIR", buffer
, ret
);
318 case SD_PATH_USER_PUBLIC
:
319 return from_user_dir("XDG_PUBLICSHARE_DIR", buffer
, ret
);
321 case SD_PATH_USER_TEMPLATES
:
322 return from_user_dir("XDG_TEMPLATES_DIR", buffer
, ret
);
324 case SD_PATH_USER_DESKTOP
:
325 return from_user_dir("XDG_DESKTOP_DIR", buffer
, ret
);
331 _public_
int sd_path_home(uint64_t type
, const char *suffix
, char **path
) {
332 char *buffer
= NULL
, *cc
;
336 assert_return(path
, -EINVAL
);
339 SD_PATH_SEARCH_BINARIES
,
340 SD_PATH_SEARCH_BINARIES_DEFAULT
,
341 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
342 SD_PATH_SEARCH_LIBRARY_ARCH
,
343 SD_PATH_SEARCH_SHARED
,
344 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
345 SD_PATH_SEARCH_STATE_FACTORY
,
346 SD_PATH_SEARCH_CONFIGURATION
)) {
348 _cleanup_strv_free_
char **l
= NULL
;
350 r
= sd_path_search(type
, suffix
, &l
);
354 buffer
= strv_join(l
, ":");
362 r
= get_path(type
, &buffer
, &ret
);
368 buffer
= strdup(ret
);
377 suffix
+= strspn(suffix
, "/");
379 if (endswith(ret
, "/"))
380 cc
= strappend(ret
, suffix
);
382 cc
= strjoin(ret
, "/", suffix
);
393 static int search_from_environment(
395 const char *env_home
,
396 const char *home_suffix
,
397 const char *env_search
,
398 bool env_search_sufficient
,
399 const char *first
, ...) {
409 e
= secure_getenv(env_search
);
411 l
= strv_split(e
, ":");
415 if (env_search_sufficient
) {
426 l
= strv_new_ap(first
, ap
);
434 e
= secure_getenv(env_home
);
435 if (e
&& path_is_absolute(e
)) {
444 if (!h
&& home_suffix
) {
445 e
= secure_getenv("HOME");
446 if (e
&& path_is_absolute(e
)) {
447 if (endswith(e
, "/"))
448 h
= strappend(e
, home_suffix
);
450 h
= strjoin(e
, "/", home_suffix
);
460 r
= strv_consume_prepend(&l
, h
);
472 # define ARRAY_SBIN_BIN(x) x "sbin", x "bin"
474 # define ARRAY_SBIN_BIN(x) x "bin"
477 static int get_search(uint64_t type
, char ***list
) {
483 case SD_PATH_SEARCH_BINARIES
:
484 return search_from_environment(list
,
489 ARRAY_SBIN_BIN("/usr/local/"),
490 ARRAY_SBIN_BIN("/usr/"),
496 case SD_PATH_SEARCH_LIBRARY_PRIVATE
:
497 return search_from_environment(list
,
509 case SD_PATH_SEARCH_LIBRARY_ARCH
:
510 return search_from_environment(list
,
512 ".local/lib/" LIB_ARCH_TUPLE
,
521 case SD_PATH_SEARCH_SHARED
:
522 return search_from_environment(list
,
531 case SD_PATH_SEARCH_CONFIGURATION_FACTORY
:
532 return search_from_environment(list
,
537 "/usr/local/share/factory/etc",
538 "/usr/share/factory/etc",
541 case SD_PATH_SEARCH_STATE_FACTORY
:
542 return search_from_environment(list
,
547 "/usr/local/share/factory/var",
548 "/usr/share/factory/var",
551 case SD_PATH_SEARCH_CONFIGURATION
:
552 return search_from_environment(list
,
560 case SD_PATH_SEARCH_BINARIES_DEFAULT
: {
563 t
= strv_split_nulstr(DEFAULT_PATH_NULSTR
);
574 _public_
int sd_path_search(uint64_t type
, const char *suffix
, char ***paths
) {
576 _cleanup_strv_free_
char **l
= NULL
, **n
= NULL
;
579 assert_return(paths
, -EINVAL
);
582 SD_PATH_SEARCH_BINARIES
,
583 SD_PATH_SEARCH_BINARIES_DEFAULT
,
584 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
585 SD_PATH_SEARCH_LIBRARY_ARCH
,
586 SD_PATH_SEARCH_SHARED
,
587 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
588 SD_PATH_SEARCH_STATE_FACTORY
,
589 SD_PATH_SEARCH_CONFIGURATION
)) {
593 r
= sd_path_home(type
, suffix
, &p
);
606 *paths
= TAKE_PTR(l
);
610 r
= get_search(type
, &l
);
615 *paths
= TAKE_PTR(l
);
619 n
= new(char*, strv_length(l
)+1);
626 if (endswith(*i
, "/"))
627 *j
= strappend(*i
, suffix
);
629 *j
= strjoin(*i
, "/", suffix
);
638 *paths
= TAKE_PTR(n
);