1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010-2012 Lennart Poettering
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.
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.
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/>.
28 #include <sys/statvfs.h>
34 #include "path-util.h"
38 bool path_is_absolute(const char *p
) {
42 bool is_path(const char *p
) {
43 return !!strchr(p
, '/');
46 int path_get_parent(const char *path
, char **_r
) {
47 const char *e
, *a
= NULL
, *b
= NULL
, *p
;
57 for (e
= path
; *e
; e
++) {
59 if (!slash
&& *e
== '/') {
63 } else if (slash
&& *e
!= '/')
78 r
= strndup(path
, p
-path
);
87 int path_split_and_make_absolute(const char *p
, char ***ret
) {
94 l
= strv_split(p
, ":");
98 r
= path_strv_make_absolute_cwd(l
);
108 char *path_make_absolute(const char *p
, const char *prefix
) {
111 /* Makes every item in the list an absolute path by prepending
112 * the prefix, if specified and necessary */
114 if (path_is_absolute(p
) || !prefix
)
117 return strjoin(prefix
, "/", p
, NULL
);
120 int path_make_absolute_cwd(const char *p
, char **ret
) {
126 /* Similar to path_make_absolute(), but prefixes with the
127 * current working directory. */
129 if (path_is_absolute(p
))
132 _cleanup_free_
char *cwd
= NULL
;
134 cwd
= get_current_dir_name();
138 c
= strjoin(cwd
, "/", p
, NULL
);
147 int path_make_relative(const char *from_dir
, const char *to_path
, char **_r
) {
155 /* Strips the common part, and adds ".." elements as necessary. */
157 if (!path_is_absolute(from_dir
))
160 if (!path_is_absolute(to_path
))
163 /* Skip the common part. */
168 from_dir
+= strspn(from_dir
, "/");
169 to_path
+= strspn(to_path
, "/");
173 /* from_dir equals to_path. */
176 /* from_dir is a parent directory of to_path. */
182 path_kill_slashes(r
);
191 a
= strcspn(from_dir
, "/");
192 b
= strcspn(to_path
, "/");
197 if (memcmp(from_dir
, to_path
, a
) != 0)
204 /* If we're here, then "from_dir" has one or more elements that need to
205 * be replaced with "..". */
207 /* Count the number of necessary ".." elements. */
208 for (n_parents
= 0;;) {
209 from_dir
+= strspn(from_dir
, "/");
214 from_dir
+= strcspn(from_dir
, "/");
218 r
= malloc(n_parents
* 3 + strlen(to_path
) + 1);
222 for (p
= r
; n_parents
> 0; n_parents
--, p
+= 3)
226 path_kill_slashes(r
);
232 int path_strv_make_absolute_cwd(char **l
) {
236 /* Goes through every item in the string list and makes it
237 * absolute. This works in place and won't rollback any
238 * changes on failure. */
243 r
= path_make_absolute_cwd(*s
, &t
);
254 char **path_strv_resolve(char **l
, const char *prefix
) {
262 /* Goes through every item in the string list and canonicalize
263 * the path. This works in place and won't rollback any
264 * changes on failure. */
268 _cleanup_free_
char *orig
= NULL
;
270 if (!path_is_absolute(*s
)) {
277 t
= strappend(prefix
, orig
);
286 u
= canonicalize_file_name(t
);
288 if (errno
== ENOENT
) {
297 if (errno
== ENOMEM
|| errno
== 0)
306 x
= path_startswith(u
, prefix
);
308 /* restore the slash if it was lost */
309 if (!startswith(x
, "/"))
320 /* canonicalized path goes outside of
321 * prefix, keep the original path instead */
340 char **path_strv_resolve_uniq(char **l
, const char *prefix
) {
345 if (!path_strv_resolve(l
, prefix
))
351 char *path_kill_slashes(char *path
) {
355 /* Removes redundant inner and trailing slashes. Modifies the
356 * passed string in-place.
358 * ///foo///bar/ becomes /foo/bar
361 for (f
= path
, t
= path
; *f
; f
++) {
376 /* Special rule, if we are talking of the root directory, a
377 trailing slash is good */
379 if (t
== path
&& slash
)
386 char* path_startswith(const char *path
, const char *prefix
) {
390 if ((path
[0] == '/') != (prefix
[0] == '/'))
396 path
+= strspn(path
, "/");
397 prefix
+= strspn(prefix
, "/");
405 a
= strcspn(path
, "/");
406 b
= strcspn(prefix
, "/");
411 if (memcmp(path
, prefix
, a
) != 0)
419 int path_compare(const char *a
, const char *b
) {
425 /* A relative path and an abolute path must not compare as equal.
426 * Which one is sorted before the other does not really matter.
427 * Here a relative path is ordered before an absolute path. */
428 d
= (a
[0] == '/') - (b
[0] == '/');
438 if (*a
== 0 && *b
== 0)
441 /* Order prefixes first: "/foo" before "/foo/bar" */
450 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
451 d
= memcmp(a
, b
, MIN(j
, k
));
453 return (d
> 0) - (d
< 0); /* sign of d */
455 /* Sort "/foo/a" before "/foo/aaa" */
456 d
= (j
> k
) - (j
< k
); /* sign of (j - k) */
465 bool path_equal(const char *a
, const char *b
) {
466 return path_compare(a
, b
) == 0;
469 bool path_equal_or_files_same(const char *a
, const char *b
) {
470 return path_equal(a
, b
) || files_same(a
, b
) > 0;
473 char* path_join(const char *root
, const char *path
, const char *rest
) {
477 return strjoin(root
, endswith(root
, "/") ? "" : "/",
478 path
[0] == '/' ? path
+1 : path
,
479 rest
? (endswith(path
, "/") ? "" : "/") : NULL
,
480 rest
&& rest
[0] == '/' ? rest
+1 : rest
,
484 rest
? (endswith(path
, "/") ? "" : "/") : NULL
,
485 rest
&& rest
[0] == '/' ? rest
+1 : rest
,
489 static int fd_fdinfo_mnt_id(int fd
, const char *filename
, int flags
, int *mnt_id
) {
490 char path
[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
491 _cleanup_free_
char *fdinfo
= NULL
;
492 _cleanup_close_
int subfd
= -1;
496 if ((flags
& AT_EMPTY_PATH
) && isempty(filename
))
497 xsprintf(path
, "/proc/self/fdinfo/%i", fd
);
499 subfd
= openat(fd
, filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_PATH
);
503 xsprintf(path
, "/proc/self/fdinfo/%i", subfd
);
506 r
= read_full_file(path
, &fdinfo
, NULL
);
507 if (r
== -ENOENT
) /* The fdinfo directory is a relatively new addition */
512 p
= startswith(fdinfo
, "mnt_id:");
514 p
= strstr(fdinfo
, "\nmnt_id:");
515 if (!p
) /* The mnt_id field is a relatively new addition */
521 p
+= strspn(p
, WHITESPACE
);
522 p
[strcspn(p
, WHITESPACE
)] = 0;
524 return safe_atoi(p
, mnt_id
);
527 int fd_is_mount_point(int fd
, const char *filename
, int flags
) {
528 union file_handle_union h
= FILE_HANDLE_INIT
, h_parent
= FILE_HANDLE_INIT
;
529 int mount_id
= -1, mount_id_parent
= -1;
530 bool nosupp
= false, check_st_dev
= true;
537 /* First we will try the name_to_handle_at() syscall, which
538 * tells us the mount id and an opaque file "handle". It is
539 * not supported everywhere though (kernel compile-time
540 * option, not all file systems are hooked up). If it works
541 * the mount id is usually good enough to tell us whether
542 * something is a mount point.
544 * If that didn't work we will try to read the mount id from
545 * /proc/self/fdinfo/<fd>. This is almost as good as
546 * name_to_handle_at(), however, does not return the
547 * opaque file handle. The opaque file handle is pretty useful
548 * to detect the root directory, which we should always
549 * consider a mount point. Hence we use this only as
550 * fallback. Exporting the mnt_id in fdinfo is a pretty recent
553 * As last fallback we do traditional fstat() based st_dev
554 * comparisons. This is how things were traditionally done,
555 * but unionfs breaks breaks this since it exposes file
556 * systems with a variety of st_dev reported. Also, btrfs
557 * subvolumes have different st_dev, even though they aren't
558 * real mounts of their own. */
560 r
= name_to_handle_at(fd
, filename
, &h
.handle
, &mount_id
, flags
);
563 /* This kernel does not support name_to_handle_at()
564 * fall back to simpler logic. */
565 goto fallback_fdinfo
;
566 else if (errno
== EOPNOTSUPP
)
567 /* This kernel or file system does not support
568 * name_to_handle_at(), hence let's see if the
569 * upper fs supports it (in which case it is a
570 * mount point), otherwise fallback to the
571 * traditional stat() logic */
577 r
= name_to_handle_at(fd
, "", &h_parent
.handle
, &mount_id_parent
, AT_EMPTY_PATH
);
579 if (errno
== EOPNOTSUPP
) {
581 /* Neither parent nor child do name_to_handle_at()?
582 We have no choice but to fall back. */
583 goto fallback_fdinfo
;
585 /* The parent can't do name_to_handle_at() but the
586 * directory we are interested in can?
587 * If so, it must be a mount point. */
593 /* The parent can do name_to_handle_at() but the
594 * directory we are interested in can't? If so, it
595 * must be a mount point. */
599 /* If the file handle for the directory we are
600 * interested in and its parent are identical, we
601 * assume this is the root directory, which is a mount
604 if (h
.handle
.handle_bytes
== h_parent
.handle
.handle_bytes
&&
605 h
.handle
.handle_type
== h_parent
.handle
.handle_type
&&
606 memcmp(h
.handle
.f_handle
, h_parent
.handle
.f_handle
, h
.handle
.handle_bytes
) == 0)
609 return mount_id
!= mount_id_parent
;
612 r
= fd_fdinfo_mnt_id(fd
, filename
, flags
, &mount_id
);
613 if (r
== -EOPNOTSUPP
)
618 r
= fd_fdinfo_mnt_id(fd
, "", AT_EMPTY_PATH
, &mount_id_parent
);
622 if (mount_id
!= mount_id_parent
)
625 /* Hmm, so, the mount ids are the same. This leaves one
626 * special case though for the root file system. For that,
627 * let's see if the parent directory has the same inode as we
628 * are interested in. Hence, let's also do fstat() checks now,
629 * too, but avoid the st_dev comparisons, since they aren't
630 * that useful on unionfs mounts. */
631 check_st_dev
= false;
634 /* yay for fstatat() taking a different set of flags than the other
636 if (flags
& AT_SYMLINK_FOLLOW
)
637 flags
&= ~AT_SYMLINK_FOLLOW
;
639 flags
|= AT_SYMLINK_NOFOLLOW
;
640 if (fstatat(fd
, filename
, &a
, flags
) < 0)
643 if (fstatat(fd
, "", &b
, AT_EMPTY_PATH
) < 0)
646 /* A directory with same device and inode as its parent? Must
647 * be the root directory */
648 if (a
.st_dev
== b
.st_dev
&&
649 a
.st_ino
== b
.st_ino
)
652 return check_st_dev
&& (a
.st_dev
!= b
.st_dev
);
655 /* flags can be AT_SYMLINK_FOLLOW or 0 */
656 int path_is_mount_point(const char *t
, int flags
) {
657 _cleanup_close_
int fd
= -1;
658 _cleanup_free_
char *canonical
= NULL
, *parent
= NULL
;
663 if (path_equal(t
, "/"))
666 /* we need to resolve symlinks manually, we can't just rely on
667 * fd_is_mount_point() to do that for us; if we have a structure like
668 * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
669 * look at needs to be /usr, not /. */
670 if (flags
& AT_SYMLINK_FOLLOW
) {
671 canonical
= canonicalize_file_name(t
);
678 r
= path_get_parent(t
, &parent
);
682 fd
= openat(AT_FDCWD
, parent
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_PATH
);
686 return fd_is_mount_point(fd
, basename(t
), flags
);
689 int path_is_read_only_fs(const char *path
) {
694 if (statvfs(path
, &st
) < 0)
697 if (st
.f_flag
& ST_RDONLY
)
700 /* On NFS, statvfs() might not reflect whether we can actually
701 * write to the remote share. Let's try again with
702 * access(W_OK) which is more reliable, at least sometimes. */
703 if (access(path
, W_OK
) < 0 && errno
== EROFS
)
709 int path_is_os_tree(const char *path
) {
713 /* We use /usr/lib/os-release as flag file if something is an OS */
714 p
= strjoina(path
, "/usr/lib/os-release");
719 /* Also check for the old location in /etc, just in case. */
720 p
= strjoina(path
, "/etc/os-release");
726 int find_binary(const char *name
, char **ret
) {
733 if (access(name
, X_OK
) < 0)
737 r
= path_make_absolute_cwd(name
, ret
);
746 * Plain getenv, not secure_getenv, because we want
747 * to actually allow the user to pick the binary.
753 last_error
= -ENOENT
;
756 _cleanup_free_
char *j
= NULL
, *element
= NULL
;
758 r
= extract_first_word(&p
, &element
, ":", EXTRACT_RELAX
|EXTRACT_DONT_COALESCE_SEPARATORS
);
764 if (!path_is_absolute(element
))
767 j
= strjoin(element
, "/", name
, NULL
);
771 if (access(j
, X_OK
) >= 0) {
775 *ret
= path_kill_slashes(j
);
788 bool paths_check_timestamp(const char* const* paths
, usec_t
*timestamp
, bool update
) {
789 bool changed
= false;
790 const char* const* i
;
797 STRV_FOREACH(i
, paths
) {
801 if (stat(*i
, &stats
) < 0)
804 u
= timespec_load(&stats
.st_mtim
);
810 log_debug("timestamp of '%s' changed", *i
);
812 /* update timestamp */
823 static int binary_is_good(const char *binary
) {
824 _cleanup_free_
char *p
= NULL
, *d
= NULL
;
827 r
= find_binary(binary
, &p
);
833 /* An fsck that is linked to /bin/true is a non-existent
836 r
= readlink_malloc(p
, &d
);
837 if (r
== -EINVAL
) /* not a symlink */
842 return !path_equal(d
, "true") &&
843 !path_equal(d
, "/bin/true") &&
844 !path_equal(d
, "/usr/bin/true") &&
845 !path_equal(d
, "/dev/null");
848 int fsck_exists(const char *fstype
) {
853 if (streq(fstype
, "auto"))
856 checker
= strjoina("fsck.", fstype
);
857 return binary_is_good(checker
);
860 int mkfs_exists(const char *fstype
) {
865 if (streq(fstype
, "auto"))
868 mkfs
= strjoina("mkfs.", fstype
);
869 return binary_is_good(mkfs
);
872 char *prefix_root(const char *root
, const char *path
) {
876 /* If root is passed, prefixes path with it. Otherwise returns
881 /* First, drop duplicate prefixing slashes from the path */
882 while (path
[0] == '/' && path
[1] == '/')
885 if (isempty(root
) || path_equal(root
, "/"))
888 l
= strlen(root
) + 1 + strlen(path
) + 1;
896 while (p
> n
&& p
[-1] == '/')
906 int parse_path_argument_and_warn(const char *path
, bool suppress_root
, char **arg
) {
911 * This function is intended to be used in command line
912 * parsers, to handle paths that are passed in. It makes the
913 * path absolute, and reduces it to NULL if omitted or
914 * root (the latter optionally).
916 * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
917 * SUCCESS! Hence, do not pass in uninitialized pointers.
925 r
= path_make_absolute_cwd(path
, &p
);
927 return log_error_errno(r
, "Failed to parse path \"%s\" and make it absolute: %m", path
);
929 path_kill_slashes(p
);
930 if (suppress_root
&& path_equal(p
, "/"))