chiark / gitweb /
3422340b6b4c5402f1ba5f72aa45737be8c894fd
[elogind.git] / src / basic / path-util.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010-2012 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 <errno.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27
28 /* When we include libgen.h because we need dirname() we immediately
29  * undefine basename() since libgen.h defines it as a macro to the
30  * POSIX version which is really broken. We prefer GNU basename(). */
31 #include <libgen.h>
32 #undef basename
33
34 #include "alloc-util.h"
35 #include "extract-word.h"
36 #include "fs-util.h"
37 #include "glob-util.h"
38 #include "log.h"
39 #include "macro.h"
40 #include "missing.h"
41 #include "path-util.h"
42 #include "stat-util.h"
43 #include "string-util.h"
44 #include "strv.h"
45 #include "time-util.h"
46
47 bool path_is_absolute(const char *p) {
48         return p[0] == '/';
49 }
50
51 bool is_path(const char *p) {
52         return !!strchr(p, '/');
53 }
54
55 #if 0 /// UNNEEDED by elogind
56 int path_split_and_make_absolute(const char *p, char ***ret) {
57         char **l;
58         int r;
59
60         assert(p);
61         assert(ret);
62
63         l = strv_split(p, ":");
64         if (!l)
65                 return -ENOMEM;
66
67         r = path_strv_make_absolute_cwd(l);
68         if (r < 0) {
69                 strv_free(l);
70                 return r;
71         }
72
73         *ret = l;
74         return r;
75 }
76
77 char *path_make_absolute(const char *p, const char *prefix) {
78         assert(p);
79
80         /* Makes every item in the list an absolute path by prepending
81          * the prefix, if specified and necessary */
82
83         if (path_is_absolute(p) || !prefix)
84                 return strdup(p);
85
86         return strjoin(prefix, "/", p, NULL);
87 }
88 #endif // 0
89
90 int path_make_absolute_cwd(const char *p, char **ret) {
91         char *c;
92
93         assert(p);
94         assert(ret);
95
96         /* Similar to path_make_absolute(), but prefixes with the
97          * current working directory. */
98
99         if (path_is_absolute(p))
100                 c = strdup(p);
101         else {
102                 _cleanup_free_ char *cwd = NULL;
103
104                 cwd = get_current_dir_name();
105                 if (!cwd)
106                         return negative_errno();
107
108                 c = strjoin(cwd, "/", p, NULL);
109         }
110         if (!c)
111                 return -ENOMEM;
112
113         *ret = c;
114         return 0;
115 }
116
117 #if 0 /// UNNEEDED by elogind
118 int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
119         char *r, *p;
120         unsigned n_parents;
121
122         assert(from_dir);
123         assert(to_path);
124         assert(_r);
125
126         /* Strips the common part, and adds ".." elements as necessary. */
127
128         if (!path_is_absolute(from_dir))
129                 return -EINVAL;
130
131         if (!path_is_absolute(to_path))
132                 return -EINVAL;
133
134         /* Skip the common part. */
135         for (;;) {
136                 size_t a;
137                 size_t b;
138
139                 from_dir += strspn(from_dir, "/");
140                 to_path += strspn(to_path, "/");
141
142                 if (!*from_dir) {
143                         if (!*to_path)
144                                 /* from_dir equals to_path. */
145                                 r = strdup(".");
146                         else
147                                 /* from_dir is a parent directory of to_path. */
148                                 r = strdup(to_path);
149
150                         if (!r)
151                                 return -ENOMEM;
152
153                         path_kill_slashes(r);
154
155                         *_r = r;
156                         return 0;
157                 }
158
159                 if (!*to_path)
160                         break;
161
162                 a = strcspn(from_dir, "/");
163                 b = strcspn(to_path, "/");
164
165                 if (a != b)
166                         break;
167
168                 if (memcmp(from_dir, to_path, a) != 0)
169                         break;
170
171                 from_dir += a;
172                 to_path += b;
173         }
174
175         /* If we're here, then "from_dir" has one or more elements that need to
176          * be replaced with "..". */
177
178         /* Count the number of necessary ".." elements. */
179         for (n_parents = 0;;) {
180                 from_dir += strspn(from_dir, "/");
181
182                 if (!*from_dir)
183                         break;
184
185                 from_dir += strcspn(from_dir, "/");
186                 n_parents++;
187         }
188
189         r = malloc(n_parents * 3 + strlen(to_path) + 1);
190         if (!r)
191                 return -ENOMEM;
192
193         for (p = r; n_parents > 0; n_parents--, p += 3)
194                 memcpy(p, "../", 3);
195
196         strcpy(p, to_path);
197         path_kill_slashes(r);
198
199         *_r = r;
200         return 0;
201 }
202
203 int path_strv_make_absolute_cwd(char **l) {
204         char **s;
205         int r;
206
207         /* Goes through every item in the string list and makes it
208          * absolute. This works in place and won't rollback any
209          * changes on failure. */
210
211         STRV_FOREACH(s, l) {
212                 char *t;
213
214                 r = path_make_absolute_cwd(*s, &t);
215                 if (r < 0)
216                         return r;
217
218                 free(*s);
219                 *s = t;
220         }
221
222         return 0;
223 }
224 #endif // 0
225
226 char **path_strv_resolve(char **l, const char *prefix) {
227         char **s;
228         unsigned k = 0;
229         bool enomem = false;
230
231         if (strv_isempty(l))
232                 return l;
233
234         /* Goes through every item in the string list and canonicalize
235          * the path. This works in place and won't rollback any
236          * changes on failure. */
237
238         STRV_FOREACH(s, l) {
239                 char *t, *u;
240                 _cleanup_free_ char *orig = NULL;
241
242                 if (!path_is_absolute(*s)) {
243                         free(*s);
244                         continue;
245                 }
246
247                 if (prefix) {
248                         orig = *s;
249                         t = strappend(prefix, orig);
250                         if (!t) {
251                                 enomem = true;
252                                 continue;
253                         }
254                 } else
255                         t = *s;
256
257                 errno = 0;
258                 u = canonicalize_file_name(t);
259                 if (!u) {
260                         if (errno == ENOENT) {
261                                 if (prefix) {
262                                         u = orig;
263                                         orig = NULL;
264                                         free(t);
265                                 } else
266                                         u = t;
267                         } else {
268                                 free(t);
269                                 if (errno == ENOMEM || errno == 0)
270                                         enomem = true;
271
272                                 continue;
273                         }
274                 } else if (prefix) {
275                         char *x;
276
277                         free(t);
278                         x = path_startswith(u, prefix);
279                         if (x) {
280                                 /* restore the slash if it was lost */
281                                 if (!startswith(x, "/"))
282                                         *(--x) = '/';
283
284                                 t = strdup(x);
285                                 free(u);
286                                 if (!t) {
287                                         enomem = true;
288                                         continue;
289                                 }
290                                 u = t;
291                         } else {
292                                 /* canonicalized path goes outside of
293                                  * prefix, keep the original path instead */
294                                 free_and_replace(u, orig);
295                         }
296                 } else
297                         free(t);
298
299                 l[k++] = u;
300         }
301
302         l[k] = NULL;
303
304         if (enomem)
305                 return NULL;
306
307         return l;
308 }
309
310 char **path_strv_resolve_uniq(char **l, const char *prefix) {
311
312         if (strv_isempty(l))
313                 return l;
314
315         if (!path_strv_resolve(l, prefix))
316                 return NULL;
317
318         return strv_uniq(l);
319 }
320
321 char *path_kill_slashes(char *path) {
322         char *f, *t;
323         bool slash = false;
324
325         /* Removes redundant inner and trailing slashes. Modifies the
326          * passed string in-place.
327          *
328          * ///foo///bar/ becomes /foo/bar
329          */
330
331         for (f = path, t = path; *f; f++) {
332
333                 if (*f == '/') {
334                         slash = true;
335                         continue;
336                 }
337
338                 if (slash) {
339                         slash = false;
340                         *(t++) = '/';
341                 }
342
343                 *(t++) = *f;
344         }
345
346         /* Special rule, if we are talking of the root directory, a
347         trailing slash is good */
348
349         if (t == path && slash)
350                 *(t++) = '/';
351
352         *t = 0;
353         return path;
354 }
355
356 char* path_startswith(const char *path, const char *prefix) {
357         assert(path);
358         assert(prefix);
359
360         /* Returns a pointer to the start of the first component after the parts matched by
361          * the prefix, iff
362          * - both paths are absolute or both paths are relative,
363          * and
364          * - each component in prefix in turn matches a component in path at the same position.
365          * An empty string will be returned when the prefix and path are equivalent.
366          *
367          * Returns NULL otherwise.
368          */
369
370         if ((path[0] == '/') != (prefix[0] == '/'))
371                 return NULL;
372
373         for (;;) {
374                 size_t a, b;
375
376                 path += strspn(path, "/");
377                 prefix += strspn(prefix, "/");
378
379                 if (*prefix == 0)
380                         return (char*) path;
381
382                 if (*path == 0)
383                         return NULL;
384
385                 a = strcspn(path, "/");
386                 b = strcspn(prefix, "/");
387
388                 if (a != b)
389                         return NULL;
390
391                 if (memcmp(path, prefix, a) != 0)
392                         return NULL;
393
394                 path += a;
395                 prefix += b;
396         }
397 }
398
399 int path_compare(const char *a, const char *b) {
400         int d;
401
402         assert(a);
403         assert(b);
404
405         /* A relative path and an abolute path must not compare as equal.
406          * Which one is sorted before the other does not really matter.
407          * Here a relative path is ordered before an absolute path. */
408         d = (a[0] == '/') - (b[0] == '/');
409         if (d != 0)
410                 return d;
411
412         for (;;) {
413                 size_t j, k;
414
415                 a += strspn(a, "/");
416                 b += strspn(b, "/");
417
418                 if (*a == 0 && *b == 0)
419                         return 0;
420
421                 /* Order prefixes first: "/foo" before "/foo/bar" */
422                 if (*a == 0)
423                         return -1;
424                 if (*b == 0)
425                         return 1;
426
427                 j = strcspn(a, "/");
428                 k = strcspn(b, "/");
429
430                 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
431                 d = memcmp(a, b, MIN(j, k));
432                 if (d != 0)
433                         return (d > 0) - (d < 0); /* sign of d */
434
435                 /* Sort "/foo/a" before "/foo/aaa" */
436                 d = (j > k) - (j < k);  /* sign of (j - k) */
437                 if (d != 0)
438                         return d;
439
440                 a += j;
441                 b += k;
442         }
443 }
444
445 bool path_equal(const char *a, const char *b) {
446         return path_compare(a, b) == 0;
447 }
448
449 bool path_equal_or_files_same(const char *a, const char *b) {
450         return path_equal(a, b) || files_same(a, b) > 0;
451 }
452
453 #if 0 /// UNNEEDED by elogind
454 char* path_join(const char *root, const char *path, const char *rest) {
455         assert(path);
456
457         if (!isempty(root))
458                 return strjoin(root, endswith(root, "/") ? "" : "/",
459                                path[0] == '/' ? path+1 : path,
460                                rest ? (endswith(path, "/") ? "" : "/") : NULL,
461                                rest && rest[0] == '/' ? rest+1 : rest,
462                                NULL);
463         else
464                 return strjoin(path,
465                                rest ? (endswith(path, "/") ? "" : "/") : NULL,
466                                rest && rest[0] == '/' ? rest+1 : rest,
467                                NULL);
468 }
469
470 int find_binary(const char *name, char **ret) {
471         int last_error, r;
472         const char *p;
473
474         assert(name);
475
476         if (is_path(name)) {
477                 if (access(name, X_OK) < 0)
478                         return -errno;
479
480                 if (ret) {
481                         r = path_make_absolute_cwd(name, ret);
482                         if (r < 0)
483                                 return r;
484                 }
485
486                 return 0;
487         }
488
489         /**
490          * Plain getenv, not secure_getenv, because we want
491          * to actually allow the user to pick the binary.
492          */
493         p = getenv("PATH");
494         if (!p)
495                 p = DEFAULT_PATH;
496
497         last_error = -ENOENT;
498
499         for (;;) {
500                 _cleanup_free_ char *j = NULL, *element = NULL;
501
502                 r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
503                 if (r < 0)
504                         return r;
505                 if (r == 0)
506                         break;
507
508                 if (!path_is_absolute(element))
509                         continue;
510
511                 j = strjoin(element, "/", name, NULL);
512                 if (!j)
513                         return -ENOMEM;
514
515                 if (access(j, X_OK) >= 0) {
516                         /* Found it! */
517
518                         if (ret) {
519                                 *ret = path_kill_slashes(j);
520                                 j = NULL;
521                         }
522
523                         return 0;
524                 }
525
526                 last_error = -errno;
527         }
528
529         return last_error;
530 }
531
532 bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
533         bool changed = false;
534         const char* const* i;
535
536         assert(timestamp);
537
538         if (paths == NULL)
539                 return false;
540
541         STRV_FOREACH(i, paths) {
542                 struct stat stats;
543                 usec_t u;
544
545                 if (stat(*i, &stats) < 0)
546                         continue;
547
548                 u = timespec_load(&stats.st_mtim);
549
550                 /* first check */
551                 if (*timestamp >= u)
552                         continue;
553
554                 log_debug("timestamp of '%s' changed", *i);
555
556                 /* update timestamp */
557                 if (update) {
558                         *timestamp = u;
559                         changed = true;
560                 } else
561                         return true;
562         }
563
564         return changed;
565 }
566
567 static int binary_is_good(const char *binary) {
568         _cleanup_free_ char *p = NULL, *d = NULL;
569         int r;
570
571         r = find_binary(binary, &p);
572         if (r == -ENOENT)
573                 return 0;
574         if (r < 0)
575                 return r;
576
577         /* An fsck that is linked to /bin/true is a non-existent
578          * fsck */
579
580         r = readlink_malloc(p, &d);
581         if (r == -EINVAL) /* not a symlink */
582                 return 1;
583         if (r < 0)
584                 return r;
585
586         return !PATH_IN_SET(d, "true"
587                                "/bin/true",
588                                "/usr/bin/true",
589                                "/dev/null");
590 }
591
592 int fsck_exists(const char *fstype) {
593         const char *checker;
594
595         assert(fstype);
596
597         if (streq(fstype, "auto"))
598                 return -EINVAL;
599
600         checker = strjoina("fsck.", fstype);
601         return binary_is_good(checker);
602 }
603
604 int mkfs_exists(const char *fstype) {
605         const char *mkfs;
606
607         assert(fstype);
608
609         if (streq(fstype, "auto"))
610                 return -EINVAL;
611
612         mkfs = strjoina("mkfs.", fstype);
613         return binary_is_good(mkfs);
614 }
615
616 char *prefix_root(const char *root, const char *path) {
617         char *n, *p;
618         size_t l;
619
620         /* If root is passed, prefixes path with it. Otherwise returns
621          * it as is. */
622
623         assert(path);
624
625         /* First, drop duplicate prefixing slashes from the path */
626         while (path[0] == '/' && path[1] == '/')
627                 path++;
628
629         if (isempty(root) || path_equal(root, "/"))
630                 return strdup(path);
631
632         l = strlen(root) + 1 + strlen(path) + 1;
633
634         n = new(char, l);
635         if (!n)
636                 return NULL;
637
638         p = stpcpy(n, root);
639
640         while (p > n && p[-1] == '/')
641                 p--;
642
643         if (path[0] != '/')
644                 *(p++) = '/';
645
646         strcpy(p, path);
647         return n;
648 }
649
650 int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
651         char *p;
652         int r;
653
654         /*
655          * This function is intended to be used in command line
656          * parsers, to handle paths that are passed in. It makes the
657          * path absolute, and reduces it to NULL if omitted or
658          * root (the latter optionally).
659          *
660          * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
661          * SUCCESS! Hence, do not pass in uninitialized pointers.
662          */
663
664         if (isempty(path)) {
665                 *arg = mfree(*arg);
666                 return 0;
667         }
668
669         r = path_make_absolute_cwd(path, &p);
670         if (r < 0)
671                 return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
672
673         path_kill_slashes(p);
674         if (suppress_root && path_equal(p, "/"))
675                 p = mfree(p);
676
677         free(*arg);
678         *arg = p;
679         return 0;
680 }
681 #endif // 0
682
683 char* dirname_malloc(const char *path) {
684         char *d, *dir, *dir2;
685
686         assert(path);
687
688         d = strdup(path);
689         if (!d)
690                 return NULL;
691
692         dir = dirname(d);
693         assert(dir);
694
695         if (dir == d)
696                 return d;
697
698         dir2 = strdup(dir);
699         free(d);
700
701         return dir2;
702 }
703
704 bool filename_is_valid(const char *p) {
705         const char *e;
706
707         if (isempty(p))
708                 return false;
709
710         if (streq(p, "."))
711                 return false;
712
713         if (streq(p, ".."))
714                 return false;
715
716         e = strchrnul(p, '/');
717         if (*e != 0)
718                 return false;
719
720         if (e - p > FILENAME_MAX)
721                 return false;
722
723         return true;
724 }
725
726 bool path_is_safe(const char *p) {
727
728         if (isempty(p))
729                 return false;
730
731         if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
732                 return false;
733
734         if (strlen(p)+1 > PATH_MAX)
735                 return false;
736
737         /* The following two checks are not really dangerous, but hey, they still are confusing */
738         if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
739                 return false;
740
741         if (strstr(p, "//"))
742                 return false;
743
744         return true;
745 }
746
747 char *file_in_same_dir(const char *path, const char *filename) {
748         char *e, *ret;
749         size_t k;
750
751         assert(path);
752         assert(filename);
753
754         /* This removes the last component of path and appends
755          * filename, unless the latter is absolute anyway or the
756          * former isn't */
757
758         if (path_is_absolute(filename))
759                 return strdup(filename);
760
761         e = strrchr(path, '/');
762         if (!e)
763                 return strdup(filename);
764
765         k = strlen(filename);
766         ret = new(char, (e + 1 - path) + k + 1);
767         if (!ret)
768                 return NULL;
769
770         memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
771         return ret;
772 }
773
774 bool hidden_or_backup_file(const char *filename) {
775         const char *p;
776
777         assert(filename);
778
779         if (filename[0] == '.' ||
780             streq(filename, "lost+found") ||
781             streq(filename, "aquota.user") ||
782             streq(filename, "aquota.group") ||
783             endswith(filename, "~"))
784                 return true;
785
786         p = strrchr(filename, '.');
787         if (!p)
788                 return false;
789
790         /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up
791          * with always new suffixes and that everybody else should just adjust to that, then it really should be on
792          * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt
793          * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional
794          * string. Specifically: there's now:
795          *
796          *    The generic suffixes "~" and ".bak" for backup files
797          *    The generic prefix "." for hidden files
798          *
799          * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist"
800          * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead.
801          */
802
803         return STR_IN_SET(p + 1,
804                           "rpmnew",
805                           "rpmsave",
806                           "rpmorig",
807                           "dpkg-old",
808                           "dpkg-new",
809                           "dpkg-tmp",
810                           "dpkg-dist",
811                           "dpkg-bak",
812                           "dpkg-backup",
813                           "dpkg-remove",
814                           "ucf-new",
815                           "ucf-old",
816                           "ucf-dist",
817                           "swp",
818                           "bak",
819                           "old",
820                           "new");
821 }
822
823 #if 0 /// UNNEEDED by elogind
824 bool is_device_path(const char *path) {
825
826         /* Returns true on paths that refer to a device, either in
827          * sysfs or in /dev */
828
829         return path_startswith(path, "/dev/") ||
830                path_startswith(path, "/sys/");
831 }
832
833 bool is_deviceallow_pattern(const char *path) {
834         return path_startswith(path, "/dev/") ||
835                startswith(path, "block-") ||
836                startswith(path, "char-");
837 }
838 #endif // 0
839
840 int systemd_installation_has_version(const char *root, unsigned minimal_version) {
841         const char *pattern;
842         int r;
843
844         /* Try to guess if systemd installation is later than the specified version. This
845          * is hacky and likely to yield false negatives, particularly if the installation
846          * is non-standard. False positives should be relatively rare.
847          */
848
849         NULSTR_FOREACH(pattern,
850                        /* /lib works for systems without usr-merge, and for systems with a sane
851                         * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
852                         * for Gentoo which does a merge without making /lib a symlink.
853                         */
854                        "lib/systemd/libsystemd-shared-*.so\0"
855                        "usr/lib/systemd/libsystemd-shared-*.so\0") {
856
857                 _cleanup_strv_free_ char **names = NULL;
858                 _cleanup_free_ char *path = NULL;
859                 char *c, **name;
860
861                 path = prefix_root(root, pattern);
862                 if (!path)
863                         return -ENOMEM;
864
865                 r = glob_extend(&names, path);
866                 if (r == -ENOENT)
867                         continue;
868                 if (r < 0)
869                         return r;
870
871                 assert_se((c = endswith(path, "*.so")));
872                 *c = '\0'; /* truncate the glob part */
873
874                 STRV_FOREACH(name, names) {
875                         /* This is most likely to run only once, hence let's not optimize anything. */
876                         char *t, *t2;
877                         unsigned version;
878
879                         t = startswith(*name, path);
880                         if (!t)
881                                 continue;
882
883                         t2 = endswith(t, ".so");
884                         if (!t2)
885                                 continue;
886
887                         t2[0] = '\0'; /* truncate the suffix */
888
889                         r = safe_atou(t, &version);
890                         if (r < 0) {
891                                 log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
892                                 continue;
893                         }
894
895                         log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
896                                   *name, version,
897                                   version >= minimal_version ? "OK" : "too old");
898                         if (version >= minimal_version)
899                                 return true;
900                 }
901         }
902
903         return false;
904 }