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