]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-path/sd-path.c
Merge pull request #12971 from yuwata/network-reassign-static-routes
[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"
07630cea 10#include "missing.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
b6b0cfaa
EGP
86 fn = strappend(c, "/user-dirs.dirs");
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
144 cc = strappend(h, p+5);
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
182 cc = strappend(h, "/Desktop");
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);
322 }
323
15411c0c 324 return -EOPNOTSUPP;
9a00f57a
LP
325}
326
2de30868 327_public_ int sd_path_home(uint64_t type, const char *suffix, char **path) {
a13de89d 328 _cleanup_free_ char *buffer = NULL;
9a00f57a 329 const char *ret;
a13de89d 330 char *cc;
9a00f57a
LP
331 int r;
332
333 assert_return(path, -EINVAL);
334
335 if (IN_SET(type,
336 SD_PATH_SEARCH_BINARIES,
e12d446b 337 SD_PATH_SEARCH_BINARIES_DEFAULT,
9a00f57a
LP
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)) {
344
345 _cleanup_strv_free_ char **l = NULL;
346
347 r = sd_path_search(type, suffix, &l);
348 if (r < 0)
349 return r;
350
351 buffer = strv_join(l, ":");
352 if (!buffer)
353 return -ENOMEM;
354
a13de89d 355 *path = TAKE_PTR(buffer);
9a00f57a
LP
356 return 0;
357 }
358
359 r = get_path(type, &buffer, &ret);
360 if (r < 0)
361 return r;
362
363 if (!suffix) {
364 if (!buffer) {
365 buffer = strdup(ret);
366 if (!buffer)
367 return -ENOMEM;
368 }
369
a13de89d 370 *path = TAKE_PTR(buffer);
9a00f57a
LP
371 return 0;
372 }
373
374 suffix += strspn(suffix, "/");
657ee2d8 375 cc = path_join(ret, suffix);
9a00f57a
LP
376 if (!cc)
377 return -ENOMEM;
378
a13de89d 379 *path = TAKE_PTR(cc);
9a00f57a
LP
380 return 0;
381}
382
383static int search_from_environment(
384 char ***list,
385 const char *env_home,
386 const char *home_suffix,
387 const char *env_search,
388 bool env_search_sufficient,
389 const char *first, ...) {
390
623550af 391 _cleanup_strv_free_ char **l = NULL;
9a00f57a
LP
392 const char *e;
393 char *h = NULL;
9a00f57a
LP
394 int r;
395
396 assert(list);
397
398 if (env_search) {
399 e = secure_getenv(env_search);
400 if (e) {
401 l = strv_split(e, ":");
402 if (!l)
403 return -ENOMEM;
404
405 if (env_search_sufficient) {
623550af 406 *list = TAKE_PTR(l);
9a00f57a
LP
407 return 0;
408 }
409 }
410 }
411
412 if (!l && first) {
413 va_list ap;
414
415 va_start(ap, first);
416 l = strv_new_ap(first, ap);
417 va_end(ap);
418
419 if (!l)
420 return -ENOMEM;
421 }
422
423 if (env_home) {
424 e = secure_getenv(env_home);
425 if (e && path_is_absolute(e)) {
426 h = strdup(e);
623550af 427 if (!h)
9a00f57a 428 return -ENOMEM;
9a00f57a
LP
429 }
430 }
431
432 if (!h && home_suffix) {
433 e = secure_getenv("HOME");
434 if (e && path_is_absolute(e)) {
657ee2d8 435 h = path_join(e, home_suffix);
623550af 436 if (!h)
9a00f57a 437 return -ENOMEM;
9a00f57a
LP
438 }
439 }
440
441 if (h) {
442 r = strv_consume_prepend(&l, h);
623550af 443 if (r < 0)
9a00f57a 444 return -ENOMEM;
9a00f57a
LP
445 }
446
623550af 447 *list = TAKE_PTR(l);
9a00f57a
LP
448 return 0;
449}
450
671f0f8d
ZJS
451#if HAVE_SPLIT_BIN
452# define ARRAY_SBIN_BIN(x) x "sbin", x "bin"
453#else
454# define ARRAY_SBIN_BIN(x) x "bin"
455#endif
456
9a00f57a
LP
457static int get_search(uint64_t type, char ***list) {
458
459 assert(list);
460
461 switch(type) {
462
463 case SD_PATH_SEARCH_BINARIES:
464 return search_from_environment(list,
465 NULL,
466 ".local/bin",
467 "PATH",
468 true,
671f0f8d
ZJS
469 ARRAY_SBIN_BIN("/usr/local/"),
470 ARRAY_SBIN_BIN("/usr/"),
349cc4a5 471#if HAVE_SPLIT_USR
671f0f8d 472 ARRAY_SBIN_BIN("/"),
9a00f57a
LP
473#endif
474 NULL);
475
476 case SD_PATH_SEARCH_LIBRARY_PRIVATE:
477 return search_from_environment(list,
478 NULL,
479 ".local/lib",
480 NULL,
481 false,
482 "/usr/local/lib",
483 "/usr/lib",
349cc4a5 484#if HAVE_SPLIT_USR
9a00f57a
LP
485 "/lib",
486#endif
487 NULL);
488
489 case SD_PATH_SEARCH_LIBRARY_ARCH:
490 return search_from_environment(list,
491 NULL,
613e3a26 492 ".local/lib/" LIB_ARCH_TUPLE,
9a00f57a
LP
493 "LD_LIBRARY_PATH",
494 true,
495 LIBDIR,
349cc4a5 496#if HAVE_SPLIT_USR
9a00f57a
LP
497 ROOTLIBDIR,
498#endif
499 NULL);
500
501 case SD_PATH_SEARCH_SHARED:
502 return search_from_environment(list,
503 "XDG_DATA_HOME",
504 ".local/share",
505 "XDG_DATA_DIRS",
506 false,
507 "/usr/local/share",
508 "/usr/share",
509 NULL);
510
511 case SD_PATH_SEARCH_CONFIGURATION_FACTORY:
512 return search_from_environment(list,
513 NULL,
514 NULL,
515 NULL,
516 false,
517 "/usr/local/share/factory/etc",
518 "/usr/share/factory/etc",
519 NULL);
520
521 case SD_PATH_SEARCH_STATE_FACTORY:
522 return search_from_environment(list,
523 NULL,
524 NULL,
525 NULL,
526 false,
527 "/usr/local/share/factory/var",
528 "/usr/share/factory/var",
529 NULL);
530
531 case SD_PATH_SEARCH_CONFIGURATION:
532 return search_from_environment(list,
533 "XDG_CONFIG_HOME",
534 ".config",
535 "XDG_CONFIG_DIRS",
536 false,
537 "/etc",
538 NULL);
e12d446b
ZJS
539
540 case SD_PATH_SEARCH_BINARIES_DEFAULT: {
541 char **t;
542
543 t = strv_split_nulstr(DEFAULT_PATH_NULSTR);
544 if (!t)
545 return -ENOMEM;
546
547 *list = t;
548 return 0;
549 }}
9a00f57a 550
15411c0c 551 return -EOPNOTSUPP;
9a00f57a
LP
552}
553
2de30868 554_public_ int sd_path_search(uint64_t type, const char *suffix, char ***paths) {
a605e46f
FB
555 char **i, **j;
556 _cleanup_strv_free_ char **l = NULL, **n = NULL;
9a00f57a
LP
557 int r;
558
559 assert_return(paths, -EINVAL);
560
561 if (!IN_SET(type,
562 SD_PATH_SEARCH_BINARIES,
e12d446b 563 SD_PATH_SEARCH_BINARIES_DEFAULT,
9a00f57a
LP
564 SD_PATH_SEARCH_LIBRARY_PRIVATE,
565 SD_PATH_SEARCH_LIBRARY_ARCH,
566 SD_PATH_SEARCH_SHARED,
567 SD_PATH_SEARCH_CONFIGURATION_FACTORY,
568 SD_PATH_SEARCH_STATE_FACTORY,
569 SD_PATH_SEARCH_CONFIGURATION)) {
570
571 char *p;
572
573 r = sd_path_home(type, suffix, &p);
574 if (r < 0)
575 return r;
576
577 l = new(char*, 2);
578 if (!l) {
579 free(p);
580 return -ENOMEM;
581 }
582
583 l[0] = p;
584 l[1] = NULL;
585
a605e46f 586 *paths = TAKE_PTR(l);
9a00f57a
LP
587 return 0;
588 }
589
590 r = get_search(type, &l);
591 if (r < 0)
592 return r;
593
594 if (!suffix) {
a605e46f 595 *paths = TAKE_PTR(l);
9a00f57a
LP
596 return 0;
597 }
598
599 n = new(char*, strv_length(l)+1);
a605e46f 600 if (!n)
9a00f57a 601 return -ENOMEM;
9a00f57a
LP
602
603 j = n;
604 STRV_FOREACH(i, l) {
657ee2d8 605 *j = path_join(*i, suffix);
a605e46f 606 if (!*j)
9a00f57a 607 return -ENOMEM;
9a00f57a
LP
608
609 j++;
610 }
611
612 *j = NULL;
a605e46f 613 *paths = TAKE_PTR(n);
9a00f57a
LP
614 return 0;
615}