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