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