diff --git a/build-aux/mock-noinline.pl b/build-aux/mock-noinline.pl index c6b40001c5..958e133885 100644 --- a/build-aux/mock-noinline.pl +++ b/build-aux/mock-noinline.pl @@ -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$/) { diff --git a/cfg.mk b/cfg.mk index 8594f64482..5ffae32f2a 100644 --- a/cfg.mk +++ b/cfg.mk @@ -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$$ diff --git a/tests/Makefile.am b/tests/Makefile.am index d3cdbff8bb..436aac285f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -146,6 +146,7 @@ EXTRA_DIST = \ virjsondata \ virmacmaptestdata \ virmock.h \ + virmockstathelpers.h \ virnetdaemondata \ virnetdevtestdata \ virnwfilterbindingxml2xmldata \ diff --git a/tests/qemusecuritymock.c b/tests/qemusecuritymock.c index d1b17d8aa4..3fdc165fb1 100644 --- a/tests/qemusecuritymock.c +++ b/tests/qemusecuritymock.c @@ -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 diff --git a/tests/vircgroupmock.c b/tests/vircgroupmock.c index 9c67a44b0d..11a24035aa 100644 --- a/tests/vircgroupmock.c +++ b/tests/vircgroupmock.c @@ -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; diff --git a/tests/virfilewrapper.c b/tests/virfilewrapper.c index 88441331ce..067cb30657 100644 --- a/tests/virfilewrapper.c +++ b/tests/virfilewrapper.c @@ -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 diff --git a/tests/virmock.h b/tests/virmock.h index 9c7ecf60ce..46631433c7 100644 --- a/tests/virmock.h +++ b/tests/virmock.h @@ -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 */ diff --git a/tests/virmockstathelpers.c b/tests/virmockstathelpers.c new file mode 100644 index 0000000000..0bbea4b437 --- /dev/null +++ b/tests/virmockstathelpers.c @@ -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 + * . + * + * 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 +#include + +/* + * 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 diff --git a/tests/virpcimock.c b/tests/virpcimock.c index ce8176cbec..7f9cdaa9b8 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -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 diff --git a/tests/virtestmock.c b/tests/virtestmock.c index 3049c90789..bc62312444 100644 --- a/tests/virtestmock.c +++ b/tests/virtestmock.c @@ -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)