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>
34 #include "string-util.h"
37 #include "path-util.h"
39 bool path_is_absolute(const char *p
) {
43 bool is_path(const char *p
) {
44 return !!strchr(p
, '/');
47 int path_get_parent(const char *path
, char **_r
) {
48 const char *e
, *a
= NULL
, *b
= NULL
, *p
;
58 for (e
= path
; *e
; e
++) {
60 if (!slash
&& *e
== '/') {
64 } else if (slash
&& *e
!= '/')
79 r
= strndup(path
, p
-path
);
88 int path_split_and_make_absolute(const char *p
, char ***ret
) {
95 l
= strv_split(p
, ":");
99 r
= path_strv_make_absolute_cwd(l
);
109 char *path_make_absolute(const char *p
, const char *prefix
) {
112 /* Makes every item in the list an absolute path by prepending
113 * the prefix, if specified and necessary */
115 if (path_is_absolute(p
) || !prefix
)
118 return strjoin(prefix
, "/", p
, NULL
);
121 int path_make_absolute_cwd(const char *p
, char **ret
) {
127 /* Similar to path_make_absolute(), but prefixes with the
128 * current working directory. */
130 if (path_is_absolute(p
))
133 _cleanup_free_
char *cwd
= NULL
;
135 cwd
= get_current_dir_name();
139 c
= strjoin(cwd
, "/", p
, NULL
);
148 int path_make_relative(const char *from_dir
, const char *to_path
, char **_r
) {
156 /* Strips the common part, and adds ".." elements as necessary. */
158 if (!path_is_absolute(from_dir
))
161 if (!path_is_absolute(to_path
))
164 /* Skip the common part. */
169 from_dir
+= strspn(from_dir
, "/");
170 to_path
+= strspn(to_path
, "/");
174 /* from_dir equals to_path. */
177 /* from_dir is a parent directory of to_path. */
183 path_kill_slashes(r
);
192 a
= strcspn(from_dir
, "/");
193 b
= strcspn(to_path
, "/");
198 if (memcmp(from_dir
, to_path
, a
) != 0)
205 /* If we're here, then "from_dir" has one or more elements that need to
206 * be replaced with "..". */
208 /* Count the number of necessary ".." elements. */
209 for (n_parents
= 0;;) {
210 from_dir
+= strspn(from_dir
, "/");
215 from_dir
+= strcspn(from_dir
, "/");
219 r
= malloc(n_parents
* 3 + strlen(to_path
) + 1);
223 for (p
= r
; n_parents
> 0; n_parents
--, p
+= 3)
227 path_kill_slashes(r
);
233 int path_strv_make_absolute_cwd(char **l
) {
237 /* Goes through every item in the string list and makes it
238 * absolute. This works in place and won't rollback any
239 * changes on failure. */
244 r
= path_make_absolute_cwd(*s
, &t
);
255 char **path_strv_resolve(char **l
, const char *prefix
) {
263 /* Goes through every item in the string list and canonicalize
264 * the path. This works in place and won't rollback any
265 * changes on failure. */
269 _cleanup_free_
char *orig
= NULL
;
271 if (!path_is_absolute(*s
)) {
278 t
= strappend(prefix
, orig
);
287 u
= canonicalize_file_name(t
);
289 if (errno
== ENOENT
) {
298 if (errno
== ENOMEM
|| errno
== 0)
307 x
= path_startswith(u
, prefix
);
309 /* restore the slash if it was lost */
310 if (!startswith(x
, "/"))
321 /* canonicalized path goes outside of
322 * prefix, keep the original path instead */
341 char **path_strv_resolve_uniq(char **l
, const char *prefix
) {
346 if (!path_strv_resolve(l
, prefix
))
352 char *path_kill_slashes(char *path
) {
356 /* Removes redundant inner and trailing slashes. Modifies the
357 * passed string in-place.
359 * ///foo///bar/ becomes /foo/bar
362 for (f
= path
, t
= path
; *f
; f
++) {
377 /* Special rule, if we are talking of the root directory, a
378 trailing slash is good */
380 if (t
== path
&& slash
)
387 char* path_startswith(const char *path
, const char *prefix
) {
391 if ((path
[0] == '/') != (prefix
[0] == '/'))
397 path
+= strspn(path
, "/");
398 prefix
+= strspn(prefix
, "/");
406 a
= strcspn(path
, "/");
407 b
= strcspn(prefix
, "/");
412 if (memcmp(path
, prefix
, a
) != 0)
420 int path_compare(const char *a
, const char *b
) {
426 /* A relative path and an abolute path must not compare as equal.
427 * Which one is sorted before the other does not really matter.
428 * Here a relative path is ordered before an absolute path. */
429 d
= (a
[0] == '/') - (b
[0] == '/');
439 if (*a
== 0 && *b
== 0)
442 /* Order prefixes first: "/foo" before "/foo/bar" */
451 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
452 d
= memcmp(a
, b
, MIN(j
, k
));
454 return (d
> 0) - (d
< 0); /* sign of d */
456 /* Sort "/foo/a" before "/foo/aaa" */
457 d
= (j
> k
) - (j
< k
); /* sign of (j - k) */
466 bool path_equal(const char *a
, const char *b
) {
467 return path_compare(a
, b
) == 0;
470 bool path_equal_or_files_same(const char *a
, const char *b
) {
471 return path_equal(a
, b
) || files_same(a
, b
) > 0;
474 char* path_join(const char *root
, const char *path
, const char *rest
) {
478 return strjoin(root
, endswith(root
, "/") ? "" : "/",
479 path
[0] == '/' ? path
+1 : path
,
480 rest
? (endswith(path
, "/") ? "" : "/") : NULL
,
481 rest
&& rest
[0] == '/' ? rest
+1 : rest
,
485 rest
? (endswith(path
, "/") ? "" : "/") : NULL
,
486 rest
&& rest
[0] == '/' ? rest
+1 : rest
,
490 static int fd_fdinfo_mnt_id(int fd
, const char *filename
, int flags
, int *mnt_id
) {
491 char path
[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
492 _cleanup_free_
char *fdinfo
= NULL
;
493 _cleanup_close_
int subfd
= -1;
497 if ((flags
& AT_EMPTY_PATH
) && isempty(filename
))
498 xsprintf(path
, "/proc/self/fdinfo/%i", fd
);
500 subfd
= openat(fd
, filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_PATH
);
504 xsprintf(path
, "/proc/self/fdinfo/%i", subfd
);
507 r
= read_full_file(path
, &fdinfo
, NULL
);
508 if (r
== -ENOENT
) /* The fdinfo directory is a relatively new addition */
513 p
= startswith(fdinfo
, "mnt_id:");
515 p
= strstr(fdinfo
, "\nmnt_id:");
516 if (!p
) /* The mnt_id field is a relatively new addition */
522 p
+= strspn(p
, WHITESPACE
);
523 p
[strcspn(p
, WHITESPACE
)] = 0;
525 return safe_atoi(p
, mnt_id
);
528 int fd_is_mount_point(int fd
, const char *filename
, int flags
) {
529 union file_handle_union h
= FILE_HANDLE_INIT
, h_parent
= FILE_HANDLE_INIT
;
530 int mount_id
= -1, mount_id_parent
= -1;
531 bool nosupp
= false, check_st_dev
= true;
538 /* First we will try the name_to_handle_at() syscall, which
539 * tells us the mount id and an opaque file "handle". It is
540 * not supported everywhere though (kernel compile-time
541 * option, not all file systems are hooked up). If it works
542 * the mount id is usually good enough to tell us whether
543 * something is a mount point.
545 * If that didn't work we will try to read the mount id from
546 * /proc/self/fdinfo/<fd>. This is almost as good as
547 * name_to_handle_at(), however, does not return the
548 * opaque file handle. The opaque file handle is pretty useful
549 * to detect the root directory, which we should always
550 * consider a mount point. Hence we use this only as
551 * fallback. Exporting the mnt_id in fdinfo is a pretty recent
554 * As last fallback we do traditional fstat() based st_dev
555 * comparisons. This is how things were traditionally done,
556 * but unionfs breaks breaks this since it exposes file
557 * systems with a variety of st_dev reported. Also, btrfs
558 * subvolumes have different st_dev, even though they aren't
559 * real mounts of their own. */
561 r
= name_to_handle_at(fd
, filename
, &h
.handle
, &mount_id
, flags
);
564 /* This kernel does not support name_to_handle_at()
565 * fall back to simpler logic. */
566 goto fallback_fdinfo
;
567 else if (errno
== EOPNOTSUPP
)
568 /* This kernel or file system does not support
569 * name_to_handle_at(), hence let's see if the
570 * upper fs supports it (in which case it is a
571 * mount point), otherwise fallback to the
572 * traditional stat() logic */
578 r
= name_to_handle_at(fd
, "", &h_parent
.handle
, &mount_id_parent
, AT_EMPTY_PATH
);
580 if (errno
== EOPNOTSUPP
) {
582 /* Neither parent nor child do name_to_handle_at()?
583 We have no choice but to fall back. */
584 goto fallback_fdinfo
;
586 /* The parent can't do name_to_handle_at() but the
587 * directory we are interested in can?
588 * If so, it must be a mount point. */
594 /* The parent can do name_to_handle_at() but the
595 * directory we are interested in can't? If so, it
596 * must be a mount point. */
600 /* If the file handle for the directory we are
601 * interested in and its parent are identical, we
602 * assume this is the root directory, which is a mount
605 if (h
.handle
.handle_bytes
== h_parent
.handle
.handle_bytes
&&
606 h
.handle
.handle_type
== h_parent
.handle
.handle_type
&&
607 memcmp(h
.handle
.f_handle
, h_parent
.handle
.f_handle
, h
.handle
.handle_bytes
) == 0)
610 return mount_id
!= mount_id_parent
;
613 r
= fd_fdinfo_mnt_id(fd
, filename
, flags
, &mount_id
);
614 if (r
== -EOPNOTSUPP
)
619 r
= fd_fdinfo_mnt_id(fd
, "", AT_EMPTY_PATH
, &mount_id_parent
);
623 if (mount_id
!= mount_id_parent
)
626 /* Hmm, so, the mount ids are the same. This leaves one
627 * special case though for the root file system. For that,
628 * let's see if the parent directory has the same inode as we
629 * are interested in. Hence, let's also do fstat() checks now,
630 * too, but avoid the st_dev comparisons, since they aren't
631 * that useful on unionfs mounts. */
632 check_st_dev
= false;
635 /* yay for fstatat() taking a different set of flags than the other
637 if (flags
& AT_SYMLINK_FOLLOW
)
638 flags
&= ~AT_SYMLINK_FOLLOW
;
640 flags
|= AT_SYMLINK_NOFOLLOW
;
641 if (fstatat(fd
, filename
, &a
, flags
) < 0)
644 if (fstatat(fd
, "", &b
, AT_EMPTY_PATH
) < 0)
647 /* A directory with same device and inode as its parent? Must
648 * be the root directory */
649 if (a
.st_dev
== b
.st_dev
&&
650 a
.st_ino
== b
.st_ino
)
653 return check_st_dev
&& (a
.st_dev
!= b
.st_dev
);
656 /* flags can be AT_SYMLINK_FOLLOW or 0 */
657 int path_is_mount_point(const char *t
, int flags
) {
658 _cleanup_close_
int fd
= -1;
659 _cleanup_free_
char *canonical
= NULL
, *parent
= NULL
;
664 if (path_equal(t
, "/"))
667 /* we need to resolve symlinks manually, we can't just rely on
668 * fd_is_mount_point() to do that for us; if we have a structure like
669 * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
670 * look at needs to be /usr, not /. */
671 if (flags
& AT_SYMLINK_FOLLOW
) {
672 canonical
= canonicalize_file_name(t
);
679 r
= path_get_parent(t
, &parent
);
683 fd
= openat(AT_FDCWD
, parent
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_PATH
);
687 return fd_is_mount_point(fd
, basename(t
), flags
);
690 int path_is_read_only_fs(const char *path
) {
695 if (statvfs(path
, &st
) < 0)
698 if (st
.f_flag
& ST_RDONLY
)
701 /* On NFS, statvfs() might not reflect whether we can actually
702 * write to the remote share. Let's try again with
703 * access(W_OK) which is more reliable, at least sometimes. */
704 if (access(path
, W_OK
) < 0 && errno
== EROFS
)
710 int path_is_os_tree(const char *path
) {
714 /* We use /usr/lib/os-release as flag file if something is an OS */
715 p
= strjoina(path
, "/usr/lib/os-release");
720 /* Also check for the old location in /etc, just in case. */
721 p
= strjoina(path
, "/etc/os-release");
727 int find_binary(const char *name
, char **ret
) {
734 if (access(name
, X_OK
) < 0)
738 r
= path_make_absolute_cwd(name
, ret
);
747 * Plain getenv, not secure_getenv, because we want
748 * to actually allow the user to pick the binary.
754 last_error
= -ENOENT
;
757 _cleanup_free_
char *j
= NULL
, *element
= NULL
;
759 r
= extract_first_word(&p
, &element
, ":", EXTRACT_RELAX
|EXTRACT_DONT_COALESCE_SEPARATORS
);
765 if (!path_is_absolute(element
))
768 j
= strjoin(element
, "/", name
, NULL
);
772 if (access(j
, X_OK
) >= 0) {
776 *ret
= path_kill_slashes(j
);
789 bool paths_check_timestamp(const char* const* paths
, usec_t
*timestamp
, bool update
) {
790 bool changed
= false;
791 const char* const* i
;
798 STRV_FOREACH(i
, paths
) {
802 if (stat(*i
, &stats
) < 0)
805 u
= timespec_load(&stats
.st_mtim
);
811 log_debug("timestamp of '%s' changed", *i
);
813 /* update timestamp */
824 static int binary_is_good(const char *binary
) {
825 _cleanup_free_
char *p
= NULL
, *d
= NULL
;
828 r
= find_binary(binary
, &p
);
834 /* An fsck that is linked to /bin/true is a non-existent
837 r
= readlink_malloc(p
, &d
);
838 if (r
== -EINVAL
) /* not a symlink */
843 return !path_equal(d
, "true") &&
844 !path_equal(d
, "/bin/true") &&
845 !path_equal(d
, "/usr/bin/true") &&
846 !path_equal(d
, "/dev/null");
849 int fsck_exists(const char *fstype
) {
854 if (streq(fstype
, "auto"))
857 checker
= strjoina("fsck.", fstype
);
858 return binary_is_good(checker
);
861 int mkfs_exists(const char *fstype
) {
866 if (streq(fstype
, "auto"))
869 mkfs
= strjoina("mkfs.", fstype
);
870 return binary_is_good(mkfs
);
873 char *prefix_root(const char *root
, const char *path
) {
877 /* If root is passed, prefixes path with it. Otherwise returns
882 /* First, drop duplicate prefixing slashes from the path */
883 while (path
[0] == '/' && path
[1] == '/')
886 if (isempty(root
) || path_equal(root
, "/"))
889 l
= strlen(root
) + 1 + strlen(path
) + 1;
897 while (p
> n
&& p
[-1] == '/')
907 int parse_path_argument_and_warn(const char *path
, bool suppress_root
, char **arg
) {
912 * This function is intended to be used in command line
913 * parsers, to handle paths that are passed in. It makes the
914 * path absolute, and reduces it to NULL if omitted or
915 * root (the latter optionally).
917 * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
918 * SUCCESS! Hence, do not pass in uninitialized pointers.
926 r
= path_make_absolute_cwd(path
, &p
);
928 return log_error_errno(r
, "Failed to parse path \"%s\" and make it absolute: %m", path
);
930 path_kill_slashes(p
);
931 if (suppress_root
&& path_equal(p
, "/"))