]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/path-util.c
Merge pull request #157 from filbranden/revert_unused_result
[thirdparty/systemd.git] / src / basic / path-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010-2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <sys/statvfs.h>
29
30 #include "macro.h"
31 #include "util.h"
32 #include "log.h"
33 #include "strv.h"
34 #include "path-util.h"
35 #include "missing.h"
36 #include "fileio.h"
37
38 bool path_is_absolute(const char *p) {
39 return p[0] == '/';
40 }
41
42 bool is_path(const char *p) {
43 return !!strchr(p, '/');
44 }
45
46 int path_get_parent(const char *path, char **_r) {
47 const char *e, *a = NULL, *b = NULL, *p;
48 char *r;
49 bool slash = false;
50
51 assert(path);
52 assert(_r);
53
54 if (!*path)
55 return -EINVAL;
56
57 for (e = path; *e; e++) {
58
59 if (!slash && *e == '/') {
60 a = b;
61 b = e;
62 slash = true;
63 } else if (slash && *e != '/')
64 slash = false;
65 }
66
67 if (*(e-1) == '/')
68 p = a;
69 else
70 p = b;
71
72 if (!p)
73 return -EINVAL;
74
75 if (p == path)
76 r = strdup("/");
77 else
78 r = strndup(path, p-path);
79
80 if (!r)
81 return -ENOMEM;
82
83 *_r = r;
84 return 0;
85 }
86
87 char **path_split_and_make_absolute(const char *p) {
88 char **l;
89 assert(p);
90
91 l = strv_split(p, ":");
92 if (!l)
93 return NULL;
94
95 if (!path_strv_make_absolute_cwd(l)) {
96 strv_free(l);
97 return NULL;
98 }
99
100 return l;
101 }
102
103 char *path_make_absolute(const char *p, const char *prefix) {
104 assert(p);
105
106 /* Makes every item in the list an absolute path by prepending
107 * the prefix, if specified and necessary */
108
109 if (path_is_absolute(p) || !prefix)
110 return strdup(p);
111
112 return strjoin(prefix, "/", p, NULL);
113 }
114
115 char *path_make_absolute_cwd(const char *p) {
116 _cleanup_free_ char *cwd = NULL;
117
118 assert(p);
119
120 /* Similar to path_make_absolute(), but prefixes with the
121 * current working directory. */
122
123 if (path_is_absolute(p))
124 return strdup(p);
125
126 cwd = get_current_dir_name();
127 if (!cwd)
128 return NULL;
129
130 return strjoin(cwd, "/", p, NULL);
131 }
132
133 int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
134 char *r, *p;
135 unsigned n_parents;
136
137 assert(from_dir);
138 assert(to_path);
139 assert(_r);
140
141 /* Strips the common part, and adds ".." elements as necessary. */
142
143 if (!path_is_absolute(from_dir))
144 return -EINVAL;
145
146 if (!path_is_absolute(to_path))
147 return -EINVAL;
148
149 /* Skip the common part. */
150 for (;;) {
151 size_t a;
152 size_t b;
153
154 from_dir += strspn(from_dir, "/");
155 to_path += strspn(to_path, "/");
156
157 if (!*from_dir) {
158 if (!*to_path)
159 /* from_dir equals to_path. */
160 r = strdup(".");
161 else
162 /* from_dir is a parent directory of to_path. */
163 r = strdup(to_path);
164
165 if (!r)
166 return -ENOMEM;
167
168 path_kill_slashes(r);
169
170 *_r = r;
171 return 0;
172 }
173
174 if (!*to_path)
175 break;
176
177 a = strcspn(from_dir, "/");
178 b = strcspn(to_path, "/");
179
180 if (a != b)
181 break;
182
183 if (memcmp(from_dir, to_path, a) != 0)
184 break;
185
186 from_dir += a;
187 to_path += b;
188 }
189
190 /* If we're here, then "from_dir" has one or more elements that need to
191 * be replaced with "..". */
192
193 /* Count the number of necessary ".." elements. */
194 for (n_parents = 0;;) {
195 from_dir += strspn(from_dir, "/");
196
197 if (!*from_dir)
198 break;
199
200 from_dir += strcspn(from_dir, "/");
201 n_parents++;
202 }
203
204 r = malloc(n_parents * 3 + strlen(to_path) + 1);
205 if (!r)
206 return -ENOMEM;
207
208 for (p = r; n_parents > 0; n_parents--, p += 3)
209 memcpy(p, "../", 3);
210
211 strcpy(p, to_path);
212 path_kill_slashes(r);
213
214 *_r = r;
215 return 0;
216 }
217
218 char **path_strv_make_absolute_cwd(char **l) {
219 char **s;
220
221 /* Goes through every item in the string list and makes it
222 * absolute. This works in place and won't rollback any
223 * changes on failure. */
224
225 STRV_FOREACH(s, l) {
226 char *t;
227
228 t = path_make_absolute_cwd(*s);
229 if (!t)
230 return NULL;
231
232 free(*s);
233 *s = t;
234 }
235
236 return l;
237 }
238
239 char **path_strv_resolve(char **l, const char *prefix) {
240 char **s;
241 unsigned k = 0;
242 bool enomem = false;
243
244 if (strv_isempty(l))
245 return l;
246
247 /* Goes through every item in the string list and canonicalize
248 * the path. This works in place and won't rollback any
249 * changes on failure. */
250
251 STRV_FOREACH(s, l) {
252 char *t, *u;
253 _cleanup_free_ char *orig = NULL;
254
255 if (!path_is_absolute(*s)) {
256 free(*s);
257 continue;
258 }
259
260 if (prefix) {
261 orig = *s;
262 t = strappend(prefix, orig);
263 if (!t) {
264 enomem = true;
265 continue;
266 }
267 } else
268 t = *s;
269
270 errno = 0;
271 u = canonicalize_file_name(t);
272 if (!u) {
273 if (errno == ENOENT) {
274 if (prefix) {
275 u = orig;
276 orig = NULL;
277 free(t);
278 } else
279 u = t;
280 } else {
281 free(t);
282 if (errno == ENOMEM || errno == 0)
283 enomem = true;
284
285 continue;
286 }
287 } else if (prefix) {
288 char *x;
289
290 free(t);
291 x = path_startswith(u, prefix);
292 if (x) {
293 /* restore the slash if it was lost */
294 if (!startswith(x, "/"))
295 *(--x) = '/';
296
297 t = strdup(x);
298 free(u);
299 if (!t) {
300 enomem = true;
301 continue;
302 }
303 u = t;
304 } else {
305 /* canonicalized path goes outside of
306 * prefix, keep the original path instead */
307 free(u);
308 u = orig;
309 orig = NULL;
310 }
311 } else
312 free(t);
313
314 l[k++] = u;
315 }
316
317 l[k] = NULL;
318
319 if (enomem)
320 return NULL;
321
322 return l;
323 }
324
325 char **path_strv_resolve_uniq(char **l, const char *prefix) {
326
327 if (strv_isempty(l))
328 return l;
329
330 if (!path_strv_resolve(l, prefix))
331 return NULL;
332
333 return strv_uniq(l);
334 }
335
336 char *path_kill_slashes(char *path) {
337 char *f, *t;
338 bool slash = false;
339
340 /* Removes redundant inner and trailing slashes. Modifies the
341 * passed string in-place.
342 *
343 * ///foo///bar/ becomes /foo/bar
344 */
345
346 for (f = path, t = path; *f; f++) {
347
348 if (*f == '/') {
349 slash = true;
350 continue;
351 }
352
353 if (slash) {
354 slash = false;
355 *(t++) = '/';
356 }
357
358 *(t++) = *f;
359 }
360
361 /* Special rule, if we are talking of the root directory, a
362 trailing slash is good */
363
364 if (t == path && slash)
365 *(t++) = '/';
366
367 *t = 0;
368 return path;
369 }
370
371 char* path_startswith(const char *path, const char *prefix) {
372 assert(path);
373 assert(prefix);
374
375 if ((path[0] == '/') != (prefix[0] == '/'))
376 return NULL;
377
378 for (;;) {
379 size_t a, b;
380
381 path += strspn(path, "/");
382 prefix += strspn(prefix, "/");
383
384 if (*prefix == 0)
385 return (char*) path;
386
387 if (*path == 0)
388 return NULL;
389
390 a = strcspn(path, "/");
391 b = strcspn(prefix, "/");
392
393 if (a != b)
394 return NULL;
395
396 if (memcmp(path, prefix, a) != 0)
397 return NULL;
398
399 path += a;
400 prefix += b;
401 }
402 }
403
404 int path_compare(const char *a, const char *b) {
405 int d;
406
407 assert(a);
408 assert(b);
409
410 /* A relative path and an abolute path must not compare as equal.
411 * Which one is sorted before the other does not really matter.
412 * Here a relative path is ordered before an absolute path. */
413 d = (a[0] == '/') - (b[0] == '/');
414 if (d)
415 return d;
416
417 for (;;) {
418 size_t j, k;
419
420 a += strspn(a, "/");
421 b += strspn(b, "/");
422
423 if (*a == 0 && *b == 0)
424 return 0;
425
426 /* Order prefixes first: "/foo" before "/foo/bar" */
427 if (*a == 0)
428 return -1;
429 if (*b == 0)
430 return 1;
431
432 j = strcspn(a, "/");
433 k = strcspn(b, "/");
434
435 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
436 d = memcmp(a, b, MIN(j, k));
437 if (d)
438 return (d > 0) - (d < 0); /* sign of d */
439
440 /* Sort "/foo/a" before "/foo/aaa" */
441 d = (j > k) - (j < k); /* sign of (j - k) */
442 if (d)
443 return d;
444
445 a += j;
446 b += k;
447 }
448 }
449
450 bool path_equal(const char *a, const char *b) {
451 return path_compare(a, b) == 0;
452 }
453
454 bool path_equal_or_files_same(const char *a, const char *b) {
455 return path_equal(a, b) || files_same(a, b) > 0;
456 }
457
458 char* path_join(const char *root, const char *path, const char *rest) {
459 assert(path);
460
461 if (!isempty(root))
462 return strjoin(root, endswith(root, "/") ? "" : "/",
463 path[0] == '/' ? path+1 : path,
464 rest ? (endswith(path, "/") ? "" : "/") : NULL,
465 rest && rest[0] == '/' ? rest+1 : rest,
466 NULL);
467 else
468 return strjoin(path,
469 rest ? (endswith(path, "/") ? "" : "/") : NULL,
470 rest && rest[0] == '/' ? rest+1 : rest,
471 NULL);
472 }
473
474 static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
475 char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
476 _cleanup_free_ char *fdinfo = NULL;
477 _cleanup_close_ int subfd = -1;
478 char *p;
479 int r;
480
481 if ((flags & AT_EMPTY_PATH) && isempty(filename))
482 xsprintf(path, "/proc/self/fdinfo/%i", fd);
483 else {
484 subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
485 if (subfd < 0)
486 return -errno;
487
488 xsprintf(path, "/proc/self/fdinfo/%i", subfd);
489 }
490
491 r = read_full_file(path, &fdinfo, NULL);
492 if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
493 return -EOPNOTSUPP;
494 if (r < 0)
495 return -errno;
496
497 p = startswith(fdinfo, "mnt_id:");
498 if (!p) {
499 p = strstr(fdinfo, "\nmnt_id:");
500 if (!p) /* The mnt_id field is a relatively new addition */
501 return -EOPNOTSUPP;
502
503 p += 8;
504 }
505
506 p += strspn(p, WHITESPACE);
507 p[strcspn(p, WHITESPACE)] = 0;
508
509 return safe_atoi(p, mnt_id);
510 }
511
512 int fd_is_mount_point(int fd, const char *filename, int flags) {
513 union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
514 int mount_id = -1, mount_id_parent = -1;
515 bool nosupp = false, check_st_dev = true;
516 struct stat a, b;
517 int r;
518
519 assert(fd >= 0);
520 assert(filename);
521
522 /* First we will try the name_to_handle_at() syscall, which
523 * tells us the mount id and an opaque file "handle". It is
524 * not supported everywhere though (kernel compile-time
525 * option, not all file systems are hooked up). If it works
526 * the mount id is usually good enough to tell us whether
527 * something is a mount point.
528 *
529 * If that didn't work we will try to read the mount id from
530 * /proc/self/fdinfo/<fd>. This is almost as good as
531 * name_to_handle_at(), however, does not return the the
532 * opaque file handle. The opaque file handle is pretty useful
533 * to detect the root directory, which we should always
534 * consider a mount point. Hence we use this only as
535 * fallback. Exporting the mnt_id in fdinfo is a pretty recent
536 * kernel addition.
537 *
538 * As last fallback we do traditional fstat() based st_dev
539 * comparisons. This is how things were traditionally done,
540 * but unionfs breaks breaks this since it exposes file
541 * systems with a variety of st_dev reported. Also, btrfs
542 * subvolumes have different st_dev, even though they aren't
543 * real mounts of their own. */
544
545 r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
546 if (r < 0) {
547 if (errno == ENOSYS)
548 /* This kernel does not support name_to_handle_at()
549 * fall back to simpler logic. */
550 goto fallback_fdinfo;
551 else if (errno == EOPNOTSUPP)
552 /* This kernel or file system does not support
553 * name_to_handle_at(), hence let's see if the
554 * upper fs supports it (in which case it is a
555 * mount point), otherwise fallback to the
556 * traditional stat() logic */
557 nosupp = true;
558 else
559 return -errno;
560 }
561
562 r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
563 if (r < 0) {
564 if (errno == EOPNOTSUPP) {
565 if (nosupp)
566 /* Neither parent nor child do name_to_handle_at()?
567 We have no choice but to fall back. */
568 goto fallback_fdinfo;
569 else
570 /* The parent can't do name_to_handle_at() but the
571 * directory we are interested in can?
572 * If so, it must be a mount point. */
573 return 1;
574 } else
575 return -errno;
576 }
577
578 /* The parent can do name_to_handle_at() but the
579 * directory we are interested in can't? If so, it
580 * must be a mount point. */
581 if (nosupp)
582 return 1;
583
584 /* If the file handle for the directory we are
585 * interested in and its parent are identical, we
586 * assume this is the root directory, which is a mount
587 * point. */
588
589 if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
590 h.handle.handle_type == h_parent.handle.handle_type &&
591 memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
592 return 1;
593
594 return mount_id != mount_id_parent;
595
596 fallback_fdinfo:
597 r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
598 if (r == -EOPNOTSUPP)
599 goto fallback_fstat;
600 if (r < 0)
601 return r;
602
603 r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
604 if (r < 0)
605 return r;
606
607 if (mount_id != mount_id_parent)
608 return 1;
609
610 /* Hmm, so, the mount ids are the same. This leaves one
611 * special case though for the root file system. For that,
612 * let's see if the parent directory has the same inode as we
613 * are interested in. Hence, let's also do fstat() checks now,
614 * too, but avoid the st_dev comparisons, since they aren't
615 * that useful on unionfs mounts. */
616 check_st_dev = false;
617
618 fallback_fstat:
619 /* yay for fstatat() taking a different set of flags than the other
620 * _at() above */
621 if (flags & AT_SYMLINK_FOLLOW)
622 flags &= ~AT_SYMLINK_FOLLOW;
623 else
624 flags |= AT_SYMLINK_NOFOLLOW;
625 if (fstatat(fd, filename, &a, flags) < 0)
626 return -errno;
627
628 if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
629 return -errno;
630
631 /* A directory with same device and inode as its parent? Must
632 * be the root directory */
633 if (a.st_dev == b.st_dev &&
634 a.st_ino == b.st_ino)
635 return 1;
636
637 return check_st_dev && (a.st_dev != b.st_dev);
638 }
639
640 /* flags can be AT_SYMLINK_FOLLOW or 0 */
641 int path_is_mount_point(const char *t, int flags) {
642 _cleanup_close_ int fd = -1;
643 _cleanup_free_ char *canonical = NULL, *parent = NULL;
644 int r;
645
646 assert(t);
647
648 if (path_equal(t, "/"))
649 return 1;
650
651 /* we need to resolve symlinks manually, we can't just rely on
652 * fd_is_mount_point() to do that for us; if we have a structure like
653 * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
654 * look at needs to be /usr, not /. */
655 if (flags & AT_SYMLINK_FOLLOW) {
656 canonical = canonicalize_file_name(t);
657 if (!canonical)
658 return -errno;
659 }
660
661 r = path_get_parent(canonical ?: t, &parent);
662 if (r < 0)
663 return r;
664
665 fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
666 if (fd < 0)
667 return -errno;
668
669 return fd_is_mount_point(fd, basename(canonical ?: t), flags);
670 }
671
672 int path_is_read_only_fs(const char *path) {
673 struct statvfs st;
674
675 assert(path);
676
677 if (statvfs(path, &st) < 0)
678 return -errno;
679
680 if (st.f_flag & ST_RDONLY)
681 return true;
682
683 /* On NFS, statvfs() might not reflect whether we can actually
684 * write to the remote share. Let's try again with
685 * access(W_OK) which is more reliable, at least sometimes. */
686 if (access(path, W_OK) < 0 && errno == EROFS)
687 return true;
688
689 return false;
690 }
691
692 int path_is_os_tree(const char *path) {
693 char *p;
694 int r;
695
696 /* We use /usr/lib/os-release as flag file if something is an OS */
697 p = strjoina(path, "/usr/lib/os-release");
698 r = access(p, F_OK);
699
700 if (r >= 0)
701 return 1;
702
703 /* Also check for the old location in /etc, just in case. */
704 p = strjoina(path, "/etc/os-release");
705 r = access(p, F_OK);
706
707 return r >= 0;
708 }
709
710 int find_binary(const char *name, bool local, char **filename) {
711 assert(name);
712
713 if (is_path(name)) {
714 if (local && access(name, X_OK) < 0)
715 return -errno;
716
717 if (filename) {
718 char *p;
719
720 p = path_make_absolute_cwd(name);
721 if (!p)
722 return -ENOMEM;
723
724 *filename = p;
725 }
726
727 return 0;
728 } else {
729 const char *path;
730 const char *word, *state;
731 size_t l;
732
733 /**
734 * Plain getenv, not secure_getenv, because we want
735 * to actually allow the user to pick the binary.
736 */
737 path = getenv("PATH");
738 if (!path)
739 path = DEFAULT_PATH;
740
741 FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
742 _cleanup_free_ char *p = NULL;
743
744 if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
745 return -ENOMEM;
746
747 if (access(p, X_OK) < 0)
748 continue;
749
750 if (filename) {
751 *filename = path_kill_slashes(p);
752 p = NULL;
753 }
754
755 return 0;
756 }
757
758 return -ENOENT;
759 }
760 }
761
762 bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
763 bool changed = false;
764 const char* const* i;
765
766 assert(timestamp);
767
768 if (paths == NULL)
769 return false;
770
771 STRV_FOREACH(i, paths) {
772 struct stat stats;
773 usec_t u;
774
775 if (stat(*i, &stats) < 0)
776 continue;
777
778 u = timespec_load(&stats.st_mtim);
779
780 /* first check */
781 if (*timestamp >= u)
782 continue;
783
784 log_debug("timestamp of '%s' changed", *i);
785
786 /* update timestamp */
787 if (update) {
788 *timestamp = u;
789 changed = true;
790 } else
791 return true;
792 }
793
794 return changed;
795 }
796
797 int fsck_exists(const char *fstype) {
798 _cleanup_free_ char *p = NULL, *d = NULL;
799 const char *checker;
800 int r;
801
802 checker = strjoina("fsck.", fstype);
803
804 r = find_binary(checker, true, &p);
805 if (r < 0)
806 return r;
807
808 /* An fsck that is linked to /bin/true is a non-existent
809 * fsck */
810
811 r = readlink_malloc(p, &d);
812 if (r >= 0 &&
813 (path_equal(d, "/bin/true") ||
814 path_equal(d, "/usr/bin/true") ||
815 path_equal(d, "/dev/null")))
816 return -ENOENT;
817
818 return 0;
819 }
820
821 char *prefix_root(const char *root, const char *path) {
822 char *n, *p;
823 size_t l;
824
825 /* If root is passed, prefixes path with it. Otherwise returns
826 * it as is. */
827
828 assert(path);
829
830 /* First, drop duplicate prefixing slashes from the path */
831 while (path[0] == '/' && path[1] == '/')
832 path++;
833
834 if (isempty(root) || path_equal(root, "/"))
835 return strdup(path);
836
837 l = strlen(root) + 1 + strlen(path) + 1;
838
839 n = new(char, l);
840 if (!n)
841 return NULL;
842
843 p = stpcpy(n, root);
844
845 while (p > n && p[-1] == '/')
846 p--;
847
848 if (path[0] != '/')
849 *(p++) = '/';
850
851 strcpy(p, path);
852 return n;
853 }