2 * Copyright (C) 2019 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see
16 * <http://www.gnu.org/licenses/>.
18 * Helpers for dealing with the many variants of stat(). This
19 * C file should be included from any file that wants to mock
30 * The POSIX stat() function might resolve to any number of different
31 * symbols in the C library.
33 * The may be an additional stat64() function exposed by the headers
36 * On 64-bit hosts the stat & stat64 functions are identical, always
37 * refering to the 64-bit ABI.
39 * On 32-bit hosts they refer to the 32-bit & 64-bit ABIs respectively.
41 * Libvirt uses _FILE_OFFSET_BITS=64 on 32-bit hosts, which causes the
42 * C library to transparently rewrite stat() calls to be stat64() calls.
43 * Libvirt will never see the 32-bit ABI from the traditional stat()
44 * call. We cannot assume this rewriting is done using a macro. It might
45 * be, but on GLibC it is done with a magic __asm__ statement to apply
46 * the rewrite at link time instead of at preprocessing.
48 * In GLibC there may be two additional functions exposed by the headers,
49 * __xstat() and __xstat64(). When these exist, stat() and stat64() are
50 * transparently rewritten to call __xstat() and __xstat64() respectively.
51 * The former symbols will not actally exist in the library at all, only
52 * the header. The leading "__" indicates the symbols are a private impl
53 * detail of the C library that applications should not care about.
54 * Unfortunately, because we are trying to mock replace the C library,
55 * we need to know about this internal impl detail.
57 * With all this in mind the list of functions we have to mock will depend
60 * - If _FILE_OFFSET_BITS is set, then we are on a 32-bit host, and we
61 * only need to mock stat64 and __xstat64. The other stat / __xstat
62 * functions exist, but we'll never call them so they can be ignored
65 * - If _FILE_OFFSET_BITS is not set, then we are on a 64-bit host and
66 * we should mock stat, stat64, __xstat & __xstat64. Either may be
69 * - If __xstat & __xstat64 exist, then stat & stat64 will not exist
70 * as symbols in the library, so the latter should not be mocked.
72 * The same all applies to lstat()
77 #if defined(HAVE_STAT) && !defined(HAVE___XSTAT) && !defined(_FILE_OFFSET_BITS)
80 #if defined(HAVE_STAT64) && !defined(HAVE___XSTAT64)
83 #if defined(HAVE___XSTAT) && !defined(_FILE_OFFSET_BITS)
86 #if defined(HAVE___XSTAT64)
87 # define MOCK___XSTAT64
89 #if defined(HAVE_LSTAT) && !defined(HAVE___LXSTAT) && !defined(_FILE_OFFSET_BITS)
92 #if defined(HAVE_LSTAT64) && !defined(HAVE___LXSTAT64)
95 #if defined(HAVE___LXSTAT) && !defined(_FILE_OFFSET_BITS)
96 # define MOCK___LXSTAT
98 #if defined(HAVE___LXSTAT64)
99 # define MOCK___LXSTAT64
103 static int (*real_stat
)(const char *path
, struct stat
*sb
);
106 static int (*real_stat64
)(const char *path
, struct stat64
*sb
);
109 static int (*real___xstat
)(int ver
, const char *path
, struct stat
*sb
);
111 #ifdef MOCK___XSTAT64
112 static int (*real___xstat64
)(int ver
, const char *path
, struct stat64
*sb
);
115 static int (*real_lstat
)(const char *path
, struct stat
*sb
);
118 static int (*real_lstat64
)(const char *path
, struct stat64
*sb
);
121 static int (*real___lxstat
)(int ver
, const char *path
, struct stat
*sb
);
123 #ifdef MOCK___LXSTAT64
124 static int (*real___lxstat64
)(int ver
, const char *path
, struct stat64
*sb
);
130 #define fdebug(msg, ...) do { if (debug) fprintf(stderr, msg, __VA_ARGS__); } while (0)
132 static void virMockStatInit(void)
138 debug
= getenv("VIR_MOCK_STAT_DEBUG");
141 VIR_MOCK_REAL_INIT(stat
);
142 fdebug("real stat %p\n", real_stat
);
145 VIR_MOCK_REAL_INIT(stat64
);
146 fdebug("real stat64 %p\n", real_stat64
);
149 VIR_MOCK_REAL_INIT(__xstat
);
150 fdebug("real __xstat %p\n", real___xstat
);
152 #ifdef MOCK___XSTAT64
153 VIR_MOCK_REAL_INIT(__xstat64
);
154 fdebug("real __xstat64 %p\n", real___xstat64
);
157 VIR_MOCK_REAL_INIT(lstat
);
158 fdebug("real lstat %p\n", real_lstat
);
161 VIR_MOCK_REAL_INIT(lstat64
);
162 fdebug("real lstat64 %p\n", real_lstat64
);
165 VIR_MOCK_REAL_INIT(__lxstat
);
166 fdebug("real __lxstat %p\n", real___lxstat
);
168 #ifdef MOCK___LXSTAT64
169 VIR_MOCK_REAL_INIT(__lxstat64
);
170 fdebug("real __lxstat64 %p\n", real___lxstat64
);
175 * @stat: the path being queried
176 * @newpath: fill with redirected path, or leave NULL to use orig path
178 * Return 0 on success, -1 on allocation error
180 static int virMockStatRedirect(const char *path
, char **newpath
);
182 #ifndef VIR_MOCK_STAT_HOOK
183 # define VIR_MOCK_STAT_HOOK do { } while (0)
187 int stat(const char *path
, struct stat
*sb
)
189 VIR_AUTOFREE(char *) newpath
= NULL
;
193 if (virMockStatRedirect(path
, &newpath
) < 0)
195 fdebug("stat redirect %s to %s sb=%p\n", path
, newpath
? newpath
: path
, sb
);
199 return real_stat(newpath
? newpath
: path
, sb
);
204 int stat64(const char *path
, struct stat64
*sb
)
206 VIR_AUTOFREE(char *) newpath
= NULL
;
210 if (virMockStatRedirect(path
, &newpath
) < 0)
212 fdebug("stat64 redirect %s to %s sb=%p\n", path
, newpath
? newpath
: path
, sb
);
216 return real_stat64(newpath
? newpath
: path
, sb
);
222 __xstat(int ver
, const char *path
, struct stat
*sb
)
224 VIR_AUTOFREE(char *) newpath
= NULL
;
228 if (virMockStatRedirect(path
, &newpath
) < 0)
230 fdebug("__xstat redirect %s to %s sb=%p\n", path
, newpath
? newpath
: path
, sb
);
234 return real___xstat(ver
, newpath
? newpath
: path
, sb
);
238 #ifdef MOCK___XSTAT64
240 __xstat64(int ver
, const char *path
, struct stat64
*sb
)
242 VIR_AUTOFREE(char *) newpath
= NULL
;
246 if (virMockStatRedirect(path
, &newpath
) < 0)
248 fdebug("__xstat64 redirect %s to %s sb=%p\n", path
, newpath
? newpath
: path
, sb
);
252 return real___xstat64(ver
, newpath
? newpath
: path
, sb
);
258 lstat(const char *path
, struct stat
*sb
)
260 VIR_AUTOFREE(char *) newpath
= NULL
;
264 if (virMockStatRedirect(path
, &newpath
) < 0)
266 fdebug("lstat redirect %s to %s sb=%p\n", path
, newpath
? newpath
: path
, sb
);
270 return real_lstat(newpath
? newpath
: path
, sb
);
276 lstat64(const char *path
, struct stat64
*sb
)
278 VIR_AUTOFREE(char *) newpath
= NULL
;
282 if (virMockStatRedirect(path
, &newpath
) < 0)
284 fdebug("lstat64 redirect %s to %s sb=%p\n", path
, newpath
? newpath
: path
, sb
);
288 return real_lstat64(newpath
? newpath
: path
, sb
);
294 __lxstat(int ver
, const char *path
, struct stat
*sb
)
296 VIR_AUTOFREE(char *) newpath
= NULL
;
300 if (virMockStatRedirect(path
, &newpath
) < 0)
302 fdebug("__lxstat redirect %s to %s sb=%p\n", path
, newpath
? newpath
: path
, sb
);
306 return real___lxstat(ver
, newpath
? newpath
: path
, sb
);
310 #ifdef MOCK___LXSTAT64
312 __lxstat64(int ver
, const char *path
, struct stat64
*sb
)
314 VIR_AUTOFREE(char *) newpath
= NULL
;
318 if (virMockStatRedirect(path
, &newpath
) < 0)
320 fdebug("__lxstat64 redirect %s to %s sb=%p\n", path
, newpath
? newpath
: path
, sb
);
324 return real___lxstat64(ver
, newpath
? newpath
: path
, sb
);