1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-22 17:34:18 +03:00

tests: fix mocking of stat() / lstat() functions

Quite a few of the tests have a need to mock the stat() / lstat()
functions and they are taking somewhat different & inconsistent
approaches none of which are actually fully correct. This is shown
by fact that 'make check' fails on 32-bit hosts. Investigation
revealed that the code was calling into the native C library impl,
not getting intercepted by our mocks.

The POSIX stat() function might resolve to any number of different
symbols in the C library.

The may be an additional stat64() function exposed by the headers
too.

On 64-bit hosts the stat & stat64 functions are identical, always
refering to the 64-bit ABI.

On 32-bit hosts they refer to the 32-bit & 64-bit ABIs respectively.

Libvirt uses _FILE_OFFSET_BITS=64 on 32-bit hosts, which causes the
C library to transparently rewrite stat() calls to be stat64() calls.
Libvirt will never see the 32-bit ABI from the traditional stat()
call. We cannot assume this rewriting is done using a macro. It might
be, but on GLibC it is done with a magic __asm__ statement to apply
the rewrite at link time instead of at preprocessing.

In GLibC there may be two additional functions exposed by the headers,
__xstat() and __xstat64(). When these exist, stat() and stat64() are
transparently rewritten to call __xstat() and __xstat64() respectively.
The former symbols will not actally exist in the library at all, only
the header. The leading "__" indicates the symbols are a private impl
detail of the C library that applications should not care about.
Unfortunately, because we are trying to mock replace the C library,
we need to know about this internal impl detail.

With all this in mind the list of functions we have to mock will depend
on several factors

 - If _FILE_OFFSET_BITS is set, then we are on a 32-bit host, and we
   only need to mock stat64 and __xstat64. The other stat / __xstat
   functions exist, but we'll never call them so they can be ignored
   for mocking.

 - If _FILE_OFFSET_BITS is not set, then we are on a 64-bit host and
   we should mock stat, stat64, __xstat & __xstat64. Either may be
   called by app code.

 - If __xstat & __xstat64 exist, then stat & stat64 will not exist
   as symbols in the library, so the latter should not be mocked.

The same all applies to lstat()

These rules are complex enough that we don't want to duplicate them
across every mock file, so this centralizes all the logic in a helper
file virmockstathelper.c that should be #included when needed. The
code merely need to provide a filename rewriting callback called
virMockStatRedirect(). Optionally VIR_MOCK_STAT_HOOK can be defined
as a macro if further processing is needed inline.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2019-04-01 17:47:25 +01:00
parent ac21141ce4
commit ff376c6283
10 changed files with 420 additions and 534 deletions

View File

@ -6,6 +6,9 @@ my %mocked;
# Functions in public header don't get the noinline annotation
# so whitelist them here
$noninlined{"virEventAddTimeout"} = 1;
# This one confuses the script as its defined in the mock file
# but is actually just a local helper
$noninlined{"virMockStatRedirect"} = 1;
foreach my $arg (@ARGV) {
if ($arg =~ /\.h$/) {

4
cfg.mk
View File

@ -1272,10 +1272,10 @@ exclude_file_name_regexp--sc_prohibit_xmlURI = ^src/util/viruri\.c$$
exclude_file_name_regexp--sc_prohibit_return_as_function = \.py$$
exclude_file_name_regexp--sc_require_config_h = \
^(examples/|tools/virsh-edit\.c$$)
^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c)
exclude_file_name_regexp--sc_require_config_h_first = \
^(examples/|tools/virsh-edit\.c$$)
^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c)
exclude_file_name_regexp--sc_trailing_blank = \
/sysinfodata/.*\.data|/virhostcpudata/.*\.cpuinfo|^gnulib/local/.*/.*diff$$

View File

@ -146,6 +146,7 @@ EXTRA_DIST = \
virjsondata \
virmacmaptestdata \
virmock.h \
virmockstathelpers.h \
virnetdaemondata \
virnetdevtestdata \
virnwfilterbindingxml2xmldata \

View File

@ -50,10 +50,6 @@
static int (*real_chown)(const char *path, uid_t uid, gid_t gid);
static int (*real_lstat)(const char *path, struct stat *sb);
static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
static int (*real_stat)(const char *path, struct stat *sb);
static int (*real___xstat)(int ver, const char *path, struct stat *sb);
static int (*real_open)(const char *path, int flags, ...);
static int (*real_close)(int fd);
@ -106,8 +102,6 @@ init_syms(void)
return;
VIR_MOCK_REAL_INIT(chown);
VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
VIR_MOCK_REAL_INIT(open);
VIR_MOCK_REAL_INIT(close);
@ -211,36 +205,35 @@ int virFileRemoveXAttr(const char *path,
}
static int
mock_stat(const char *path,
struct stat *sb)
{
uint32_t *val;
virMutexLock(&m);
init_hash();
memset(sb, 0, sizeof(*sb));
sb->st_mode = S_IFREG | 0666;
sb->st_size = 123456;
sb->st_ino = 1;
if (!(val = virHashLookup(chown_paths, path))) {
/* New path. Set the defaults */
sb->st_uid = DEFAULT_UID;
sb->st_gid = DEFAULT_GID;
} else {
/* Known path. Set values passed to chown() earlier */
sb->st_uid = *val % 16;
sb->st_gid = *val >> 16;
}
virMutexUnlock(&m);
return 0;
}
#define VIR_MOCK_STAT_HOOK \
do { \
if (getenv(ENVVAR)) { \
uint32_t *val; \
\
virMutexLock(&m); \
init_hash(); \
\
memset(sb, 0, sizeof(*sb)); \
\
sb->st_mode = S_IFREG | 0666; \
sb->st_size = 123456; \
sb->st_ino = 1; \
\
if (!(val = virHashLookup(chown_paths, path))) { \
/* New path. Set the defaults */ \
sb->st_uid = DEFAULT_UID; \
sb->st_gid = DEFAULT_GID; \
} else { \
/* Known path. Set values passed to chown() earlier */ \
sb->st_uid = *val % 16; \
sb->st_gid = *val >> 16; \
} \
\
virMutexUnlock(&m); \
\
return 0; \
} \
} while (0)
static int
mock_chown(const char *path,
@ -276,68 +269,12 @@ mock_chown(const char *path,
}
#ifdef HAVE___LXSTAT
int
__lxstat(int ver, const char *path, struct stat *sb)
#include "virmockstathelpers.c"
static int
virMockStatRedirect(const char *path ATTRIBUTE_UNUSED, char **newpath ATTRIBUTE_UNUSED)
{
int ret;
init_syms();
if (getenv(ENVVAR))
ret = mock_stat(path, sb);
else
ret = real___lxstat(ver, path, sb);
return ret;
}
#endif /* HAVE___LXSTAT */
int
lstat(const char *path, struct stat *sb)
{
int ret;
init_syms();
if (getenv(ENVVAR))
ret = mock_stat(path, sb);
else
ret = real_lstat(path, sb);
return ret;
}
#ifdef HAVE___XSTAT
int
__xstat(int ver, const char *path, struct stat *sb)
{
int ret;
init_syms();
if (getenv(ENVVAR))
ret = mock_stat(path, sb);
else
ret = real___xstat(ver, path, sb);
return ret;
}
#endif /* HAVE___XSTAT */
int
stat(const char *path, struct stat *sb)
{
int ret;
init_syms();
if (getenv(ENVVAR))
ret = mock_stat(path, sb);
else
ret = real_stat(path, sb);
return ret;
return 0;
}
@ -386,6 +323,8 @@ close(int fd)
{
int ret;
init_syms();
if (fd == 42 && getenv(ENVVAR))
ret = 0;
else

View File

@ -38,10 +38,6 @@
static int (*real_open)(const char *path, int flags, ...);
static FILE *(*real_fopen)(const char *path, const char *mode);
static int (*real_access)(const char *path, int mode);
static int (*real_stat)(const char *path, struct stat *sb);
static int (*real___xstat)(int ver, const char *path, struct stat *sb);
static int (*real_lstat)(const char *path, struct stat *sb);
static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
static int (*real_mkdir)(const char *path, mode_t mode);
/* Don't make static, since it causes problems with clang
@ -317,8 +313,6 @@ static void init_syms(void)
VIR_MOCK_REAL_INIT(fopen);
VIR_MOCK_REAL_INIT(access);
VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
VIR_MOCK_REAL_INIT(mkdir);
VIR_MOCK_REAL_INIT(open);
}
@ -508,139 +502,41 @@ int access(const char *path, int mode)
return ret;
}
int __lxstat(int ver, const char *path, struct stat *sb)
# define VIR_MOCK_STAT_HOOK \
do { \
if (STRPREFIX(path, fakedevicedir0)) { \
sb->st_mode = S_IFBLK; \
sb->st_rdev = makedev(8, 0); \
return 0; \
} else if (STRPREFIX(path, fakedevicedir1)) { \
sb->st_mode = S_IFBLK; \
sb->st_rdev = makedev(9, 0); \
return 0; \
} \
} while (0)
# include "virmockstathelpers.c"
static int
virMockStatRedirect(const char *path, char **newpath)
{
int ret;
init_syms();
if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
init_sysfs();
char *newpath;
if (asprintf(&newpath, "%s%s",
fakesysfscgroupdir,
path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
errno = ENOMEM;
return -1;
}
ret = real___lxstat(ver, newpath, sb);
free(newpath);
} else if (STRPREFIX(path, fakedevicedir0)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(8, 0);
return 0;
} else if (STRPREFIX(path, fakedevicedir1)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(9, 0);
return 0;
} else {
ret = real___lxstat(ver, path, sb);
}
return ret;
}
int lstat(const char *path, struct stat *sb)
{
int ret;
init_syms();
if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
init_sysfs();
char *newpath;
if (asprintf(&newpath, "%s%s",
fakesysfscgroupdir,
path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
errno = ENOMEM;
return -1;
}
ret = real_lstat(newpath, sb);
free(newpath);
} else if (STRPREFIX(path, fakedevicedir0)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(8, 0);
return 0;
} else if (STRPREFIX(path, fakedevicedir1)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(9, 0);
return 0;
} else {
ret = real_lstat(path, sb);
}
return ret;
}
int __xstat(int ver, const char *path, struct stat *sb)
{
int ret;
init_syms();
if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
init_sysfs();
char *newpath;
if (asprintf(&newpath, "%s%s",
fakesysfscgroupdir,
path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
errno = ENOMEM;
return -1;
}
ret = real___xstat(ver, newpath, sb);
free(newpath);
} else if (STRPREFIX(path, fakedevicedir0)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(8, 0);
return 0;
} else if (STRPREFIX(path, fakedevicedir1)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(9, 0);
return 0;
} else {
ret = real___xstat(ver, path, sb);
}
return ret;
}
int stat(const char *path, struct stat *sb)
{
char *newpath = NULL;
int ret;
init_syms();
if (STREQ(path, SYSFS_CPU_PRESENT)) {
init_sysfs();
if (asprintf(&newpath, "%s/%s",
if (asprintf(newpath, "%s/%s",
fakesysfscgroupdir,
SYSFS_CPU_PRESENT_MOCKED) < 0) {
errno = ENOMEM;
SYSFS_CPU_PRESENT_MOCKED) < 0)
return -1;
}
} else if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
init_sysfs();
if (asprintf(&newpath, "%s%s",
if (asprintf(newpath, "%s%s",
fakesysfscgroupdir,
path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
errno = ENOMEM;
return -1;
}
} else if (STRPREFIX(path, fakedevicedir0)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(8, 0);
return 0;
} else if (STRPREFIX(path, fakedevicedir1)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(9, 0);
return 0;
} else {
if (!(newpath = strdup(path)))
path + strlen(SYSFS_CGROUP_PREFIX)) < 0)
return -1;
}
ret = real_stat(newpath, sb);
free(newpath);
return ret;
return 0;
}
int mkdir(const char *path, mode_t mode)
{
int ret;

View File

@ -39,15 +39,9 @@ static size_t nprefixes;
static const char **prefixes;
/* TODO: callbacks */
static int (*real_open)(const char *path, int flags, ...);
static FILE *(*real_fopen)(const char *path, const char *mode);
static int (*real_access)(const char *path, int mode);
static int (*real_stat)(const char *path, struct stat *sb);
static int (*real___xstat)(int ver, const char *path, struct stat *sb);
static int (*real_lstat)(const char *path, struct stat *sb);
static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
static int (*real_mkdir)(const char *path, mode_t mode);
static DIR *(*real_opendir)(const char *path);
@ -58,8 +52,6 @@ static void init_syms(void)
VIR_MOCK_REAL_INIT(fopen);
VIR_MOCK_REAL_INIT(access);
VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
VIR_MOCK_REAL_INIT(mkdir);
VIR_MOCK_REAL_INIT(open);
VIR_MOCK_REAL_INIT(opendir);
@ -115,10 +107,11 @@ virFileWrapperClearPrefixes(void)
VIR_FREE(overrides);
}
static char *
virFileWrapperOverridePrefix(const char *path)
# include "virmockstathelpers.c"
int
virMockStatRedirect(const char *path, char **newpath)
{
char *ret = NULL;
size_t i = 0;
for (i = 0; i < noverrides; i++) {
@ -127,16 +120,13 @@ virFileWrapperOverridePrefix(const char *path)
if (!tmp)
continue;
if (virAsprintfQuiet(&ret, "%s%s", overrides[i], tmp) < 0)
return NULL;
if (virAsprintfQuiet(newpath, "%s%s", overrides[i], tmp) < 0)
return -1;
break;
}
if (!ret)
ignore_value(VIR_STRDUP_QUIET(ret, path));
return ret;
return 0;
}
@ -144,8 +134,7 @@ virFileWrapperOverridePrefix(const char *path)
do { \
init_syms(); \
\
newpath = virFileWrapperOverridePrefix(path); \
if (!newpath) \
if (virMockStatRedirect(path, &newpath) < 0) \
abort(); \
} while (0)
@ -156,7 +145,7 @@ FILE *fopen(const char *path, const char *mode)
PATH_OVERRIDE(newpath, path);
return real_fopen(newpath, mode);
return real_fopen(newpath ? newpath : path, mode);
}
int access(const char *path, int mode)
@ -165,56 +154,7 @@ int access(const char *path, int mode)
PATH_OVERRIDE(newpath, path);
return real_access(newpath, mode);
}
# ifdef HAVE___LXSTAT
int __lxstat(int ver, const char *path, struct stat *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
PATH_OVERRIDE(newpath, path);
return real___lxstat(ver, newpath, sb);
}
# endif /* HAVE___LXSTAT */
int lstat(const char *path, struct stat *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
PATH_OVERRIDE(newpath, path);
return real_lstat(newpath, sb);
}
# ifdef HAVE___XSTAT
int __xstat(int ver, const char *path, struct stat *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
PATH_OVERRIDE(newpath, path);
return real___xstat(ver, newpath, sb);
}
# endif /* HAVE___XSTAT */
int stat(const char *path, struct stat *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
PATH_OVERRIDE(newpath, path);
return real_stat(newpath, sb);
}
int mkdir(const char *path, mode_t mode)
{
VIR_AUTOFREE(char *) newpath = NULL;
PATH_OVERRIDE(newpath, path);
return real_mkdir(newpath, mode);
return real_access(newpath ? newpath : path, mode);
}
int open(const char *path, int flags, ...)
@ -234,7 +174,7 @@ int open(const char *path, int flags, ...)
va_end(ap);
}
return real_open(newpath, flags, mode);
return real_open(newpath ? newpath : path, flags, mode);
}
DIR *opendir(const char *path)
@ -243,6 +183,7 @@ DIR *opendir(const char *path)
PATH_OVERRIDE(newpath, path);
return real_opendir(newpath);
return real_opendir(newpath ? newpath : path);
}
#endif

View File

@ -290,15 +290,4 @@
} \
} while (0)
# define VIR_MOCK_REAL_INIT_ALT(name1, name2) \
do { \
real_ ## name1 = dlsym(RTLD_NEXT, #name1); \
real_ ## name2 = dlsym(RTLD_NEXT, #name2); \
if (!real_##name1 && !real_##name2) { \
fprintf(stderr, "Cannot find real '%s' or '%s' symbol\n", \
#name1, #name2); \
abort(); \
} \
} while (0)
#endif /* LIBVIRT_VIRMOCK_H */

326
tests/virmockstathelpers.c Normal file
View File

@ -0,0 +1,326 @@
/*
* Copyright (C) 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
* Helpers for dealing with the many variants of stat(). This
* C file should be included from any file that wants to mock
* stat() correctly.
*/
#include "virmock.h"
#include "viralloc.h"
#include <sys/stat.h>
#include <unistd.h>
/*
* The POSIX stat() function might resolve to any number of different
* symbols in the C library.
*
* The may be an additional stat64() function exposed by the headers
* too.
*
* On 64-bit hosts the stat & stat64 functions are identical, always
* refering to the 64-bit ABI.
*
* On 32-bit hosts they refer to the 32-bit & 64-bit ABIs respectively.
*
* Libvirt uses _FILE_OFFSET_BITS=64 on 32-bit hosts, which causes the
* C library to transparently rewrite stat() calls to be stat64() calls.
* Libvirt will never see the 32-bit ABI from the traditional stat()
* call. We cannot assume this rewriting is done using a macro. It might
* be, but on GLibC it is done with a magic __asm__ statement to apply
* the rewrite at link time instead of at preprocessing.
*
* In GLibC there may be two additional functions exposed by the headers,
* __xstat() and __xstat64(). When these exist, stat() and stat64() are
* transparently rewritten to call __xstat() and __xstat64() respectively.
* The former symbols will not actally exist in the library at all, only
* the header. The leading "__" indicates the symbols are a private impl
* detail of the C library that applications should not care about.
* Unfortunately, because we are trying to mock replace the C library,
* we need to know about this internal impl detail.
*
* With all this in mind the list of functions we have to mock will depend
* on several factors
*
* - If _FILE_OFFSET_BITS is set, then we are on a 32-bit host, and we
* only need to mock stat64 and __xstat64. The other stat / __xstat
* functions exist, but we'll never call them so they can be ignored
* for mocking.
*
* - If _FILE_OFFSET_BITS is not set, then we are on a 64-bit host and
* we should mock stat, stat64, __xstat & __xstat64. Either may be
* called by app code.
*
* - If __xstat & __xstat64 exist, then stat & stat64 will not exist
* as symbols in the library, so the latter should not be mocked.
*
* The same all applies to lstat()
*/
#if defined(HAVE_STAT) && !defined(HAVE___XSTAT) && !defined(_FILE_OFFSET_BITS)
# define MOCK_STAT
#endif
#if defined(HAVE_STAT64) && !defined(HAVE___XSTAT64)
# define MOCK_STAT64
#endif
#if defined(HAVE___XSTAT) && !defined(_FILE_OFFSET_BITS)
# define MOCK___XSTAT
#endif
#if defined(HAVE___XSTAT64)
# define MOCK___XSTAT64
#endif
#if defined(HAVE_LSTAT) && !defined(HAVE___LXSTAT) && !defined(_FILE_OFFSET_BITS)
# define MOCK_LSTAT
#endif
#if defined(HAVE_LSTAT64) && !defined(HAVE___LXSTAT64)
# define MOCK_LSTAT64
#endif
#if defined(HAVE___LXSTAT) && !defined(_FILE_OFFSET_BITS)
# define MOCK___LXSTAT
#endif
#if defined(HAVE___LXSTAT64)
# define MOCK___LXSTAT64
#endif
#ifdef MOCK_STAT
static int (*real_stat)(const char *path, struct stat *sb);
#endif
#ifdef MOCK_STAT64
static int (*real_stat64)(const char *path, struct stat64 *sb);
#endif
#ifdef MOCK___XSTAT
static int (*real___xstat)(int ver, const char *path, struct stat *sb);
#endif
#ifdef MOCK___XSTAT64
static int (*real___xstat64)(int ver, const char *path, struct stat64 *sb);
#endif
#ifdef MOCK_LSTAT
static int (*real_lstat)(const char *path, struct stat *sb);
#endif
#ifdef MOCK_LSTAT64
static int (*real_lstat64)(const char *path, struct stat64 *sb);
#endif
#ifdef MOCK___LXSTAT
static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
#endif
#ifdef MOCK___LXSTAT64
static int (*real___lxstat64)(int ver, const char *path, struct stat64 *sb);
#endif
static bool init;
static bool debug;
#define fdebug(msg, ...) do { if (debug) fprintf(stderr, msg, __VA_ARGS__); } while (0)
static void virMockStatInit(void)
{
if (init)
return;
init = true;
debug = getenv("VIR_MOCK_STAT_DEBUG");
#ifdef MOCK_STAT
VIR_MOCK_REAL_INIT(stat);
fdebug("real stat %p\n", real_stat);
#endif
#ifdef MOCK_STAT64
VIR_MOCK_REAL_INIT(stat64);
fdebug("real stat64 %p\n", real_stat64);
#endif
#ifdef MOCK___XSTAT
VIR_MOCK_REAL_INIT(__xstat);
fdebug("real __xstat %p\n", real___xstat);
#endif
#ifdef MOCK___XSTAT64
VIR_MOCK_REAL_INIT(__xstat64);
fdebug("real __xstat64 %p\n", real___xstat64);
#endif
#ifdef MOCK_LSTAT
VIR_MOCK_REAL_INIT(lstat);
fdebug("real lstat %p\n", real_lstat);
#endif
#ifdef MOCK_LSTAT64
VIR_MOCK_REAL_INIT(lstat64);
fdebug("real lstat64 %p\n", real_lstat64);
#endif
#ifdef MOCK___LXSTAT
VIR_MOCK_REAL_INIT(__lxstat);
fdebug("real __lxstat %p\n", real___lxstat);
#endif
#ifdef MOCK___LXSTAT64
VIR_MOCK_REAL_INIT(__lxstat64);
fdebug("real __lxstat64 %p\n", real___lxstat64);
#endif
}
/*
* @stat: the path being queried
* @newpath: fill with redirected path, or leave NULL to use orig path
*
* Return 0 on success, -1 on allocation error
*/
static int virMockStatRedirect(const char *path, char **newpath);
#ifndef VIR_MOCK_STAT_HOOK
# define VIR_MOCK_STAT_HOOK do { } while (0)
#endif
#ifdef MOCK_STAT
int stat(const char *path, struct stat *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
virMockStatInit();
if (virMockStatRedirect(path, &newpath) < 0)
abort();
fdebug("stat redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
VIR_MOCK_STAT_HOOK;
return real_stat(newpath ? newpath : path, sb);
}
#endif
#ifdef MOCK_STAT64
int stat64(const char *path, struct stat64 *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
virMockStatInit();
if (virMockStatRedirect(path, &newpath) < 0)
abort();
fdebug("stat64 redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
VIR_MOCK_STAT_HOOK;
return real_stat64(newpath ? newpath : path, sb);
}
#endif
#ifdef MOCK___XSTAT
int
__xstat(int ver, const char *path, struct stat *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
virMockStatInit();
if (virMockStatRedirect(path, &newpath) < 0)
abort();
fdebug("__xstat redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
VIR_MOCK_STAT_HOOK;
return real___xstat(ver, newpath ? newpath : path, sb);
}
#endif
#ifdef MOCK___XSTAT64
int
__xstat64(int ver, const char *path, struct stat64 *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
virMockStatInit();
if (virMockStatRedirect(path, &newpath) < 0)
abort();
fdebug("__xstat64 redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
VIR_MOCK_STAT_HOOK;
return real___xstat64(ver, newpath ? newpath : path, sb);
}
#endif
#ifdef MOCK_LSTAT
int
lstat(const char *path, struct stat *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
virMockStatInit();
if (virMockStatRedirect(path, &newpath) < 0)
abort();
fdebug("lstat redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
VIR_MOCK_STAT_HOOK;
return real_lstat(newpath ? newpath : path, sb);
}
#endif
#ifdef MOCK_LSTAT64
int
lstat64(const char *path, struct stat64 *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
virMockStatInit();
if (virMockStatRedirect(path, &newpath) < 0)
abort();
fdebug("lstat64 redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
VIR_MOCK_STAT_HOOK;
return real_lstat64(newpath ? newpath : path, sb);
}
#endif
#ifdef MOCK___LXSTAT
int
__lxstat(int ver, const char *path, struct stat *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
virMockStatInit();
if (virMockStatRedirect(path, &newpath) < 0)
abort();
fdebug("__lxstat redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
VIR_MOCK_STAT_HOOK;
return real___lxstat(ver, newpath ? newpath : path, sb);
}
#endif
#ifdef MOCK___LXSTAT64
int
__lxstat64(int ver, const char *path, struct stat64 *sb)
{
VIR_AUTOFREE(char *) newpath = NULL;
virMockStatInit();
if (virMockStatRedirect(path, &newpath) < 0)
abort();
fdebug("__lxstat64 redirect %s to %s sb=%p\n", path, newpath ? newpath : path, sb);
VIR_MOCK_STAT_HOOK;
return real___lxstat64(ver, newpath ? newpath : path, sb);
}
#endif

View File

@ -31,10 +31,6 @@
# include "dirname.h"
static int (*real_access)(const char *path, int mode);
static int (*real_lstat)(const char *path, struct stat *sb);
static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
static int (*real_stat)(const char *path, struct stat *sb);
static int (*real___xstat)(int ver, const char *path, struct stat *sb);
static int (*real_open)(const char *path, int flags, ...);
static int (*real_close)(int fd);
static DIR * (*real_opendir)(const char *name);
@ -365,15 +361,9 @@ pci_device_new_from_stub(const struct pciDevice *data)
if (virFileMakePath(devpath) < 0)
ABORT("Unable to create: %s", devpath);
if (real_stat && real_stat(configSrc, &sb) == 0)
if (stat(configSrc, &sb) == 0)
configSrcExists = true;
# ifdef HAVE___XSTAT
if (!configSrcExists &&
real___xstat && real___xstat(_STAT_VER, configSrc, &sb) == 0)
configSrcExists = true;
# endif
/* If there is a config file for the device within virpcitestdata dir,
* symlink it. Otherwise create a dummy config file. */
if (configSrcExists) {
@ -813,8 +803,6 @@ init_syms(void)
return;
VIR_MOCK_REAL_INIT(access);
VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
VIR_MOCK_REAL_INIT(open);
VIR_MOCK_REAL_INIT(close);
VIR_MOCK_REAL_INIT(opendir);
@ -896,85 +884,17 @@ access(const char *path, int mode)
return ret;
}
# ifdef HAVE___LXSTAT
int
__lxstat(int ver, const char *path, struct stat *sb)
static int
virMockStatRedirect(const char *path, char **newpath)
{
int ret;
init_syms();
if (STRPREFIX(path, SYSFS_PCI_PREFIX)) {
char *newpath;
if (getrealpath(&newpath, path) < 0)
if (getrealpath(newpath, path) < 0)
return -1;
ret = real___lxstat(ver, newpath, sb);
VIR_FREE(newpath);
} else {
ret = real___lxstat(ver, path, sb);
}
return ret;
}
# endif /* HAVE___LXSTAT */
int
lstat(const char *path, struct stat *sb)
{
int ret;
init_syms();
if (STRPREFIX(path, SYSFS_PCI_PREFIX)) {
char *newpath;
if (getrealpath(&newpath, path) < 0)
return -1;
ret = real_lstat(newpath, sb);
VIR_FREE(newpath);
} else {
ret = real_lstat(path, sb);
}
return ret;
return 0;
}
# ifdef HAVE___XSTAT
int
__xstat(int ver, const char *path, struct stat *sb)
{
int ret;
init_syms();
if (STRPREFIX(path, SYSFS_PCI_PREFIX)) {
char *newpath;
if (getrealpath(&newpath, path) < 0)
return -1;
ret = real___xstat(ver, newpath, sb);
VIR_FREE(newpath);
} else {
ret = real___xstat(ver, path, sb);
}
return ret;
}
# endif /* HAVE___XSTAT */
int
stat(const char *path, struct stat *sb)
{
int ret;
init_syms();
if (STRPREFIX(path, SYSFS_PCI_PREFIX)) {
char *newpath;
if (getrealpath(&newpath, path) < 0)
return -1;
ret = real_stat(newpath, sb);
VIR_FREE(newpath);
} else {
ret = real_stat(path, sb);
}
return ret;
}
int
open(const char *path, int flags, ...)
@ -1058,6 +978,9 @@ virFileCanonicalizePath(const char *path)
return ret;
}
# include "virmockstathelpers.c"
#else
/* Nothing to override on this platform */
#endif

View File

@ -36,33 +36,9 @@
#include "viralloc.h"
#include "virfile.h"
/* stat can be a macro as follows:
*
* #define stat stat64
*
* This wouldn't fly with our mock. Make sure that the macro (and
* all its friends) are undefined. We don't want anybody mangling
* our code. */
#undef stat
#undef stat64
#undef __xstat
#undef __xstat64
#undef lstat
#undef lstat64
#undef __lxstat
#undef __lxstat64
static int (*real_open)(const char *path, int flags, ...);
static FILE *(*real_fopen)(const char *path, const char *mode);
static int (*real_access)(const char *path, int mode);
static int (*real_stat)(const char *path, struct stat *sb);
static int (*real_stat64)(const char *path, void *sb);
static int (*real___xstat)(int ver, const char *path, struct stat *sb);
static int (*real___xstat64)(int ver, const char *path, void *sb);
static int (*real_lstat)(const char *path, struct stat *sb);
static int (*real_lstat64)(const char *path, void *sb);
static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
static int (*real___lxstat64)(int ver, const char *path, void *sb);
static int (*real_connect)(int fd, const struct sockaddr *addr, socklen_t addrlen);
static const char *progname;
@ -78,10 +54,6 @@ static void init_syms(void)
VIR_MOCK_REAL_INIT(open);
VIR_MOCK_REAL_INIT(fopen);
VIR_MOCK_REAL_INIT(access);
VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
VIR_MOCK_REAL_INIT_ALT(stat64, __xstat64);
VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
VIR_MOCK_REAL_INIT_ALT(lstat64, __lxstat64);
VIR_MOCK_REAL_INIT(connect);
}
@ -217,119 +189,15 @@ int access(const char *path, int mode)
return real_access(path, mode);
}
/* Okay, the following ifdef rain forest may look messy at a
* first glance. But here's the thing: during run time linking of
* a binary, stat() may not be actually needing symbol stat. It
* might as well not had been stat() in the first place (see the
* reasoning at the beginning of this file). However, if we would
* expose stat symbol here, we will poison the well and trick
* dynamic linker into thinking we are some old binary that still
* uses the symbol. So whenever code from upper layers calls
* stat(), the control would get here, but real_stat can actually
* be a NULL pointer because newer glibc have __xstat instead.
* Worse, it can have __xstat64 instead __xstat.
*
* Anyway, these ifdefs are there to implement the following
* preference function:
*
* stat < stat64 < __xstat < __xstat64
*
* It's the same story with lstat.
* Also, I feel sorry for you that you had to read this.
*/
#if defined(HAVE_STAT) && !defined(HAVE___XSTAT)
int stat(const char *path, struct stat *sb)
#define VIR_MOCK_STAT_HOOK CHECK_PATH(path)
#include "virmockstathelpers.c"
static int virMockStatRedirect(const char *path ATTRIBUTE_UNUSED, char **newpath ATTRIBUTE_UNUSED)
{
init_syms();
checkPath(path, "stat");
return real_stat(path, sb);
return 0;
}
#endif
#if defined(HAVE_STAT64) && !defined(HAVE___XSTAT64)
int stat64(const char *path, struct stat64 *sb)
{
init_syms();
checkPath(path, "stat");
return real_stat64(path, sb);
}
#endif
#if defined(HAVE___XSTAT) && !defined(HAVE___XSTAT64)
int
__xstat(int ver, const char *path, struct stat *sb)
{
init_syms();
checkPath(path, "stat");
return real___xstat(ver, path, sb);
}
#endif
#if defined(HAVE___XSTAT64)
int
__xstat64(int ver, const char *path, struct stat64 *sb)
{
init_syms();
checkPath(path, "stat");
return real___xstat64(ver, path, sb);
}
#endif
#if defined(HAVE_LSTAT) && !defined(HAVE___LXSTAT)
int
lstat(const char *path, struct stat *sb)
{
init_syms();
checkPath(path, "lstat");
return real_lstat(path, sb);
}
#endif
#if defined(HAVE_LSTAT64) && !defined(HAVE___LXSTAT64)
int
lstat64(const char *path, struct stat64 *sb)
{
init_syms();
checkPath(path, "lstat");
return real_lstat64(path, sb);
}
#endif
#if defined(HAVE___LXSTAT) && !defined(HAVE___LXSTAT64)
int
__lxstat(int ver, const char *path, struct stat *sb)
{
init_syms();
checkPath(path, "lstat");
return real___lxstat(ver, path, sb);
}
#endif
#if defined(HAVE___LXSTAT64)
int
__lxstat64(int ver, const char *path, struct stat64 *sb)
{
init_syms();
checkPath(path, "lstat");
return real___lxstat64(ver, path, sb);
}
#endif
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)