Hey,
path_is_mount_point() can report some false positive that a file is a
mount point on some file systems (like overlayfs).
The function tries to call name_to_handle_at(), if this one isn't
supported by the file system, then a fallback using stat() is triggered
on the entity (which can be a file). This compares the parent directory
and entity st_dev.
However, some file systems (seems overlayfs at least) would report a
major(st_dev) as 0 on directories and not on files. The current
path_is_mount_point() fallback logic would thus reports that every files
is a mount point. The enclosed patch introduces a second fallback to
read /proc/mounts, and ensures there is no shadowing by later mounting
of parent directories. This slower path is only used when the 2 first
methods failed to determine with assurance if the path is a mount point
or not.
Note that from what I heard, glib is going to use a similar mechanism.
Also we could on the longer term maybe getting the whole
path_is_mount_point() logic into libmount from util-linux, using
mnt_get_mountpoint() (but this one only use st_dev comparison presently)?
As usual, I'm opened on any modification on this patch.
Cheers,
Didier
>From 47a8d7546f3fa959344431770f75d8e422192ba3 Mon Sep 17 00:00:00 2001
From: Didier Roche <didro...@ubuntu.com>
Date: Mon, 9 Mar 2015 09:09:30 +0100
Subject: [PATCH] path_is_mount_point: handle false positive on some fs
path_is_mount_point detection mechanism was wrongly reporting every file
as mount point on file systems like overlayfs:
- name_to_handle_at is not supported
- stat() on directories returns a 0 st_dev (and so different from file stat())
In this case, we fall back to the slower path: directly reading /proc/mounts
and matching any mount point corresponding to the path if present. Ensure that
there isn't any hiding mounts.
---
src/shared/path-util.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 65 insertions(+), 1 deletion(-)
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 12d1ec3..2464569 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -457,7 +457,9 @@ int path_is_mount_point(const char *t, bool allow_symlink) {
union file_handle_union h = FILE_HANDLE_INIT;
int mount_id = -1, mount_id_parent = -1;
- _cleanup_free_ char *parent = NULL;
+ _cleanup_free_ char *parent = NULL, *path = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ bool mountpoint_found = false;
struct stat a, b;
int r;
bool nosupp = false;
@@ -533,7 +535,69 @@ fallback:
if (r < 0)
return -errno;
+ /* if parent major block is 0, this can be an overlay fs,
+ fallback to reading /proc/mounts */
+ if (major(b.st_dev) == 0)
+ goto fallback_proc_mounts;
+
return a.st_dev != b.st_dev;
+
+fallback_proc_mounts:
+ if (allow_symlink) {
+ r = readlink_and_make_absolute(t, &path);
+ if (r < 0) {
+ if (errno == ENOENT)
+ return 0;
+
+ return -errno;
+ }
+ } else
+ path = strdup(t);
+
+ f = fopen("/proc/mounts", "re");
+ if (!f) {
+ if (errno == ENOENT)
+ return 0;
+ return -errno;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *mountpoint = NULL, *unesc_mountpoint = NULL;
+ r = fscanf(f,
+ "%*s " /* (1) fs spec */
+ "%ms " /* (2) mount point */
+ "%*[^\n]", /* not interested by other values */
+ &mountpoint);
+ if (r != 1) {
+ if (r == EOF)
+ break;
+ if (ferror(f) && errno)
+ return -errno;
+
+ continue;
+ }
+
+ unesc_mountpoint = cunescape(mountpoint);
+ if (!unesc_mountpoint)
+ return -ENOMEM;
+
+ /* check that our mount point isn't hidden by a later mount of a parent dir */
+ if (mountpoint_found) {
+ size_t l = strlen(unesc_mountpoint);
+ if (strlen(path) > l &&
+ path_startswith(path, unesc_mountpoint) &&
+ (unesc_mountpoint[l-1] == '/' || path[l] == '/'))
+ mountpoint_found = false;
+ }
+
+ if (path_equal(path, unesc_mountpoint))
+ mountpoint_found = true;
+ }
+
+ if (mountpoint_found)
+ return 1;
+
+ return 0;
}
int path_is_read_only_fs(const char *path) {
--
2.1.4
_______________________________________________
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel