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
;
49 e
= secure_getenv(envname
);
50 if (e
&& path_is_absolute(e
)) {
60 if (!path_extend(&h
, suffix
))
68 static int from_user_dir(const char *field
, char **buffer
, const char **ret
) {
69 _cleanup_fclose_
FILE *f
= NULL
;
70 _cleanup_free_
char *b
= NULL
;
71 _cleanup_free_
const char *fn
= NULL
;
80 r
= from_home_dir("XDG_CONFIG_HOME", ".config", &b
, &c
);
84 fn
= path_join(c
, "user-dirs.dirs");
96 /* This is an awful parse, but it follows closely what
97 * xdg-user-dirs does upstream */
101 _cleanup_free_
char *line
= NULL
;
104 r
= read_line(f
, LONG_LINE_MAX
, &line
);
112 if (!strneq(l
, field
, n
))
116 p
+= strspn(p
, WHITESPACE
);
122 p
+= strspn(p
, WHITESPACE
);
133 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
134 if (startswith(p
, "$HOME/")) {
135 _cleanup_free_
char *h
= NULL
;
137 r
= get_home_dir(&h
);
141 if (!path_extend(&h
, p
+5))
147 } else if (streq(p
, "$HOME")) {
149 r
= get_home_dir(buffer
);
155 } else if (path_is_absolute(p
)) {
169 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
170 if (streq(field
, "XDG_DESKTOP_DIR")) {
171 _cleanup_free_
char *h
= NULL
;
173 r
= get_home_dir(&h
);
177 if (!path_extend(&h
, "Desktop"))
183 r
= get_home_dir(buffer
);
193 static int get_path(uint64_t type
, char **buffer
, const char **ret
) {
201 case SD_PATH_TEMPORARY
:
204 case SD_PATH_TEMPORARY_LARGE
:
205 return var_tmp_dir(ret
);
207 case SD_PATH_SYSTEM_BINARIES
:
211 case SD_PATH_SYSTEM_INCLUDE
:
212 *ret
= "/usr/include";
215 case SD_PATH_SYSTEM_LIBRARY_PRIVATE
:
219 case SD_PATH_SYSTEM_LIBRARY_ARCH
:
223 case SD_PATH_SYSTEM_SHARED
:
227 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY
:
228 *ret
= "/usr/share/factory/etc";
231 case SD_PATH_SYSTEM_STATE_FACTORY
:
232 *ret
= "/usr/share/factory/var";
235 case SD_PATH_SYSTEM_CONFIGURATION
:
239 case SD_PATH_SYSTEM_RUNTIME
:
243 case SD_PATH_SYSTEM_RUNTIME_LOGS
:
247 case SD_PATH_SYSTEM_STATE_PRIVATE
:
251 case SD_PATH_SYSTEM_STATE_LOGS
:
255 case SD_PATH_SYSTEM_STATE_CACHE
:
259 case SD_PATH_SYSTEM_STATE_SPOOL
:
263 case SD_PATH_USER_BINARIES
:
264 return from_home_dir(NULL
, ".local/bin", buffer
, ret
);
266 case SD_PATH_USER_LIBRARY_PRIVATE
:
267 return from_home_dir(NULL
, ".local/lib", buffer
, ret
);
269 case SD_PATH_USER_LIBRARY_ARCH
:
270 return from_home_dir(NULL
, ".local/lib/" LIB_ARCH_TUPLE
, buffer
, ret
);
272 case SD_PATH_USER_SHARED
:
273 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer
, ret
);
275 case SD_PATH_USER_CONFIGURATION
:
276 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer
, ret
);
278 case SD_PATH_USER_RUNTIME
:
279 return from_environment("XDG_RUNTIME_DIR", NULL
, ret
);
281 case SD_PATH_USER_STATE_CACHE
:
282 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer
, ret
);
285 r
= get_home_dir(buffer
);
292 case SD_PATH_USER_DOCUMENTS
:
293 return from_user_dir("XDG_DOCUMENTS_DIR", buffer
, ret
);
295 case SD_PATH_USER_MUSIC
:
296 return from_user_dir("XDG_MUSIC_DIR", buffer
, ret
);
298 case SD_PATH_USER_PICTURES
:
299 return from_user_dir("XDG_PICTURES_DIR", buffer
, ret
);
301 case SD_PATH_USER_VIDEOS
:
302 return from_user_dir("XDG_VIDEOS_DIR", buffer
, ret
);
304 case SD_PATH_USER_DOWNLOAD
:
305 return from_user_dir("XDG_DOWNLOAD_DIR", buffer
, ret
);
307 case SD_PATH_USER_PUBLIC
:
308 return from_user_dir("XDG_PUBLICSHARE_DIR", buffer
, ret
);
310 case SD_PATH_USER_TEMPLATES
:
311 return from_user_dir("XDG_TEMPLATES_DIR", buffer
, ret
);
313 case SD_PATH_USER_DESKTOP
:
314 return from_user_dir("XDG_DESKTOP_DIR", buffer
, ret
);
316 case SD_PATH_SYSTEMD_UTIL
:
317 *ret
= ROOTPREFIX_NOSLASH
"/lib/systemd";
320 case SD_PATH_SYSTEMD_SYSTEM_UNIT
:
321 *ret
= SYSTEM_DATA_UNIT_DIR
;
324 case SD_PATH_SYSTEMD_SYSTEM_PRESET
:
325 *ret
= ROOTPREFIX_NOSLASH
"/lib/systemd/system-preset";
328 case SD_PATH_SYSTEMD_USER_UNIT
:
329 *ret
= USER_DATA_UNIT_DIR
;
332 case SD_PATH_SYSTEMD_USER_PRESET
:
333 *ret
= ROOTPREFIX_NOSLASH
"/lib/systemd/user-preset";
336 case SD_PATH_SYSTEMD_SYSTEM_CONF
:
337 *ret
= SYSTEM_CONFIG_UNIT_DIR
;
340 case SD_PATH_SYSTEMD_USER_CONF
:
341 *ret
= USER_CONFIG_UNIT_DIR
;
344 case SD_PATH_SYSTEMD_SYSTEM_GENERATOR
:
345 *ret
= SYSTEM_GENERATOR_DIR
;
348 case SD_PATH_SYSTEMD_USER_GENERATOR
:
349 *ret
= USER_GENERATOR_DIR
;
352 case SD_PATH_SYSTEMD_SLEEP
:
353 *ret
= ROOTPREFIX_NOSLASH
"/lib/systemd/system-sleep";
356 case SD_PATH_SYSTEMD_SHUTDOWN
:
357 *ret
= ROOTPREFIX_NOSLASH
"/lib/systemd/system-shutdown";
360 case SD_PATH_TMPFILES
:
361 *ret
= "/usr/lib/tmpfiles.d";
364 case SD_PATH_SYSUSERS
:
365 *ret
= ROOTPREFIX_NOSLASH
"/lib/sysusers.d";
369 *ret
= ROOTPREFIX_NOSLASH
"/lib/sysctl.d";
373 *ret
= ROOTPREFIX_NOSLASH
"/lib/binfmt.d";
376 case SD_PATH_MODULES_LOAD
:
377 *ret
= ROOTPREFIX_NOSLASH
"/lib/modules-load.d";
380 case SD_PATH_CATALOG
:
381 *ret
= "/usr/lib/systemd/catalog";
388 static int get_path_alloc(uint64_t type
, const char *suffix
, char **path
) {
389 _cleanup_free_
char *buffer
= NULL
;
390 char *buffer2
= NULL
;
396 r
= get_path(type
, &buffer
, &ret
);
401 suffix
+= strspn(suffix
, "/");
402 buffer2
= path_join(ret
, suffix
);
405 } else if (!buffer
) {
406 buffer
= strdup(ret
);
411 *path
= buffer2
?: TAKE_PTR(buffer
);
415 _public_
int sd_path_lookup(uint64_t type
, const char *suffix
, char **path
) {
418 assert_return(path
, -EINVAL
);
420 r
= get_path_alloc(type
, suffix
, path
);
421 if (r
!= -EOPNOTSUPP
)
424 /* Fall back to sd_path_lookup_strv */
425 _cleanup_strv_free_
char **l
= NULL
;
428 r
= sd_path_lookup_strv(type
, suffix
, &l
);
432 buffer
= strv_join(l
, ":");
440 static int search_from_environment(
442 const char *env_home
,
443 const char *home_suffix
,
444 const char *env_search
,
445 bool env_search_sufficient
,
446 const char *first
, ...) {
448 _cleanup_strv_free_
char **l
= NULL
;
456 e
= secure_getenv(env_search
);
458 l
= strv_split(e
, ":");
462 if (env_search_sufficient
) {
473 l
= strv_new_ap(first
, ap
);
481 e
= secure_getenv(env_home
);
482 if (e
&& path_is_absolute(e
)) {
489 if (!h
&& home_suffix
) {
490 e
= secure_getenv("HOME");
491 if (e
&& path_is_absolute(e
)) {
492 h
= path_join(e
, home_suffix
);
499 r
= strv_consume_prepend(&l
, h
);
509 # define ARRAY_SBIN_BIN(x) x "sbin", x "bin"
511 # define ARRAY_SBIN_BIN(x) x "bin"
514 static int get_search(uint64_t type
, char ***list
) {
521 case SD_PATH_SEARCH_BINARIES
:
522 return search_from_environment(list
,
527 ARRAY_SBIN_BIN("/usr/local/"),
528 ARRAY_SBIN_BIN("/usr/"),
534 case SD_PATH_SEARCH_LIBRARY_PRIVATE
:
535 return search_from_environment(list
,
547 case SD_PATH_SEARCH_LIBRARY_ARCH
:
548 return search_from_environment(list
,
550 ".local/lib/" LIB_ARCH_TUPLE
,
559 case SD_PATH_SEARCH_SHARED
:
560 return search_from_environment(list
,
569 case SD_PATH_SEARCH_CONFIGURATION_FACTORY
:
570 return search_from_environment(list
,
575 "/usr/local/share/factory/etc",
576 "/usr/share/factory/etc",
579 case SD_PATH_SEARCH_STATE_FACTORY
:
580 return search_from_environment(list
,
585 "/usr/local/share/factory/var",
586 "/usr/share/factory/var",
589 case SD_PATH_SEARCH_CONFIGURATION
:
590 return search_from_environment(list
,
598 case SD_PATH_SEARCH_BINARIES_DEFAULT
:
599 return strv_from_nulstr(list
, DEFAULT_PATH_NULSTR
);
601 case SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT
:
602 case SD_PATH_SYSTEMD_SEARCH_USER_UNIT
: {
603 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
604 const UnitFileScope scope
= type
== SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT
?
605 UNIT_FILE_SYSTEM
: UNIT_FILE_USER
;
607 r
= lookup_paths_init(&lp
, scope
, 0, NULL
);
611 *list
= TAKE_PTR(lp
.search_path
);
615 case SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR
:
616 case SD_PATH_SYSTEMD_SEARCH_USER_GENERATOR
: {
618 const UnitFileScope scope
= type
== SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR
?
619 UNIT_FILE_SYSTEM
: UNIT_FILE_USER
;
621 t
= generator_binary_paths(scope
);
629 case SD_PATH_SYSTEMD_SEARCH_NETWORK
:
630 return strv_from_nulstr(list
, NETWORK_DIRS_NULSTR
);
637 _public_
int sd_path_lookup_strv(uint64_t type
, const char *suffix
, char ***paths
) {
638 _cleanup_strv_free_
char **l
= NULL
, **n
= NULL
;
641 assert_return(paths
, -EINVAL
);
643 r
= get_search(type
, &l
);
644 if (r
== -EOPNOTSUPP
) {
645 _cleanup_free_
char *t
= NULL
;
647 r
= get_path_alloc(type
, suffix
, &t
);
657 *paths
= TAKE_PTR(l
);
664 *paths
= TAKE_PTR(l
);
668 n
= new(char*, strv_length(l
)+1);
674 *j
= path_join(*i
, suffix
);
682 *paths
= TAKE_PTR(n
);