2016-05-13 12:08:29 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2016 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "virmock.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <fcntl.h>
|
2016-04-18 12:10:33 +00:00
|
|
|
#include <execinfo.h>
|
|
|
|
#include <sys/file.h>
|
2016-05-16 15:15:46 +00:00
|
|
|
#include <sys/stat.h>
|
2018-07-08 07:24:34 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
|
# include <sys/un.h>
|
|
|
|
#endif
|
2016-05-13 12:08:29 +00:00
|
|
|
|
|
|
|
#include "internal.h"
|
|
|
|
#include "configmake.h"
|
2016-04-18 12:10:33 +00:00
|
|
|
#include "virstring.h"
|
|
|
|
#include "viralloc.h"
|
|
|
|
#include "virfile.h"
|
2016-05-13 12:08:29 +00:00
|
|
|
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
/* 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
|
|
|
|
|
2016-05-13 12:08:29 +00:00
|
|
|
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);
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
static int (*real_stat64)(const char *path, void *sb);
|
2016-05-13 12:08:29 +00:00
|
|
|
static int (*real___xstat)(int ver, const char *path, struct stat *sb);
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
static int (*real___xstat64)(int ver, const char *path, void *sb);
|
2016-05-13 12:08:29 +00:00
|
|
|
static int (*real_lstat)(const char *path, struct stat *sb);
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
static int (*real_lstat64)(const char *path, void *sb);
|
2016-05-13 12:08:29 +00:00
|
|
|
static int (*real___lxstat)(int ver, const char *path, struct stat *sb);
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
static int (*real___lxstat64)(int ver, const char *path, void *sb);
|
2018-07-08 07:24:34 +00:00
|
|
|
static int (*real_connect)(int fd, const struct sockaddr *addr, socklen_t addrlen);
|
2016-05-13 12:08:29 +00:00
|
|
|
|
2016-04-18 12:10:33 +00:00
|
|
|
static const char *progname;
|
|
|
|
const char *output;
|
|
|
|
|
|
|
|
#define VIR_FILE_ACCESS_DEFAULT abs_builddir "/test_file_access.txt"
|
|
|
|
|
2016-05-13 12:08:29 +00:00
|
|
|
static void init_syms(void)
|
|
|
|
{
|
|
|
|
if (real_open)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_MOCK_REAL_INIT(open);
|
|
|
|
VIR_MOCK_REAL_INIT(fopen);
|
|
|
|
VIR_MOCK_REAL_INIT(access);
|
|
|
|
VIR_MOCK_REAL_INIT_ALT(stat, __xstat);
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
VIR_MOCK_REAL_INIT_ALT(stat64, __xstat64);
|
2016-05-13 12:08:29 +00:00
|
|
|
VIR_MOCK_REAL_INIT_ALT(lstat, __lxstat);
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
VIR_MOCK_REAL_INIT_ALT(lstat64, __lxstat64);
|
2018-07-08 07:24:34 +00:00
|
|
|
VIR_MOCK_REAL_INIT(connect);
|
2016-05-13 12:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-07-08 07:32:03 +00:00
|
|
|
printFile(const char *file,
|
|
|
|
const char *func)
|
2016-05-13 12:08:29 +00:00
|
|
|
{
|
2016-04-18 12:10:33 +00:00
|
|
|
FILE *fp;
|
|
|
|
const char *testname = getenv("VIR_TEST_MOCK_TESTNAME");
|
|
|
|
|
|
|
|
if (!progname) {
|
|
|
|
progname = getenv("VIR_TEST_MOCK_PROGNAME");
|
|
|
|
|
|
|
|
if (!progname)
|
|
|
|
return;
|
|
|
|
|
|
|
|
output = getenv("VIR_TEST_FILE_ACCESS_OUTPUT");
|
|
|
|
if (!output)
|
|
|
|
output = VIR_FILE_ACCESS_DEFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(fp = real_fopen(output, "a"))) {
|
|
|
|
fprintf(stderr, "Unable to open %s: %s\n", output, strerror(errno));
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flock(fileno(fp), LOCK_EX) < 0) {
|
|
|
|
fprintf(stderr, "Unable to lock %s: %s\n", output, strerror(errno));
|
|
|
|
fclose(fp);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now append the following line into the output file:
|
2018-07-08 07:32:03 +00:00
|
|
|
* $file: $progname: $func: $testname */
|
2016-04-18 12:10:33 +00:00
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
fprintf(fp, "%s: %s: %s", file, func, progname);
|
2016-04-18 12:10:33 +00:00
|
|
|
if (testname)
|
|
|
|
fprintf(fp, ": %s", testname);
|
|
|
|
|
|
|
|
fputc('\n', fp);
|
|
|
|
|
|
|
|
flock(fileno(fp), LOCK_UN);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
#define CHECK_PATH(path) \
|
|
|
|
checkPath(path, __FUNCTION__)
|
|
|
|
|
2016-04-18 12:10:33 +00:00
|
|
|
static void
|
2018-07-08 07:32:03 +00:00
|
|
|
checkPath(const char *path,
|
|
|
|
const char *func)
|
2016-04-18 12:10:33 +00:00
|
|
|
{
|
|
|
|
char *fullPath = NULL;
|
|
|
|
char *relPath = NULL;
|
|
|
|
char *crippledPath = NULL;
|
|
|
|
|
|
|
|
if (path[0] != '/' &&
|
|
|
|
virAsprintfQuiet(&relPath, "./%s", path) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2018-05-03 08:04:38 +00:00
|
|
|
/* Le sigh. virFileCanonicalizePath() expects @path to exist, otherwise
|
|
|
|
* it will return an error. So if we are called over an non-existent
|
|
|
|
* file, this could return an error. In that case do our best and hope
|
|
|
|
* we will catch possible errors. */
|
|
|
|
if ((fullPath = virFileCanonicalizePath(relPath ? relPath : path))) {
|
2016-04-18 12:10:33 +00:00
|
|
|
path = fullPath;
|
|
|
|
} else {
|
|
|
|
/* Yeah, our worst nightmares just became true. Path does
|
|
|
|
* not exist. Cut off the last component and retry. */
|
|
|
|
if (VIR_STRDUP_QUIET(crippledPath, relPath ? relPath : path) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virFileRemoveLastComponent(crippledPath);
|
|
|
|
|
2018-05-03 08:04:38 +00:00
|
|
|
if ((fullPath = virFileCanonicalizePath(crippledPath)))
|
2016-04-18 12:10:33 +00:00
|
|
|
path = fullPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!STRPREFIX(path, abs_topsrcdir) &&
|
|
|
|
!STRPREFIX(path, abs_topbuilddir)) {
|
2018-07-08 07:32:03 +00:00
|
|
|
printFile(path, func);
|
2016-04-18 12:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(crippledPath);
|
|
|
|
VIR_FREE(relPath);
|
|
|
|
VIR_FREE(fullPath);
|
|
|
|
|
|
|
|
return;
|
|
|
|
error:
|
|
|
|
fprintf(stderr, "Out of memory\n");
|
|
|
|
abort();
|
2016-05-13 12:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int open(const char *path, int flags, ...)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
init_syms();
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
CHECK_PATH(path);
|
2016-05-13 12:08:29 +00:00
|
|
|
|
|
|
|
if (flags & O_CREAT) {
|
|
|
|
va_list ap;
|
|
|
|
mode_t mode;
|
|
|
|
va_start(ap, flags);
|
2018-04-30 15:30:12 +00:00
|
|
|
mode = (mode_t) va_arg(ap, int);
|
2016-05-13 12:08:29 +00:00
|
|
|
va_end(ap);
|
|
|
|
ret = real_open(path, flags, mode);
|
|
|
|
} else {
|
|
|
|
ret = real_open(path, flags);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *fopen(const char *path, const char *mode)
|
|
|
|
{
|
|
|
|
init_syms();
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
CHECK_PATH(path);
|
2016-05-13 12:08:29 +00:00
|
|
|
|
|
|
|
return real_fopen(path, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int access(const char *path, int mode)
|
|
|
|
{
|
|
|
|
init_syms();
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
CHECK_PATH(path);
|
2016-05-13 12:08:29 +00:00
|
|
|
|
|
|
|
return real_access(path, mode);
|
|
|
|
}
|
|
|
|
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
/* Okay, the following ifdef rain forest may look messy at a
|
|
|
|
* first glance. But here's the thing: during run time linking of
|
2018-12-04 17:08:14 +00:00
|
|
|
* a binary, stat() may not be actually needing symbol stat. It
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
* 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)
|
2016-05-13 12:08:29 +00:00
|
|
|
int stat(const char *path, struct stat *sb)
|
|
|
|
{
|
|
|
|
init_syms();
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
checkPath(path, "stat");
|
2016-05-13 12:08:29 +00:00
|
|
|
|
2016-05-16 15:15:46 +00:00
|
|
|
return real_stat(path, sb);
|
2016-05-13 12:08:29 +00:00
|
|
|
}
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(HAVE_STAT64) && !defined(HAVE___XSTAT64)
|
|
|
|
int stat64(const char *path, struct stat64 *sb)
|
|
|
|
{
|
|
|
|
init_syms();
|
2016-05-13 12:08:29 +00:00
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
checkPath(path, "stat");
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
|
|
|
|
return real_stat64(path, sb);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(HAVE___XSTAT) && !defined(HAVE___XSTAT64)
|
2016-05-13 12:08:29 +00:00
|
|
|
int
|
|
|
|
__xstat(int ver, const char *path, struct stat *sb)
|
|
|
|
{
|
|
|
|
init_syms();
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
checkPath(path, "stat");
|
2016-05-13 12:08:29 +00:00
|
|
|
|
2016-05-16 15:15:46 +00:00
|
|
|
return real___xstat(ver, path, sb);
|
2016-05-13 12:08:29 +00:00
|
|
|
}
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(HAVE___XSTAT64)
|
|
|
|
int
|
|
|
|
__xstat64(int ver, const char *path, struct stat64 *sb)
|
|
|
|
{
|
|
|
|
init_syms();
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
checkPath(path, "stat");
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
|
|
|
|
return real___xstat64(ver, path, sb);
|
|
|
|
}
|
|
|
|
#endif
|
2016-05-13 12:08:29 +00:00
|
|
|
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
#if defined(HAVE_LSTAT) && !defined(HAVE___LXSTAT)
|
2016-05-13 12:08:29 +00:00
|
|
|
int
|
|
|
|
lstat(const char *path, struct stat *sb)
|
|
|
|
{
|
|
|
|
init_syms();
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
checkPath(path, "lstat");
|
2016-05-13 12:08:29 +00:00
|
|
|
|
2016-05-16 15:15:46 +00:00
|
|
|
return real_lstat(path, sb);
|
2016-05-13 12:08:29 +00:00
|
|
|
}
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
#endif
|
2016-05-13 12:08:29 +00:00
|
|
|
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
#if defined(HAVE_LSTAT64) && !defined(HAVE___LXSTAT64)
|
|
|
|
int
|
|
|
|
lstat64(const char *path, struct stat64 *sb)
|
|
|
|
{
|
|
|
|
init_syms();
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
checkPath(path, "lstat");
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
|
|
|
|
return real_lstat64(path, sb);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(HAVE___LXSTAT) && !defined(HAVE___LXSTAT64)
|
2016-05-13 12:08:29 +00:00
|
|
|
int
|
|
|
|
__lxstat(int ver, const char *path, struct stat *sb)
|
|
|
|
{
|
|
|
|
init_syms();
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
checkPath(path, "lstat");
|
2016-05-13 12:08:29 +00:00
|
|
|
|
2016-05-16 15:15:46 +00:00
|
|
|
return real___lxstat(ver, path, sb);
|
2016-05-13 12:08:29 +00:00
|
|
|
}
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(HAVE___LXSTAT64)
|
|
|
|
int
|
|
|
|
__lxstat64(int ver, const char *path, struct stat64 *sb)
|
|
|
|
{
|
|
|
|
init_syms();
|
|
|
|
|
2018-07-08 07:32:03 +00:00
|
|
|
checkPath(path, "lstat");
|
virtestmock: Mock stat() properly
There is a lot to explain, but I try to make it as short as
possible. I'd start by pasting some parts of sys/stat.h:
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
__extern_inline int
__NTH (stat (const char *__path, struct stat *__statbuf))
{
return __xstat (_STAT_VER, __path, __statbuf);
}
Only one of these is effective at once, due to some usage of
the mess we are dealing with in here. So, basically, while
compiling or linking stat() in our code can be transformed into
some other func. Or a dragon.
Now, if you read stat(2) manpage, esp. "C library/kernel
differences" section, you'll learn that glibc uses some tricks
for older applications to work. I haven't gotten around actual
code that does this, but based on my observations, if 'stat'
symbol is found, glibc assumes it's dealing with ancient
application. Unfortunately, it can be just ours stat coming from
our mock. Therefore, calling stat() from a test will end up in
our mock. But since glibc is not exposing the symbol anymore, our
call of real_stat() will SIGSEGV immediately as the pointer to
function is NULL. Therefore, we should expose only those symbols
we know glibc has.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-05-17 14:26:53 +00:00
|
|
|
|
|
|
|
return real___lxstat64(ver, path, sb);
|
|
|
|
}
|
|
|
|
#endif
|
2018-07-08 07:24:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
|
|
|
{
|
|
|
|
init_syms();
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
|
if (addrlen == sizeof(struct sockaddr_un)) {
|
|
|
|
struct sockaddr_un *tmp = (struct sockaddr_un *) addr;
|
|
|
|
if (tmp->sun_family == AF_UNIX)
|
2018-07-08 07:32:03 +00:00
|
|
|
CHECK_PATH(tmp->sun_path);
|
2018-07-08 07:24:34 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return real_connect(sockfd, addr, addrlen);
|
|
|
|
}
|