]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-path/sd-path.c
build-sys: use #if Y instead of #ifdef Y everywhere
[thirdparty/systemd.git] / src / libsystemd / sd-path / sd-path.c
CommitLineData
9a00f57a
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2014 Lennart Poettering
5
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.
10
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.
15
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/>.
18***/
19
07630cea
LP
20#include "sd-path.h"
21
b5efdb8a 22#include "alloc-util.h"
9a00f57a 23#include "architecture.h"
3ffd4af2 24#include "fd-util.h"
0d39fa9c 25#include "fileio.h"
fccb4486 26#include "fs-util.h"
07630cea 27#include "missing.h"
9a00f57a 28#include "path-util.h"
07630cea 29#include "string-util.h"
9a00f57a 30#include "strv.h"
b1d4f8e1 31#include "user-util.h"
07630cea 32#include "util.h"
9a00f57a
LP
33
34static int from_environment(const char *envname, const char *fallback, const char **ret) {
35 assert(ret);
36
37 if (envname) {
38 const char *e;
39
40 e = secure_getenv(envname);
41 if (e && path_is_absolute(e)) {
42 *ret = e;
43 return 0;
44 }
45 }
46
47 if (fallback) {
48 *ret = fallback;
49 return 0;
50 }
51
52 return -ENXIO;
53}
54
55static int from_home_dir(const char *envname, const char *suffix, char **buffer, const char **ret) {
56 _cleanup_free_ char *h = NULL;
57 char *cc = NULL;
58 int r;
59
60 assert(suffix);
61 assert(buffer);
62 assert(ret);
63
64 if (envname) {
65 const char *e = NULL;
66
67 e = secure_getenv(envname);
68 if (e && path_is_absolute(e)) {
69 *ret = e;
70 return 0;
71 }
72 }
73
74 r = get_home_dir(&h);
75 if (r < 0)
76 return r;
77
78 if (endswith(h, "/"))
79 cc = strappend(h, suffix);
80 else
605405c6 81 cc = strjoin(h, "/", suffix);
9a00f57a
LP
82 if (!cc)
83 return -ENOMEM;
84
85 *buffer = cc;
86 *ret = cc;
87 return 0;
88}
89
90static int from_user_dir(const char *field, char **buffer, const char **ret) {
91 _cleanup_fclose_ FILE *f = NULL;
92 _cleanup_free_ char *b = NULL;
b6b0cfaa
EGP
93 _cleanup_free_ const char *fn = NULL;
94 const char *c = NULL;
9a00f57a
LP
95 char line[LINE_MAX];
96 size_t n;
97 int r;
98
99 assert(field);
100 assert(buffer);
101 assert(ret);
102
b6b0cfaa 103 r = from_home_dir("XDG_CONFIG_HOME", ".config", &b, &c);
9a00f57a
LP
104 if (r < 0)
105 return r;
106
b6b0cfaa
EGP
107 fn = strappend(c, "/user-dirs.dirs");
108 if (!fn)
109 return -ENOMEM;
110
9a00f57a
LP
111 f = fopen(fn, "re");
112 if (!f) {
113 if (errno == ENOENT)
114 goto fallback;
115
116 return -errno;
117 }
118
119 /* This is an awful parse, but it follows closely what
120 * xdg-user-dirs does upstream */
121
122 n = strlen(field);
123 FOREACH_LINE(line, f, return -errno) {
124 char *l, *p, *e;
125
126 l = strstrip(line);
127
128 if (!strneq(l, field, n))
129 continue;
130
131 p = l + n;
132 p += strspn(p, WHITESPACE);
133
134 if (*p != '=')
135 continue;
136 p++;
137
138 p += strspn(p, WHITESPACE);
139
140 if (*p != '"')
141 continue;
142 p++;
143
144 e = strrchr(p, '"');
145 if (!e)
146 continue;
147 *e = 0;
148
149 /* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
150 if (startswith(p, "$HOME/")) {
151 _cleanup_free_ char *h = NULL;
152 char *cc;
153
154 r = get_home_dir(&h);
155 if (r < 0)
156 return r;
157
158 cc = strappend(h, p+5);
159 if (!cc)
160 return -ENOMEM;
161
162 *buffer = cc;
163 *ret = cc;
164 return 0;
165 } else if (streq(p, "$HOME")) {
166
167 r = get_home_dir(buffer);
168 if (r < 0)
169 return r;
170
171 *ret = *buffer;
172 return 0;
173 } else if (path_is_absolute(p)) {
174 char *copy;
175
176 copy = strdup(p);
177 if (!copy)
178 return -ENOMEM;
179
180 *buffer = copy;
181 *ret = copy;
182 return 0;
183 }
184 }
185
186fallback:
187 /* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
188 if (streq(field, "XDG_DESKTOP_DIR")) {
189 _cleanup_free_ char *h = NULL;
190 char *cc;
191
192 r = get_home_dir(&h);
193 if (r < 0)
194 return r;
195
196 cc = strappend(h, "/Desktop");
197 if (!cc)
198 return -ENOMEM;
199
200 *buffer = cc;
201 *ret = cc;
202 } else {
203
204 r = get_home_dir(buffer);
205 if (r < 0)
206 return r;
207
208 *ret = *buffer;
209 }
210
211 return 0;
212}
213
214static int get_path(uint64_t type, char **buffer, const char **ret) {
215 int r;
216
217 assert(buffer);
218 assert(ret);
219
220 switch (type) {
221
222 case SD_PATH_TEMPORARY:
fccb4486 223 return tmp_dir(ret);
9a00f57a
LP
224
225 case SD_PATH_TEMPORARY_LARGE:
fccb4486 226 return var_tmp_dir(ret);
9a00f57a
LP
227
228 case SD_PATH_SYSTEM_BINARIES:
229 *ret = "/usr/bin";
230 return 0;
231
232 case SD_PATH_SYSTEM_INCLUDE:
233 *ret = "/usr/include";
234 return 0;
235
236 case SD_PATH_SYSTEM_LIBRARY_PRIVATE:
237 *ret = "/usr/lib";
238 return 0;
239
240 case SD_PATH_SYSTEM_LIBRARY_ARCH:
241 *ret = LIBDIR;
242 return 0;
243
244 case SD_PATH_SYSTEM_SHARED:
245 *ret = "/usr/share";
246 return 0;
247
248 case SD_PATH_SYSTEM_CONFIGURATION_FACTORY:
249 *ret = "/usr/share/factory/etc";
250 return 0;
251
252 case SD_PATH_SYSTEM_STATE_FACTORY:
253 *ret = "/usr/share/factory/var";
254 return 0;
255
256 case SD_PATH_SYSTEM_CONFIGURATION:
257 *ret = "/etc";
258 return 0;
259
260 case SD_PATH_SYSTEM_RUNTIME:
261 *ret = "/run";
262 return 0;
263
264 case SD_PATH_SYSTEM_RUNTIME_LOGS:
265 *ret = "/run/log";
266 return 0;
267
268 case SD_PATH_SYSTEM_STATE_PRIVATE:
269 *ret = "/var/lib";
270 return 0;
271
272 case SD_PATH_SYSTEM_STATE_LOGS:
273 *ret = "/var/log";
274 return 0;
275
276 case SD_PATH_SYSTEM_STATE_CACHE:
277 *ret = "/var/cache";
278 return 0;
279
280 case SD_PATH_SYSTEM_STATE_SPOOL:
281 *ret = "/var/spool";
282 return 0;
283
284 case SD_PATH_USER_BINARIES:
285 return from_home_dir(NULL, ".local/bin", buffer, ret);
286
287 case SD_PATH_USER_LIBRARY_PRIVATE:
288 return from_home_dir(NULL, ".local/lib", buffer, ret);
289
290 case SD_PATH_USER_LIBRARY_ARCH:
613e3a26 291 return from_home_dir(NULL, ".local/lib/" LIB_ARCH_TUPLE, buffer, ret);
9a00f57a
LP
292
293 case SD_PATH_USER_SHARED:
294 return from_home_dir("XDG_DATA_HOME", ".local/share", buffer, ret);
295
296 case SD_PATH_USER_CONFIGURATION:
297 return from_home_dir("XDG_CONFIG_HOME", ".config", buffer, ret);
298
299 case SD_PATH_USER_RUNTIME:
300 return from_environment("XDG_RUNTIME_DIR", NULL, ret);
301
302 case SD_PATH_USER_STATE_CACHE:
303 return from_home_dir("XDG_CACHE_HOME", ".cache", buffer, ret);
304
305 case SD_PATH_USER:
306 r = get_home_dir(buffer);
307 if (r < 0)
308 return r;
309
310 *ret = *buffer;
311 return 0;
312
313 case SD_PATH_USER_DOCUMENTS:
314 return from_user_dir("XDG_DOCUMENTS_DIR", buffer, ret);
315
316 case SD_PATH_USER_MUSIC:
317 return from_user_dir("XDG_MUSIC_DIR", buffer, ret);
318
319 case SD_PATH_USER_PICTURES:
320 return from_user_dir("XDG_PICTURES_DIR", buffer, ret);
321
322 case SD_PATH_USER_VIDEOS:
323 return from_user_dir("XDG_VIDEOS_DIR", buffer, ret);
324
325 case SD_PATH_USER_DOWNLOAD:
326 return from_user_dir("XDG_DOWNLOAD_DIR", buffer, ret);
327
328 case SD_PATH_USER_PUBLIC:
329 return from_user_dir("XDG_PUBLICSHARE_DIR", buffer, ret);
330
331 case SD_PATH_USER_TEMPLATES:
332 return from_user_dir("XDG_TEMPLATES_DIR", buffer, ret);
333
334 case SD_PATH_USER_DESKTOP:
335 return from_user_dir("XDG_DESKTOP_DIR", buffer, ret);
336 }
337
15411c0c 338 return -EOPNOTSUPP;
9a00f57a
LP
339}
340
2de30868 341_public_ int sd_path_home(uint64_t type, const char *suffix, char **path) {
9a00f57a
LP
342 char *buffer = NULL, *cc;
343 const char *ret;
344 int r;
345
346 assert_return(path, -EINVAL);
347
348 if (IN_SET(type,
349 SD_PATH_SEARCH_BINARIES,
350 SD_PATH_SEARCH_LIBRARY_PRIVATE,
351 SD_PATH_SEARCH_LIBRARY_ARCH,
352 SD_PATH_SEARCH_SHARED,
353 SD_PATH_SEARCH_CONFIGURATION_FACTORY,
354 SD_PATH_SEARCH_STATE_FACTORY,
355 SD_PATH_SEARCH_CONFIGURATION)) {
356
357 _cleanup_strv_free_ char **l = NULL;
358
359 r = sd_path_search(type, suffix, &l);
360 if (r < 0)
361 return r;
362
363 buffer = strv_join(l, ":");
364 if (!buffer)
365 return -ENOMEM;
366
367 *path = buffer;
368 return 0;
369 }
370
371 r = get_path(type, &buffer, &ret);
372 if (r < 0)
373 return r;
374
375 if (!suffix) {
376 if (!buffer) {
377 buffer = strdup(ret);
378 if (!buffer)
379 return -ENOMEM;
380 }
381
382 *path = buffer;
383 return 0;
384 }
385
386 suffix += strspn(suffix, "/");
387
388 if (endswith(ret, "/"))
389 cc = strappend(ret, suffix);
390 else
605405c6 391 cc = strjoin(ret, "/", suffix);
9a00f57a
LP
392
393 free(buffer);
394
395 if (!cc)
396 return -ENOMEM;
397
398 *path = cc;
399 return 0;
400}
401
402static int search_from_environment(
403 char ***list,
404 const char *env_home,
405 const char *home_suffix,
406 const char *env_search,
407 bool env_search_sufficient,
408 const char *first, ...) {
409
410 const char *e;
411 char *h = NULL;
412 char **l = NULL;
413 int r;
414
415 assert(list);
416
417 if (env_search) {
418 e = secure_getenv(env_search);
419 if (e) {
420 l = strv_split(e, ":");
421 if (!l)
422 return -ENOMEM;
423
424 if (env_search_sufficient) {
425 *list = l;
426 return 0;
427 }
428 }
429 }
430
431 if (!l && first) {
432 va_list ap;
433
434 va_start(ap, first);
435 l = strv_new_ap(first, ap);
436 va_end(ap);
437
438 if (!l)
439 return -ENOMEM;
440 }
441
442 if (env_home) {
443 e = secure_getenv(env_home);
444 if (e && path_is_absolute(e)) {
445 h = strdup(e);
446 if (!h) {
447 strv_free(l);
448 return -ENOMEM;
449 }
450 }
451 }
452
453 if (!h && home_suffix) {
454 e = secure_getenv("HOME");
455 if (e && path_is_absolute(e)) {
456 if (endswith(e, "/"))
457 h = strappend(e, home_suffix);
458 else
605405c6 459 h = strjoin(e, "/", home_suffix);
9a00f57a
LP
460
461 if (!h) {
462 strv_free(l);
463 return -ENOMEM;
464 }
465 }
466 }
467
468 if (h) {
469 r = strv_consume_prepend(&l, h);
470 if (r < 0) {
471 strv_free(l);
472 return -ENOMEM;
473 }
474 }
475
476 *list = l;
477 return 0;
478}
479
480static int get_search(uint64_t type, char ***list) {
481
482 assert(list);
483
484 switch(type) {
485
486 case SD_PATH_SEARCH_BINARIES:
487 return search_from_environment(list,
488 NULL,
489 ".local/bin",
490 "PATH",
491 true,
492 "/usr/local/sbin",
493 "/usr/local/bin",
494 "/usr/sbin",
495 "/usr/bin",
349cc4a5 496#if HAVE_SPLIT_USR
9a00f57a
LP
497 "/sbin",
498 "/bin",
499#endif
500 NULL);
501
502 case SD_PATH_SEARCH_LIBRARY_PRIVATE:
503 return search_from_environment(list,
504 NULL,
505 ".local/lib",
506 NULL,
507 false,
508 "/usr/local/lib",
509 "/usr/lib",
349cc4a5 510#if HAVE_SPLIT_USR
9a00f57a
LP
511 "/lib",
512#endif
513 NULL);
514
515 case SD_PATH_SEARCH_LIBRARY_ARCH:
516 return search_from_environment(list,
517 NULL,
613e3a26 518 ".local/lib/" LIB_ARCH_TUPLE,
9a00f57a
LP
519 "LD_LIBRARY_PATH",
520 true,
521 LIBDIR,
349cc4a5 522#if HAVE_SPLIT_USR
9a00f57a
LP
523 ROOTLIBDIR,
524#endif
525 NULL);
526
527 case SD_PATH_SEARCH_SHARED:
528 return search_from_environment(list,
529 "XDG_DATA_HOME",
530 ".local/share",
531 "XDG_DATA_DIRS",
532 false,
533 "/usr/local/share",
534 "/usr/share",
535 NULL);
536
537 case SD_PATH_SEARCH_CONFIGURATION_FACTORY:
538 return search_from_environment(list,
539 NULL,
540 NULL,
541 NULL,
542 false,
543 "/usr/local/share/factory/etc",
544 "/usr/share/factory/etc",
545 NULL);
546
547 case SD_PATH_SEARCH_STATE_FACTORY:
548 return search_from_environment(list,
549 NULL,
550 NULL,
551 NULL,
552 false,
553 "/usr/local/share/factory/var",
554 "/usr/share/factory/var",
555 NULL);
556
557 case SD_PATH_SEARCH_CONFIGURATION:
558 return search_from_environment(list,
559 "XDG_CONFIG_HOME",
560 ".config",
561 "XDG_CONFIG_DIRS",
562 false,
563 "/etc",
564 NULL);
565 }
566
15411c0c 567 return -EOPNOTSUPP;
9a00f57a
LP
568}
569
2de30868 570_public_ int sd_path_search(uint64_t type, const char *suffix, char ***paths) {
9a00f57a
LP
571 char **l, **i, **j, **n;
572 int r;
573
574 assert_return(paths, -EINVAL);
575
576 if (!IN_SET(type,
577 SD_PATH_SEARCH_BINARIES,
578 SD_PATH_SEARCH_LIBRARY_PRIVATE,
579 SD_PATH_SEARCH_LIBRARY_ARCH,
580 SD_PATH_SEARCH_SHARED,
581 SD_PATH_SEARCH_CONFIGURATION_FACTORY,
582 SD_PATH_SEARCH_STATE_FACTORY,
583 SD_PATH_SEARCH_CONFIGURATION)) {
584
585 char *p;
586
587 r = sd_path_home(type, suffix, &p);
588 if (r < 0)
589 return r;
590
591 l = new(char*, 2);
592 if (!l) {
593 free(p);
594 return -ENOMEM;
595 }
596
597 l[0] = p;
598 l[1] = NULL;
599
600 *paths = l;
601 return 0;
602 }
603
604 r = get_search(type, &l);
605 if (r < 0)
606 return r;
607
608 if (!suffix) {
609 *paths = l;
610 return 0;
611 }
612
613 n = new(char*, strv_length(l)+1);
614 if (!n) {
615 strv_free(l);
616 return -ENOMEM;
617 }
618
619 j = n;
620 STRV_FOREACH(i, l) {
621
622 if (endswith(*i, "/"))
623 *j = strappend(*i, suffix);
624 else
605405c6 625 *j = strjoin(*i, "/", suffix);
9a00f57a
LP
626
627 if (!*j) {
628 strv_free(l);
629 strv_free(n);
630 return -ENOMEM;
631 }
632
633 j++;
634 }
635
636 *j = NULL;
637 *paths = n;
638 return 0;
639}