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