5ff110
From 703d3a465850b768e627705a587cfd8095fe0be7 Mon Sep 17 00:00:00 2001
5ff110
Message-Id: <703d3a465850b768e627705a587cfd8095fe0be7@dist-git>
5ff110
From: Michal Privoznik <mprivozn@redhat.com>
5ff110
Date: Tue, 23 Oct 2018 11:40:58 +0100
5ff110
Subject: [PATCH] virfile: Take symlink into account in virFileIsSharedFixFUSE
5ff110
5ff110
RHEL-7.7: https://bugzilla.redhat.com/show_bug.cgi?id=1640465
5ff110
RHEL-7.6.z: https://bugzilla.redhat.com/show_bug.cgi?id=1641798
5ff110
5ff110
Weirdly enough, there can be symlinks in the path we are trying
5ff110
to fix. If it is the case our clever algorithm that finds matches
5ff110
against mount table won't work. Canonicalize path at the
5ff110
beginning then.
5ff110
5ff110
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
5ff110
Reviewed-by: Erik Skultety <eskultet@redhat.com>
5ff110
(cherry picked from commit c0790e3a09f57da0bd25c7eac4a35ed6e7e9e858)
5ff110
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
5ff110
Reviewed-by: Erik Skultety <eskultet@redhat.com>
5ff110
---
5ff110
 cfg.mk              |  2 +-
5ff110
 src/util/virfile.c  | 15 +++++++++++++--
5ff110
 tests/virfilemock.c | 33 ++++++++++++++++++++++++++++++++-
5ff110
 tests/virfiletest.c |  1 +
5ff110
 4 files changed, 47 insertions(+), 4 deletions(-)
5ff110
5ff110
diff --git a/cfg.mk b/cfg.mk
5ff110
index 6bebd0ad9f..e3e94bf6f0 100644
5ff110
--- a/cfg.mk
5ff110
+++ b/cfg.mk
5ff110
@@ -1216,7 +1216,7 @@ exclude_file_name_regexp--sc_prohibit_select = \
5ff110
 	^cfg\.mk$$
5ff110
 
5ff110
 exclude_file_name_regexp--sc_prohibit_canonicalize_file_name = \
5ff110
-  ^cfg\.mk$$
5ff110
+  ^(cfg\.mk|tests/virfilemock\.c)$$
5ff110
 
5ff110
 exclude_file_name_regexp--sc_prohibit_raw_allocation = \
5ff110
   ^(docs/hacking\.html\.in|src/util/viralloc\.[ch]|examples/.*|tests/(securityselinuxhelper|(vircgroup|nss)mock|commandhelper)\.c|tools/wireshark/src/packet-libvirt\.c)$$
5ff110
diff --git a/src/util/virfile.c b/src/util/virfile.c
5ff110
index e1dee7633a..716b55d770 100644
5ff110
--- a/src/util/virfile.c
5ff110
+++ b/src/util/virfile.c
5ff110
@@ -3549,9 +3549,19 @@ virFileIsSharedFixFUSE(const char *path,
5ff110
     char mntbuf[1024];
5ff110
     char *mntDir = NULL;
5ff110
     char *mntType = NULL;
5ff110
+    char *canonPath = NULL;
5ff110
     size_t maxMatching = 0;
5ff110
     int ret = -1;
5ff110
 
5ff110
+    if (!(canonPath = virFileCanonicalizePath(path))) {
5ff110
+        virReportSystemError(errno,
5ff110
+                             _("unable to canonicalize %s"),
5ff110
+                             path);
5ff110
+        return -1;
5ff110
+    }
5ff110
+
5ff110
+    VIR_DEBUG("Path canonicalization: %s->%s", path, canonPath);
5ff110
+
5ff110
     if (!(f = setmntent(PROC_MOUNTS, "r"))) {
5ff110
         virReportSystemError(errno,
5ff110
                              _("Unable to open %s"),
5ff110
@@ -3563,7 +3573,7 @@ virFileIsSharedFixFUSE(const char *path,
5ff110
         const char *p;
5ff110
         size_t len = strlen(mb.mnt_dir);
5ff110
 
5ff110
-        if (!(p = STRSKIP(path, mb.mnt_dir)))
5ff110
+        if (!(p = STRSKIP(canonPath, mb.mnt_dir)))
5ff110
             continue;
5ff110
 
5ff110
         if (*(p - 1) != '/' && *p != '/' && *p != '\0')
5ff110
@@ -3581,12 +3591,13 @@ virFileIsSharedFixFUSE(const char *path,
5ff110
 
5ff110
     if (STREQ_NULLABLE(mntType, "fuse.glusterfs")) {
5ff110
         VIR_DEBUG("Found gluster FUSE mountpoint=%s for path=%s. "
5ff110
-                  "Fixing shared FS type", mntDir, path);
5ff110
+                  "Fixing shared FS type", mntDir, canonPath);
5ff110
         *f_type = GFS2_MAGIC;
5ff110
     }
5ff110
 
5ff110
     ret = 0;
5ff110
  cleanup:
5ff110
+    VIR_FREE(canonPath);
5ff110
     VIR_FREE(mntType);
5ff110
     VIR_FREE(mntDir);
5ff110
     endmntent(f);
5ff110
diff --git a/tests/virfilemock.c b/tests/virfilemock.c
5ff110
index 822c757380..ae5c8d025a 100644
5ff110
--- a/tests/virfilemock.c
5ff110
+++ b/tests/virfilemock.c
5ff110
@@ -28,11 +28,14 @@
5ff110
 #endif
5ff110
 
5ff110
 #include "virmock.h"
5ff110
+#include "virstring.h"
5ff110
+#include "viralloc.h"
5ff110
 
5ff110
 #define VIR_FROM_THIS VIR_FROM_NONE
5ff110
 
5ff110
 static FILE *(*real_setmntent)(const char *filename, const char *type);
5ff110
 static int (*real_statfs)(const char *path, struct statfs *buf);
5ff110
+static char *(*real_canonicalize_file_name)(const char *path);
5ff110
 
5ff110
 
5ff110
 static void
5ff110
@@ -43,6 +46,7 @@ init_syms(void)
5ff110
 
5ff110
     VIR_MOCK_REAL_INIT(setmntent);
5ff110
     VIR_MOCK_REAL_INIT(statfs);
5ff110
+    VIR_MOCK_REAL_INIT(canonicalize_file_name);
5ff110
 }
5ff110
 
5ff110
 
5ff110
@@ -94,6 +98,7 @@ statfs_mock(const char *mtab,
5ff110
     FILE *f;
5ff110
     struct mntent mb;
5ff110
     char mntbuf[1024];
5ff110
+    char *canonPath = NULL;
5ff110
     int ret = -1;
5ff110
 
5ff110
     if (!(f = real_setmntent(mtab, "r"))) {
5ff110
@@ -101,10 +106,16 @@ statfs_mock(const char *mtab,
5ff110
         return -1;
5ff110
     }
5ff110
 
5ff110
+    /* We don't need to do this in callers because real statfs(2)
5ff110
+     * does that for us. However, in mocked implementation we
5ff110
+     * need to do this. */
5ff110
+    if (!(canonPath = canonicalize_file_name(path)))
5ff110
+        return -1;
5ff110
+
5ff110
     while (getmntent_r(f, &mb, mntbuf, sizeof(mntbuf))) {
5ff110
         int ftype;
5ff110
 
5ff110
-        if (STRNEQ(mb.mnt_dir, path))
5ff110
+        if (STRNEQ(mb.mnt_dir, canonPath))
5ff110
             continue;
5ff110
 
5ff110
         if (STREQ(mb.mnt_type, "nfs") ||
5ff110
@@ -136,6 +147,7 @@ statfs_mock(const char *mtab,
5ff110
     }
5ff110
 
5ff110
     endmntent(f);
5ff110
+    VIR_FREE(canonPath);
5ff110
     return ret;
5ff110
 }
5ff110
 
5ff110
@@ -152,3 +164,22 @@ statfs(const char *path, struct statfs *buf)
5ff110
 
5ff110
     return real_statfs(path, buf);
5ff110
 }
5ff110
+
5ff110
+
5ff110
+char *
5ff110
+canonicalize_file_name(const char *path)
5ff110
+{
5ff110
+    if (getenv("LIBVIRT_MTAB")) {
5ff110
+        const char *p;
5ff110
+        char *ret;
5ff110
+
5ff110
+        if ((p = STRSKIP(path, "/some/symlink")))
5ff110
+            ignore_value(virAsprintfQuiet(&ret, "/gluster%s", p));
5ff110
+        else
5ff110
+            ignore_value(VIR_STRDUP_QUIET(ret, path));
5ff110
+
5ff110
+        return ret;
5ff110
+    }
5ff110
+
5ff110
+    return real_canonicalize_file_name(path);
5ff110
+}
5ff110
diff --git a/tests/virfiletest.c b/tests/virfiletest.c
5ff110
index be4dbf8910..a246d601ba 100644
5ff110
--- a/tests/virfiletest.c
5ff110
+++ b/tests/virfiletest.c
5ff110
@@ -457,6 +457,7 @@ mymain(void)
5ff110
     DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/nfs/blah", false);
5ff110
     DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/gluster/file", true);
5ff110
     DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/gluster/sshfs/file", false);
5ff110
+    DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/some/symlink/file", true);
5ff110
 
5ff110
     return ret != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
5ff110
 }
5ff110
-- 
0a7476
2.21.0
5ff110