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