2 This file is part of systemd.
4 Copyright 2014 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "alloc-util.h"
23 #include "architecture.h"
27 #include "path-util.h"
28 #include "string-util.h"
30 #include "user-util.h"
33 static int from_environment(const char *envname
, const char *fallback
, const char **ret
) {
39 e
= secure_getenv(envname
);
40 if (e
&& path_is_absolute(e
)) {
54 static int from_home_dir(const char *envname
, const char *suffix
, char **buffer
, const char **ret
) {
55 _cleanup_free_
char *h
= NULL
;
66 e
= secure_getenv(envname
);
67 if (e
&& path_is_absolute(e
)) {
78 cc
= strappend(h
, suffix
);
80 cc
= strjoin(h
, "/", suffix
);
89 static int from_user_dir(const char *field
, char **buffer
, const char **ret
) {
90 _cleanup_fclose_
FILE *f
= NULL
;
91 _cleanup_free_
char *b
= NULL
;
92 _cleanup_free_
const char *fn
= NULL
;
102 r
= from_home_dir("XDG_CONFIG_HOME", ".config", &b
, &c
);
106 fn
= strappend(c
, "/user-dirs.dirs");
118 /* This is an awful parse, but it follows closely what
119 * xdg-user-dirs does upstream */
122 FOREACH_LINE(line
, f
, return -errno
) {
127 if (!strneq(l
, field
, n
))
131 p
+= strspn(p
, WHITESPACE
);
137 p
+= strspn(p
, WHITESPACE
);
148 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
149 if (startswith(p
, "$HOME/")) {
150 _cleanup_free_
char *h
= NULL
;
153 r
= get_home_dir(&h
);
157 cc
= strappend(h
, p
+5);
164 } else if (streq(p
, "$HOME")) {
166 r
= get_home_dir(buffer
);
172 } else if (path_is_absolute(p
)) {
186 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
187 if (streq(field
, "XDG_DESKTOP_DIR")) {
188 _cleanup_free_
char *h
= NULL
;
191 r
= get_home_dir(&h
);
195 cc
= strappend(h
, "/Desktop");
203 r
= get_home_dir(buffer
);
213 static int get_path(uint64_t type
, char **buffer
, const char **ret
) {
221 case SD_PATH_TEMPORARY
:
222 return from_environment("TMPDIR", "/tmp", ret
);
224 case SD_PATH_TEMPORARY_LARGE
:
225 return from_environment("TMPDIR", "/var/tmp", ret
);
227 case SD_PATH_SYSTEM_BINARIES
:
231 case SD_PATH_SYSTEM_INCLUDE
:
232 *ret
= "/usr/include";
235 case SD_PATH_SYSTEM_LIBRARY_PRIVATE
:
239 case SD_PATH_SYSTEM_LIBRARY_ARCH
:
243 case SD_PATH_SYSTEM_SHARED
:
247 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY
:
248 *ret
= "/usr/share/factory/etc";
251 case SD_PATH_SYSTEM_STATE_FACTORY
:
252 *ret
= "/usr/share/factory/var";
255 case SD_PATH_SYSTEM_CONFIGURATION
:
259 case SD_PATH_SYSTEM_RUNTIME
:
263 case SD_PATH_SYSTEM_RUNTIME_LOGS
:
267 case SD_PATH_SYSTEM_STATE_PRIVATE
:
271 case SD_PATH_SYSTEM_STATE_LOGS
:
275 case SD_PATH_SYSTEM_STATE_CACHE
:
279 case SD_PATH_SYSTEM_STATE_SPOOL
:
283 case SD_PATH_USER_BINARIES
:
284 return from_home_dir(NULL
, ".local/bin", buffer
, ret
);
286 case SD_PATH_USER_LIBRARY_PRIVATE
:
287 return from_home_dir(NULL
, ".local/lib", buffer
, ret
);
289 case SD_PATH_USER_LIBRARY_ARCH
:
290 return from_home_dir(NULL
, ".local/lib/" LIB_ARCH_TUPLE
, buffer
, ret
);
292 case SD_PATH_USER_SHARED
:
293 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer
, ret
);
295 case SD_PATH_USER_CONFIGURATION
:
296 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer
, ret
);
298 case SD_PATH_USER_RUNTIME
:
299 return from_environment("XDG_RUNTIME_DIR", NULL
, ret
);
301 case SD_PATH_USER_STATE_CACHE
:
302 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer
, ret
);
305 r
= get_home_dir(buffer
);
312 case SD_PATH_USER_DOCUMENTS
:
313 return from_user_dir("XDG_DOCUMENTS_DIR", buffer
, ret
);
315 case SD_PATH_USER_MUSIC
:
316 return from_user_dir("XDG_MUSIC_DIR", buffer
, ret
);
318 case SD_PATH_USER_PICTURES
:
319 return from_user_dir("XDG_PICTURES_DIR", buffer
, ret
);
321 case SD_PATH_USER_VIDEOS
:
322 return from_user_dir("XDG_VIDEOS_DIR", buffer
, ret
);
324 case SD_PATH_USER_DOWNLOAD
:
325 return from_user_dir("XDG_DOWNLOAD_DIR", buffer
, ret
);
327 case SD_PATH_USER_PUBLIC
:
328 return from_user_dir("XDG_PUBLICSHARE_DIR", buffer
, ret
);
330 case SD_PATH_USER_TEMPLATES
:
331 return from_user_dir("XDG_TEMPLATES_DIR", buffer
, ret
);
333 case SD_PATH_USER_DESKTOP
:
334 return from_user_dir("XDG_DESKTOP_DIR", buffer
, ret
);
340 _public_
int sd_path_home(uint64_t type
, const char *suffix
, char **path
) {
341 char *buffer
= NULL
, *cc
;
345 assert_return(path
, -EINVAL
);
348 SD_PATH_SEARCH_BINARIES
,
349 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
350 SD_PATH_SEARCH_LIBRARY_ARCH
,
351 SD_PATH_SEARCH_SHARED
,
352 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
353 SD_PATH_SEARCH_STATE_FACTORY
,
354 SD_PATH_SEARCH_CONFIGURATION
)) {
356 _cleanup_strv_free_
char **l
= NULL
;
358 r
= sd_path_search(type
, suffix
, &l
);
362 buffer
= strv_join(l
, ":");
370 r
= get_path(type
, &buffer
, &ret
);
376 buffer
= strdup(ret
);
385 suffix
+= strspn(suffix
, "/");
387 if (endswith(ret
, "/"))
388 cc
= strappend(ret
, suffix
);
390 cc
= strjoin(ret
, "/", suffix
);
401 static int search_from_environment(
403 const char *env_home
,
404 const char *home_suffix
,
405 const char *env_search
,
406 bool env_search_sufficient
,
407 const char *first
, ...) {
417 e
= secure_getenv(env_search
);
419 l
= strv_split(e
, ":");
423 if (env_search_sufficient
) {
434 l
= strv_new_ap(first
, ap
);
442 e
= secure_getenv(env_home
);
443 if (e
&& path_is_absolute(e
)) {
452 if (!h
&& home_suffix
) {
453 e
= secure_getenv("HOME");
454 if (e
&& path_is_absolute(e
)) {
455 if (endswith(e
, "/"))
456 h
= strappend(e
, home_suffix
);
458 h
= strjoin(e
, "/", home_suffix
);
468 r
= strv_consume_prepend(&l
, h
);
479 static int get_search(uint64_t type
, char ***list
) {
485 case SD_PATH_SEARCH_BINARIES
:
486 return search_from_environment(list
,
495 #ifdef HAVE_SPLIT_USR
501 case SD_PATH_SEARCH_LIBRARY_PRIVATE
:
502 return search_from_environment(list
,
509 #ifdef HAVE_SPLIT_USR
514 case SD_PATH_SEARCH_LIBRARY_ARCH
:
515 return search_from_environment(list
,
517 ".local/lib/" LIB_ARCH_TUPLE
,
521 #ifdef HAVE_SPLIT_USR
526 case SD_PATH_SEARCH_SHARED
:
527 return search_from_environment(list
,
536 case SD_PATH_SEARCH_CONFIGURATION_FACTORY
:
537 return search_from_environment(list
,
542 "/usr/local/share/factory/etc",
543 "/usr/share/factory/etc",
546 case SD_PATH_SEARCH_STATE_FACTORY
:
547 return search_from_environment(list
,
552 "/usr/local/share/factory/var",
553 "/usr/share/factory/var",
556 case SD_PATH_SEARCH_CONFIGURATION
:
557 return search_from_environment(list
,
569 _public_
int sd_path_search(uint64_t type
, const char *suffix
, char ***paths
) {
570 char **l
, **i
, **j
, **n
;
573 assert_return(paths
, -EINVAL
);
576 SD_PATH_SEARCH_BINARIES
,
577 SD_PATH_SEARCH_LIBRARY_PRIVATE
,
578 SD_PATH_SEARCH_LIBRARY_ARCH
,
579 SD_PATH_SEARCH_SHARED
,
580 SD_PATH_SEARCH_CONFIGURATION_FACTORY
,
581 SD_PATH_SEARCH_STATE_FACTORY
,
582 SD_PATH_SEARCH_CONFIGURATION
)) {
586 r
= sd_path_home(type
, suffix
, &p
);
603 r
= get_search(type
, &l
);
612 n
= new(char*, strv_length(l
)+1);
621 if (endswith(*i
, "/"))
622 *j
= strappend(*i
, suffix
);
624 *j
= strjoin(*i
, "/", suffix
);