1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include "alloc-util.h"
24 #include "architecture.h"
29 #include "path-util.h"
30 #include "string-util.h"
32 #include "user-util.h"
35 static int from_environment(const char *envname
, const char *fallback
, const char **ret
) {
41 e
= secure_getenv(envname
);
42 if (e
&& path_is_absolute(e
)) {
56 static int from_home_dir(const char *envname
, const char *suffix
, char **buffer
, const char **ret
) {
57 _cleanup_free_
char *h
= NULL
;
68 e
= secure_getenv(envname
);
69 if (e
&& path_is_absolute(e
)) {
80 cc
= strappend(h
, suffix
);
82 cc
= strjoin(h
, "/", suffix
);
91 static int from_user_dir(const char *field
, char **buffer
, const char **ret
) {
92 _cleanup_fclose_
FILE *f
= NULL
;
93 _cleanup_free_
char *b
= NULL
;
94 _cleanup_free_
const char *fn
= NULL
;
104 r
= from_home_dir("XDG_CONFIG_HOME", ".config", &b
, &c
);
108 fn
= strappend(c
, "/user-dirs.dirs");
120 /* This is an awful parse, but it follows closely what
121 * xdg-user-dirs does upstream */
124 FOREACH_LINE(line
, f
, return -errno
) {
129 if (!strneq(l
, field
, n
))
133 p
+= strspn(p
, WHITESPACE
);
139 p
+= strspn(p
, WHITESPACE
);
150 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
151 if (startswith(p
, "$HOME/")) {
152 _cleanup_free_
char *h
= NULL
;
155 r
= get_home_dir(&h
);
159 cc
= strappend(h
, p
+5);
166 } else if (streq(p
, "$HOME")) {
168 r
= get_home_dir(buffer
);
174 } else if (path_is_absolute(p
)) {
188 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
189 if (streq(field
, "XDG_DESKTOP_DIR")) {
190 _cleanup_free_
char *h
= NULL
;
193 r
= get_home_dir(&h
);
197 cc
= strappend(h
, "/Desktop");
205 r
= get_home_dir(buffer
);
215 static int get_path(uint64_t type
, char **buffer
, const char **ret
) {
223 case SD_PATH_TEMPORARY
:
226 case SD_PATH_TEMPORARY_LARGE
:
227 return var_tmp_dir(ret
);
229 case SD_PATH_SYSTEM_BINARIES
:
233 case SD_PATH_SYSTEM_INCLUDE
:
234 *ret
= "/usr/include";
237 case SD_PATH_SYSTEM_LIBRARY_PRIVATE
:
241 case SD_PATH_SYSTEM_LIBRARY_ARCH
:
245 case SD_PATH_SYSTEM_SHARED
:
249 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY
:
250 *ret
= "/usr/share/factory/etc";
253 case SD_PATH_SYSTEM_STATE_FACTORY
:
254 *ret
= "/usr/share/factory/var";
257 case SD_PATH_SYSTEM_CONFIGURATION
:
261 case SD_PATH_SYSTEM_RUNTIME
:
265 case SD_PATH_SYSTEM_RUNTIME_LOGS
:
269 case SD_PATH_SYSTEM_STATE_PRIVATE
:
273 case SD_PATH_SYSTEM_STATE_LOGS
:
277 case SD_PATH_SYSTEM_STATE_CACHE
:
281 case SD_PATH_SYSTEM_STATE_SPOOL
:
285 case SD_PATH_USER_BINARIES
:
286 return from_home_dir(NULL
, ".local/bin", buffer
, ret
);
288 case SD_PATH_USER_LIBRARY_PRIVATE
:
289 return from_home_dir(NULL
, ".local/lib", buffer
, ret
);
291 case SD_PATH_USER_LIBRARY_ARCH
:
292 return from_home_dir(NULL
, ".local/lib/" LIB_ARCH_TUPLE
, buffer
, ret
);
294 case SD_PATH_USER_SHARED
:
295 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer
, ret
);
297 case SD_PATH_USER_CONFIGURATION
:
298 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer
, ret
);
300 case SD_PATH_USER_RUNTIME
:
301 return from_environment("XDG_RUNTIME_DIR", NULL
, ret
);
303 case SD_PATH_USER_STATE_CACHE
:
304 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer
, ret
);
307 r
= get_home_dir(buffer
);
314 case SD_PATH_USER_DOCUMENTS
:
315 return from_user_dir("XDG_DOCUMENTS_DIR", buffer
, ret
);
317 case SD_PATH_USER_MUSIC
:
318 return from_user_dir("XDG_MUSIC_DIR", buffer
, ret
);
320 case SD_PATH_USER_PICTURES
:
321 return from_user_dir("XDG_PICTURES_DIR", buffer
, ret
);
323 case SD_PATH_USER_VIDEOS
:
324 return from_user_dir("XDG_VIDEOS_DIR", buffer
, ret
);
326 case SD_PATH_USER_DOWNLOAD
:
327 return from_user_dir("XDG_DOWNLOAD_DIR", buffer
, ret
);
329 case SD_PATH_USER_PUBLIC
:
330 return from_user_dir("XDG_PUBLICSHARE_DIR", buffer
, ret
);
332 case SD_PATH_USER_TEMPLATES
:
333 return from_user_dir("XDG_TEMPLATES_DIR", buffer
, ret
);
335 case SD_PATH_USER_DESKTOP
:
336 return from_user_dir("XDG_DESKTOP_DIR", buffer
, ret
);
342 _public_
int sd_path_home(uint64_t type
, const char *suffix
, char **path
) {
343 char *buffer
= NULL
, *cc
;
347 assert_return(path
, -EINVAL
);
350 SD_PATH_SEARCH_BINARIES
,
351 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
352 SD_PATH_SEARCH_LIBRARY_ARCH
,
353 SD_PATH_SEARCH_SHARED
,
354 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
355 SD_PATH_SEARCH_STATE_FACTORY
,
356 SD_PATH_SEARCH_CONFIGURATION
)) {
358 _cleanup_strv_free_
char **l
= NULL
;
360 r
= sd_path_search(type
, suffix
, &l
);
364 buffer
= strv_join(l
, ":");
372 r
= get_path(type
, &buffer
, &ret
);
378 buffer
= strdup(ret
);
387 suffix
+= strspn(suffix
, "/");
389 if (endswith(ret
, "/"))
390 cc
= strappend(ret
, suffix
);
392 cc
= strjoin(ret
, "/", suffix
);
403 static int search_from_environment(
405 const char *env_home
,
406 const char *home_suffix
,
407 const char *env_search
,
408 bool env_search_sufficient
,
409 const char *first
, ...) {
419 e
= secure_getenv(env_search
);
421 l
= strv_split(e
, ":");
425 if (env_search_sufficient
) {
436 l
= strv_new_ap(first
, ap
);
444 e
= secure_getenv(env_home
);
445 if (e
&& path_is_absolute(e
)) {
454 if (!h
&& home_suffix
) {
455 e
= secure_getenv("HOME");
456 if (e
&& path_is_absolute(e
)) {
457 if (endswith(e
, "/"))
458 h
= strappend(e
, home_suffix
);
460 h
= strjoin(e
, "/", home_suffix
);
470 r
= strv_consume_prepend(&l
, h
);
481 static int get_search(uint64_t type
, char ***list
) {
487 case SD_PATH_SEARCH_BINARIES
:
488 return search_from_environment(list
,
503 case SD_PATH_SEARCH_LIBRARY_PRIVATE
:
504 return search_from_environment(list
,
516 case SD_PATH_SEARCH_LIBRARY_ARCH
:
517 return search_from_environment(list
,
519 ".local/lib/" LIB_ARCH_TUPLE
,
528 case SD_PATH_SEARCH_SHARED
:
529 return search_from_environment(list
,
538 case SD_PATH_SEARCH_CONFIGURATION_FACTORY
:
539 return search_from_environment(list
,
544 "/usr/local/share/factory/etc",
545 "/usr/share/factory/etc",
548 case SD_PATH_SEARCH_STATE_FACTORY
:
549 return search_from_environment(list
,
554 "/usr/local/share/factory/var",
555 "/usr/share/factory/var",
558 case SD_PATH_SEARCH_CONFIGURATION
:
559 return search_from_environment(list
,
571 _public_
int sd_path_search(uint64_t type
, const char *suffix
, char ***paths
) {
572 char **l
, **i
, **j
, **n
;
575 assert_return(paths
, -EINVAL
);
578 SD_PATH_SEARCH_BINARIES
,
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
);
605 r
= get_search(type
, &l
);
614 n
= new(char*, strv_length(l
)+1);
623 if (endswith(*i
, "/"))
624 *j
= strappend(*i
, suffix
);
626 *j
= strjoin(*i
, "/", suffix
);