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