Daniel P. Berrangé 76097a
From ff376c6283c97217fa65766e3b24d27929e3ff6e Mon Sep 17 00:00:00 2001
Daniel P. Berrangé 76097a
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Daniel P. Berrangé 76097a
Date: Mon, 1 Apr 2019 17:47:25 +0100
Daniel P. Berrangé 76097a
Subject: [PATCH] tests: fix mocking of stat() / lstat() functions
Daniel P. Berrangé 76097a
MIME-Version: 1.0
Daniel P. Berrangé 76097a
Content-Type: text/plain; charset=UTF-8
Daniel P. Berrangé 76097a
Content-Transfer-Encoding: 8bit
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
Quite a few of the tests have a need to mock the stat() / lstat()
Daniel P. Berrangé 76097a
functions and they are taking somewhat different & inconsistent
Daniel P. Berrangé 76097a
approaches none of which are actually fully correct. This is shown
Daniel P. Berrangé 76097a
by fact that 'make check' fails on 32-bit hosts. Investigation
Daniel P. Berrangé 76097a
revealed that the code was calling into the native C library impl,
Daniel P. Berrangé 76097a
not getting intercepted by our mocks.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
The POSIX stat() function might resolve to any number of different
Daniel P. Berrangé 76097a
symbols in the C library.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
The may be an additional stat64() function exposed by the headers
Daniel P. Berrangé 76097a
too.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
On 64-bit hosts the stat & stat64 functions are identical, always
Daniel P. Berrangé 76097a
refering to the 64-bit ABI.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
On 32-bit hosts they refer to the 32-bit & 64-bit ABIs respectively.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
Libvirt uses _FILE_OFFSET_BITS=64 on 32-bit hosts, which causes the
Daniel P. Berrangé 76097a
C library to transparently rewrite stat() calls to be stat64() calls.
Daniel P. Berrangé 76097a
Libvirt will never see the 32-bit ABI from the traditional stat()
Daniel P. Berrangé 76097a
call. We cannot assume this rewriting is done using a macro. It might
Daniel P. Berrangé 76097a
be, but on GLibC it is done with a magic __asm__ statement to apply
Daniel P. Berrangé 76097a
the rewrite at link time instead of at preprocessing.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
In GLibC there may be two additional functions exposed by the headers,
Daniel P. Berrangé 76097a
__xstat() and __xstat64(). When these exist, stat() and stat64() are
Daniel P. Berrangé 76097a
transparently rewritten to call __xstat() and __xstat64() respectively.
Daniel P. Berrangé 76097a
The former symbols will not actally exist in the library at all, only
Daniel P. Berrangé 76097a
the header. The leading "__" indicates the symbols are a private impl
Daniel P. Berrangé 76097a
detail of the C library that applications should not care about.
Daniel P. Berrangé 76097a
Unfortunately, because we are trying to mock replace the C library,
Daniel P. Berrangé 76097a
we need to know about this internal impl detail.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
With all this in mind the list of functions we have to mock will depend
Daniel P. Berrangé 76097a
on several factors
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
 - If _FILE_OFFSET_BITS is set, then we are on a 32-bit host, and we
Daniel P. Berrangé 76097a
   only need to mock stat64 and __xstat64. The other stat / __xstat
Daniel P. Berrangé 76097a
   functions exist, but we'll never call them so they can be ignored
Daniel P. Berrangé 76097a
   for mocking.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
 - If _FILE_OFFSET_BITS is not set, then we are on a 64-bit host and
Daniel P. Berrangé 76097a
   we should mock stat, stat64, __xstat & __xstat64. Either may be
Daniel P. Berrangé 76097a
   called by app code.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
 - If __xstat & __xstat64 exist, then stat & stat64 will not exist
Daniel P. Berrangé 76097a
   as symbols in the library, so the latter should not be mocked.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
The same all applies to lstat()
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
These rules are complex enough that we don't want to duplicate them
Daniel P. Berrangé 76097a
across every mock file, so this centralizes all the logic in a helper
Daniel P. Berrangé 76097a
file virmockstathelper.c that should be #included when needed. The
Daniel P. Berrangé 76097a
code merely need to provide a filename rewriting callback called
Daniel P. Berrangé 76097a
virMockStatRedirect(). Optionally VIR_MOCK_STAT_HOOK can be defined
Daniel P. Berrangé 76097a
as a macro if further processing is needed inline.
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Daniel P. Berrangé 76097a
---
Daniel P. Berrangé 76097a
 build-aux/mock-noinline.pl |   3 +
Daniel P. Berrangé 76097a
 cfg.mk                     |   4 +-
Daniel P. Berrangé 76097a
 tests/Makefile.am          |   1 +
Daniel P. Berrangé 76097a
 tests/qemusecuritymock.c   | 131 ++++-----------
Daniel P. Berrangé 76097a
 tests/vircgroupmock.c      | 146 +++--------------
Daniel P. Berrangé 76097a
 tests/virfilewrapper.c     |  85 ++--------
Daniel P. Berrangé 76097a
 tests/virmock.h            |  11 --
Daniel P. Berrangé 76097a
 tests/virmockstathelpers.c | 326 +++++++++++++++++++++++++++++++++++++
Daniel P. Berrangé 76097a
 tests/virpcimock.c         |  93 +----------
Daniel P. Berrangé 76097a
 tests/virtestmock.c        | 140 +---------------
Daniel P. Berrangé 76097a
 10 files changed, 413 insertions(+), 527 deletions(-)
Daniel P. Berrangé 76097a
 create mode 100644 tests/virmockstathelpers.c
Daniel P. Berrangé 76097a
Daniel P. Berrangé 76097a
diff --git a/cfg.mk b/cfg.mk
Daniel P. Berrangé 76097a
index 8594f64482..5ffae32f2a 100644
Daniel P. Berrangé 76097a
--- a/cfg.mk
Daniel P. Berrangé 76097a
+++ b/cfg.mk
Daniel P. Berrangé 76097a
@@ -1272,10 +1272,10 @@ exclude_file_name_regexp--sc_prohibit_xmlURI = ^src/util/viruri\.c$$
Daniel P. Berrangé 76097a
 exclude_file_name_regexp--sc_prohibit_return_as_function = \.py$$
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 exclude_file_name_regexp--sc_require_config_h = \
Daniel P. Berrangé 76097a
-	^(examples/|tools/virsh-edit\.c$$)
Daniel P. Berrangé 76097a
+	^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 exclude_file_name_regexp--sc_require_config_h_first = \
Daniel P. Berrangé 76097a
-	^(examples/|tools/virsh-edit\.c$$)
Daniel P. Berrangé 76097a
+	^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 exclude_file_name_regexp--sc_trailing_blank = \
Daniel P. Berrangé 76097a
   /sysinfodata/.*\.data|/virhostcpudata/.*\.cpuinfo|^gnulib/local/.*/.*diff$$
Daniel P. Berrangé 76097a
diff --git a/tests/qemusecuritymock.c b/tests/qemusecuritymock.c
Daniel P. Berrangé 76097a
index d1b17d8aa4..3fdc165fb1 100644
Daniel P. Berrangé 76097a
--- a/tests/qemusecuritymock.c
Daniel P. Berrangé 76097a
+++ b/tests/qemusecuritymock.c
Daniel P. Berrangé 76097a
@@ -50,10 +50,6 @@
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 static int (*real_chown)(const char *path, uid_t uid, gid_t gid);
Daniel P. Berrangé 76097a
-static int (*real_lstat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real_stat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real___xstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
 static int (*real_open)(const char *path, int flags, ...);
Daniel P. Berrangé 76097a
 static int (*real_close)(int fd);
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
@@ -106,8 +102,6 @@ init_syms(void)
Daniel P. Berrangé 76097a
         return;
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(chown);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(open);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(close);
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
@@ -211,36 +205,35 @@ int virFileRemoveXAttr(const char *path,
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-static int
Daniel P. Berrangé 76097a
-mock_stat(const char *path,
Daniel P. Berrangé 76097a
-          struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    uint32_t *val;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    virMutexLock(&m);
Daniel P. Berrangé 76097a
-    init_hash();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    memset(sb, 0, sizeof(*sb));
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    sb->st_mode = S_IFREG | 0666;
Daniel P. Berrangé 76097a
-    sb->st_size = 123456;
Daniel P. Berrangé 76097a
-    sb->st_ino = 1;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    if (!(val = virHashLookup(chown_paths, path))) {
Daniel P. Berrangé 76097a
-        /* New path. Set the defaults */
Daniel P. Berrangé 76097a
-        sb->st_uid = DEFAULT_UID;
Daniel P. Berrangé 76097a
-        sb->st_gid = DEFAULT_GID;
Daniel P. Berrangé 76097a
-    } else {
Daniel P. Berrangé 76097a
-        /* Known path. Set values passed to chown() earlier */
Daniel P. Berrangé 76097a
-        sb->st_uid = *val % 16;
Daniel P. Berrangé 76097a
-        sb->st_gid = *val >> 16;
Daniel P. Berrangé 76097a
-    }
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    virMutexUnlock(&m);
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return 0;
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
+#define VIR_MOCK_STAT_HOOK \
Daniel P. Berrangé 76097a
+    do { \
Daniel P. Berrangé 76097a
+        if (getenv(ENVVAR)) { \
Daniel P. Berrangé 76097a
+            uint32_t *val; \
Daniel P. Berrangé 76097a
+\
Daniel P. Berrangé 76097a
+            virMutexLock(&m); \
Daniel P. Berrangé 76097a
+            init_hash(); \
Daniel P. Berrangé 76097a
+\
Daniel P. Berrangé 76097a
+            memset(sb, 0, sizeof(*sb)); \
Daniel P. Berrangé 76097a
+\
Daniel P. Berrangé 76097a
+            sb->st_mode = S_IFREG | 0666; \
Daniel P. Berrangé 76097a
+            sb->st_size = 123456; \
Daniel P. Berrangé 76097a
+            sb->st_ino = 1; \
Daniel P. Berrangé 76097a
+\
Daniel P. Berrangé 76097a
+            if (!(val = virHashLookup(chown_paths, path))) { \
Daniel P. Berrangé 76097a
+                /* New path. Set the defaults */ \
Daniel P. Berrangé 76097a
+                sb->st_uid = DEFAULT_UID; \
Daniel P. Berrangé 76097a
+                sb->st_gid = DEFAULT_GID; \
Daniel P. Berrangé 76097a
+            } else { \
Daniel P. Berrangé 76097a
+                /* Known path. Set values passed to chown() earlier */ \
Daniel P. Berrangé 76097a
+                sb->st_uid = *val % 16; \
Daniel P. Berrangé 76097a
+                sb->st_gid = *val >> 16; \
Daniel P. Berrangé 76097a
+            } \
Daniel P. Berrangé 76097a
+\
Daniel P. Berrangé 76097a
+            virMutexUnlock(&m); \
Daniel P. Berrangé 76097a
+\
Daniel P. Berrangé 76097a
+            return 0; \
Daniel P. Berrangé 76097a
+        } \
Daniel P. Berrangé 76097a
+    } while (0)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 static int
Daniel P. Berrangé 76097a
 mock_chown(const char *path,
Daniel P. Berrangé 76097a
@@ -276,68 +269,12 @@ mock_chown(const char *path,
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-#ifdef HAVE___LXSTAT
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-__lxstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    if (getenv(ENVVAR))
Daniel P. Berrangé 76097a
-        ret = mock_stat(path, sb);
Daniel P. Berrangé 76097a
-    else
Daniel P. Berrangé 76097a
-        ret = real___lxstat(ver, path, sb);
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-#endif /* HAVE___LXSTAT */
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-lstat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    if (getenv(ENVVAR))
Daniel P. Berrangé 76097a
-        ret = mock_stat(path, sb);
Daniel P. Berrangé 76097a
-    else
Daniel P. Berrangé 76097a
-        ret = real_lstat(path, sb);
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-#ifdef HAVE___XSTAT
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-__xstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    if (getenv(ENVVAR))
Daniel P. Berrangé 76097a
-        ret = mock_stat(path, sb);
Daniel P. Berrangé 76097a
-    else
Daniel P. Berrangé 76097a
-        ret = real___xstat(ver, path, sb);
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-#endif /* HAVE___XSTAT */
Daniel P. Berrangé 76097a
+#include "virmockstathelpers.c"
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-stat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
+static int
Daniel P. Berrangé 76097a
+virMockStatRedirect(const char *path ATTRIBUTE_UNUSED, char **newpath ATTRIBUTE_UNUSED)
Daniel P. Berrangé 76097a
 {
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    if (getenv(ENVVAR))
Daniel P. Berrangé 76097a
-        ret = mock_stat(path, sb);
Daniel P. Berrangé 76097a
-    else
Daniel P. Berrangé 76097a
-        ret = real_stat(path, sb);
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
+    return 0;
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
@@ -386,6 +323,8 @@ close(int fd)
Daniel P. Berrangé 76097a
 {
Daniel P. Berrangé 76097a
     int ret;
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
+    init_syms();
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
     if (fd == 42 && getenv(ENVVAR))
Daniel P. Berrangé 76097a
         ret = 0;
Daniel P. Berrangé 76097a
     else
Daniel P. Berrangé 76097a
diff --git a/tests/vircgroupmock.c b/tests/vircgroupmock.c
Daniel P. Berrangé 76097a
index 9c67a44b0d..11a24035aa 100644
Daniel P. Berrangé 76097a
--- a/tests/vircgroupmock.c
Daniel P. Berrangé 76097a
+++ b/tests/vircgroupmock.c
Daniel P. Berrangé 76097a
@@ -38,10 +38,6 @@
Daniel P. Berrangé 76097a
 static int (*real_open)(const char *path, int flags, ...);
Daniel P. Berrangé 76097a
 static FILE *(*real_fopen)(const char *path, const char *mode);
Daniel P. Berrangé 76097a
 static int (*real_access)(const char *path, int mode);
Daniel P. Berrangé 76097a
-static int (*real_stat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real___xstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real_lstat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
 static int (*real_mkdir)(const char *path, mode_t mode);
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 /* Don't make static, since it causes problems with clang
Daniel P. Berrangé 76097a
@@ -317,8 +313,6 @@ static void init_syms(void)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(fopen);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(access);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(mkdir);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(open);
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
@@ -508,139 +502,41 @@ int access(const char *path, int mode)
Daniel P. Berrangé 76097a
     return ret;
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-int __lxstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
Daniel P. Berrangé 76097a
-        init_sysfs();
Daniel P. Berrangé 76097a
-        char *newpath;
Daniel P. Berrangé 76097a
-        if (asprintf(&newpath, "%s%s",
Daniel P. Berrangé 76097a
-                     fakesysfscgroupdir,
Daniel P. Berrangé 76097a
-                     path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
Daniel P. Berrangé 76097a
-            errno = ENOMEM;
Daniel P. Berrangé 76097a
-            return -1;
Daniel P. Berrangé 76097a
-        }
Daniel P. Berrangé 76097a
-        ret = real___lxstat(ver, newpath, sb);
Daniel P. Berrangé 76097a
-        free(newpath);
Daniel P. Berrangé 76097a
-    } else if (STRPREFIX(path, fakedevicedir0)) {
Daniel P. Berrangé 76097a
-        sb->st_mode = S_IFBLK;
Daniel P. Berrangé 76097a
-        sb->st_rdev = makedev(8, 0);
Daniel P. Berrangé 76097a
-        return 0;
Daniel P. Berrangé 76097a
-    } else if (STRPREFIX(path, fakedevicedir1)) {
Daniel P. Berrangé 76097a
-        sb->st_mode = S_IFBLK;
Daniel P. Berrangé 76097a
-        sb->st_rdev = makedev(9, 0);
Daniel P. Berrangé 76097a
-        return 0;
Daniel P. Berrangé 76097a
-    } else {
Daniel P. Berrangé 76097a
-        ret = real___lxstat(ver, path, sb);
Daniel P. Berrangé 76097a
-    }
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-int lstat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
Daniel P. Berrangé 76097a
-        init_sysfs();
Daniel P. Berrangé 76097a
-        char *newpath;
Daniel P. Berrangé 76097a
-        if (asprintf(&newpath, "%s%s",
Daniel P. Berrangé 76097a
-                     fakesysfscgroupdir,
Daniel P. Berrangé 76097a
-                     path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
Daniel P. Berrangé 76097a
-            errno = ENOMEM;
Daniel P. Berrangé 76097a
-            return -1;
Daniel P. Berrangé 76097a
-        }
Daniel P. Berrangé 76097a
-        ret = real_lstat(newpath, sb);
Daniel P. Berrangé 76097a
-        free(newpath);
Daniel P. Berrangé 76097a
-    } else if (STRPREFIX(path, fakedevicedir0)) {
Daniel P. Berrangé 76097a
-        sb->st_mode = S_IFBLK;
Daniel P. Berrangé 76097a
-        sb->st_rdev = makedev(8, 0);
Daniel P. Berrangé 76097a
-        return 0;
Daniel P. Berrangé 76097a
-    } else if (STRPREFIX(path, fakedevicedir1)) {
Daniel P. Berrangé 76097a
-        sb->st_mode = S_IFBLK;
Daniel P. Berrangé 76097a
-        sb->st_rdev = makedev(9, 0);
Daniel P. Berrangé 76097a
-        return 0;
Daniel P. Berrangé 76097a
-    } else {
Daniel P. Berrangé 76097a
-        ret = real_lstat(path, sb);
Daniel P. Berrangé 76097a
-    }
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-int __xstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
+# define VIR_MOCK_STAT_HOOK \
Daniel P. Berrangé 76097a
+    do { \
Daniel P. Berrangé 76097a
+        if (STRPREFIX(path, fakedevicedir0)) { \
Daniel P. Berrangé 76097a
+            sb->st_mode = S_IFBLK; \
Daniel P. Berrangé 76097a
+            sb->st_rdev = makedev(8, 0); \
Daniel P. Berrangé 76097a
+            return 0; \
Daniel P. Berrangé 76097a
+        } else if (STRPREFIX(path, fakedevicedir1)) { \
Daniel P. Berrangé 76097a
+            sb->st_mode = S_IFBLK; \
Daniel P. Berrangé 76097a
+            sb->st_rdev = makedev(9, 0); \
Daniel P. Berrangé 76097a
+            return 0; \
Daniel P. Berrangé 76097a
+        } \
Daniel P. Berrangé 76097a
+    } while (0)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-    if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
Daniel P. Berrangé 76097a
-        init_sysfs();
Daniel P. Berrangé 76097a
-        char *newpath;
Daniel P. Berrangé 76097a
-        if (asprintf(&newpath, "%s%s",
Daniel P. Berrangé 76097a
-                     fakesysfscgroupdir,
Daniel P. Berrangé 76097a
-                     path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
Daniel P. Berrangé 76097a
-            errno = ENOMEM;
Daniel P. Berrangé 76097a
-            return -1;
Daniel P. Berrangé 76097a
-        }
Daniel P. Berrangé 76097a
-        ret = real___xstat(ver, newpath, sb);
Daniel P. Berrangé 76097a
-        free(newpath);
Daniel P. Berrangé 76097a
-    } else if (STRPREFIX(path, fakedevicedir0)) {
Daniel P. Berrangé 76097a
-        sb->st_mode = S_IFBLK;
Daniel P. Berrangé 76097a
-        sb->st_rdev = makedev(8, 0);
Daniel P. Berrangé 76097a
-        return 0;
Daniel P. Berrangé 76097a
-    } else if (STRPREFIX(path, fakedevicedir1)) {
Daniel P. Berrangé 76097a
-        sb->st_mode = S_IFBLK;
Daniel P. Berrangé 76097a
-        sb->st_rdev = makedev(9, 0);
Daniel P. Berrangé 76097a
-        return 0;
Daniel P. Berrangé 76097a
-    } else {
Daniel P. Berrangé 76097a
-        ret = real___xstat(ver, path, sb);
Daniel P. Berrangé 76097a
-    }
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
+# include "virmockstathelpers.c"
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-int stat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
+static int
Daniel P. Berrangé 76097a
+virMockStatRedirect(const char *path, char **newpath)
Daniel P. Berrangé 76097a
 {
Daniel P. Berrangé 76097a
-    char *newpath = NULL;
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
     if (STREQ(path, SYSFS_CPU_PRESENT)) {
Daniel P. Berrangé 76097a
         init_sysfs();
Daniel P. Berrangé 76097a
-        if (asprintf(&newpath, "%s/%s",
Daniel P. Berrangé 76097a
+        if (asprintf(newpath, "%s/%s",
Daniel P. Berrangé 76097a
                      fakesysfscgroupdir,
Daniel P. Berrangé 76097a
-                     SYSFS_CPU_PRESENT_MOCKED) < 0) {
Daniel P. Berrangé 76097a
-            errno = ENOMEM;
Daniel P. Berrangé 76097a
+                     SYSFS_CPU_PRESENT_MOCKED) < 0)
Daniel P. Berrangé 76097a
             return -1;
Daniel P. Berrangé 76097a
-        }
Daniel P. Berrangé 76097a
     } else if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
Daniel P. Berrangé 76097a
         init_sysfs();
Daniel P. Berrangé 76097a
-        if (asprintf(&newpath, "%s%s",
Daniel P. Berrangé 76097a
+        if (asprintf(newpath, "%s%s",
Daniel P. Berrangé 76097a
                      fakesysfscgroupdir,
Daniel P. Berrangé 76097a
-                     path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
Daniel P. Berrangé 76097a
-            errno = ENOMEM;
Daniel P. Berrangé 76097a
-            return -1;
Daniel P. Berrangé 76097a
-        }
Daniel P. Berrangé 76097a
-    } else if (STRPREFIX(path, fakedevicedir0)) {
Daniel P. Berrangé 76097a
-        sb->st_mode = S_IFBLK;
Daniel P. Berrangé 76097a
-        sb->st_rdev = makedev(8, 0);
Daniel P. Berrangé 76097a
-        return 0;
Daniel P. Berrangé 76097a
-    } else if (STRPREFIX(path, fakedevicedir1)) {
Daniel P. Berrangé 76097a
-        sb->st_mode = S_IFBLK;
Daniel P. Berrangé 76097a
-        sb->st_rdev = makedev(9, 0);
Daniel P. Berrangé 76097a
-        return 0;
Daniel P. Berrangé 76097a
-    } else {
Daniel P. Berrangé 76097a
-        if (!(newpath = strdup(path)))
Daniel P. Berrangé 76097a
+                     path + strlen(SYSFS_CGROUP_PREFIX)) < 0)
Daniel P. Berrangé 76097a
             return -1;
Daniel P. Berrangé 76097a
     }
Daniel P. Berrangé 76097a
-    ret = real_stat(newpath, sb);
Daniel P. Berrangé 76097a
-    free(newpath);
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
+    return 0;
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
 int mkdir(const char *path, mode_t mode)
Daniel P. Berrangé 76097a
 {
Daniel P. Berrangé 76097a
     int ret;
Daniel P. Berrangé 76097a
diff --git a/tests/virfilewrapper.c b/tests/virfilewrapper.c
Daniel P. Berrangé 76097a
index 88441331ce..067cb30657 100644
Daniel P. Berrangé 76097a
--- a/tests/virfilewrapper.c
Daniel P. Berrangé 76097a
+++ b/tests/virfilewrapper.c
Daniel P. Berrangé 76097a
@@ -39,15 +39,9 @@ static size_t nprefixes;
Daniel P. Berrangé 76097a
 static const char **prefixes;
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 /* TODO: callbacks */
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
 static int (*real_open)(const char *path, int flags, ...);
Daniel P. Berrangé 76097a
 static FILE *(*real_fopen)(const char *path, const char *mode);
Daniel P. Berrangé 76097a
 static int (*real_access)(const char *path, int mode);
Daniel P. Berrangé 76097a
-static int (*real_stat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real___xstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real_lstat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
 static int (*real_mkdir)(const char *path, mode_t mode);
Daniel P. Berrangé 76097a
 static DIR *(*real_opendir)(const char *path);
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
@@ -58,8 +52,6 @@ static void init_syms(void)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(fopen);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(access);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(mkdir);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(open);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(opendir);
Daniel P. Berrangé 76097a
@@ -115,10 +107,11 @@ virFileWrapperClearPrefixes(void)
Daniel P. Berrangé 76097a
     VIR_FREE(overrides);
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-static char *
Daniel P. Berrangé 76097a
-virFileWrapperOverridePrefix(const char *path)
Daniel P. Berrangé 76097a
+# include "virmockstathelpers.c"
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+int
Daniel P. Berrangé 76097a
+virMockStatRedirect(const char *path, char **newpath)
Daniel P. Berrangé 76097a
 {
Daniel P. Berrangé 76097a
-    char *ret = NULL;
Daniel P. Berrangé 76097a
     size_t i = 0;
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
     for (i = 0; i < noverrides; i++) {
Daniel P. Berrangé 76097a
@@ -127,16 +120,13 @@ virFileWrapperOverridePrefix(const char *path)
Daniel P. Berrangé 76097a
         if (!tmp)
Daniel P. Berrangé 76097a
             continue;
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-        if (virAsprintfQuiet(&ret, "%s%s", overrides[i], tmp) < 0)
Daniel P. Berrangé 76097a
-            return NULL;
Daniel P. Berrangé 76097a
+        if (virAsprintfQuiet(newpath, "%s%s", overrides[i], tmp) < 0)
Daniel P. Berrangé 76097a
+            return -1;
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
         break;
Daniel P. Berrangé 76097a
     }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-    if (!ret)
Daniel P. Berrangé 76097a
-        ignore_value(VIR_STRDUP_QUIET(ret, path));
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
+    return 0;
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
@@ -144,8 +134,7 @@ virFileWrapperOverridePrefix(const char *path)
Daniel P. Berrangé 76097a
     do { \
Daniel P. Berrangé 76097a
         init_syms(); \
Daniel P. Berrangé 76097a
  \
Daniel P. Berrangé 76097a
-        newpath = virFileWrapperOverridePrefix(path); \
Daniel P. Berrangé 76097a
-        if (!newpath) \
Daniel P. Berrangé 76097a
+        if (virMockStatRedirect(path, &newpath) < 0) \
Daniel P. Berrangé 76097a
             abort(); \
Daniel P. Berrangé 76097a
     } while (0)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
@@ -156,7 +145,7 @@ FILE *fopen(const char *path, const char *mode)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
     PATH_OVERRIDE(newpath, path);
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-    return real_fopen(newpath, mode);
Daniel P. Berrangé 76097a
+    return real_fopen(newpath ? newpath : path, mode);
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 int access(const char *path, int mode)
Daniel P. Berrangé 76097a
@@ -165,56 +154,7 @@ int access(const char *path, int mode)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
     PATH_OVERRIDE(newpath, path);
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-    return real_access(newpath, mode);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-# ifdef HAVE___LXSTAT
Daniel P. Berrangé 76097a
-int __lxstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    PATH_OVERRIDE(newpath, path);
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real___lxstat(ver, newpath, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-# endif /* HAVE___LXSTAT */
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-int lstat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    PATH_OVERRIDE(newpath, path);
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real_lstat(newpath, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-# ifdef HAVE___XSTAT
Daniel P. Berrangé 76097a
-int __xstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    PATH_OVERRIDE(newpath, path);
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real___xstat(ver, newpath, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-# endif /* HAVE___XSTAT */
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-int stat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    PATH_OVERRIDE(newpath, path);
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real_stat(newpath, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-int mkdir(const char *path, mode_t mode)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    PATH_OVERRIDE(newpath, path);
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real_mkdir(newpath, mode);
Daniel P. Berrangé 76097a
+    return real_access(newpath ? newpath : path, mode);
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 int open(const char *path, int flags, ...)
Daniel P. Berrangé 76097a
@@ -234,7 +174,7 @@ int open(const char *path, int flags, ...)
Daniel P. Berrangé 76097a
         va_end(ap);
Daniel P. Berrangé 76097a
     }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-    return real_open(newpath, flags, mode);
Daniel P. Berrangé 76097a
+    return real_open(newpath ? newpath : path, flags, mode);
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 DIR *opendir(const char *path)
Daniel P. Berrangé 76097a
@@ -243,6 +183,7 @@ DIR *opendir(const char *path)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
     PATH_OVERRIDE(newpath, path);
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-    return real_opendir(newpath);
Daniel P. Berrangé 76097a
+    return real_opendir(newpath ? newpath : path);
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
 #endif
Daniel P. Berrangé 76097a
diff --git a/tests/virmock.h b/tests/virmock.h
Daniel P. Berrangé 76097a
index 9c7ecf60ce..46631433c7 100644
Daniel P. Berrangé 76097a
--- a/tests/virmock.h
Daniel P. Berrangé 76097a
+++ b/tests/virmock.h
Daniel P. Berrangé 76097a
@@ -290,15 +290,4 @@
Daniel P. Berrangé 76097a
         } \
Daniel P. Berrangé 76097a
     } while (0)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-# define VIR_MOCK_REAL_INIT_ALT(name1, name2) \
Daniel P. Berrangé 76097a
-    do { \
Daniel P. Berrangé 76097a
-        real_ ## name1 = dlsym(RTLD_NEXT, #name1); \
Daniel P. Berrangé 76097a
-        real_ ## name2 = dlsym(RTLD_NEXT, #name2); \
Daniel P. Berrangé 76097a
-        if (!real_##name1 && !real_##name2) { \
Daniel P. Berrangé 76097a
-            fprintf(stderr, "Cannot find real '%s' or '%s' symbol\n", \
Daniel P. Berrangé 76097a
-                    #name1, #name2); \
Daniel P. Berrangé 76097a
-            abort(); \
Daniel P. Berrangé 76097a
-        } \
Daniel P. Berrangé 76097a
-    } while (0)
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
 #endif /* LIBVIRT_VIRMOCK_H */
Daniel P. Berrangé 76097a
diff --git a/tests/virmockstathelpers.c b/tests/virmockstathelpers.c
Daniel P. Berrangé 76097a
new file mode 100644
Daniel P. Berrangé 76097a
index 0000000000..0bbea4b437
Daniel P. Berrangé 76097a
--- /dev/null
Daniel P. Berrangé 76097a
+++ b/tests/virmockstathelpers.c
Daniel P. Berrangé 76097a
@@ -0,0 +1,326 @@
Daniel P. Berrangé 76097a
+/*
Daniel P. Berrangé 76097a
+ * Copyright (C) 2019 Red Hat, Inc.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * This library is free software; you can redistribute it and/or
Daniel P. Berrangé 76097a
+ * modify it under the terms of the GNU Lesser General Public
Daniel P. Berrangé 76097a
+ * License as published by the Free Software Foundation; either
Daniel P. Berrangé 76097a
+ * version 2.1 of the License, or (at your option) any later version.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * This library is distributed in the hope that it will be useful,
Daniel P. Berrangé 76097a
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Daniel P. Berrangé 76097a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Daniel P. Berrangé 76097a
+ * Lesser General Public License for more details.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * You should have received a copy of the GNU Lesser General Public
Daniel P. Berrangé 76097a
+ * License along with this library.  If not, see
Daniel P. Berrangé 76097a
+ * <http://www.gnu.org/licenses/>.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * Helpers for dealing with the many variants of stat(). This
Daniel P. Berrangé 76097a
+ * C file should be included from any file that wants to mock
Daniel P. Berrangé 76097a
+ * stat() correctly.
Daniel P. Berrangé 76097a
+ */
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#include "virmock.h"
Daniel P. Berrangé 76097a
+#include "viralloc.h"
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#include <sys/stat.h>
Daniel P. Berrangé 76097a
+#include <unistd.h>
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+/*
Daniel P. Berrangé 76097a
+ * The POSIX stat() function might resolve to any number of different
Daniel P. Berrangé 76097a
+ * symbols in the C library.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * The may be an additional stat64() function exposed by the headers
Daniel P. Berrangé 76097a
+ * too.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * On 64-bit hosts the stat & stat64 functions are identical, always
Daniel P. Berrangé 76097a
+ * refering to the 64-bit ABI.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * On 32-bit hosts they refer to the 32-bit & 64-bit ABIs respectively.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * Libvirt uses _FILE_OFFSET_BITS=64 on 32-bit hosts, which causes the
Daniel P. Berrangé 76097a
+ * C library to transparently rewrite stat() calls to be stat64() calls.
Daniel P. Berrangé 76097a
+ * Libvirt will never see the 32-bit ABI from the traditional stat()
Daniel P. Berrangé 76097a
+ * call. We cannot assume this rewriting is done using a macro. It might
Daniel P. Berrangé 76097a
+ * be, but on GLibC it is done with a magic __asm__ statement to apply
Daniel P. Berrangé 76097a
+ * the rewrite at link time instead of at preprocessing.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * In GLibC there may be two additional functions exposed by the headers,
Daniel P. Berrangé 76097a
+ * __xstat() and __xstat64(). When these exist, stat() and stat64() are
Daniel P. Berrangé 76097a
+ * transparently rewritten to call __xstat() and __xstat64() respectively.
Daniel P. Berrangé 76097a
+ * The former symbols will not actally exist in the library at all, only
Daniel P. Berrangé 76097a
+ * the header. The leading "__" indicates the symbols are a private impl
Daniel P. Berrangé 76097a
+ * detail of the C library that applications should not care about.
Daniel P. Berrangé 76097a
+ * Unfortunately, because we are trying to mock replace the C library,
Daniel P. Berrangé 76097a
+ * we need to know about this internal impl detail.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * With all this in mind the list of functions we have to mock will depend
Daniel P. Berrangé 76097a
+ * on several factors
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ *  - If _FILE_OFFSET_BITS is set, then we are on a 32-bit host, and we
Daniel P. Berrangé 76097a
+ *    only need to mock stat64 and __xstat64. The other stat / __xstat
Daniel P. Berrangé 76097a
+ *    functions exist, but we'll never call them so they can be ignored
Daniel P. Berrangé 76097a
+ *    for mocking.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ *  - If _FILE_OFFSET_BITS is not set, then we are on a 64-bit host and
Daniel P. Berrangé 76097a
+ *    we should mock stat, stat64, __xstat & __xstat64. Either may be
Daniel P. Berrangé 76097a
+ *    called by app code.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ *  - If __xstat & __xstat64 exist, then stat & stat64 will not exist
Daniel P. Berrangé 76097a
+ *    as symbols in the library, so the latter should not be mocked.
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * The same all applies to lstat()
Daniel P. Berrangé 76097a
+ */
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#if defined(HAVE_STAT) && !defined(HAVE___XSTAT) && !defined(_FILE_OFFSET_BITS)
Daniel P. Berrangé 76097a
+# define MOCK_STAT
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#if defined(HAVE_STAT64) && !defined(HAVE___XSTAT64)
Daniel P. Berrangé 76097a
+# define MOCK_STAT64
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#if defined(HAVE___XSTAT) && !defined(_FILE_OFFSET_BITS)
Daniel P. Berrangé 76097a
+# define MOCK___XSTAT
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#if defined(HAVE___XSTAT64)
Daniel P. Berrangé 76097a
+# define MOCK___XSTAT64
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#if defined(HAVE_LSTAT) && !defined(HAVE___LXSTAT) && !defined(_FILE_OFFSET_BITS)
Daniel P. Berrangé 76097a
+# define MOCK_LSTAT
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#if defined(HAVE_LSTAT64) && !defined(HAVE___LXSTAT64)
Daniel P. Berrangé 76097a
+# define MOCK_LSTAT64
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#if defined(HAVE___LXSTAT) && !defined(_FILE_OFFSET_BITS)
Daniel P. Berrangé 76097a
+# define MOCK___LXSTAT
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#if defined(HAVE___LXSTAT64)
Daniel P. Berrangé 76097a
+# define MOCK___LXSTAT64
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifdef MOCK_STAT
Daniel P. Berrangé 76097a
+static int (*real_stat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK_STAT64
Daniel P. Berrangé 76097a
+static int (*real_stat64)(const char *path, struct stat64 *sb);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK___XSTAT
Daniel P. Berrangé 76097a
+static int (*real___xstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK___XSTAT64
Daniel P. Berrangé 76097a
+static int (*real___xstat64)(int ver, const char *path, struct stat64 *sb);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK_LSTAT
Daniel P. Berrangé 76097a
+static int (*real_lstat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK_LSTAT64
Daniel P. Berrangé 76097a
+static int (*real_lstat64)(const char *path, struct stat64 *sb);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK___LXSTAT
Daniel P. Berrangé 76097a
+static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK___LXSTAT64
Daniel P. Berrangé 76097a
+static int (*real___lxstat64)(int ver, const char *path, struct stat64 *sb);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+static bool init;
Daniel P. Berrangé 76097a
+static bool debug;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#define fdebug(msg, ...) do { if (debug) fprintf(stderr, msg, __VA_ARGS__); } while (0)
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+static void virMockStatInit(void)
Daniel P. Berrangé 76097a
+{
Daniel P. Berrangé 76097a
+    if (init)
Daniel P. Berrangé 76097a
+        return;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    init = true;
Daniel P. Berrangé 76097a
+    debug = getenv("VIR_MOCK_STAT_DEBUG");
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifdef MOCK_STAT
Daniel P. Berrangé 76097a
+    VIR_MOCK_REAL_INIT(stat);
Daniel P. Berrangé 76097a
+    fdebug("real stat %p\n", real_stat);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK_STAT64
Daniel P. Berrangé 76097a
+    VIR_MOCK_REAL_INIT(stat64);
Daniel P. Berrangé 76097a
+    fdebug("real stat64 %p\n", real_stat64);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK___XSTAT
Daniel P. Berrangé 76097a
+    VIR_MOCK_REAL_INIT(__xstat);
Daniel P. Berrangé 76097a
+    fdebug("real __xstat %p\n", real___xstat);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK___XSTAT64
Daniel P. Berrangé 76097a
+    VIR_MOCK_REAL_INIT(__xstat64);
Daniel P. Berrangé 76097a
+    fdebug("real __xstat64 %p\n", real___xstat64);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK_LSTAT
Daniel P. Berrangé 76097a
+    VIR_MOCK_REAL_INIT(lstat);
Daniel P. Berrangé 76097a
+    fdebug("real lstat %p\n", real_lstat);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK_LSTAT64
Daniel P. Berrangé 76097a
+    VIR_MOCK_REAL_INIT(lstat64);
Daniel P. Berrangé 76097a
+    fdebug("real lstat64 %p\n", real_lstat64);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK___LXSTAT
Daniel P. Berrangé 76097a
+    VIR_MOCK_REAL_INIT(__lxstat);
Daniel P. Berrangé 76097a
+    fdebug("real __lxstat %p\n", real___lxstat);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+#ifdef MOCK___LXSTAT64
Daniel P. Berrangé 76097a
+    VIR_MOCK_REAL_INIT(__lxstat64);
Daniel P. Berrangé 76097a
+    fdebug("real __lxstat64 %p\n", real___lxstat64);
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+}
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+/*
Daniel P. Berrangé 76097a
+ * @stat: the path being queried
Daniel P. Berrangé 76097a
+ * @newpath: fill with redirected path, or leave NULL to use orig path
Daniel P. Berrangé 76097a
+ *
Daniel P. Berrangé 76097a
+ * Return 0 on success, -1 on allocation error
Daniel P. Berrangé 76097a
+ */
Daniel P. Berrangé 76097a
+static int virMockStatRedirect(const char *path, char **newpath);
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifndef VIR_MOCK_STAT_HOOK
Daniel P. Berrangé 76097a
+# define VIR_MOCK_STAT_HOOK do { } while (0)
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifdef MOCK_STAT
Daniel P. Berrangé 76097a
+int stat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
+{
Daniel P. Berrangé 76097a
+    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    virMockStatInit();
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    if (virMockStatRedirect(path, &newpath) < 0)
Daniel P. Berrangé 76097a
+        abort();
Daniel P. Berrangé 76097a
+    fdebug("stat redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    VIR_MOCK_STAT_HOOK;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    return real_stat(newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+}
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifdef MOCK_STAT64
Daniel P. Berrangé 76097a
+int stat64(const char *path, struct stat64 *sb)
Daniel P. Berrangé 76097a
+{
Daniel P. Berrangé 76097a
+    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    virMockStatInit();
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    if (virMockStatRedirect(path, &newpath) < 0)
Daniel P. Berrangé 76097a
+        abort();
Daniel P. Berrangé 76097a
+    fdebug("stat64 redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    VIR_MOCK_STAT_HOOK;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    return real_stat64(newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+}
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifdef MOCK___XSTAT
Daniel P. Berrangé 76097a
+int
Daniel P. Berrangé 76097a
+__xstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
+{
Daniel P. Berrangé 76097a
+    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    virMockStatInit();
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    if (virMockStatRedirect(path, &newpath) < 0)
Daniel P. Berrangé 76097a
+        abort();
Daniel P. Berrangé 76097a
+    fdebug("__xstat redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    VIR_MOCK_STAT_HOOK;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    return real___xstat(ver, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+}
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifdef MOCK___XSTAT64
Daniel P. Berrangé 76097a
+int
Daniel P. Berrangé 76097a
+__xstat64(int ver, const char *path, struct stat64 *sb)
Daniel P. Berrangé 76097a
+{
Daniel P. Berrangé 76097a
+    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    virMockStatInit();
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    if (virMockStatRedirect(path, &newpath) < 0)
Daniel P. Berrangé 76097a
+        abort();
Daniel P. Berrangé 76097a
+    fdebug("__xstat64 redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    VIR_MOCK_STAT_HOOK;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    return real___xstat64(ver, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+}
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifdef MOCK_LSTAT
Daniel P. Berrangé 76097a
+int
Daniel P. Berrangé 76097a
+lstat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
+{
Daniel P. Berrangé 76097a
+    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    virMockStatInit();
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    if (virMockStatRedirect(path, &newpath) < 0)
Daniel P. Berrangé 76097a
+        abort();
Daniel P. Berrangé 76097a
+    fdebug("lstat redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    VIR_MOCK_STAT_HOOK;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    return real_lstat(newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+}
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifdef MOCK_LSTAT64
Daniel P. Berrangé 76097a
+int
Daniel P. Berrangé 76097a
+lstat64(const char *path, struct stat64 *sb)
Daniel P. Berrangé 76097a
+{
Daniel P. Berrangé 76097a
+    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    virMockStatInit();
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    if (virMockStatRedirect(path, &newpath) < 0)
Daniel P. Berrangé 76097a
+        abort();
Daniel P. Berrangé 76097a
+    fdebug("lstat64 redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    VIR_MOCK_STAT_HOOK;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    return real_lstat64(newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+}
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifdef MOCK___LXSTAT
Daniel P. Berrangé 76097a
+int
Daniel P. Berrangé 76097a
+__lxstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
+{
Daniel P. Berrangé 76097a
+    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    virMockStatInit();
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    if (virMockStatRedirect(path, &newpath) < 0)
Daniel P. Berrangé 76097a
+        abort();
Daniel P. Berrangé 76097a
+    fdebug("__lxstat redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    VIR_MOCK_STAT_HOOK;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    return real___lxstat(ver, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+}
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+#ifdef MOCK___LXSTAT64
Daniel P. Berrangé 76097a
+int
Daniel P. Berrangé 76097a
+__lxstat64(int ver, const char *path, struct stat64 *sb)
Daniel P. Berrangé 76097a
+{
Daniel P. Berrangé 76097a
+    VIR_AUTOFREE(char *) newpath = NULL;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    virMockStatInit();
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    if (virMockStatRedirect(path, &newpath) < 0)
Daniel P. Berrangé 76097a
+        abort();
Daniel P. Berrangé 76097a
+    fdebug("__lxstat64 redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    VIR_MOCK_STAT_HOOK;
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+    return real___lxstat64(ver, newpath ? newpath : path, sb);
Daniel P. Berrangé 76097a
+}
Daniel P. Berrangé 76097a
+#endif
Daniel P. Berrangé 76097a
diff --git a/tests/virpcimock.c b/tests/virpcimock.c
Daniel P. Berrangé 76097a
index ce8176cbec..7f9cdaa9b8 100644
Daniel P. Berrangé 76097a
--- a/tests/virpcimock.c
Daniel P. Berrangé 76097a
+++ b/tests/virpcimock.c
Daniel P. Berrangé 76097a
@@ -31,10 +31,6 @@
Daniel P. Berrangé 76097a
 # include "dirname.h"
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 static int (*real_access)(const char *path, int mode);
Daniel P. Berrangé 76097a
-static int (*real_lstat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real_stat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real___xstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
 static int (*real_open)(const char *path, int flags, ...);
Daniel P. Berrangé 76097a
 static int (*real_close)(int fd);
Daniel P. Berrangé 76097a
 static DIR * (*real_opendir)(const char *name);
Daniel P. Berrangé 76097a
@@ -365,15 +361,9 @@ pci_device_new_from_stub(const struct pciDevice *data)
Daniel P. Berrangé 76097a
     if (virFileMakePath(devpath) < 0)
Daniel P. Berrangé 76097a
         ABORT("Unable to create: %s", devpath);
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-    if (real_stat && real_stat(configSrc, &sb) == 0)
Daniel P. Berrangé 76097a
+    if (stat(configSrc, &sb) == 0)
Daniel P. Berrangé 76097a
         configSrcExists = true;
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-# ifdef HAVE___XSTAT
Daniel P. Berrangé 76097a
-    if (!configSrcExists &&
Daniel P. Berrangé 76097a
-        real___xstat && real___xstat(_STAT_VER, configSrc, &sb) == 0)
Daniel P. Berrangé 76097a
-        configSrcExists = true;
Daniel P. Berrangé 76097a
-# endif
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
     /* If there is a config file for the device within virpcitestdata dir,
Daniel P. Berrangé 76097a
      * symlink it. Otherwise create a dummy config file. */
Daniel P. Berrangé 76097a
     if (configSrcExists) {
Daniel P. Berrangé 76097a
@@ -813,8 +803,6 @@ init_syms(void)
Daniel P. Berrangé 76097a
         return;
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(access);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(open);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(close);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(opendir);
Daniel P. Berrangé 76097a
@@ -896,85 +884,17 @@ access(const char *path, int mode)
Daniel P. Berrangé 76097a
     return ret;
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-# ifdef HAVE___LXSTAT
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-__lxstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    if (STRPREFIX(path, SYSFS_PCI_PREFIX)) {
Daniel P. Berrangé 76097a
-        char *newpath;
Daniel P. Berrangé 76097a
-        if (getrealpath(&newpath, path) < 0)
Daniel P. Berrangé 76097a
-            return -1;
Daniel P. Berrangé 76097a
-        ret = real___lxstat(ver, newpath, sb);
Daniel P. Berrangé 76097a
-        VIR_FREE(newpath);
Daniel P. Berrangé 76097a
-    } else {
Daniel P. Berrangé 76097a
-        ret = real___lxstat(ver, path, sb);
Daniel P. Berrangé 76097a
-    }
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-# endif /* HAVE___LXSTAT */
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-lstat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    if (STRPREFIX(path, SYSFS_PCI_PREFIX)) {
Daniel P. Berrangé 76097a
-        char *newpath;
Daniel P. Berrangé 76097a
-        if (getrealpath(&newpath, path) < 0)
Daniel P. Berrangé 76097a
-            return -1;
Daniel P. Berrangé 76097a
-        ret = real_lstat(newpath, sb);
Daniel P. Berrangé 76097a
-        VIR_FREE(newpath);
Daniel P. Berrangé 76097a
-    } else {
Daniel P. Berrangé 76097a
-        ret = real_lstat(path, sb);
Daniel P. Berrangé 76097a
-    }
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-# ifdef HAVE___XSTAT
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-__xstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
+static int
Daniel P. Berrangé 76097a
+virMockStatRedirect(const char *path, char **newpath)
Daniel P. Berrangé 76097a
 {
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
     if (STRPREFIX(path, SYSFS_PCI_PREFIX)) {
Daniel P. Berrangé 76097a
-        char *newpath;
Daniel P. Berrangé 76097a
-        if (getrealpath(&newpath, path) < 0)
Daniel P. Berrangé 76097a
+        if (getrealpath(newpath, path) < 0)
Daniel P. Berrangé 76097a
             return -1;
Daniel P. Berrangé 76097a
-        ret = real___xstat(ver, newpath, sb);
Daniel P. Berrangé 76097a
-        VIR_FREE(newpath);
Daniel P. Berrangé 76097a
-    } else {
Daniel P. Berrangé 76097a
-        ret = real___xstat(ver, path, sb);
Daniel P. Berrangé 76097a
     }
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
+    return 0;
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
-# endif /* HAVE___XSTAT */
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-stat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    int ret;
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    if (STRPREFIX(path, SYSFS_PCI_PREFIX)) {
Daniel P. Berrangé 76097a
-        char *newpath;
Daniel P. Berrangé 76097a
-        if (getrealpath(&newpath, path) < 0)
Daniel P. Berrangé 76097a
-            return -1;
Daniel P. Berrangé 76097a
-        ret = real_stat(newpath, sb);
Daniel P. Berrangé 76097a
-        VIR_FREE(newpath);
Daniel P. Berrangé 76097a
-    } else {
Daniel P. Berrangé 76097a
-        ret = real_stat(path, sb);
Daniel P. Berrangé 76097a
-    }
Daniel P. Berrangé 76097a
-    return ret;
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 int
Daniel P. Berrangé 76097a
 open(const char *path, int flags, ...)
Daniel P. Berrangé 76097a
@@ -1058,6 +978,9 @@ virFileCanonicalizePath(const char *path)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
     return ret;
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
+# include "virmockstathelpers.c"
Daniel P. Berrangé 76097a
+
Daniel P. Berrangé 76097a
 #else
Daniel P. Berrangé 76097a
 /* Nothing to override on this platform */
Daniel P. Berrangé 76097a
 #endif
Daniel P. Berrangé 76097a
diff --git a/tests/virtestmock.c b/tests/virtestmock.c
Daniel P. Berrangé 76097a
index 3049c90789..bc62312444 100644
Daniel P. Berrangé 76097a
--- a/tests/virtestmock.c
Daniel P. Berrangé 76097a
+++ b/tests/virtestmock.c
Daniel P. Berrangé 76097a
@@ -36,33 +36,9 @@
Daniel P. Berrangé 76097a
 #include "viralloc.h"
Daniel P. Berrangé 76097a
 #include "virfile.h"
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-/* stat can be a macro as follows:
Daniel P. Berrangé 76097a
- *
Daniel P. Berrangé 76097a
- *   #define stat stat64
Daniel P. Berrangé 76097a
- *
Daniel P. Berrangé 76097a
- * This wouldn't fly with our mock. Make sure that the macro (and
Daniel P. Berrangé 76097a
- * all its friends) are undefined. We don't want anybody mangling
Daniel P. Berrangé 76097a
- * our code. */
Daniel P. Berrangé 76097a
-#undef stat
Daniel P. Berrangé 76097a
-#undef stat64
Daniel P. Berrangé 76097a
-#undef __xstat
Daniel P. Berrangé 76097a
-#undef __xstat64
Daniel P. Berrangé 76097a
-#undef lstat
Daniel P. Berrangé 76097a
-#undef lstat64
Daniel P. Berrangé 76097a
-#undef __lxstat
Daniel P. Berrangé 76097a
-#undef __lxstat64
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
 static int (*real_open)(const char *path, int flags, ...);
Daniel P. Berrangé 76097a
 static FILE *(*real_fopen)(const char *path, const char *mode);
Daniel P. Berrangé 76097a
 static int (*real_access)(const char *path, int mode);
Daniel P. Berrangé 76097a
-static int (*real_stat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real_stat64)(const char *path, void *sb);
Daniel P. Berrangé 76097a
-static int (*real___xstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real___xstat64)(int ver, const char *path, void *sb);
Daniel P. Berrangé 76097a
-static int (*real_lstat)(const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real_lstat64)(const char *path, void *sb);
Daniel P. Berrangé 76097a
-static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
Daniel P. Berrangé 76097a
-static int (*real___lxstat64)(int ver, const char *path, void *sb);
Daniel P. Berrangé 76097a
 static int (*real_connect)(int fd, const struct sockaddr *addr, socklen_t addrlen);
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 static const char *progname;
Daniel P. Berrangé 76097a
@@ -78,10 +54,6 @@ static void init_syms(void)
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(open);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(fopen);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(access);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(stat64, __xstat64);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
Daniel P. Berrangé 76097a
-    VIR_MOCK_REAL_INIT_ALT(lstat64, __lxstat64);
Daniel P. Berrangé 76097a
     VIR_MOCK_REAL_INIT(connect);
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
@@ -217,119 +189,15 @@ int access(const char *path, int mode)
Daniel P. Berrangé 76097a
     return real_access(path, mode);
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-/* Okay, the following ifdef rain forest may look messy at a
Daniel P. Berrangé 76097a
- * first glance. But here's the thing: during run time linking of
Daniel P. Berrangé 76097a
- * a binary, stat() may not be actually needing symbol stat. It
Daniel P. Berrangé 76097a
- * might as well not had been stat() in the first place (see the
Daniel P. Berrangé 76097a
- * reasoning at the beginning of this file). However, if we would
Daniel P. Berrangé 76097a
- * expose stat symbol here, we will poison the well and trick
Daniel P. Berrangé 76097a
- * dynamic linker into thinking we are some old binary that still
Daniel P. Berrangé 76097a
- * uses the symbol. So whenever code from upper layers calls
Daniel P. Berrangé 76097a
- * stat(), the control would get here, but real_stat can actually
Daniel P. Berrangé 76097a
- * be a NULL pointer because newer glibc have __xstat instead.
Daniel P. Berrangé 76097a
- * Worse, it can have __xstat64 instead __xstat.
Daniel P. Berrangé 76097a
- *
Daniel P. Berrangé 76097a
- * Anyway, these ifdefs are there to implement the following
Daniel P. Berrangé 76097a
- * preference function:
Daniel P. Berrangé 76097a
- *
Daniel P. Berrangé 76097a
- * stat < stat64 < __xstat < __xstat64
Daniel P. Berrangé 76097a
- *
Daniel P. Berrangé 76097a
- * It's the same story with lstat.
Daniel P. Berrangé 76097a
- * Also, I feel sorry for you that you had to read this.
Daniel P. Berrangé 76097a
- */
Daniel P. Berrangé 76097a
-#if defined(HAVE_STAT) && !defined(HAVE___XSTAT)
Daniel P. Berrangé 76097a
-int stat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-    checkPath(path, "stat");
Daniel P. Berrangé 76097a
+#define VIR_MOCK_STAT_HOOK CHECK_PATH(path)
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-    return real_stat(path, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-#endif
Daniel P. Berrangé 76097a
+#include "virmockstathelpers.c"
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
-#if defined(HAVE_STAT64) && !defined(HAVE___XSTAT64)
Daniel P. Berrangé 76097a
-int stat64(const char *path, struct stat64 *sb)
Daniel P. Berrangé 76097a
+static int virMockStatRedirect(const char *path ATTRIBUTE_UNUSED, char **newpath ATTRIBUTE_UNUSED)
Daniel P. Berrangé 76097a
 {
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    checkPath(path, "stat");
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real_stat64(path, sb);
Daniel P. Berrangé 76097a
+    return 0;
Daniel P. Berrangé 76097a
 }
Daniel P. Berrangé 76097a
-#endif
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-#if defined(HAVE___XSTAT) && !defined(HAVE___XSTAT64)
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-__xstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    checkPath(path, "stat");
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real___xstat(ver, path, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-#endif
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-#if defined(HAVE___XSTAT64)
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-__xstat64(int ver, const char *path, struct stat64 *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    checkPath(path, "stat");
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real___xstat64(ver, path, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-#endif
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-#if defined(HAVE_LSTAT) && !defined(HAVE___LXSTAT)
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-lstat(const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    checkPath(path, "lstat");
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real_lstat(path, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-#endif
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-#if defined(HAVE_LSTAT64) && !defined(HAVE___LXSTAT64)
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-lstat64(const char *path, struct stat64 *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    checkPath(path, "lstat");
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real_lstat64(path, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-#endif
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-#if defined(HAVE___LXSTAT) && !defined(HAVE___LXSTAT64)
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-__lxstat(int ver, const char *path, struct stat *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    checkPath(path, "lstat");
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real___lxstat(ver, path, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-#endif
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-#if defined(HAVE___LXSTAT64)
Daniel P. Berrangé 76097a
-int
Daniel P. Berrangé 76097a
-__lxstat64(int ver, const char *path, struct stat64 *sb)
Daniel P. Berrangé 76097a
-{
Daniel P. Berrangé 76097a
-    init_syms();
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    checkPath(path, "lstat");
Daniel P. Berrangé 76097a
-
Daniel P. Berrangé 76097a
-    return real___lxstat64(ver, path, sb);
Daniel P. Berrangé 76097a
-}
Daniel P. Berrangé 76097a
-#endif
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 
Daniel P. Berrangé 76097a
 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
Daniel P. Berrangé 76097a
-- 
Daniel P. Berrangé 76097a
2.20.1
Daniel P. Berrangé 76097a