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/>.
21 #include "architecture.h"
22 #include "path-util.h"
27 static int from_environment(const char *envname, const char *fallback, const char **ret) {
33 e = secure_getenv(envname);
34 if (e && path_is_absolute(e)) {
48 static int from_home_dir(const char *envname, const char *suffix, char **buffer, const char **ret) {
49 _cleanup_free_ char *h = NULL;
60 e = secure_getenv(envname);
61 if (e && path_is_absolute(e)) {
72 cc = strappend(h, suffix);
74 cc = strjoin(h, "/", suffix, NULL);
83 static int from_user_dir(const char *field, char **buffer, const char **ret) {
84 _cleanup_fclose_ FILE *f = NULL;
85 _cleanup_free_ char *b = NULL;
86 const char *fn = NULL;
95 r = from_home_dir(NULL, ".config/user-dirs.dirs", &b, &fn);
107 /* This is an awful parse, but it follows closely what
108 * xdg-user-dirs does upstream */
111 FOREACH_LINE(line, f, return -errno) {
116 if (!strneq(l, field, n))
120 p += strspn(p, WHITESPACE);
126 p += strspn(p, WHITESPACE);
137 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
138 if (startswith(p, "$HOME/")) {
139 _cleanup_free_ char *h = NULL;
142 r = get_home_dir(&h);
146 cc = strappend(h, p+5);
153 } else if (streq(p, "$HOME")) {
155 r = get_home_dir(buffer);
161 } else if (path_is_absolute(p)) {
175 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
176 if (streq(field, "XDG_DESKTOP_DIR")) {
177 _cleanup_free_ char *h = NULL;
180 r = get_home_dir(&h);
184 cc = strappend(h, "/Desktop");
192 r = get_home_dir(buffer);
202 static int get_path(uint64_t type, char **buffer, const char **ret) {
210 case SD_PATH_TEMPORARY:
211 return from_environment("TMPDIR", "/tmp", ret);
213 case SD_PATH_TEMPORARY_LARGE:
214 return from_environment("TMPDIR", "/var/tmp", ret);
216 case SD_PATH_SYSTEM_BINARIES:
220 case SD_PATH_SYSTEM_INCLUDE:
221 *ret = "/usr/include";
224 case SD_PATH_SYSTEM_LIBRARY_PRIVATE:
228 case SD_PATH_SYSTEM_LIBRARY_ARCH:
232 case SD_PATH_SYSTEM_SHARED:
236 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY:
237 *ret = "/usr/share/factory/etc";
240 case SD_PATH_SYSTEM_STATE_FACTORY:
241 *ret = "/usr/share/factory/var";
244 case SD_PATH_SYSTEM_CONFIGURATION:
248 case SD_PATH_SYSTEM_RUNTIME:
252 case SD_PATH_SYSTEM_RUNTIME_LOGS:
256 case SD_PATH_SYSTEM_STATE_PRIVATE:
260 case SD_PATH_SYSTEM_STATE_LOGS:
264 case SD_PATH_SYSTEM_STATE_CACHE:
268 case SD_PATH_SYSTEM_STATE_SPOOL:
272 case SD_PATH_USER_BINARIES:
273 return from_home_dir(NULL, ".local/bin", buffer, ret);
275 case SD_PATH_USER_LIBRARY_PRIVATE:
276 return from_home_dir(NULL, ".local/lib", buffer, ret);
278 case SD_PATH_USER_LIBRARY_ARCH:
279 return from_home_dir(NULL, ".local/lib/" LIB_ARCH_TUPLE, buffer, ret);
281 case SD_PATH_USER_SHARED:
282 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer, ret);
284 case SD_PATH_USER_CONFIGURATION:
285 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer, ret);
287 case SD_PATH_USER_RUNTIME:
288 return from_environment("XDG_RUNTIME_DIR", NULL, ret);
290 case SD_PATH_USER_STATE_CACHE:
291 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer, ret);
294 r = get_home_dir(buffer);
301 case SD_PATH_USER_DOCUMENTS:
302 return from_user_dir("XDG_DOCUMENTS_DIR", buffer, ret);
304 case SD_PATH_USER_MUSIC:
305 return from_user_dir("XDG_MUSIC_DIR", buffer, ret);
307 case SD_PATH_USER_PICTURES:
308 return from_user_dir("XDG_PICTURES_DIR", buffer, ret);
310 case SD_PATH_USER_VIDEOS:
311 return from_user_dir("XDG_VIDEOS_DIR", buffer, ret);
313 case SD_PATH_USER_DOWNLOAD:
314 return from_user_dir("XDG_DOWNLOAD_DIR", buffer, ret);
316 case SD_PATH_USER_PUBLIC:
317 return from_user_dir("XDG_PUBLICSHARE_DIR", buffer, ret);
319 case SD_PATH_USER_TEMPLATES:
320 return from_user_dir("XDG_TEMPLATES_DIR", buffer, ret);
322 case SD_PATH_USER_DESKTOP:
323 return from_user_dir("XDG_DESKTOP_DIR", buffer, ret);
329 _public_ int sd_path_home(uint64_t type, const char *suffix, char **path) {
330 char *buffer = NULL, *cc;
334 assert_return(path, -EINVAL);
337 SD_PATH_SEARCH_BINARIES,
338 SD_PATH_SEARCH_LIBRARY_PRIVATE,
339 SD_PATH_SEARCH_LIBRARY_ARCH,
340 SD_PATH_SEARCH_SHARED,
341 SD_PATH_SEARCH_CONFIGURATION_FACTORY,
342 SD_PATH_SEARCH_STATE_FACTORY,
343 SD_PATH_SEARCH_CONFIGURATION)) {
345 _cleanup_strv_free_ char **l = NULL;
347 r = sd_path_search(type, suffix, &l);
351 buffer = strv_join(l, ":");
359 r = get_path(type, &buffer, &ret);
365 buffer = strdup(ret);
374 suffix += strspn(suffix, "/");
376 if (endswith(ret, "/"))
377 cc = strappend(ret, suffix);
379 cc = strjoin(ret, "/", suffix, NULL);
390 static int search_from_environment(
392 const char *env_home,
393 const char *home_suffix,
394 const char *env_search,
395 bool env_search_sufficient,
396 const char *first, ...) {
406 e = secure_getenv(env_search);
408 l = strv_split(e, ":");
412 if (env_search_sufficient) {
423 l = strv_new_ap(first, ap);
431 e = secure_getenv(env_home);
432 if (e && path_is_absolute(e)) {
441 if (!h && home_suffix) {
442 e = secure_getenv("HOME");
443 if (e && path_is_absolute(e)) {
444 if (endswith(e, "/"))
445 h = strappend(e, home_suffix);
447 h = strjoin(e, "/", home_suffix, NULL);
457 r = strv_consume_prepend(&l, h);
468 static int get_search(uint64_t type, char ***list) {
474 case SD_PATH_SEARCH_BINARIES:
475 return search_from_environment(list,
484 #ifdef HAVE_SPLIT_USR
490 case SD_PATH_SEARCH_LIBRARY_PRIVATE:
491 return search_from_environment(list,
498 #ifdef HAVE_SPLIT_USR
503 case SD_PATH_SEARCH_LIBRARY_ARCH:
504 return search_from_environment(list,
506 ".local/lib/" LIB_ARCH_TUPLE,
510 #ifdef HAVE_SPLIT_USR
515 case SD_PATH_SEARCH_SHARED:
516 return search_from_environment(list,
525 case SD_PATH_SEARCH_CONFIGURATION_FACTORY:
526 return search_from_environment(list,
531 "/usr/local/share/factory/etc",
532 "/usr/share/factory/etc",
535 case SD_PATH_SEARCH_STATE_FACTORY:
536 return search_from_environment(list,
541 "/usr/local/share/factory/var",
542 "/usr/share/factory/var",
545 case SD_PATH_SEARCH_CONFIGURATION:
546 return search_from_environment(list,
558 _public_ int sd_path_search(uint64_t type, const char *suffix, char ***paths) {
559 char **l, **i, **j, **n;
562 assert_return(paths, -EINVAL);
565 SD_PATH_SEARCH_BINARIES,
566 SD_PATH_SEARCH_LIBRARY_PRIVATE,
567 SD_PATH_SEARCH_LIBRARY_ARCH,
568 SD_PATH_SEARCH_SHARED,
569 SD_PATH_SEARCH_CONFIGURATION_FACTORY,
570 SD_PATH_SEARCH_STATE_FACTORY,
571 SD_PATH_SEARCH_CONFIGURATION)) {
575 r = sd_path_home(type, suffix, &p);
592 r = get_search(type, &l);
601 n = new(char*, strv_length(l)+1);
610 if (endswith(*i, "/"))
611 *j = strappend(*i, suffix);
613 *j = strjoin(*i, "/", suffix, NULL);