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/>.
27 #include <sys/statvfs.h>
35 #include "path-util.h"
36 #include "string-util.h"
40 bool path_is_absolute(const char *p
) {
44 bool is_path(const char *p
) {
45 return !!strchr(p
, '/');
48 int path_get_parent(const char *path
, char **_r
) {
49 const char *e
, *a
= NULL
, *b
= NULL
, *p
;
59 for (e
= path
; *e
; e
++) {
61 if (!slash
&& *e
== '/') {
65 } else if (slash
&& *e
!= '/')
80 r
= strndup(path
, p
-path
);
89 int path_split_and_make_absolute(const char *p
, char ***ret
) {
96 l
= strv_split(p
, ":");
100 r
= path_strv_make_absolute_cwd(l
);
110 char *path_make_absolute(const char *p
, const char *prefix
) {
113 /* Makes every item in the list an absolute path by prepending
114 * the prefix, if specified and necessary */
116 if (path_is_absolute(p
) || !prefix
)
119 return strjoin(prefix
, "/", p
, NULL
);
122 int path_make_absolute_cwd(const char *p
, char **ret
) {
128 /* Similar to path_make_absolute(), but prefixes with the
129 * current working directory. */
131 if (path_is_absolute(p
))
134 _cleanup_free_
char *cwd
= NULL
;
136 cwd
= get_current_dir_name();
140 c
= strjoin(cwd
, "/", p
, NULL
);
149 int path_make_relative(const char *from_dir
, const char *to_path
, char **_r
) {
157 /* Strips the common part, and adds ".." elements as necessary. */
159 if (!path_is_absolute(from_dir
))
162 if (!path_is_absolute(to_path
))
165 /* Skip the common part. */
170 from_dir
+= strspn(from_dir
, "/");
171 to_path
+= strspn(to_path
, "/");
175 /* from_dir equals to_path. */
178 /* from_dir is a parent directory of to_path. */
184 path_kill_slashes(r
);
193 a
= strcspn(from_dir
, "/");
194 b
= strcspn(to_path
, "/");
199 if (memcmp(from_dir
, to_path
, a
) != 0)
206 /* If we're here, then "from_dir" has one or more elements that need to
207 * be replaced with "..". */
209 /* Count the number of necessary ".." elements. */
210 for (n_parents
= 0;;) {
211 from_dir
+= strspn(from_dir
, "/");
216 from_dir
+= strcspn(from_dir
, "/");
220 r
= malloc(n_parents
* 3 + strlen(to_path
) + 1);
224 for (p
= r
; n_parents
> 0; n_parents
--, p
+= 3)
228 path_kill_slashes(r
);
234 int path_strv_make_absolute_cwd(char **l
) {
238 /* Goes through every item in the string list and makes it
239 * absolute. This works in place and won't rollback any
240 * changes on failure. */
245 r
= path_make_absolute_cwd(*s
, &t
);
256 char **path_strv_resolve(char **l
, const char *prefix
) {
264 /* Goes through every item in the string list and canonicalize
265 * the path. This works in place and won't rollback any
266 * changes on failure. */
270 _cleanup_free_
char *orig
= NULL
;
272 if (!path_is_absolute(*s
)) {
279 t
= strappend(prefix
, orig
);
288 u
= canonicalize_file_name(t
);
290 if (errno
== ENOENT
) {
299 if (errno
== ENOMEM
|| errno
== 0)
308 x
= path_startswith(u
, prefix
);
310 /* restore the slash if it was lost */
311 if (!startswith(x
, "/"))
322 /* canonicalized path goes outside of
323 * prefix, keep the original path instead */
342 char **path_strv_resolve_uniq(char **l
, const char *prefix
) {
347 if (!path_strv_resolve(l
, prefix
))
353 char *path_kill_slashes(char *path
) {
357 /* Removes redundant inner and trailing slashes. Modifies the
358 * passed string in-place.
360 * ///foo///bar/ becomes /foo/bar
363 for (f
= path
, t
= path
; *f
; f
++) {
378 /* Special rule, if we are talking of the root directory, a
379 trailing slash is good */
381 if (t
== path
&& slash
)
388 char* path_startswith(const char *path
, const char *prefix
) {
392 if ((path
[0] == '/') != (prefix
[0] == '/'))
398 path
+= strspn(path
, "/");
399 prefix
+= strspn(prefix
, "/");
407 a
= strcspn(path
, "/");
408 b
= strcspn(prefix
, "/");
413 if (memcmp(path
, prefix
, a
) != 0)
421 int path_compare(const char *a
, const char *b
) {
427 /* A relative path and an abolute path must not compare as equal.
428 * Which one is sorted before the other does not really matter.
429 * Here a relative path is ordered before an absolute path. */
430 d
= (a
[0] == '/') - (b
[0] == '/');
440 if (*a
== 0 && *b
== 0)
443 /* Order prefixes first: "/foo" before "/foo/bar" */
452 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
453 d
= memcmp(a
, b
, MIN(j
, k
));
455 return (d
> 0) - (d
< 0); /* sign of d */
457 /* Sort "/foo/a" before "/foo/aaa" */
458 d
= (j
> k
) - (j
< k
); /* sign of (j - k) */
467 bool path_equal(const char *a
, const char *b
) {
468 return path_compare(a
, b
) == 0;
471 bool path_equal_or_files_same(const char *a
, const char *b
) {
472 return path_equal(a
, b
) || files_same(a
, b
) > 0;
475 char* path_join(const char *root
, const char *path
, const char *rest
) {
479 return strjoin(root
, endswith(root
, "/") ? "" : "/",
480 path
[0] == '/' ? path
+1 : path
,
481 rest
? (endswith(path
, "/") ? "" : "/") : NULL
,
482 rest
&& rest
[0] == '/' ? rest
+1 : rest
,
486 rest
? (endswith(path
, "/") ? "" : "/") : NULL
,
487 rest
&& rest
[0] == '/' ? rest
+1 : rest
,
491 static int fd_fdinfo_mnt_id(int fd
, const char *filename
, int flags
, int *mnt_id
) {
492 char path
[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
493 _cleanup_free_
char *fdinfo
= NULL
;
494 _cleanup_close_
int subfd
= -1;
498 if ((flags
& AT_EMPTY_PATH
) && isempty(filename
))
499 xsprintf(path
, "/proc/self/fdinfo/%i", fd
);
501 subfd
= openat(fd
, filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_PATH
);
505 xsprintf(path
, "/proc/self/fdinfo/%i", subfd
);
508 r
= read_full_file(path
, &fdinfo
, NULL
);
509 if (r
== -ENOENT
) /* The fdinfo directory is a relatively new addition */
514 p
= startswith(fdinfo
, "mnt_id:");
516 p
= strstr(fdinfo
, "\nmnt_id:");
517 if (!p
) /* The mnt_id field is a relatively new addition */
523 p
+= strspn(p
, WHITESPACE
);
524 p
[strcspn(p
, WHITESPACE
)] = 0;
526 return safe_atoi(p
, mnt_id
);
529 int fd_is_mount_point(int fd
, const char *filename
, int flags
) {
530 union file_handle_union h
= FILE_HANDLE_INIT
, h_parent
= FILE_HANDLE_INIT
;
531 int mount_id
= -1, mount_id_parent
= -1;
532 bool nosupp
= false, check_st_dev
= true;
539 /* First we will try the name_to_handle_at() syscall, which
540 * tells us the mount id and an opaque file "handle". It is
541 * not supported everywhere though (kernel compile-time
542 * option, not all file systems are hooked up). If it works
543 * the mount id is usually good enough to tell us whether
544 * something is a mount point.
546 * If that didn't work we will try to read the mount id from
547 * /proc/self/fdinfo/<fd>. This is almost as good as
548 * name_to_handle_at(), however, does not return the
549 * opaque file handle. The opaque file handle is pretty useful
550 * to detect the root directory, which we should always
551 * consider a mount point. Hence we use this only as
552 * fallback. Exporting the mnt_id in fdinfo is a pretty recent
555 * As last fallback we do traditional fstat() based st_dev
556 * comparisons. This is how things were traditionally done,
557 * but unionfs breaks breaks this since it exposes file
558 * systems with a variety of st_dev reported. Also, btrfs
559 * subvolumes have different st_dev, even though they aren't
560 * real mounts of their own. */
562 r
= name_to_handle_at(fd
, filename
, &h
.handle
, &mount_id
, flags
);
565 /* This kernel does not support name_to_handle_at()
566 * fall back to simpler logic. */
567 goto fallback_fdinfo
;
568 else if (errno
== EOPNOTSUPP
)
569 /* This kernel or file system does not support
570 * name_to_handle_at(), hence let's see if the
571 * upper fs supports it (in which case it is a
572 * mount point), otherwise fallback to the
573 * traditional stat() logic */
579 r
= name_to_handle_at(fd
, "", &h_parent
.handle
, &mount_id_parent
, AT_EMPTY_PATH
);
581 if (errno
== EOPNOTSUPP
) {
583 /* Neither parent nor child do name_to_handle_at()?
584 We have no choice but to fall back. */
585 goto fallback_fdinfo
;
587 /* The parent can't do name_to_handle_at() but the
588 * directory we are interested in can?
589 * If so, it must be a mount point. */
595 /* The parent can do name_to_handle_at() but the
596 * directory we are interested in can't? If so, it
597 * must be a mount point. */
601 /* If the file handle for the directory we are
602 * interested in and its parent are identical, we
603 * assume this is the root directory, which is a mount
606 if (h
.handle
.handle_bytes
== h_parent
.handle
.handle_bytes
&&
607 h
.handle
.handle_type
== h_parent
.handle
.handle_type
&&
608 memcmp(h
.handle
.f_handle
, h_parent
.handle
.f_handle
, h
.handle
.handle_bytes
) == 0)
611 return mount_id
!= mount_id_parent
;
614 r
= fd_fdinfo_mnt_id(fd
, filename
, flags
, &mount_id
);
615 if (r
== -EOPNOTSUPP
)
620 r
= fd_fdinfo_mnt_id(fd
, "", AT_EMPTY_PATH
, &mount_id_parent
);
624 if (mount_id
!= mount_id_parent
)
627 /* Hmm, so, the mount ids are the same. This leaves one
628 * special case though for the root file system. For that,
629 * let's see if the parent directory has the same inode as we
630 * are interested in. Hence, let's also do fstat() checks now,
631 * too, but avoid the st_dev comparisons, since they aren't
632 * that useful on unionfs mounts. */
633 check_st_dev
= false;
636 /* yay for fstatat() taking a different set of flags than the other
638 if (flags
& AT_SYMLINK_FOLLOW
)
639 flags
&= ~AT_SYMLINK_FOLLOW
;
641 flags
|= AT_SYMLINK_NOFOLLOW
;
642 if (fstatat(fd
, filename
, &a
, flags
) < 0)
645 if (fstatat(fd
, "", &b
, AT_EMPTY_PATH
) < 0)
648 /* A directory with same device and inode as its parent? Must
649 * be the root directory */
650 if (a
.st_dev
== b
.st_dev
&&
651 a
.st_ino
== b
.st_ino
)
654 return check_st_dev
&& (a
.st_dev
!= b
.st_dev
);
657 /* flags can be AT_SYMLINK_FOLLOW or 0 */
658 int path_is_mount_point(const char *t
, int flags
) {
659 _cleanup_close_
int fd
= -1;
660 _cleanup_free_
char *canonical
= NULL
, *parent
= NULL
;
665 if (path_equal(t
, "/"))
668 /* we need to resolve symlinks manually, we can't just rely on
669 * fd_is_mount_point() to do that for us; if we have a structure like
670 * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
671 * look at needs to be /usr, not /. */
672 if (flags
& AT_SYMLINK_FOLLOW
) {
673 canonical
= canonicalize_file_name(t
);
680 r
= path_get_parent(t
, &parent
);
684 fd
= openat(AT_FDCWD
, parent
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_PATH
);
688 return fd_is_mount_point(fd
, basename(t
), flags
);
691 int path_is_read_only_fs(const char *path
) {
696 if (statvfs(path
, &st
) < 0)
699 if (st
.f_flag
& ST_RDONLY
)
702 /* On NFS, statvfs() might not reflect whether we can actually
703 * write to the remote share. Let's try again with
704 * access(W_OK) which is more reliable, at least sometimes. */
705 if (access(path
, W_OK
) < 0 && errno
== EROFS
)
711 int path_is_os_tree(const char *path
) {
715 /* We use /usr/lib/os-release as flag file if something is an OS */
716 p
= strjoina(path
, "/usr/lib/os-release");
721 /* Also check for the old location in /etc, just in case. */
722 p
= strjoina(path
, "/etc/os-release");
728 int find_binary(const char *name
, char **ret
) {
735 if (access(name
, X_OK
) < 0)
739 r
= path_make_absolute_cwd(name
, ret
);
748 * Plain getenv, not secure_getenv, because we want
749 * to actually allow the user to pick the binary.
755 last_error
= -ENOENT
;
758 _cleanup_free_
char *j
= NULL
, *element
= NULL
;
760 r
= extract_first_word(&p
, &element
, ":", EXTRACT_RELAX
|EXTRACT_DONT_COALESCE_SEPARATORS
);
766 if (!path_is_absolute(element
))
769 j
= strjoin(element
, "/", name
, NULL
);
773 if (access(j
, X_OK
) >= 0) {
777 *ret
= path_kill_slashes(j
);
790 bool paths_check_timestamp(const char* const* paths
, usec_t
*timestamp
, bool update
) {
791 bool changed
= false;
792 const char* const* i
;
799 STRV_FOREACH(i
, paths
) {
803 if (stat(*i
, &stats
) < 0)
806 u
= timespec_load(&stats
.st_mtim
);
812 log_debug("timestamp of '%s' changed", *i
);
814 /* update timestamp */
825 static int binary_is_good(const char *binary
) {
826 _cleanup_free_
char *p
= NULL
, *d
= NULL
;
829 r
= find_binary(binary
, &p
);
835 /* An fsck that is linked to /bin/true is a non-existent
838 r
= readlink_malloc(p
, &d
);
839 if (r
== -EINVAL
) /* not a symlink */
844 return !path_equal(d
, "true") &&
845 !path_equal(d
, "/bin/true") &&
846 !path_equal(d
, "/usr/bin/true") &&
847 !path_equal(d
, "/dev/null");
850 int fsck_exists(const char *fstype
) {
855 if (streq(fstype
, "auto"))
858 checker
= strjoina("fsck.", fstype
);
859 return binary_is_good(checker
);
862 int mkfs_exists(const char *fstype
) {
867 if (streq(fstype
, "auto"))
870 mkfs
= strjoina("mkfs.", fstype
);
871 return binary_is_good(mkfs
);
874 char *prefix_root(const char *root
, const char *path
) {
878 /* If root is passed, prefixes path with it. Otherwise returns
883 /* First, drop duplicate prefixing slashes from the path */
884 while (path
[0] == '/' && path
[1] == '/')
887 if (isempty(root
) || path_equal(root
, "/"))
890 l
= strlen(root
) + 1 + strlen(path
) + 1;
898 while (p
> n
&& p
[-1] == '/')
908 int parse_path_argument_and_warn(const char *path
, bool suppress_root
, char **arg
) {
913 * This function is intended to be used in command line
914 * parsers, to handle paths that are passed in. It makes the
915 * path absolute, and reduces it to NULL if omitted or
916 * root (the latter optionally).
918 * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
919 * SUCCESS! Hence, do not pass in uninitialized pointers.
927 r
= path_make_absolute_cwd(path
, &p
);
929 return log_error_errno(r
, "Failed to parse path \"%s\" and make it absolute: %m", path
);
931 path_kill_slashes(p
);
932 if (suppress_root
&& path_equal(p
, "/"))