1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "sd-path.h"
4 
5 #include "alloc-util.h"
6 #include "architecture.h"
7 #include "fd-util.h"
8 #include "fileio.h"
9 #include "fs-util.h"
10 #include "path-lookup.h"
11 #include "path-util.h"
12 #include "string-util.h"
13 #include "strv.h"
14 #include "user-util.h"
15 #include "util.h"
16 
from_environment(const char * envname,const char * fallback,const char ** ret)17 static 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 
from_home_dir(const char * envname,const char * suffix,char ** buffer,const char ** ret)38 static int from_home_dir(const char *envname, const char *suffix, char **buffer, const char **ret) {
39         _cleanup_free_ char *h = NULL;
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 
60         if (!path_extend(&h, suffix))
61                 return -ENOMEM;
62 
63         *buffer = h;
64         *ret = TAKE_PTR(h);
65         return 0;
66 }
67 
from_user_dir(const char * field,char ** buffer,const char ** ret)68 static int from_user_dir(const char *field, char **buffer, const char **ret) {
69         _cleanup_fclose_ FILE *f = NULL;
70         _cleanup_free_ char *b = NULL;
71         _cleanup_free_ const char *fn = NULL;
72         const char *c = NULL;
73         size_t n;
74         int r;
75 
76         assert(field);
77         assert(buffer);
78         assert(ret);
79 
80         r = from_home_dir("XDG_CONFIG_HOME", ".config", &b, &c);
81         if (r < 0)
82                 return r;
83 
84         fn = path_join(c, "user-dirs.dirs");
85         if (!fn)
86                 return -ENOMEM;
87 
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);
100         for (;;) {
101                 _cleanup_free_ char *line = NULL;
102                 char *l, *p, *e;
103 
104                 r = read_line(f, LONG_LINE_MAX, &line);
105                 if (r < 0)
106                         return r;
107                 if (r == 0)
108                         break;
109 
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;
136 
137                         r = get_home_dir(&h);
138                         if (r < 0)
139                                 return r;
140 
141                         if (!path_extend(&h, p+5))
142                                 return -ENOMEM;
143 
144                         *buffer = h;
145                         *ret = TAKE_PTR(h);
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 
168 fallback:
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;
172 
173                 r = get_home_dir(&h);
174                 if (r < 0)
175                         return r;
176 
177                 if (!path_extend(&h, "Desktop"))
178                         return -ENOMEM;
179 
180                 *buffer = h;
181                 *ret = TAKE_PTR(h);
182         } else {
183                 r = get_home_dir(buffer);
184                 if (r < 0)
185                         return r;
186 
187                 *ret = *buffer;
188         }
189 
190         return 0;
191 }
192 
get_path(uint64_t type,char ** buffer,const char ** ret)193 static 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:
202                 return tmp_dir(ret);
203 
204         case SD_PATH_TEMPORARY_LARGE:
205                 return var_tmp_dir(ret);
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:
270                 return from_home_dir(NULL, ".local/lib/" LIB_ARCH_TUPLE, buffer, ret);
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);
315 
316         case SD_PATH_SYSTEMD_UTIL:
317                 *ret = ROOTPREFIX_NOSLASH "/lib/systemd";
318                 return 0;
319 
320         case SD_PATH_SYSTEMD_SYSTEM_UNIT:
321                 *ret = SYSTEM_DATA_UNIT_DIR;
322                 return 0;
323 
324         case SD_PATH_SYSTEMD_SYSTEM_PRESET:
325                 *ret = ROOTPREFIX_NOSLASH "/lib/systemd/system-preset";
326                 return 0;
327 
328         case SD_PATH_SYSTEMD_USER_UNIT:
329                 *ret = USER_DATA_UNIT_DIR;
330                 return 0;
331 
332         case SD_PATH_SYSTEMD_USER_PRESET:
333                 *ret = ROOTPREFIX_NOSLASH "/lib/systemd/user-preset";
334                 return 0;
335 
336         case SD_PATH_SYSTEMD_SYSTEM_CONF:
337                 *ret = SYSTEM_CONFIG_UNIT_DIR;
338                 return 0;
339 
340         case SD_PATH_SYSTEMD_USER_CONF:
341                 *ret = USER_CONFIG_UNIT_DIR;
342                 return 0;
343 
344         case SD_PATH_SYSTEMD_SYSTEM_GENERATOR:
345                 *ret = SYSTEM_GENERATOR_DIR;
346                 return 0;
347 
348         case SD_PATH_SYSTEMD_USER_GENERATOR:
349                 *ret = USER_GENERATOR_DIR;
350                 return 0;
351 
352         case SD_PATH_SYSTEMD_SLEEP:
353                 *ret = ROOTPREFIX_NOSLASH "/lib/systemd/system-sleep";
354                 return 0;
355 
356         case SD_PATH_SYSTEMD_SHUTDOWN:
357                 *ret = ROOTPREFIX_NOSLASH "/lib/systemd/system-shutdown";
358                 return 0;
359 
360         case SD_PATH_TMPFILES:
361                 *ret = "/usr/lib/tmpfiles.d";
362                 return 0;
363 
364         case SD_PATH_SYSUSERS:
365                 *ret = ROOTPREFIX_NOSLASH "/lib/sysusers.d";
366                 return 0;
367 
368         case SD_PATH_SYSCTL:
369                 *ret = ROOTPREFIX_NOSLASH "/lib/sysctl.d";
370                 return 0;
371 
372         case SD_PATH_BINFMT:
373                 *ret = ROOTPREFIX_NOSLASH "/lib/binfmt.d";
374                 return 0;
375 
376         case SD_PATH_MODULES_LOAD:
377                 *ret = ROOTPREFIX_NOSLASH "/lib/modules-load.d";
378                 return 0;
379 
380         case SD_PATH_CATALOG:
381                 *ret = "/usr/lib/systemd/catalog";
382                 return 0;
383         }
384 
385         return -EOPNOTSUPP;
386 }
387 
get_path_alloc(uint64_t type,const char * suffix,char ** path)388 static int get_path_alloc(uint64_t type, const char *suffix, char **path) {
389         _cleanup_free_ char *buffer = NULL;
390         char *buffer2 = NULL;
391         const char *ret;
392         int r;
393 
394         assert(path);
395 
396         r = get_path(type, &buffer, &ret);
397         if (r < 0)
398                 return r;
399 
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);
407                 if (!buffer)
408                         return -ENOMEM;
409         }
410 
411         *path = buffer2 ?: TAKE_PTR(buffer);
412         return 0;
413 }
414 
sd_path_lookup(uint64_t type,const char * suffix,char ** path)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)
422                 return r;
423 
424         /* Fall back to sd_path_lookup_strv */
425         _cleanup_strv_free_ char **l = NULL;
426         char *buffer;
427 
428         r = sd_path_lookup_strv(type, suffix, &l);
429         if (r < 0)
430                 return r;
431 
432         buffer = strv_join(l, ":");
433         if (!buffer)
434                 return -ENOMEM;
435 
436         *path = buffer;
437         return 0;
438 }
439 
search_from_environment(char *** list,const char * env_home,const char * home_suffix,const char * env_search,bool env_search_sufficient,const char * first,...)440 static 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 
448         _cleanup_strv_free_ char **l = NULL;
449         const char *e;
450         char *h = NULL;
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) {
463                                 *list = TAKE_PTR(l);
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);
484                         if (!h)
485                                 return -ENOMEM;
486                 }
487         }
488 
489         if (!h && home_suffix) {
490                 e = secure_getenv("HOME");
491                 if (e && path_is_absolute(e)) {
492                         h = path_join(e, home_suffix);
493                         if (!h)
494                                 return -ENOMEM;
495                 }
496         }
497 
498         if (h) {
499                 r = strv_consume_prepend(&l, h);
500                 if (r < 0)
501                         return -ENOMEM;
502         }
503 
504         *list = TAKE_PTR(l);
505         return 0;
506 }
507 
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 
get_search(uint64_t type,char *** list)514 static int get_search(uint64_t type, char ***list) {
515         int r;
516 
517         assert(list);
518 
519         switch (type) {
520 
521         case SD_PATH_SEARCH_BINARIES:
522                 return search_from_environment(list,
523                                                NULL,
524                                                ".local/bin",
525                                                "PATH",
526                                                true,
527                                                ARRAY_SBIN_BIN("/usr/local/"),
528                                                ARRAY_SBIN_BIN("/usr/"),
529 #if HAVE_SPLIT_USR
530                                                ARRAY_SBIN_BIN("/"),
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",
542 #if HAVE_SPLIT_USR
543                                                "/lib",
544 #endif
545                                                NULL);
546 
547         case SD_PATH_SEARCH_LIBRARY_ARCH:
548                 return search_from_environment(list,
549                                                NULL,
550                                                ".local/lib/" LIB_ARCH_TUPLE,
551                                                "LD_LIBRARY_PATH",
552                                                true,
553                                                LIBDIR,
554 #if HAVE_SPLIT_USR
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);
597 
598         case SD_PATH_SEARCH_BINARIES_DEFAULT:
599                 return strv_from_nulstr(list, DEFAULT_PATH_NULSTR);
600 
601         case SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT:
602         case SD_PATH_SYSTEMD_SEARCH_USER_UNIT: {
603                 _cleanup_(lookup_paths_free) LookupPaths lp = {};
604                 const LookupScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT ?
605                                                     LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER;
606 
607                 r = lookup_paths_init(&lp, scope, 0, NULL);
608                 if (r < 0)
609                         return r;
610 
611                 *list = TAKE_PTR(lp.search_path);
612                 return 0;
613         }
614 
615         case SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR:
616         case SD_PATH_SYSTEMD_SEARCH_USER_GENERATOR: {
617                 char **t;
618                 const LookupScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR ?
619                                                     LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER;
620 
621                 t = generator_binary_paths(scope);
622                 if (!t)
623                         return -ENOMEM;
624 
625                 *list = t;
626                 return 0;
627         }
628 
629         case SD_PATH_SYSTEMD_SEARCH_NETWORK:
630                 return strv_from_nulstr(list, NETWORK_DIRS_NULSTR);
631 
632         }
633 
634         return -EOPNOTSUPP;
635 }
636 
sd_path_lookup_strv(uint64_t type,const char * suffix,char *** paths)637 _public_ int sd_path_lookup_strv(uint64_t type, const char *suffix, char ***paths) {
638         _cleanup_strv_free_ char **l = NULL, **n = NULL;
639         int r;
640 
641         assert_return(paths, -EINVAL);
642 
643         r = get_search(type, &l);
644         if (r == -EOPNOTSUPP) {
645                 _cleanup_free_ char *t = NULL;
646 
647                 r = get_path_alloc(type, suffix, &t);
648                 if (r < 0)
649                         return r;
650 
651                 l = new(char*, 2);
652                 if (!l)
653                         return -ENOMEM;
654                 l[0] = TAKE_PTR(t);
655                 l[1] = NULL;
656 
657                 *paths = TAKE_PTR(l);
658                 return 0;
659 
660         } else if (r < 0)
661                 return r;
662 
663         if (!suffix) {
664                 *paths = TAKE_PTR(l);
665                 return 0;
666         }
667 
668         n = new(char*, strv_length(l)+1);
669         if (!n)
670                 return -ENOMEM;
671 
672         char **j = n;
673         STRV_FOREACH(i, l) {
674                 *j = path_join(*i, suffix);
675                 if (!*j)
676                         return -ENOMEM;
677 
678                 j++;
679         }
680         *j = NULL;
681 
682         *paths = TAKE_PTR(n);
683         return 0;
684 }
685