mirror of
https://github.com/wolfcw/libfaketime.git
synced 2026-05-18 17:26:09 +03:00
Compare commits
354 Commits
v0.9.5
...
pthread_co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46a0f84c1e | ||
|
|
985d666d73 | ||
|
|
9dcaf53fd7 | ||
|
|
02bc1fccae | ||
|
|
2c02fc08ef | ||
|
|
2d5126411b | ||
|
|
ee4f57d8a5 | ||
|
|
f09c98a89f | ||
|
|
527da8441b | ||
|
|
79defa361e | ||
|
|
6d7c42e2df | ||
|
|
a7e536bcca | ||
|
|
5466cd8a5f | ||
|
|
61490dc09a | ||
|
|
db47664840 | ||
|
|
bc24e278ff | ||
|
|
b0b9432ea4 | ||
|
|
84fc285923 | ||
|
|
806c05f49d | ||
|
|
fe6eeae423 | ||
|
|
f26242b655 | ||
|
|
e0ca33132d | ||
|
|
cbf1d729ed | ||
|
|
543f6b5040 | ||
|
|
aa9eb1006d | ||
|
|
14cf8d7ba8 | ||
|
|
f4ae29fb91 | ||
|
|
a9142e0e9a | ||
|
|
b7fff74716 | ||
|
|
e26859e5ca | ||
|
|
3155e0ee38 | ||
|
|
078a4e4060 | ||
|
|
9043941fa9 | ||
|
|
973111d78a | ||
|
|
4bab3179ce | ||
|
|
2090f5e548 | ||
|
|
f88c8d4221 | ||
|
|
9a73db074b | ||
|
|
932c138112 | ||
|
|
9e27b2ed8b | ||
|
|
c9f292ee39 | ||
|
|
d37421dbe7 | ||
|
|
89161a0cdf | ||
|
|
f87c2f8915 | ||
|
|
ce1d39c98f | ||
|
|
262d1d574f | ||
|
|
06d49adc12 | ||
|
|
1686664c97 | ||
|
|
5217bcd13d | ||
|
|
8ae4c9bc0e | ||
|
|
6733dc3a8d | ||
|
|
008d33fdf2 | ||
|
|
5a0071f952 | ||
|
|
51f1248593 | ||
|
|
e70b143733 | ||
|
|
e1073c8733 | ||
|
|
01b0b4bb56 | ||
|
|
5f5756ccd9 | ||
|
|
bca9f1bf90 | ||
|
|
d3f3ee38c6 | ||
|
|
a3f9410e51 | ||
|
|
a92d6ffe7c | ||
|
|
253774c8d8 | ||
|
|
986e6e1cdc | ||
|
|
0bfb72b627 | ||
|
|
5a1bd98979 | ||
|
|
7e62881c8f | ||
|
|
0e6b1b2460 | ||
|
|
1297568caf | ||
|
|
940502b3de | ||
|
|
26b4b395e9 | ||
|
|
0b0cc29d2e | ||
|
|
a5885f1479 | ||
|
|
0872c6c0c0 | ||
|
|
a51a38d0ae | ||
|
|
f47223ff12 | ||
|
|
7b1d0958b5 | ||
|
|
17522c5ba1 | ||
|
|
5e62eafcc2 | ||
|
|
01f6bc76c9 | ||
|
|
f329eee8c5 | ||
|
|
c89582fc1f | ||
|
|
9a38e5d775 | ||
|
|
7f4e5c378a | ||
|
|
9337bccfcb | ||
|
|
3668fd9b0f | ||
|
|
3a81c6becd | ||
|
|
3db9d20828 | ||
|
|
20e74b1b02 | ||
|
|
00d6edf90c | ||
|
|
811283e683 | ||
|
|
a8283c646d | ||
|
|
2ca0b719e3 | ||
|
|
f6ddc32695 | ||
|
|
8de66f799f | ||
|
|
63fe6f0be5 | ||
|
|
062abac575 | ||
|
|
004222585e | ||
|
|
9c59e24d33 | ||
|
|
46dc625642 | ||
|
|
8f2c856d8e | ||
|
|
b4a822cd6a | ||
|
|
54994ceb0d | ||
|
|
3c0b101a84 | ||
|
|
44a6d1f0fa | ||
|
|
772d9523a7 | ||
|
|
8b5519d496 | ||
|
|
3ba66842aa | ||
|
|
4359458c7c | ||
|
|
726c4657fc | ||
|
|
8853afb509 | ||
|
|
48f280ac86 | ||
|
|
47e6f5f33d | ||
|
|
e4e5ea6211 | ||
|
|
206ae9ea80 | ||
|
|
cce377b371 | ||
|
|
5e6ed4cd2c | ||
|
|
55e634a6ca | ||
|
|
532816864e | ||
|
|
4564afb924 | ||
|
|
5b8673df54 | ||
|
|
e00ba47ca9 | ||
|
|
ca2f3fefa1 | ||
|
|
dacc5866a7 | ||
|
|
b35e7c8ca6 | ||
|
|
25a60d0292 | ||
|
|
d90c8c26d3 | ||
|
|
c683c81417 | ||
|
|
f19d68ea32 | ||
|
|
c36674c27f | ||
|
|
112809f986 | ||
|
|
9498b2cacc | ||
|
|
c9a3b1bace | ||
|
|
834953480e | ||
|
|
c1d10321a7 | ||
|
|
58ccfb6c27 | ||
|
|
1e25e1f042 | ||
|
|
690ed3f158 | ||
|
|
d2f0daf092 | ||
|
|
c5b5d0b56e | ||
|
|
f8a0ad2496 | ||
|
|
0e3269efdc | ||
|
|
04e78e67bf | ||
|
|
0e798503a4 | ||
|
|
a7f7a54e1d | ||
|
|
8075c2e250 | ||
|
|
a12ca58dfa | ||
|
|
b4dea2ef9b | ||
|
|
796b30bebf | ||
|
|
70d26ec15c | ||
|
|
052239d828 | ||
|
|
fe8c0acee6 | ||
|
|
c44a332e0e | ||
|
|
a54f204209 | ||
|
|
195888434a | ||
|
|
f7de52c07b | ||
|
|
0efe7b3e3e | ||
|
|
b542e14959 | ||
|
|
78385ba8b7 | ||
|
|
b3dcef470e | ||
|
|
90f11685b5 | ||
|
|
d7ef17a0de | ||
|
|
3123ad7fe2 | ||
|
|
af2d2e5111 | ||
|
|
11fbc2ada1 | ||
|
|
f92d919fb0 | ||
|
|
22f8c3dd36 | ||
|
|
a0fe6b56b0 | ||
|
|
fdc3c81ae0 | ||
|
|
10b9818c2c | ||
|
|
826f8b7792 | ||
|
|
5d1e6325f2 | ||
|
|
8ed946cb63 | ||
|
|
108370f850 | ||
|
|
3de0d02353 | ||
|
|
dc2ae5eef3 | ||
|
|
1c05fdd333 | ||
|
|
c60390a7e3 | ||
|
|
ece59abf39 | ||
|
|
d79ed053d7 | ||
|
|
416c5f4708 | ||
|
|
a238cfa2b6 | ||
|
|
ba32d1b01c | ||
|
|
30ba0b852a | ||
|
|
5932e38032 | ||
|
|
13748ddb22 | ||
|
|
5f033fe486 | ||
|
|
52108dba7a | ||
|
|
5ddb237842 | ||
|
|
314b1298c9 | ||
|
|
7573d20cd4 | ||
|
|
0c8905f4ad | ||
|
|
57917c4d5a | ||
|
|
e85863f671 | ||
|
|
d5c0050684 | ||
|
|
b855b8a0d3 | ||
|
|
29efeed247 | ||
|
|
c13e41024e | ||
|
|
65cdc7b718 | ||
|
|
d923612c2b | ||
|
|
59127e7514 | ||
|
|
3b494ac6c9 | ||
|
|
073d185102 | ||
|
|
a70db9196a | ||
|
|
7498c405ed | ||
|
|
aa091db286 | ||
|
|
5e56e9a8fe | ||
|
|
fe42c2b4cf | ||
|
|
579b908580 | ||
|
|
2827a69ffe | ||
|
|
949183381f | ||
|
|
ff48a007a2 | ||
|
|
9846eceb10 | ||
|
|
7bc0d5044f | ||
|
|
ceac4c7036 | ||
|
|
5c4fdb5173 | ||
|
|
150a6cb3b2 | ||
|
|
39a85e380c | ||
|
|
825043515f | ||
|
|
335617c4c7 | ||
|
|
96668a9c6d | ||
|
|
24fd806e6b | ||
|
|
39c6872f6d | ||
|
|
5c6518c597 | ||
|
|
93148b3599 | ||
|
|
9a2c84d68c | ||
|
|
8e5af129ff | ||
|
|
096c11b563 | ||
|
|
9bfae502d1 | ||
|
|
0d964363a4 | ||
|
|
8107db7849 | ||
|
|
c9473def03 | ||
|
|
baeed314cf | ||
|
|
90727b7d19 | ||
|
|
8c22d91057 | ||
|
|
a5d7f5b1cc | ||
|
|
229ce22fbc | ||
|
|
0487e41c34 | ||
|
|
b3a2667e9f | ||
|
|
6a4d1cc84e | ||
|
|
87d2a67401 | ||
|
|
3881dd2ebf | ||
|
|
fb91c4fcde | ||
|
|
ab7a2302f2 | ||
|
|
d117ad79a2 | ||
|
|
5235f6f417 | ||
|
|
3376334dfc | ||
|
|
bb635e4367 | ||
|
|
a79f5330f4 | ||
|
|
0dee4f88e0 | ||
|
|
c9a681c3e3 | ||
|
|
4ce283594f | ||
|
|
d42a2a9ec7 | ||
|
|
5d41d41da8 | ||
|
|
46aa5773c7 | ||
|
|
3fe3cf1536 | ||
|
|
b23fbd5c5e | ||
|
|
fa88a28c4d | ||
|
|
6e4037768a | ||
|
|
fa91edb0a3 | ||
|
|
725c80673c | ||
|
|
4a9c93475e | ||
|
|
842c2e4269 | ||
|
|
af0b2f85a7 | ||
|
|
120f6898f4 | ||
|
|
3c0ce9c885 | ||
|
|
2c78776aaf | ||
|
|
5dd65efa14 | ||
|
|
d1fdfb1950 | ||
|
|
57b098c98a | ||
|
|
47e958b753 | ||
|
|
1d5976d1ab | ||
|
|
582ae36e1d | ||
|
|
8fb6330a28 | ||
|
|
da778084e5 | ||
|
|
9220b5c58e | ||
|
|
b68f2820c4 | ||
|
|
4786b94f8e | ||
|
|
0d790dabb6 | ||
|
|
6de283f621 | ||
|
|
7f907c32fc | ||
|
|
0af6be50cb | ||
|
|
b193c95475 | ||
|
|
d95d96f5ea | ||
|
|
904cc5007d | ||
|
|
811b7916ad | ||
|
|
74425d76e1 | ||
|
|
3a26d7b3bb | ||
|
|
4398deaa3d | ||
|
|
18f5ec0671 | ||
|
|
638a535b5f | ||
|
|
cc4c1c3a29 | ||
|
|
6357820d52 | ||
|
|
64cb35857c | ||
|
|
28d0acfedb | ||
|
|
3ed13f498c | ||
|
|
afbb1f20c2 | ||
|
|
68772ec36a | ||
|
|
3bb30f74b3 | ||
|
|
0bde083556 | ||
|
|
10b479cf29 | ||
|
|
75896bdd32 | ||
|
|
6c207c9c68 | ||
|
|
527478d318 | ||
|
|
48ef50f6c3 | ||
|
|
035add4eff | ||
|
|
455261985d | ||
|
|
e680ca9bce | ||
|
|
1c5a717528 | ||
|
|
bdd0f0aea9 | ||
|
|
7c26cffac6 | ||
|
|
cac3dc732a | ||
|
|
c7d7eeb49d | ||
|
|
cae9387908 | ||
|
|
a6c8bb4636 | ||
|
|
95b70c7acc | ||
|
|
841b782a4c | ||
|
|
03da54787c | ||
|
|
d19da98bb4 | ||
|
|
3bed636a41 | ||
|
|
70aa6b394d | ||
|
|
1faf137f72 | ||
|
|
7d1a8307e1 | ||
|
|
7fdcd1adaf | ||
|
|
c3e4760338 | ||
|
|
740e2858dc | ||
|
|
1b6cdf3d0f | ||
|
|
a34c2bd8c3 | ||
|
|
b28b5c3a5d | ||
|
|
106818614d | ||
|
|
e653c388bf | ||
|
|
64519e28e0 | ||
|
|
0d04c87755 | ||
|
|
c2ca839b6a | ||
|
|
368f58c0f8 | ||
|
|
04ae576541 | ||
|
|
2d0cc5d86b | ||
|
|
3a8a2b0351 | ||
|
|
1f938d9642 | ||
|
|
5fb86ae178 | ||
|
|
27a4e3a7ad | ||
|
|
23200c4321 | ||
|
|
76edab7837 | ||
|
|
3ac3286356 | ||
|
|
bb278fc159 | ||
|
|
1bb5ee3920 | ||
|
|
d1e7781db6 | ||
|
|
9c2b1a6295 | ||
|
|
3a2d8e2ccc | ||
|
|
c719a977a7 | ||
|
|
c1cc101f91 | ||
|
|
cd3597174c | ||
|
|
458c6d693d | ||
|
|
a8f8378e77 |
23
.github/workflows/make-test.yml
vendored
Normal file
23
.github/workflows/make-test.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Run make test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
schedule:
|
||||
- cron: '30 9 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make
|
||||
run: FAKETIME_COMPILE_CFLAGS="-DFORCE_MONOTONIC_FIX" make
|
||||
- name: make test
|
||||
run: make test
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,9 +1,16 @@
|
||||
*.o
|
||||
*.so.1
|
||||
timetest
|
||||
test/getrandom_test
|
||||
test/lib*.so
|
||||
test/use_lib_*
|
||||
test/run_*
|
||||
test/repeat_random
|
||||
test/getentropy_test
|
||||
test/syscall_test
|
||||
test/variadic_promotion
|
||||
|
||||
src/libfaketime.dylib.1
|
||||
src/libfaketime.1.dylib
|
||||
src/core
|
||||
src/faketime
|
||||
|
||||
|
||||
21
.travis.yml
Normal file
21
.travis.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
language: c
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
arch: amd64
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
arch: ppc64le
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
osx_image: xcode11
|
||||
|
||||
script:
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- if [ "$TRAVIS_ARCH" = ppc64le ]; then
|
||||
FAKETIME_COMPILE_CFLAGS="-DFORCE_MONOTONIC_FIX -DFORCE_PTHREAD_NONVER" make;
|
||||
else
|
||||
FAKETIME_COMPILE_CFLAGS="-DFORCE_MONOTONIC_FIX" make;
|
||||
fi
|
||||
- make test
|
||||
25
Makefile
25
Makefile
@@ -1,31 +1,36 @@
|
||||
INSTALL ?= install
|
||||
|
||||
UNAME=$(shell uname)
|
||||
SELECTOR:=$(shell if test "${UNAME}" = "Darwin" ; then echo "-f Makefile.OSX" ; fi)
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
all:
|
||||
$(MAKE) -C src all
|
||||
$(MAKE) $(SELECTOR) -C src all
|
||||
|
||||
test:
|
||||
$(MAKE) -C test all
|
||||
$(MAKE) $(SELECTOR) -C src all
|
||||
$(MAKE) $(SELECTOR) -C test all
|
||||
|
||||
install:
|
||||
$(MAKE) -C src install
|
||||
$(MAKE) -C man install
|
||||
$(MAKE) $(SELECTOR) -C src install
|
||||
$(MAKE) $(SELECTOR) -C man install
|
||||
$(INSTALL) -dm0755 "${DESTDIR}${PREFIX}/share/doc/faketime/"
|
||||
$(INSTALL) -m0644 README "${DESTDIR}${PREFIX}/share/doc/faketime/README"
|
||||
$(INSTALL) -m0644 NEWS "${DESTDIR}${PREFIX}/share/doc/faketime/NEWS"
|
||||
|
||||
uninstall:
|
||||
$(MAKE) -C src uninstall
|
||||
$(MAKE) -C man uninstall
|
||||
$(MAKE) $(SELECTOR) -C src uninstall
|
||||
$(MAKE) $(SELECTOR) -C man uninstall
|
||||
rm -f "${DESTDIR}${PREFIX}/share/doc/faketime/README"
|
||||
rm -f "${DESTDIR}${PREFIX}/share/doc/faketime/NEWS"
|
||||
rmdir "${DESTDIR}${PREFIX}/share/doc/faketime"
|
||||
|
||||
clean:
|
||||
$(MAKE) -C src clean
|
||||
$(MAKE) -C test clean
|
||||
$(MAKE) $(SELECTOR) -C src clean
|
||||
$(MAKE) $(SELECTOR) -C test clean
|
||||
|
||||
distclean:
|
||||
$(MAKE) -C src distclean
|
||||
$(MAKE) -C test distclean
|
||||
$(MAKE) $(SELECTOR) -C src distclean
|
||||
$(MAKE) $(SELECTOR) -C test distclean
|
||||
|
||||
.PHONY: all test install uninstall clean distclean
|
||||
|
||||
33
Makefile.OSX
33
Makefile.OSX
@@ -1,33 +0,0 @@
|
||||
INSTALL ?= install
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
all:
|
||||
$(MAKE) -f Makefile.OSX -C src all
|
||||
|
||||
test:
|
||||
$(MAKE) -f Makefile.OSX -C test all
|
||||
|
||||
install:
|
||||
$(MAKE) -f Makefile.OSX -C src install
|
||||
$(MAKE) -f Makefile.OSX -C man install
|
||||
$(INSTALL) -dm0755 "${DESTDIR}${PREFIX}/share/doc/faketime/"
|
||||
$(INSTALL) -m0644 README "${DESTDIR}${PREFIX}/share/doc/faketime/README"
|
||||
$(INSTALL) -m0644 NEWS "${DESTDIR}${PREFIX}/share/doc/faketime/NEWS"
|
||||
|
||||
uninstall:
|
||||
$(MAKE) -f Makefile.OSX -C src uninstall
|
||||
$(MAKE) -f Makefile.OSX -C man uninstall
|
||||
rm -f "${DESTDIR}${PREFIX}/share/doc/faketime/README"
|
||||
rm -f "${DESTDIR}${PREFIX}/share/doc/faketime/NEWS"
|
||||
rmdir "${DESTDIR}${PREFIX}/share/doc/faketime"
|
||||
|
||||
clean:
|
||||
$(MAKE) -f Makefile.OSX -C src clean
|
||||
$(MAKE) -f Makefile.OSX -C test clean
|
||||
|
||||
distclean:
|
||||
$(MAKE) -f Makefile.OSX -C src distclean
|
||||
$(MAKE) -f Makefile.OSX -C test distclean
|
||||
|
||||
.PHONY: all test install uninstall clean distclean
|
||||
81
NEWS
81
NEWS
@@ -1,3 +1,82 @@
|
||||
Since 0.9.9:
|
||||
- improved macOS Monterey support through dyld interposing
|
||||
- changed interception hooks for stat() and similar functions,
|
||||
refactored to use a common handler (@sirainen)
|
||||
- added support for timespec_get, timerfd_{get,set} (@sliquister)
|
||||
- generic syscall() interception for selected syscalls (@dkg)
|
||||
- improved testing system (@dkg)
|
||||
|
||||
Since 0.9.8:
|
||||
- When compiled with the CFLAG FAKE_RANDOM set,
|
||||
libfaketime will intercept calls to getrandom()
|
||||
and return pseudorandom numbers for determinism.
|
||||
The mechanism needs to be activated by setting
|
||||
the environment variable FAKERANDOM_SEED to a
|
||||
64-bit seed value, e.g., "0x12345678DEADBEEF".
|
||||
Please note that this completely breaks the
|
||||
security of random numbers for cryptographic
|
||||
purposes and should only be used for deterministic
|
||||
tests. Never use this in production!
|
||||
- When the environment variable FAKETIME_TIMESTAMP_FILE is
|
||||
set, points to a writeable (creatable) custom config file
|
||||
and the environment variable FAKETIME_UPDATE_TIMESTAMP_FILE
|
||||
is "1", then the file also is updated on each call. By
|
||||
this, a common "virtual time" can be shared by several
|
||||
processes, where each can adjust the time for all.
|
||||
- Additional link-time LDFLAGS can be passed via the
|
||||
environment variable FAKETIME_LINK_FLAGS when
|
||||
running 'make'.
|
||||
- Compile-time CFLAG FAKE_SETTIME can be enabled to
|
||||
intercept calls to clock_settime(), settimeofday(), and
|
||||
adjtime(). (suggested and prototyped by @ojura)
|
||||
- Additional compile-time CFLAGs can be passed via the
|
||||
environment variable FAKETIME_COMPILE_CFLAGS when
|
||||
running 'make'.
|
||||
- src/Makefile CFLAG FORCE_PTHREAD_NONVER should be set on
|
||||
systems that hang on CLOCK_REALTIME, or that hang on
|
||||
CLOCK_MONOTONIC where FORCE_MONOTONIC_FIX is not sufficient.
|
||||
|
||||
Since 0.9.7:
|
||||
- Passthrough for unknown clock ids to avoid error messages
|
||||
- Fixes for multithreaded operations (mliertzer, qnox)
|
||||
- glibc-related fixes (jprjr) and gcc8 support (tpetazzoni)
|
||||
- Improved error message output on parsing errors
|
||||
- fix file stat() faking when 'i' modifier is used for determinism
|
||||
- Use FAKETIME="%" to take FAKETIME setting from a file as
|
||||
specified in FAKETIME_FOLLOW_FILE
|
||||
- Added FAKETIME_DONT_RESET environment variable to avoid
|
||||
faketime resets when subprocesses are started (similar to
|
||||
the old v0.9.6 behavior)
|
||||
- Added FAKETIME_XRESET to avoid large clock jumps when
|
||||
the 'x' modifier is used and changed during run-time
|
||||
- Do not fake time during libfaketime initialization to
|
||||
improve compatibility with memory allocation libraries that
|
||||
use time-related functions themselves
|
||||
- Fixes for shared memory related issues, especially when
|
||||
not using the faketime wrapper
|
||||
- Updated glibc compatibility settings for various platforms
|
||||
- Support for clock_nanosleep() with realtime and monotonic clocks
|
||||
- Support for epoll_wait(), epoll_pwait(), and pselect()
|
||||
- src/Makefile CFLAG FORCE_MONOTONIC_FIX should be set (only) on
|
||||
platforms where the test program hangs forever at the
|
||||
CLOCK_MONOTONIC test.
|
||||
|
||||
Since 0.9.6:
|
||||
- Julien Gilli added an option to disable monotonic time faking
|
||||
- Azat Khuzhin added support for COARSE clocks
|
||||
- Preliminary support for CLOCK_BOOTTIME (Linux)
|
||||
- Fixed compilation on macOS (High) Sierra and various compiler warnings
|
||||
- Support for select() call added by Hitoshi Harada (umitanuki)
|
||||
- Updated documentation
|
||||
|
||||
Since 0.9.5:
|
||||
- fixed crashes that happened when other LD_PRELOAD libraries were used
|
||||
- fixed passing through of return values when using the faketime wrapper
|
||||
- fixed compile-time issues with CLOCK_MONOTONIC_RAW on some platforms
|
||||
- rbalint added Filter commands: FAKETIME_ONLY_CMDS and
|
||||
FAKETIME_SKIP_CMDS control which (sub-)processes libfaketime
|
||||
is applied to.
|
||||
|
||||
Since 0.9:
|
||||
- ryandesign at MacPorts provided a Portfile for MacPorts and
|
||||
fixed various build issues on OSX.
|
||||
@@ -41,7 +120,7 @@ Since 0.8.2:
|
||||
|
||||
Since 0.8.1:
|
||||
- Added a MacOS port.
|
||||
Thanks to Derrick Brashear!
|
||||
Thanks to Daria Phoebe Brashear!
|
||||
- Added a functional test framework that aids in automatically
|
||||
determining whether libfaketime works properly on the current
|
||||
machine. Thanks to Don Fong!
|
||||
|
||||
470
README
470
README
@@ -1,7 +1,5 @@
|
||||
=======================================================
|
||||
libfaketime, version 0.9.5 (October 2013)
|
||||
(previously also know as FakeTime Preload Library)
|
||||
=======================================================
|
||||
libfaketime, version 0.9.10 (February 2022)
|
||||
===========================================
|
||||
|
||||
|
||||
Content of this file:
|
||||
@@ -18,89 +16,108 @@ Content of this file:
|
||||
e) Advanced features and caveats
|
||||
f) Faking the date and time system-wide
|
||||
g) Using the "faketime" wrapper script
|
||||
h) "Limiting" libfaketime
|
||||
i) Spawning an external process
|
||||
j) Saving timestamps to file, loading them from file
|
||||
h) "Limiting" libfaketime based on elapsed time or number of calls
|
||||
i) "Limiting" libfaketime per process
|
||||
j) Spawning an external process
|
||||
k) Saving timestamps to file, loading them from file
|
||||
l) Replacing random numbers with deterministic number sequences
|
||||
5. License
|
||||
6. Contact
|
||||
|
||||
|
||||
|
||||
1. Introduction
|
||||
---------------
|
||||
|
||||
libfaketime intercepts various system calls which programs use to
|
||||
retrieve the current date and time. It can then report faked dates and times
|
||||
(as specified by you, the user) to these programs. This means you can modify
|
||||
the system time a program sees without having to change the time system-wide.
|
||||
libfaketime intercepts various system calls that programs use to retrieve the
|
||||
current date and time. It then reports modified (faked) dates and times (as
|
||||
specified by you, the user) to these programs. This means you can modify the
|
||||
system time a program sees without having to change the time system-wide.
|
||||
|
||||
libfaketime allows you to specify both absolute dates (e.g., 01/01/2004) and
|
||||
relative dates (e.g., 10 days ago).
|
||||
|
||||
libfaketime might be used for various purposes, for example
|
||||
|
||||
- running legacy software with y2k bugs
|
||||
- testing software for year-2038 compliance
|
||||
- deterministic build processes
|
||||
- debugging time-related issues, such as expired SSL certificates
|
||||
- running software which ceases to run outside a certain timeframe
|
||||
- using different system-wide date and time settings, e.g., on OpenVZ-
|
||||
based virtual machines running on the same host.
|
||||
- testing software for year-2038 compliance
|
||||
|
||||
libfaketime ships with a command line wrapper called "faketime" that makes it
|
||||
easier to use, but does not expose all of libfaketime's functionality. If your
|
||||
use case is not covered by the faketime command, make sure to look in this
|
||||
documentation whether it can be achieved by using libfaketime directly.
|
||||
|
||||
|
||||
2. Compatibility issues
|
||||
-----------------------
|
||||
|
||||
* libfaketime has been designed on and for Linux, but is supposed and has been
|
||||
reported to work on other *NIXes as well, including Mac OS X.
|
||||
- libfaketime is supposed to work on Linux and macOS.
|
||||
Your mileage may vary; some other *NIXes have been reported to work as well.
|
||||
|
||||
* libfaketime uses the library preload mechanism and thus cannot work with
|
||||
- libfaketime uses the library preload mechanism of your operating system's
|
||||
linker (which is involved in starting programs) and thus cannot work with
|
||||
statically linked binaries or binaries that have the setuid-flag set (e.g.,
|
||||
suidroot programs like "ping" or "passwd"). Please see you system linker's
|
||||
manpage for further details (man ld).
|
||||
manpage for further details.
|
||||
|
||||
* As of version 0.7, support has been added for use in a pthreads environment. A
|
||||
separate library is built (libfaketimeMT.so.1) which contains the pthread
|
||||
synchronization calls. This library also single-threads calls through the
|
||||
time() intercept, because several variables are statically cached by the
|
||||
library and could cause issues when accessed without synchronization. However,
|
||||
the performance penalty for this might be an issue for some applications. If
|
||||
this is the case, you can try using an unsynchronized time() intercept by
|
||||
removing the -DPTHREAD_SINGLETHREADED_TIME from the Makefile and rebuilding
|
||||
libfaketimeMT.so.1 . Thanks to David North, TDI!
|
||||
- libfaketime supports the pthreads environment. A separate library is built
|
||||
(libfaketimeMT.so.1), which contains the pthread synchronization calls. This
|
||||
library also single-threads calls through the time() intercept because
|
||||
several variables are statically cached by the library and could cause issues
|
||||
when accessed without synchronization.
|
||||
|
||||
* If and only if you want to run Java programs with faked times in the future
|
||||
(not in the past) on Linux, you also should set the environment variable
|
||||
LD_ASSUME_KERNEL=2.4.19 before running the appropriate "java" command. This
|
||||
fixes an occasional bug where Java locks up at exiting. Again, this is only
|
||||
required for Java with faked times in the future. Thanks to Jamie Cameron for
|
||||
reporting this issue and finding a workaround!
|
||||
However, the performance penalty for this might be an issue for some
|
||||
applications. If this is the case, you can try using an unsynchronized time()
|
||||
intercept by removing the -DPTHREAD_SINGLETHREADED_TIME from the Makefile and
|
||||
rebuilding libfaketimeMT.so.1
|
||||
|
||||
* Java-/JVM-based applications work but you need to pass in an extra argument
|
||||
(FAKETIME_DONT_FAKE_MONOTONIC). See usage basics below for details. Without
|
||||
this argument the java command usually hangs.
|
||||
|
||||
* libfaketime will eventually be bypassed by applications that dynamically load
|
||||
system libraries, such as librt, explicitly themselves instead of relying on
|
||||
the linker to do so at application start time. libfaketime will not work with
|
||||
those applications unless you can modify them.
|
||||
|
||||
This apparently happens a lot in complex run-time environments, e.g., for
|
||||
programs written in golang, for some Java Virtual Machine implementations,
|
||||
etc. Since libfaketime is effectively bypassed in such situations, there's
|
||||
nothing we can do about it. Please consider asking the appropriate developers
|
||||
and vendors to implement their runtime environment in a way that supports
|
||||
intercepting selected system calls through LD_PRELOAD.
|
||||
|
||||
* Applications can explicitly be designed to prevent libfaketime from working,
|
||||
e.g., by checking whether certain environment variables are set or whether
|
||||
libfaketime-specific files are present.
|
||||
|
||||
* CLOCK_MONOTONIC test: Running "make test" performs a series of tests after
|
||||
successful compilation of the libfaketime library. On some platforms, the
|
||||
"CLOCK_MONOTONIC test" will apparently hang forever. If and only if this
|
||||
happens on your platform, add the CFLAG -DFORCE_MONOTONIC_FIX to
|
||||
src/Makefile and recompile libfaketime. Do not set FORCE_MONOTONIC_FIX on
|
||||
platforms where the test does not hang.
|
||||
|
||||
If you observe hangs on the CLOCK_REALTIME test, add the CFLAG
|
||||
-DFORCE_PTHREAD_NONVER. Also set this FORCE_PTHREAD_NONVER flag in case
|
||||
FORCE_MONOTONIC_FIX alone does not solve the hang on the MONOTONIC_CLOCK
|
||||
test.
|
||||
|
||||
|
||||
3. Installation
|
||||
---------------
|
||||
|
||||
Running "make" should compile both library versions and a test program, which
|
||||
it then also executes.
|
||||
Running "make" compiles both library versions and a test program, which it then
|
||||
also executes.
|
||||
|
||||
If the test works fine, you should copy the libfaketime libraries
|
||||
(libfaketime.so.1, and libfaketimeMT.so.1) to the place you want them in.
|
||||
Running "make install" will attempt to place them in /usr/local/lib/faketime
|
||||
and will install the wrapper shell script "faketime" in /usr/local/bin, both of
|
||||
which most likely will require root privileges; however, from a technical point
|
||||
which most likely will require root privileges. However, from a technical point
|
||||
of view, there is no necessity for a system-wide installation, so you can use
|
||||
libfaketime also on machines where you do not have root privileges. You may want
|
||||
to adjust the PREFIX variable in the Makefiles accordingly.
|
||||
libfaketime also on machines where you do not have root privileges. You may
|
||||
want to adjust the PREFIX variable in the Makefiles accordingly.
|
||||
|
||||
By default, the Makefile compiles/links libfaketime for your default system
|
||||
architecture. If you need to build, e.g., 32-bit files on a 64-bit platform,
|
||||
@@ -114,16 +131,15 @@ not need this feature or if it confuses the application you want to use FTPL
|
||||
with, define the environment variable NO_FAKE_STAT, and the intercepted stat
|
||||
calls will be passed through unaltered.
|
||||
|
||||
On OS X, it is necessary to compile differently, due to the different
|
||||
behavior dyld has. Use the Makefile.MacOS provided to compile
|
||||
On macOS, it is necessary to compile differently, due to the different
|
||||
behavior dyld has. Use the Makefile.OSX file provided to compile
|
||||
libfaketime.1.dylib. Additionally, instead of using LD_PRELOAD,
|
||||
the variable DYLD_INSERT_LIBRARIES should be set to the path to
|
||||
libfaketime.1.dylib, and the variable DYLD_FORCE_FLAT_NAMESPACE should be
|
||||
set (to anything). Mac OS X users should read README.OSX for additional
|
||||
set (to anything). macOS users should read README.OSX for additional
|
||||
details.
|
||||
|
||||
|
||||
|
||||
4. Usage
|
||||
--------
|
||||
|
||||
@@ -135,26 +151,29 @@ Using libfaketime on a program of your choice consists of two steps:
|
||||
1. Making sure libfaketime gets loaded by the system's linker.
|
||||
2. Specify the faked time.
|
||||
|
||||
|
||||
As an example, we want the "date" command to report our faked time. To do so,
|
||||
we could use the following command line on Linux:
|
||||
|
||||
user@host> date
|
||||
Tue Nov 23 12:01:05 CEST 2007
|
||||
Tue Nov 23 12:01:05 CEST 2016
|
||||
|
||||
user@host> LD_PRELOAD=/usr/local/lib/libfaketime.so.1 FAKETIME="-15d" date
|
||||
Mon Nov 8 12:01:12 CEST 2007
|
||||
Mon Nov 8 12:01:12 CEST 2016
|
||||
|
||||
user@host> LD_PRELOAD=/usr/local/lib/libfaketime.so.1 FAKETIME="-15d"
|
||||
FAKETIME_DONT_FAKE_MONOTONIC=1 java -version
|
||||
java version "1.8.0_111"
|
||||
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
|
||||
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
|
||||
|
||||
The basic way of running any command/program with libfaketime enabled is to
|
||||
make sure the environment variable LD_PRELOAD contains the full path and
|
||||
make sure the environment variable LD_PRELOAD contains the path and
|
||||
filename of the libfaketime library. This can either be done by setting it once
|
||||
beforehand:
|
||||
|
||||
export LD_PRELOAD=/path/to/libfaketime.so.1
|
||||
(now run any command you want)
|
||||
|
||||
|
||||
Or it can be done by specifying it on the command line itself:
|
||||
|
||||
LD_PRELOAD=/path/to/libfaketime.so.1 your_command_here
|
||||
@@ -162,28 +181,36 @@ LD_PRELOAD=/path/to/libfaketime.so.1 your_command_here
|
||||
(These examples are for the bash shell; how environment variables are set may
|
||||
vary on your system.)
|
||||
|
||||
On Linux, library search paths can be set as part of the linker configuration.
|
||||
LD_PRELOAD then also works with relative paths. For example, when libfaketime.so.1
|
||||
is installed as /path/to/libfaketime.so.1, you can add /path/to to an appropriate
|
||||
linker configuration file, e.g., /etc/ld.so.conf.d/local.conf, and then run
|
||||
the "ldconfig" command. Afterwards, using LD_PRELOAD=libfaketime.so.1 suffices.
|
||||
|
||||
However, also the faked time should be specified; otherwise, libfaketime
|
||||
will be loaded, but just report the real system time. There are three
|
||||
ways to specify the faked time:
|
||||
However, also the faked time should be specified; otherwise, libfaketime will
|
||||
be loaded, but just report the real system time. There are multiple ways to
|
||||
specify the faked time:
|
||||
|
||||
a) By setting the environment variable FAKETIME.
|
||||
b) By using the file .faketimerc in your home directory.
|
||||
c) By using the file /etc/faketimerc for a system-wide default.
|
||||
b) By using the file given in the environment variable FAKETIME_TIMESTAMP_FILE
|
||||
c) By using the file .faketimerc in your home directory.
|
||||
d) By using the file /etc/faketimerc for a system-wide default.
|
||||
e) By using FAKETIME_UPDATE_TIMESTAMP_FILE and date -s "<time>" or alike.
|
||||
|
||||
If you want to use b) or c), $HOME/.faketimerc or /etc/faketimerc consist of
|
||||
If you want to use b) c) or d), $HOME/.faketimerc or /etc/faketimerc consist of
|
||||
only one line of text with exactly the same content as the FAKETIME environment
|
||||
variable, which is described below. Note that /etc/faketimerc will only be used
|
||||
if there is no $HOME/.faketimerc, and the FAKETIME environment variable always
|
||||
has priority over the files.
|
||||
if there is no $HOME/.faketimerc and no FAKETIME_TIMESTAMP_FILE file exists.
|
||||
Also, the FAKETIME environment variable _always_ has priority over the files.
|
||||
For FAKETIME_UPDATE_TIMESTAMP_FILE please see below.
|
||||
|
||||
|
||||
4b) Using absolute dates
|
||||
------------------------
|
||||
|
||||
The format which _must_ be used for _absolute_ dates is "YYYY-MM-DD hh:mm:ss".
|
||||
For example, the 24th of December, 2002, 8:30 PM would have to be specified as
|
||||
FAKETIME="2002-12-24 20:30:00".
|
||||
The format that _must_ be used for _absolute_ dates is "YYYY-MM-DD hh:mm:ss".
|
||||
For example, the 24th of December, 2020, 8:30 PM would have to be specified as
|
||||
FAKETIME="2020-12-24 20:30:00".
|
||||
|
||||
|
||||
4c) Using 'start at' dates
|
||||
@@ -191,15 +218,31 @@ FAKETIME="2002-12-24 20:30:00".
|
||||
|
||||
(Thanks to a major contribution by David North, TDI in version 0.7)
|
||||
|
||||
The format which _must_ be used for _start_at_ dates is "@YYYY-MM-DD hh:mm:ss".
|
||||
For example, the 24th of December, 2002, 8:30 PM would have to be specified as
|
||||
FAKETIME="@2002-12-24 20:30:00".
|
||||
The format that _must_ be used for _start_at_ dates is "@YYYY-MM-DD hh:mm:ss".
|
||||
For example, the 24th of December, 2020, 8:30 PM would have to be specified as
|
||||
FAKETIME="@2020-12-24 20:30:00".
|
||||
|
||||
The absolute dates described in 4b simulate a STOPPED system clock at the
|
||||
The absolute dates described in 4b) simulate a STOPPED system clock at the
|
||||
specified absolute time. The 'start at' format allows a 'relative' clock
|
||||
operation as described below in section 4d, but using a 'start at' time
|
||||
operation as described below in section 4d), but using a 'start at' time
|
||||
instead of an offset time.
|
||||
|
||||
If the started process itself starts other (child) processes, they by default
|
||||
will start with the specified start-at-date again. If this is not what you need,
|
||||
set the environment variable FAKETIME_DONT_RESET=1. Try these examples to see
|
||||
the difference:
|
||||
|
||||
LD_PRELOAD=src/libfaketime.so.1 FAKETIME="@2000-01-01 11:12:13" \
|
||||
FAKETIME_DONT_RESET=1 \
|
||||
/bin/bash -c 'while [ $SECONDS -lt 5 ]; do date; sleep 1; done'
|
||||
|
||||
LD_PRELOAD=src/libfaketime.so.1 FAKETIME="@2000-01-01 11:12:13" \
|
||||
/bin/bash -c 'while [ $SECONDS -lt 5 ]; do date; sleep 1; done'
|
||||
|
||||
In the second example, the "date" command will always print the same time,
|
||||
while in the first example, with FAKETIME_DONT_RESET set, time will increment
|
||||
even though all the "date" commands are new processes.
|
||||
|
||||
|
||||
4d) Using offsets for relative dates
|
||||
------------------------------------
|
||||
@@ -208,27 +251,31 @@ Relative date offsets can be positive or negative, thus what you put into
|
||||
FAKETIME _must_ either start with a + or a -, followed by a number, and
|
||||
optionally followed by a multiplier:
|
||||
|
||||
- by default, the offset you specify is in seconds. Example:
|
||||
- By default, the offset you specify is in seconds. Example:
|
||||
|
||||
export FAKETIME="-120" will set the faked time 2 minutes (120 seconds) behind
|
||||
the real time.
|
||||
|
||||
- the multipliers "m", "h", "d" and "y" can be used to specify the offset in
|
||||
- The multipliers "m", "h", "d" and "y" can be used to specify the offset in
|
||||
minutes, hours, days and years (365 days each), respectively. Examples:
|
||||
|
||||
export FAKETIME="-10m" sets the faked time 10 minutes behind the real time.
|
||||
export FAKETIME="+14d" sets the faked time to 14 days in the future.
|
||||
|
||||
Please note that if you need other multipliers (weeks, months etc.) or higher
|
||||
precision (e.g., correct leap year handling), you should use either the
|
||||
faketime wrapper or the GNU date command as shown in the first of the three
|
||||
examples below.
|
||||
|
||||
You now should understand the complete example we've used before:
|
||||
|
||||
LD_PRELOAD=/usr/local/lib/libfaketime.so.1 FAKETIME="-15d" date
|
||||
|
||||
This command line makes sure FTPL gets loaded and sets the faked time to
|
||||
This command line makes sure libfaketime gets loaded and sets the faked time to
|
||||
15 days in the past.
|
||||
|
||||
Moreno Baricevic has contributed support for the FAKETIME_FMT environment
|
||||
variable, which allows to optionally set the strptime() format:
|
||||
variable, which allows you to optionally set the strptime() format:
|
||||
|
||||
Some simple examples:
|
||||
LD_PRELOAD=./libfaketime.so.1 FAKETIME_FMT=%s FAKETIME="`date +%s -d'1 year ago'`" date
|
||||
@@ -252,7 +299,7 @@ depends on your locale settings, so actually you might need to use
|
||||
|
||||
FAKETIME="+1.5h"
|
||||
|
||||
You should figure out the proper delimiter, e.g. by using libfaketime on
|
||||
You should figure out the proper delimiter, e.g., by using libfaketime on
|
||||
a command like /bin/date where you immediately can verify whether it worked as
|
||||
expected.
|
||||
|
||||
@@ -268,14 +315,19 @@ twice as fast. Similarly,
|
||||
FAKETIME="+1y x0,5"
|
||||
|
||||
will make the clock run only half as fast. As stated above, the fraction
|
||||
delimiter depends on your locale.
|
||||
delimiter depends on your locale. Furthermore,
|
||||
|
||||
FAKETIME="+1y i2,0"
|
||||
|
||||
will make the clock step two seconds per each time(), etc. call, running
|
||||
will make the clock step two seconds per each time(), etc. call, being
|
||||
completely independently of the system clock. It helps running programs
|
||||
with some determinism. In this single case all spawned processes will use
|
||||
the same global clock without restaring it at the start of each process.
|
||||
the same global clock without restarting it at the start of each process.
|
||||
|
||||
Please note that using "x" or "i" in FAKETIME still requires giving an offset
|
||||
(see section 4d). This means that "+1y x2" will work, but "x2" only will not.
|
||||
If you do not want to fake the time, but just modify clock speed, use something
|
||||
like "+0 x2", i.e., use an explicit zero offset as a prefix in your FAKETIME.
|
||||
|
||||
For testing, your should run a command like
|
||||
|
||||
@@ -287,10 +339,9 @@ think that 10 seconds have passed ($SECONDS is a bash-internal variable
|
||||
measuring the time since the shell was started).
|
||||
|
||||
(Please note that replacing "echo $SECONDS" e.g. with a call to "/bin/date"
|
||||
will not give the expected result, since /bin/date will always be started
|
||||
as a new process for which also FTPL will be re-initialized. It will show
|
||||
the correct offset (1.5 years in the future), but no speed-ups or
|
||||
slow-downs.)
|
||||
will not give the expected result, since /bin/date will always be started as a
|
||||
new process for which also libfaketime will be re-initialized. It will show the
|
||||
correct offset (1.5 years in the future), but no speed-ups or slow-downs.)
|
||||
|
||||
For applications that should use a different date & time each time they are
|
||||
run, consider using the included timeprivacy wrapper shellscript (contributed
|
||||
@@ -304,8 +355,8 @@ Whenever possible, you should use relative offsets or 'start at' dates,
|
||||
and not use absolute dates.
|
||||
|
||||
Why? Because the absolute date/time you set is fixed, i.e., if a program
|
||||
retrieves the current time, and retrieves the current time again 5
|
||||
minutes later, it will still get the same result twice. This is likely to break
|
||||
retrieves the current time, and retrieves the current time again 5 minutes
|
||||
later, it will still get the same result twice. This is likely to break
|
||||
programs which measure the time passing by (e.g., a mail program which checks
|
||||
for new mail every X minutes).
|
||||
|
||||
@@ -313,12 +364,160 @@ Using relative offsets or 'start at' dates solves this problem.
|
||||
libfaketime then will always report the faked time based on the real
|
||||
current time and the offset you've specified.
|
||||
|
||||
Please also note that your specification of the fake time is cached for 10
|
||||
seconds in order to enhance the library's performance. Thus, if you change the
|
||||
Please also note that your default specification of the fake time is cached for
|
||||
10 seconds in order to enhance the library's performance. Thus, if you change the
|
||||
content of $HOME/.faketimerc or /etc/faketimerc while a program is running, it
|
||||
may take up to 10 seconds before the new fake time is applied. If this is a
|
||||
problem in your scenario, you can disable caching at compile time by adding the
|
||||
command line option -DNO_CACHING to this library's Makefile.
|
||||
problem in your scenario, you can change number of seconds before the file is read
|
||||
again with environment variable FAKETIME_CACHE_DURATION, or disable caching at all
|
||||
with FAKETIME_NO_CACHE=1. Remember that disabling the cache may negatively
|
||||
influence the performance (especially when not using FAKETIME environment
|
||||
but configuration files, such as FAKETIME_TIMESTAMP_FILE).
|
||||
|
||||
|
||||
Setting FAKETIME by means of a file timestamp
|
||||
---------------------------------------------
|
||||
|
||||
Based on a proposal by Hitoshi Harada (umitanuki), the "start at" time can now be
|
||||
set through any file in the file system by setting the FAKETIME environment variable
|
||||
to "%" (a percent sign) and FAKETIME_FOLLOW_FILE to the name of the file whose
|
||||
modification timestamp shall be used as source for the "start at" time.
|
||||
|
||||
Usage example:
|
||||
|
||||
# create any file with December 24th, 2009, 12:34:56 as timestamp
|
||||
touch -t 0912241234.56 /tmp/my-demo-file.tmp
|
||||
|
||||
# run a bash shell with an endless loop printing the current time
|
||||
LD_PRELOAD=/path/to/libfaketime.so.1 \
|
||||
FAKETIME='%' FAKETIME_FOLLOW_FILE=/tmp/my-demo-file.tmp \
|
||||
FAKETIME_DONT_RESET=1 \
|
||||
bash -c 'while true ; do date ; sleep 1 ; done'
|
||||
|
||||
# now, while the above is running, change the file's timestamp
|
||||
# (in a different terminal window or whatever)
|
||||
touch -t 2002290123.45 /tmp/my-demo-file.tmp
|
||||
|
||||
|
||||
Changing the 'x' modifier during run-time
|
||||
-----------------------------------------
|
||||
|
||||
Using FAKETIME_TIMESTAMP_FILE allows for easily changing the FAKETIME setting
|
||||
while a program is running:
|
||||
|
||||
echo "+0 x1" > /tmp/my-faketime.rc
|
||||
LD_PRELOAD=libfaketime.so.1 FAKETIME_TIMESTAMP_FILE="/tmp/my-faketime.rc" \
|
||||
FAKETIME_NO_CACHE=1 ./some-program &
|
||||
sleep 10 ; echo "+0 x10" > /tmp/my-faketime.rc
|
||||
|
||||
Changing the speed of the wall clock time, i.e., using a different 'x' modifier
|
||||
during run-time, by default can lead to greater jumps that may confuse the
|
||||
program. For example, if the program has been running for 10 seconds on 'x1',
|
||||
and then the setting is changed to 'x10', the faked time will look to the
|
||||
program as if it has been running for more than 100 instead of just more than
|
||||
10 seconds.
|
||||
|
||||
By setting the environment variable FAKETIME_XRESET to any value, transitions
|
||||
between different 'x' modifier values will be significantly smoothed:
|
||||
|
||||
LD_PRELOAD=libfaketime.so.1 FAKETIME_TIMESTAMP_FILE="/tmp/my-faketime.rc" \
|
||||
FAKETIME_NO_CACHE=1 FAKETIME_XRESET=1 ./some-program &
|
||||
|
||||
Setting FAKETIME_XRESET ensures that wall clock time begins to run faster
|
||||
only after the 'x' modifier has been changed (when increasing it) and also
|
||||
ensures that the reported faked time does not jump back to past values
|
||||
(when decreasing it).
|
||||
|
||||
Please note that FAKETIME_XRESET internally works by resetting libfaketime's
|
||||
internal time-keeping data structures, which may have side effects on reported
|
||||
file timestamps. Using FAKETIME_XRESET should be considered experimental at
|
||||
the moment.
|
||||
|
||||
|
||||
Cleaning up shared memory
|
||||
-------------------------
|
||||
|
||||
libfaketime uses semaphores and shared memory on platforms that support it in
|
||||
order to sync faketime settings across parent-child processes.
|
||||
|
||||
Please note that this does not share the time set by settimeofday (for that
|
||||
see FAKETIME_UPDATE_TIMESTAMP_FILE below).
|
||||
|
||||
libfaketime will clean up when it exits properly.
|
||||
However, when processes are terminated (e.g., by Ctrl-C on command line),
|
||||
shared memory cannot be cleaned up properly. In such
|
||||
cases, you should occasionally delete
|
||||
|
||||
/dev/shm/faketime_shm_* and
|
||||
/dev/shm/sem.faketime_sem_*
|
||||
|
||||
manually (or properly automated). Leftover files there from processes that
|
||||
already have been terminated are not a problem in general, but result in a
|
||||
libfaketime error the next time a process is started with a process id for
|
||||
which such a stale semaphore/shared memory exists. Thus, if you run across
|
||||
the following error message
|
||||
|
||||
libfaketime: In ft_shm_create(), shm_open failed: File exists
|
||||
|
||||
please cleanup /dev/shm as described above. This is especially relevant
|
||||
for long-running systems (servers with high uptime) and systems on which
|
||||
a lot of processes are started (e.g., servers handling many containers
|
||||
or similar virtualization mechanisms).
|
||||
|
||||
|
||||
Intercepting time-setting calls
|
||||
-------------------------------
|
||||
|
||||
libfaketime can be compiled with the CFLAG "-DFAKE_SETTIME" in order
|
||||
to also intercept time-setting functions, i.e., clock_settime(),
|
||||
settimeofday(), and adjtime(). The FAKETIME environment
|
||||
variable will be adjusted on each call.
|
||||
|
||||
When the environment variable FAKETIME_TIMESTAMP_FILE is set, points to a
|
||||
writeable (creatable) custom config file and the environment variable
|
||||
FAKETIME_UPDATE_TIMESTAMP_FILE is "1", then the file also is updated on each
|
||||
call. By this, a common "virtual time" can be shared by several
|
||||
processes, where each can adjust the time for all.
|
||||
|
||||
|
||||
Sharing "virtual settable time" between independent processes
|
||||
-------------------------------------------------------------
|
||||
|
||||
When libfaketime was compiled with FAKETIME_COMPILE_CFLAGS="-DFAKE_SETTIME",
|
||||
it can be configured to support a common time offset for multiple processes.
|
||||
This for example allows to use "ntpdate" as normal user without affecting
|
||||
system clock, interactively testing software with different dates or testing
|
||||
complex software with multiple independent processes that themself use
|
||||
settime internally.
|
||||
|
||||
Examples:
|
||||
|
||||
$ export LD_PRELOAD=libfaketime.so.1
|
||||
$ export FAKETIME_TIMESTAMP_FILE="/tmp/my-faketime.rc"
|
||||
$ export FAKETIME_UPDATE_TIMESTAMP_FILE=1
|
||||
$ export FAKETIME_CACHE_DURATION=1 # in seconds
|
||||
# or: export FAKETIME_NO_CACHE=1
|
||||
|
||||
$ date -s "1999-12-24 16:00:00"
|
||||
Fri Dec 24 16:00:00 CET 1999
|
||||
$ LD_PRELOAD="" date
|
||||
Thu Apr 9 15:19:38 CEST 2020
|
||||
$ date
|
||||
Fri Dec 24 16:00:02 CET 1999
|
||||
$ /usr/sbin/ntpdate -u clock.isc.org
|
||||
9 Apr 15:18:37 ntpdate[718]: step time server xx offset 640390517.057257 sec
|
||||
$ date
|
||||
Thu Apr 9 15:18:40 CEST 2020
|
||||
|
||||
In another terminal, script or environmment the same variables could be set
|
||||
and the same time would be printed.
|
||||
This also avoid the need to directly update the rc config file to use
|
||||
different times, but of course only supports time offsets.
|
||||
|
||||
Please note that this feature is not compatible with several other features,
|
||||
such as FAKETIME_FOLLOW_FILE, FAKETIME_XRESET and maybe others. After first
|
||||
settime, offsets will be used in FAKETIME_TIMESTAMP_FILE, even if it
|
||||
initially used advanced time specification options.
|
||||
|
||||
|
||||
4f) Faking the date and time system-wide
|
||||
@@ -357,7 +556,7 @@ faketime 'last Friday 5 pm' /your/command/here
|
||||
|
||||
Of course, also absolute dates can be used, such as in
|
||||
|
||||
faketime '2008-12-24 08:15:42' /bin/date
|
||||
faketime '2018-12-24 08:15:42' /bin/date
|
||||
|
||||
Thanks to Daniel Kahn Gillmor for providing these suggestions!
|
||||
|
||||
@@ -365,8 +564,8 @@ Balint Reczey has rewritten the wrapper in 0.9.5 from a simple shell script
|
||||
to an efficient wrapper application.
|
||||
|
||||
|
||||
4h) "Limiting" libfaketime
|
||||
--------------------------
|
||||
4h) "Limiting" libfaketime based on elapsed time or number of calls
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Starting with version 0.9, libfaketime can be configured to not be continuously
|
||||
active, but only during a certain time interval.
|
||||
@@ -380,12 +579,12 @@ Dynamic changes to the faked time are alternatively possible by
|
||||
- changing the FAKETIME environment variable at run-time; this is the preferred
|
||||
way if you use libfaketime for debugging and testing as a programmer, as it
|
||||
gives you the most direct control of libfaketime without any performance
|
||||
penalities.
|
||||
penalties.
|
||||
|
||||
- not using the FAKETIME environment variable, but specifying the fake time in a
|
||||
file (such as ~/.faketimerc). You can change the content of this file at
|
||||
run-time. This works best with caching disabled (see Makefile), but comes at a
|
||||
performance cost because this file has to be read and evaluated each time.
|
||||
- not using the FAKETIME environment variable, but specifying the fake time in
|
||||
a file (such as ~/.faketimerc). You can change the content of this file at
|
||||
run-time. This works best with caching disabled, but comes at a performance
|
||||
cost because this file has to be read and evaluated each time.
|
||||
|
||||
The feature described here works based on two pairs of environment variables,
|
||||
|
||||
@@ -430,12 +629,40 @@ functionality unless you are sure you really need it and know what you are
|
||||
doing.
|
||||
|
||||
|
||||
4i) Spawning an external process
|
||||
4i) "Limiting" libfaketime per process
|
||||
--------------------------------------
|
||||
|
||||
faketime can be instructed to fake time related calls only for selected
|
||||
commands or to fake time for each command except for a certain subset of
|
||||
commands.
|
||||
|
||||
The environment variables are FAKETIME_ONLY_CMDS and FAKETIME_SKIP_CMDS
|
||||
respectively.
|
||||
|
||||
Example:
|
||||
FAKETIME_ONLY_CMDS=javadoc faketime '2008-12-24 08:15:42' make
|
||||
will run the "make" command but the time faking will only be applied
|
||||
to javadoc processes.
|
||||
|
||||
Multiple commands are separated by commas.
|
||||
|
||||
Example:
|
||||
FAKETIME_SKIP_CMDS="javadoc,ctags" faketime '2008-12-24 08:15:42' make
|
||||
will run the "make" command and apply time faking for everything "make"
|
||||
does except for javadoc and ctags processes.
|
||||
|
||||
FAKETIME_ONLY_CMDS and FAKETIME_SKIP_CMDS are mutually exclusive, i.e.,
|
||||
you cannot set them both at the same time. faketime will terminate with
|
||||
an error message if both environment variables are set.
|
||||
|
||||
|
||||
4j) Spawning an external process
|
||||
--------------------------------
|
||||
|
||||
From version 0.9 on, libfaketime can execute a shell command once after an
|
||||
arbitrary number of seconds or number of time-related system calls of the
|
||||
program started. This has two limitations one needs to be aware of:
|
||||
From version 0.9 on, libfaketime can execute a shell command once after a) an
|
||||
arbitrary number of seconds has passed or b) a number of time-related system
|
||||
calls has been made by the program since it started. This has two limitations
|
||||
one needs to be aware of:
|
||||
|
||||
* Spawning the external process happens during a time-related system call
|
||||
of the original program. If you want the external process to be started
|
||||
@@ -463,10 +690,15 @@ time-related system function call that "myprogram" performs after running for 5
|
||||
seconds.
|
||||
|
||||
|
||||
4j) Saving timestamps to file, loading them from file
|
||||
4k) Saving timestamps to file, loading them from file
|
||||
-----------------------------------------------------
|
||||
|
||||
Faketime can save faked timestamps to a file specified by FAKETIME_SAVE_FILE
|
||||
To store and load timestamp _offsets_ using _one and the same_ file allowing
|
||||
to share a common "virtual time" between independent processes, please see
|
||||
FAKETIME_UPDATE_TIMESTAMP_FILE above. The FAKETIME_SAVE_FILE feature is
|
||||
different.
|
||||
|
||||
faketime can save faked timestamps to a file specified by FAKETIME_SAVE_FILE
|
||||
environment variable. It can also use the file specified by FAKETIME_LOAD_FILE
|
||||
to replay timestamps from it. After consuming the whole file, libfaketime
|
||||
returns to using the rule set in FAKETIME variable, but the timestamp processes
|
||||
@@ -481,15 +713,50 @@ struct saved_timestamp {
|
||||
uint64_t nsec;
|
||||
};
|
||||
|
||||
Faketime needs to be run using the faketime wrapper to use these files. This
|
||||
faketime needs to be run using the faketime wrapper to use these files. This
|
||||
functionality has been added by Balint Reczey in v0.9.5.
|
||||
|
||||
|
||||
4l) Replacing random numbers with deterministic number sequences
|
||||
----------------------------------------------------------------
|
||||
|
||||
libfaketime can be compiled with the CFLAG FAKE_RANDOM set (see src/Makefile).
|
||||
|
||||
When compiled this way, libfaketime additionally intercepts calls to the
|
||||
function getrandom(), which currently is Linux-specific.
|
||||
|
||||
This functionality is intended to feed a sequence of deterministic, repeatable
|
||||
numbers to applications, which use getrandom(), instead of the random numbers
|
||||
provided by /dev/[u]random.
|
||||
|
||||
For creating the deterministic number sequence, libfaketime internally
|
||||
uses Bernard Widynski's Middle Square Weyl Sequence Random Number Generator,
|
||||
see https://mswsrng.wixsite.com/rand.
|
||||
|
||||
It requires a 64-bit seed value, which has to be passed via the environment
|
||||
variable FAKERANDOM_SEED, as in, for example
|
||||
|
||||
LD_PRELOAD=src/libfaketime.so.1 \
|
||||
FAKERANDOM_SEED="0x12345678DEADBEEF" \
|
||||
test/getrandom_test
|
||||
|
||||
Whenever the same seed value is used, the same sequence of "random-looking"
|
||||
numbers is generated.
|
||||
|
||||
Please be aware that this definitely breaks any security properties that
|
||||
may be attributed to random numbers delivered by getrandom(), e.g., in the
|
||||
context of cryptographic operations. Use it for deterministic testing
|
||||
purposes only. Never use it in production.
|
||||
|
||||
For a discussion on why this apparently not date-/time-related function
|
||||
has been added to libfaketime and how it may evolve, see Github issue #275.
|
||||
|
||||
|
||||
5. License
|
||||
----------
|
||||
|
||||
libfaketime has been released under the GNU Public License, GPL. Please see the
|
||||
included COPYING file.
|
||||
libfaketime has been released under the GNU General Public License, GPL.
|
||||
Please see the included COPYING file.
|
||||
|
||||
|
||||
6. Contact
|
||||
@@ -499,4 +766,3 @@ Bug reports, feature suggestions, success reports, and patches/pull
|
||||
requests are highly appreciated:
|
||||
|
||||
https://github.com/wolfcw/libfaketime
|
||||
|
||||
|
||||
96
README.OSX
96
README.OSX
@@ -1,37 +1,56 @@
|
||||
README file for libfaketime on Mac OS X
|
||||
=======================================
|
||||
README file for libfaketime on macOS
|
||||
====================================
|
||||
|
||||
Support for Mac OS X is still considered preliminary, although many
|
||||
command line and GUI applications will run stable.
|
||||
|
||||
Developments and tests are done on OSX 10.8+ currently, although the
|
||||
current version will also work with OSX 10.7.
|
||||
|
||||
Version 0.9.5 no longer works with OSX <= 10.6 due to changes in the
|
||||
underlying system libraries. If you need libfaketime on OSX <= 10.6,
|
||||
please use libfaketime version 0.9.
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
! If you compiled libfaketime successfully but even the simple examples !
|
||||
! with the "date" command do not seem to work, please see the notes about !
|
||||
! SIP (system integrity protection) in this document! !
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
|
||||
Installing and using libfaketime on OS X is slightly different than
|
||||
Support for macOS has meanwhile matured and many command line and
|
||||
GUI applications will run stable.
|
||||
|
||||
Developments and tests are done on Catalina currently.
|
||||
|
||||
Version 0.9.5 and higher no longer work with OSX <= 10.6 due to
|
||||
changes in the underlying system libraries. If you need libfaketime
|
||||
on OSX <= 10.6, please use libfaketime version 0.9.
|
||||
|
||||
Installing and using libfaketime on macOS is slightly different than
|
||||
on Linux. Please make sure to read the README file for general
|
||||
setup and usage, and refer to this file only about OS X specifics.
|
||||
setup and usage, and refer to this file only about macOS specifics.
|
||||
|
||||
|
||||
1) Installing libfaketime on OS X
|
||||
---------------------------------
|
||||
1) Installing libfaketime on macOS
|
||||
----------------------------------
|
||||
|
||||
If you use MacPorts, libfaketime can be installed on the command line
|
||||
as follows:
|
||||
|
||||
sudo port install libfaketime
|
||||
|
||||
Otherwise, you have to compile and install libfaketime manually; this
|
||||
Or, if you use Fink, install using:
|
||||
|
||||
fink install libfaketime
|
||||
|
||||
Or, if you use Homebrew, install using:
|
||||
|
||||
brew install libfaketime
|
||||
|
||||
Please inform the respective package maintainers if the latest release
|
||||
is not yet available this way. With homebrew, you can typically use
|
||||
"brew install --HEAD" to install from the latest source automatically.
|
||||
|
||||
Otherwise, you have to compile and install libfaketime manually; this
|
||||
will require a working installation of Xcode and its command line tools
|
||||
on your machine.
|
||||
|
||||
Use the OSX-specific Makefile that is provided:
|
||||
You can compile libfaketime by running the command
|
||||
|
||||
make -f Makefile.OSX
|
||||
make
|
||||
|
||||
in libfaketime's top-level directory.
|
||||
|
||||
The resulting library will be named libfaketime.1.dylib ; to check
|
||||
whether it works properly, run the test suite and verify whether its
|
||||
@@ -41,11 +60,11 @@ output is correct:
|
||||
make -f Makefile.OSX
|
||||
|
||||
|
||||
2) Using libfaketime from the command line on OS X
|
||||
--------------------------------------------------
|
||||
2) Using libfaketime from the command line on macOS
|
||||
---------------------------------------------------
|
||||
|
||||
You will need to set three environment variables. In a Terminal.app
|
||||
or iTerm2 session, the following commands can be used:
|
||||
or any other CLI session, the following commands can be used:
|
||||
|
||||
export DYLD_FORCE_FLAT_NAMESPACE=1
|
||||
export DYLD_INSERT_LIBRARIES=/path/to/libfaketime.1.dylib
|
||||
@@ -55,7 +74,7 @@ Please refer to the general README file concerning the format
|
||||
of the FAKETIME environment variable value and other environment
|
||||
variables that are related to it.
|
||||
|
||||
The "faketime" wrapper application has been adapted to OS X;
|
||||
The "faketime" wrapper application has been adapted to macOS;
|
||||
it offers the same limited libfaketime functionality as on Linux
|
||||
in a simple-to-use manner without the need to manually set
|
||||
those environment variables. Run "faketime" without parameters
|
||||
@@ -66,7 +85,7 @@ for help and use "man faketime" for details.
|
||||
--------------------------------------------
|
||||
|
||||
Given the limited number of system calls libfaketime intercepts,
|
||||
it may not work too well with specific GUI applications on OS X.
|
||||
it may not work too well with specific GUI applications on macOS.
|
||||
This can result in crashes after a seemingly random time, or an
|
||||
application will not or at least not always see the faked time,
|
||||
and so on.
|
||||
@@ -113,14 +132,37 @@ such updates, including own new builds when using Xcode.
|
||||
|
||||
Please feel free to report non-working applications on the Github
|
||||
libfaketime issues website. This may help us to identify further
|
||||
time-related system calls that need to be intercepted on OS X.
|
||||
time-related system calls that need to be intercepted on macOS.
|
||||
|
||||
https://github.com/wolfcw/libfaketime/issues
|
||||
|
||||
However, there are two important aspects:
|
||||
|
||||
4) Notes for developers of OS X applications
|
||||
--------------------------------------------
|
||||
- When reporting non-working applications, please make sure that your issue is
|
||||
not related to SIP (system integrity protection). For example, on a
|
||||
SIP-enabled, default macOS installation, libfaketime will not work for
|
||||
programs like /bin/bash because the path /bin is SIP-protected. Copy your
|
||||
application to a non-SIP-protected path, and if libfaketime still does not
|
||||
work, feel free to report it.
|
||||
|
||||
Please note that this also applies to simple programs such as /bin/date,
|
||||
which is used as an example in the libfaketime documentation and help texts.
|
||||
|
||||
Again, either disable SIP on your system (which might not be the best idea),
|
||||
or copy the applications / programs you want to use with libfaketime to
|
||||
a different path, which is not SIP-protected, e.g., within your home directory.
|
||||
|
||||
- We cannot and will not help with using libfaketime for proprietary or
|
||||
commercial software unless you are its developer trying to integrate
|
||||
libfaketime. Please contact the developers or the vendor directly if
|
||||
you have problems using libfaketime with non-free / not open sourced
|
||||
macOS applications.
|
||||
|
||||
|
||||
4) Notes for developers of macOS applications
|
||||
---------------------------------------------
|
||||
|
||||
The environment variable FAKETIME can be changed at application run-time
|
||||
and always takes precedence over other user-controlled settings. It can
|
||||
be re-set to 0 (zero) to work around potential incompatibilities.
|
||||
be re-set to 0 (zero) to work around potential incompatibilities or if
|
||||
you do not want libfaketime applied to your software.
|
||||
|
||||
@@ -4,19 +4,26 @@ This file contains information for libfaketime developers and contributors.
|
||||
GENERAL
|
||||
=======
|
||||
|
||||
Starting with libfaketime v0.9.5, development and issue handling is
|
||||
completely done via Github:
|
||||
Starting with libfaketime v0.9.5, development and issue handling is
|
||||
completely done via Github:
|
||||
|
||||
https://github.com/wolfcw/libfaketime
|
||||
|
||||
- Official releases are tagged.
|
||||
- Code contributions and bugfixes are merged into the "development" branch,
|
||||
which is considered unstable and may contain code that is not yet fully
|
||||
tested.
|
||||
- The "master" branch is updated with tested code only; it is ensured that
|
||||
it compiles and works cleanly at least on current Linux and OS X systems.
|
||||
- Official releases are tagged.
|
||||
|
||||
Code contributions are highly welcome, preferrably via pull requests on Github.
|
||||
- Code contributions and bugfixes should be submitted to and then merged into
|
||||
the "development" branch, which is considered unstable and may contain code
|
||||
that is not yet fully tested.
|
||||
|
||||
- The "master" branch is updated with tested code only; it is ensured that
|
||||
it compiles and works cleanly at least on current Linux and macOS systems.
|
||||
|
||||
Code contributions are highly welcome, preferably via pull requests on Github.
|
||||
|
||||
Please have a look at issues labelled as "help wanted" in the Github issue
|
||||
tracker. If you are interested in contributing to libfaketime, helping with
|
||||
these issues is not only much appreciated, but also a good way to familiarize
|
||||
yourself with the overall codebase.
|
||||
|
||||
|
||||
CODE STYLE
|
||||
@@ -43,16 +50,16 @@ void do_nothing(int how_often)
|
||||
}
|
||||
}
|
||||
|
||||
- Use -DDEBUG and #ifdef DEBUG for development and testing. Avoid printing
|
||||
to stdout or stderr outside "#ifdef DEBUG"; if it is necessary to inform
|
||||
the user a run-time, prefix your output with "faketime" or make otherwise
|
||||
sure that the user knows where the message is coming from.
|
||||
- Use -DDEBUG and #ifdef DEBUG for development and testing. Avoid printing to
|
||||
stdout or stderr outside "#ifdef DEBUG"; if it is necessary to inform the
|
||||
user a run-time, prefix your output with "libfaketime" or make otherwise sure
|
||||
that the user knows where the message is coming from.
|
||||
|
||||
- If you add new functions to libfaketime.c, try placing them somewhere
|
||||
where they fit will: Usually, functions are grouped by functionality
|
||||
(e.g., all functions related to faking file timestamps). If that's not
|
||||
possible, group them by contributor, or document your placement strategy
|
||||
in the commit message.
|
||||
in the commit message.
|
||||
|
||||
|
||||
DEVELOPMENT, BUILDING, AND TESTING
|
||||
@@ -62,19 +69,19 @@ DEVELOPMENT, BUILDING, AND TESTING
|
||||
the modification fixes bugs :-)).
|
||||
|
||||
- Add tests for new features. Extend test/timetest.c appropriately and
|
||||
try to use the functional testing framework wherever possible.
|
||||
try to use the functional testing framework wherever possible.
|
||||
|
||||
- Compiler and linker warnings are treated as errors and not acceptable.
|
||||
|
||||
- If you cannot test the code on both Linux and OS X yourself, please
|
||||
let us know and consider wrapping your code in #ifdef / #ifndef __APPLE__
|
||||
statements.
|
||||
- If you cannot test the code on both Linux and macOS yourself, please
|
||||
let us know and consider wrapping your code in #ifdef / #ifndef __APPLE__
|
||||
statements.
|
||||
|
||||
|
||||
DOCUMENTATION
|
||||
=============
|
||||
|
||||
For anything more than small bugfixes, please update the user documentation
|
||||
For anything more than small bugfixes, please update the user documentation
|
||||
and credits appropriately:
|
||||
|
||||
- The NEWS file should mention the change and your credits.
|
||||
@@ -83,8 +90,8 @@ and credits appropriately:
|
||||
- The manpage man/faketime.1 should be updated when the wrapper application
|
||||
is modified.
|
||||
|
||||
For credits, please either mention your real name, your Github username, or
|
||||
your email address.
|
||||
For credits, please either mention your real name, your Github username, or
|
||||
your email address.
|
||||
|
||||
In your own interest, please be verbose on user documentation and comments
|
||||
in the source code. Users will not know about new features unless they are
|
||||
@@ -97,7 +104,7 @@ RELEASES
|
||||
|
||||
Official new releases are created whenever a significant amount of changes
|
||||
(bugfixes or new functionality) has piled up; on average, there is one new
|
||||
official release per year. Users who need to stick to the bleeding edge
|
||||
official release per 1-2 years. Users who need to stick to the bleeding edge
|
||||
are supposed to use the current state of the "master" branch at any time.
|
||||
|
||||
libfaketime maintainers for several Linux distributions are informed about
|
||||
|
||||
67
README.packagers
Normal file
67
README.packagers
Normal file
@@ -0,0 +1,67 @@
|
||||
README for packagers of libfaketime
|
||||
|
||||
First, thank you for your efforts to make libfaketime packages available
|
||||
on your platform / distribution!
|
||||
|
||||
libfaketime has tagged releases about once every 1-2 years, made available
|
||||
through github.com/wolfcw/libfaketime, but usually it is also safe (i.e.,
|
||||
stable) to use the latest HEAD of the master branch, which contains bug
|
||||
fixes since the last tagged release.
|
||||
|
||||
You may want to familiarize yourself with the options you can set into
|
||||
src/Makefile, but sane defaults for stable operations have been chosen.
|
||||
|
||||
Currently, libfaketime does not use autotools yet, so there is
|
||||
_no_ ./configure step, but "make" and "make test" will work as expected.
|
||||
|
||||
For "make test", an optional environment variable FAKETIME_TESTLIB can
|
||||
be set, pointing to the path and filename of the libfaketime library
|
||||
to be used for tests; the default is "../src/libfaketime.so.1".
|
||||
|
||||
|
||||
However, one problem makes it somewhat difficult to get libfaketime
|
||||
working on different platforms:
|
||||
|
||||
libfaketime currently has the challenge that depending on the version
|
||||
of glibc and the platform (e.g., x86_64 or aarch64) certain compiler
|
||||
CFLAGS have to be set manually, as we have not yet found a way to
|
||||
safely determine behavior at run-time automatically.
|
||||
|
||||
Please proceed as follows:
|
||||
|
||||
- run "make test". If everything runs through smoothly and you do not
|
||||
encounter any hangs or test failure reports, use the binaries as
|
||||
they are.
|
||||
|
||||
- If you encounter endless hangs during the CLOCK_REALTIME test,
|
||||
add -DFORCE_PTHREAD_NONVER to the CFLAGS.
|
||||
|
||||
- If you encounter endless hangs during the CLOCK_MONOTONIC test,
|
||||
add -DFORCE_MONOTONIC_FIX to the CFLAGS. If it works with that,
|
||||
it's fine, otherwise additionally use -DFORCE_PTHREAD_NONVER.
|
||||
|
||||
CFLAGS can also be passed through the FAKETIME_COMPILE_CFLAGS environment
|
||||
variable, so for example
|
||||
|
||||
FAKETIME_COMPILE_CFLAGS="-DFORCE_PTHREAD_NONVER" make test
|
||||
|
||||
would create the libfaketime binaries and run the tests with the
|
||||
FORCE_PTHREAD_NONVER flag set in a single step. Likewise there is
|
||||
FAKETIME_LINK_FLAGS.
|
||||
|
||||
Please do not use FORCE_MONOTONIC_FIX by default, as it would result
|
||||
in incorrect operations on platforms that do not need it.
|
||||
|
||||
Our observations with a limited number of Linux distributions is that
|
||||
libfaketime may require different compile flags per platform even
|
||||
if the same distribution and glibc version is used across these
|
||||
platforms.
|
||||
|
||||
As soon as we have found a reliable way to automatically choose the
|
||||
correct compile-time flags, we will remove this burden from you as
|
||||
packager for obvious reasons. Until then, please feel free to report
|
||||
your experiences with different platforms and distribution versions
|
||||
through the issue tracker on Github.
|
||||
|
||||
Again, thanks for your time and effort to make libfaketime available
|
||||
easily for everyone else!
|
||||
22
TODO
22
TODO
@@ -1,11 +1,15 @@
|
||||
Open issues / next steps for libfaketime development
|
||||
Open issues / next steps for libfaketime development:
|
||||
|
||||
Please see the issue tracker on Github - https://github.com/wolfcw/libfaketime
|
||||
|
||||
- New features, such as additional system calls to intercept, are labelled
|
||||
"feature request" when they are considered for implementation
|
||||
|
||||
- Issues labelled "help wanted" should be your starting point if you are
|
||||
interested in contributing to libfaketime
|
||||
|
||||
Besides the open issues, two major changes are planned for the next release:
|
||||
|
||||
- integrate manchicken's autoconf/automake support to get rid of separate Makefile.OSX
|
||||
|
||||
- add more functional tests that check more than the basic functionality
|
||||
- use the testing framework to also implement unit tests
|
||||
- make the new "limiting" and "spawning" features more flexible to use
|
||||
and available through the wrapper shell script
|
||||
- fake timer_create and friends
|
||||
- handle CLOCK_REALTIME_COARSE and CLOCK_MONOTONIC_COARSE
|
||||
- work around thread local storage issue, e.g., by using pthreads
|
||||
- add autoconf/automake support to get rid of separate Makefile.OSX
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ all:
|
||||
|
||||
install:
|
||||
$(INSTALL) -Dm0644 faketime.1 "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
|
||||
gzip -f "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
|
||||
gzip -nf "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
|
||||
|
||||
uninstall:
|
||||
rm -f "${DESTDIR}${PREFIX}/share/man/man1/faketime.1.gz"
|
||||
|
||||
@@ -5,7 +5,7 @@ PREFIX ?= /usr/local
|
||||
all:
|
||||
|
||||
install:
|
||||
$(INSTALL) -dm0644 "${DESTDIR}${PREFIX}/share/man/man1"
|
||||
$(INSTALL) -dm0755 "${DESTDIR}${PREFIX}/share/man/man1"
|
||||
$(INSTALL) -m0644 faketime.1 "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
|
||||
gzip -f "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH FAKETIME "1" "October 2013" "faketime 0.9.5" wolfcw
|
||||
.TH FAKETIME "1" "February 2022" "faketime 0.9.10" wolfcw
|
||||
.SH NAME
|
||||
faketime \- manipulate the system time for a given command
|
||||
.SH SYNOPSIS
|
||||
@@ -7,11 +7,11 @@ faketime \- manipulate the system time for a given command
|
||||
.SH DESCRIPTION
|
||||
.\" \fIfaketime\fR will trick the given program into seeing the specified timestamp as its starting date and time.
|
||||
.PP
|
||||
The given command will be tricked into believing that the current system time is the one specified in the timestamp. The wall clock will continue to run
|
||||
from this date and time unless specified otherwise (see advanced options). Actually, faketime is a simple wrapper for libfaketime, which uses the LD_PRELOAD
|
||||
mechanism to load a small library which intercepts system calls to functions such as
|
||||
\fItime(2)\fR and \fIfstat(2)\fR. This wrapper exposes only a subset of libfaketime's functionality; please refer to the README file that came with faketime
|
||||
for more details and advanced options, or have a look at http://github.com/wolfcw/libfaketime
|
||||
The given command will be tricked into believing that the current system time is the one specified in the timestamp.
|
||||
Filesystem timestamps will also be reported relative to this timestamp.
|
||||
The wall clock will continue to run from this date and time unless specified otherwise (see advanced options).
|
||||
Actually, faketime is a simple wrapper for libfaketime, which uses the LD_PRELOAD mechanism to load a small library which intercepts system calls to functions such as \fItime(2)\fR and \fIfstat(2)\fR.
|
||||
This wrapper exposes only a subset of libfaketime's functionality; please refer to the README file that came with faketime for more details and advanced options, or have a look at https://github.com/wolfcw/libfaketime
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-\-help\fR
|
||||
@@ -23,8 +23,17 @@ show version information and quit.
|
||||
\fB\-m\fR
|
||||
use the multi-threading variant of libfaketime.
|
||||
.TP
|
||||
\fB\-p <PID>\fR
|
||||
pretend that the program's process ID is PID. (only available if built with FAKE_PID)
|
||||
.TP
|
||||
\fB\-f\fR
|
||||
use the advanced timestamp specification format.
|
||||
.TP
|
||||
\fB\--exclude-monotonic\fR
|
||||
Do not fake time when the program makes a call to clock_gettime with a CLOCK_MONOTONIC clock.
|
||||
.TP
|
||||
\fB\--date-prog <PATH>\fR
|
||||
Use a specific GNU-date compatible implementation of the helper used to transform "timestamp format" strings into programmatically usable dates, instead of a compile-time default guess for the generic target platform.
|
||||
|
||||
.SH EXAMPLES
|
||||
.nf
|
||||
@@ -33,44 +42,58 @@ faketime '2008-12-24 08:15:42' /bin/date
|
||||
faketime -f '+2,5y x10,0' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'
|
||||
faketime -f '+2,5y x0,50' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'
|
||||
faketime -f '+2,5y i2,0' /bin/bash -c 'while true; do date ; sleep 1 ; done'
|
||||
In this single case all spawned processes will use the same global clock without restaring it at the start of each process.
|
||||
In this single case all spawned processes will use the same global clock without restarting it at the start of each process.
|
||||
|
||||
(Please note that it depends on your locale settings whether . or , has to be used for fractional offsets)
|
||||
.fi
|
||||
.SH ADVANCED TIMESTAMP FORMAT
|
||||
The simple timestamp format used by default applies the \fB/bin/date -d\fR command to parse user-friendly specifications such as 'last friday'. When using
|
||||
the faketime option \fB\-f\fR, the timestamp specified on the command line is directly passed to libfaketime, which enables a couple of additional features
|
||||
such as speeding the clock up or slowing it down for the target program. It is strongly recommended that you have a look at the libfaketime documentation. Summary:
|
||||
The simple timestamp format used by default applies the \fB/bin/date -d\fR command to parse user-friendly specifications such as 'last friday'.
|
||||
When using the faketime option \fB\-f\fR, the timestamp specified on the command line is directly passed to libfaketime, which enables a couple of additional features such as speeding the clock up or slowing it down for the target program.
|
||||
It is strongly recommended that you have a look at the libfaketime documentation.
|
||||
Summary:
|
||||
.TP
|
||||
Freeze clock at absolute timestamp: \fB"YYYY-MM-DD hh:mm:ss"\fR
|
||||
If you want to specify an absolute point in time, exactly this format must be used. Please note that freezing the clock is usually not what you want and may break the application. Only use if you know what you're doing!
|
||||
If you want to specify an absolute point in time, exactly this format must be used.
|
||||
Please note that freezing the clock is usually not what you want and may break the application.
|
||||
Only use if you know what you're doing!
|
||||
.TP
|
||||
Relative time offset: \fB"[+/-]123[m/h/d/y]\fR, e.g. "+60m", "+2y"
|
||||
This is the most often used format and specifies the faked time relatively to the current real time. The first character of the format string \fBmust\fR be a + or a -. The numeric value by default represents seconds, but the modifiers m, h, d, and y can be used to specify minutes, hours, days, or years, respectively. For example, "-2y" means "two years ago". Fractional time offsets can be used, e.g. "+2,5y", which means "two and a half years in the future". Please note that the fraction delimiter depends on your locale settings, so if "+2,5y" does not work, you might want to try "+2.5y".
|
||||
Relative time offset: \fB"[+/-]123[m/h/d/y]"\fR, e.g., "+60m", "+2y"
|
||||
This is the most often used format and specifies the faked time relatively to the current real time.
|
||||
The first character of the format string \fBmust\fR be a + or a -.
|
||||
The numeric value by default represents seconds, but the modifiers m, h, d, and y can be used to specify minutes, hours, days, or years, respectively.
|
||||
For example, "-2y" means "two years ago". Fractional time offsets can be used, e.g., "+2,5y", which means "two and a half years in the future".
|
||||
Please note that the fraction delimiter depends on your locale settings, so if "+2,5y" does not work, you might want to try "+2.5y".
|
||||
.TP
|
||||
Start-at timestamps: \fB"@YYYY-MM-DD hh:mm:ss"\fR
|
||||
The wall clock will start counting at the given timestamp for the program. This can be used for specifying absolute timestamps without freezing the clock.
|
||||
The wall clock will start counting at the given timestamp for the program.
|
||||
This can be used for specifying absolute timestamps without freezing the clock.
|
||||
.SH ADVANCED USAGE
|
||||
When using relative time offsets or start-at timestamps (see ADVANCED TIMESTAMP FORMAT above and option \fB\-f\fR), the clock speed can be adjusted, i.e. time may run faster or slower for the executed program. For example, \fB"+5y x10"\fR will set the faked time 5 years into the future and make the time pass 10 times as fast (one real second equals 10 seconds measured by the program). Similarly, the flow of time can be slowed, e.g. using \fB"-7d x0,2"\fR, which will set the faked time 7 days in the past and set the clock speed to 20 percent, i.e. it takes five real world seconds for one second measured by the program. Again, depending on your locale, either "x2.0" or "x2,0" may be required regarding the delimiter. You can also make faketime to advance the reported time by a preset interval upon each time() call independently from the system's time using \fB"-7d i2,0"\fR, where
|
||||
\fB"i"\fR is followed by the increase interval in seconds.
|
||||
When using relative time offsets or start-at timestamps (see ADVANCED TIMESTAMP FORMAT above and option \fB\-f\fR), the clock speed can be adjusted, i.e., time may run faster or slower for the executed program.
|
||||
For example, \fB"+5y x10"\fR will set the faked time 5 years into the future and make the time pass 10 times as fast (one real second equals 10 seconds measured by the program).
|
||||
Similarly, the flow of time can be slowed, e.g., using \fB"-7d x0,2"\fR, which will set the faked time 7 days in the past and set the clock speed to 20 percent, i.e., it takes five real world seconds for one second measured by the program.
|
||||
Again, depending on your locale, either "x2.0" or "x2,0" may be required regarding the delimiter.
|
||||
You can also make faketime to advance the reported time by a preset interval upon each time() call independently from the system's time using \fB"-7d i2,0"\fR, where \fB"i"\fR is followed by the increase interval in seconds.
|
||||
.PP
|
||||
Faking times for multiple programs or even system-wide can be simplified by using ~/.faketimerc files and /etc/faketimerc. Please refer to the README that came with faketime for warnings and details.
|
||||
Faking times for multiple programs or even system-wide can be simplified by using ~/.faketimerc files and /etc/faketimerc.
|
||||
Please refer to the README that came with faketime for warnings and details.
|
||||
.PP
|
||||
Faking of filesystem timestamps may be disabled by setting the NO_FAKE_STAT environment variable to a non-empty value.
|
||||
.SH AUTHOR
|
||||
Please see the README and NEWS files for contributers.
|
||||
Please see the README and NEWS files for contributors.
|
||||
.SH BUGS
|
||||
Due to limitations of the LD_PRELOAD mechanism, faketime will not work with suidroot and statically linked programs.
|
||||
While timestamps and time offsets will work for child processes, speeding the clock up or slowing it down might not
|
||||
work for child processes spawned by the executed program as expected; a new instance of libfaketime is used for each
|
||||
child process, which means that the libfaketime start time, which is used in speed adjustments, will also be
|
||||
re-initialized. Some programs may dynamically load system libraries, such as librt, at run-time and therefore bypass libfaketime. You may report programs that do not work with libfaketime, but only if they are available as open source.
|
||||
While timestamps and time offsets will work for child processes, speeding the clock up or slowing it down might not work for child processes spawned by the executed program as expected;
|
||||
a new instance of libfaketime is used for each child process, which means that the libfaketime start time, which is used in speed adjustments, will also be re-initialized.
|
||||
Some programs may dynamically load system libraries, such as librt, at run-time and therefore bypass libfaketime.
|
||||
You may report programs that do not work with libfaketime, but only if they are available as open source.
|
||||
.SH "REPORTING BUGS"
|
||||
Please use https://github.com/wolfcw/libfaketime/issues
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2003-2013 by the libfaketime authors.
|
||||
Copyright \(co 2003-2021 by the libfaketime authors.
|
||||
.PP
|
||||
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You may redistribute copies of faketime under the
|
||||
terms of the GNU General Public License.
|
||||
There is NO warranty;
|
||||
not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
You may redistribute copies of faketime under the terms of the GNU General Public License.
|
||||
.br
|
||||
For more information about these matters, see the file named COPYING.
|
||||
.SH "SEE ALSO"
|
||||
|
||||
119
src/Makefile
119
src/Makefile
@@ -1,22 +1,19 @@
|
||||
#
|
||||
# Notes:
|
||||
#
|
||||
# * Compilation Defines:
|
||||
# * Compilation Defines that are set by default:
|
||||
#
|
||||
# FAKE_STAT
|
||||
# - Enables time faking also for files' timestamps.
|
||||
# - Enables time faking when reading files' timestamps.
|
||||
#
|
||||
# NO_ATFILE
|
||||
# - Disables support for the fstatat() group of functions
|
||||
# FAKE_SLEEP
|
||||
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
|
||||
#
|
||||
# PTHREAD
|
||||
# - Define this to enable multithreading support.
|
||||
# FAKE_TIMERS
|
||||
# - Also intercept timer_settime() and timer_gettime()
|
||||
#
|
||||
# PTHREAD_SINGLETHREADED_TIME
|
||||
# - Define this if you want to single-thread time() ... there ARE
|
||||
# possibile caching side-effects in a multithreaded environment
|
||||
# without this, but the performance impact may require you to
|
||||
# try it unsynchronized.
|
||||
# FAKE_PTHREAD
|
||||
# - Intercept pthread_cond_timedwait
|
||||
#
|
||||
# FAKE_INTERNAL_CALLS
|
||||
# - Also intercept libc internal __functions, e.g. not just time(),
|
||||
@@ -24,23 +21,68 @@
|
||||
# that make use of low-level system calls, such as Java Virtual
|
||||
# Machines.
|
||||
#
|
||||
# FAKE_SLEEP
|
||||
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
|
||||
# PTHREAD_SINGLETHREADED_TIME (only set in libfaketimeMT.so)
|
||||
# - Define this if you want to single-thread time() ... there ARE
|
||||
# possible caching side-effects in a multithreaded environment
|
||||
# without this, but the performance impact may require you to
|
||||
# try it unsynchronized.
|
||||
#
|
||||
# FAKE_TIMERS
|
||||
# - Also intercept timer_settime() and timer_gettime()
|
||||
# * Compilation Defines that are unset by default:
|
||||
#
|
||||
# NO_CACHING
|
||||
# - Disables the caching of the fake time offset. Only disable caching
|
||||
# if you change the fake time offset during program runtime very
|
||||
# frequently. Disabling the cache may negatively influence the
|
||||
# performance.
|
||||
# FAKE_FILE_TIMESTAMPS, FAKE_UTIME
|
||||
# - Enables time faking for the utime* functions. If enabled via
|
||||
# FAKE_FILE_TIMESTAMPS, the faking is opt-in at runtime using
|
||||
# with the FAKE_UTIME environment variable. If enabled via
|
||||
# FAKE_UTIME, the faking is opt-out at runtime.
|
||||
#
|
||||
# MULTI_ARCH
|
||||
# - If MULTI_ARCH is set, the faketime wrapper program will put a literal
|
||||
# $LIB into the LD_PRELOAD environment variable it creates, which makes
|
||||
# ld automatically choose the correct library version to use for the
|
||||
# target binary. Use for Linux platforms with Multi-Arch support only!
|
||||
# NO_ATFILE
|
||||
# - Disables support for the fstatat() group of functions
|
||||
#
|
||||
# FAKE_SETTIME
|
||||
# - Intercept clock_settime(), settimeofday(), and adjtime()
|
||||
#
|
||||
# FAKE_RANDOM
|
||||
# - Intercept getrandom()
|
||||
#
|
||||
# FAKE_PID
|
||||
# - Intercept getpid()
|
||||
#
|
||||
# INTERCEPT_SYSCALL
|
||||
# - (On GNU/Linux only) intercept glibc's syscall() for known relevant syscalls.
|
||||
# If enabled, this currently only works to divert the getrandom syscall.
|
||||
#
|
||||
# - note that on unusual architectures, if INTERCEPT_SYSCALL is set, you may
|
||||
# need to explicitly define variadic_promotion_t (e.g. by putting
|
||||
# -Dvariadic_promotion_t=int into CFLAGS). See src/faketime_common.h for
|
||||
# more info.
|
||||
#
|
||||
# FAKE_STATELESS
|
||||
# - Remove support for any functionality that requires sharing state across
|
||||
# threads of a process, or different processes. This decreases the risk of
|
||||
# interference with a program's normal execution, at the cost of supporting
|
||||
# fewer ways of specifying the time.
|
||||
# Concretely, this currently:
|
||||
# - disables PTHREAD_SINGLETHREADED_TIME, which can cause deadlocks in
|
||||
# multithreaded programs that fork due to making clock_gettime not
|
||||
# async-signal-safe
|
||||
# - disables all shared-memory across processes
|
||||
#
|
||||
# FORCE_MONOTONIC_FIX
|
||||
# - If the test program hangs forever on
|
||||
# " pthread_cond_timedwait: CLOCK_MONOTONIC test
|
||||
# (Intentionally sleeping 1 second...) "
|
||||
# then add -DFORCE_MONOTONIC_FIX to CFLAGS and recompile.
|
||||
# (This is a platform-specific issue we cannot handle at run-time.)
|
||||
#
|
||||
# MULTI_ARCH
|
||||
# - If MULTI_ARCH is set, the faketime wrapper program will put a literal
|
||||
# $LIB into the LD_PRELOAD environment variable it creates, which makes
|
||||
# ld automatically choose the correct library version to use for the
|
||||
# target binary. Use for Linux platforms with Multi-Arch support only!
|
||||
#
|
||||
# SILENT
|
||||
# - avoid that the faketime wrapper complains when running within a
|
||||
# libfaketime environment
|
||||
#
|
||||
# * Compilation addition: second libMT target added for building the pthread-
|
||||
# enabled library as a separate library
|
||||
@@ -56,8 +98,8 @@
|
||||
# Change PREFIX to where you want libfaketime (libraries and wrapper binary) installed.
|
||||
# LIBDIRNAME is relative to PREFIX. The default is to install into $PREFIX/lib/faketime,
|
||||
# but you can set LIBDIRNAME to, e.g., /lib64 if you want to install it elsewhere.
|
||||
# LIBDIRNAME has been introduced to support MultiLib systems. Please do not change the
|
||||
# default value on MultiArch systems.
|
||||
# LIBDIRNAME has been introduced to support MultiLib systems. Please do not change the
|
||||
# default value on MultiArch systems.
|
||||
#
|
||||
# For testing in the current directory without installation, try make PREFIX= LIBDIRNAME='.'
|
||||
|
||||
@@ -66,11 +108,22 @@ INSTALL ?= install
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
LIBDIRNAME ?= /lib/faketime
|
||||
PLATFORM ?=$(shell uname)
|
||||
|
||||
CFLAGS += -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -DFAKE_PTHREAD -DFAKE_STAT -DFAKE_UTIME -DFAKE_SLEEP -DFAKE_TIMERS -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"' -DLIBDIRNAME='"'$(LIBDIRNAME)'"' $(FAKETIME_COMPILE_CFLAGS)
|
||||
ifeq ($(PLATFORM),SunOS)
|
||||
CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=600
|
||||
endif
|
||||
|
||||
CFLAGS += -std=gnu99 -Wall -Wextra -Werror -DFAKE_STAT -DFAKE_SLEEP -DFAKE_TIMERS -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"' -DLIBDIRNAME='"'$(LIBDIRNAME)'"'
|
||||
LIB_LDFLAGS += -shared
|
||||
LDFLAGS += -Wl,--version-script=libfaketime.map -lrt
|
||||
LDADD += -ldl -lm -lpthread -lrt
|
||||
|
||||
LDFLAGS += $(FAKETIME_LINK_FLAGS) -lpthread
|
||||
ifneq ($(PLATFORM),SunOS)
|
||||
LDFLAGS += -Wl,--version-script=libfaketime.map
|
||||
endif
|
||||
|
||||
LDADD += -ldl -lm -lrt
|
||||
BIN_LDFLAGS += -lrt
|
||||
|
||||
SRC = libfaketime.c
|
||||
LIBS_OBJ = libfaketime.o libfaketimeMT.o
|
||||
@@ -81,16 +134,16 @@ LIBS = libfaketime.so.${SONAME} libfaketimeMT.so.${SONAME}
|
||||
|
||||
all: ${LIBS} ${BINS}
|
||||
|
||||
faketimeMT.o: EXTRA_FLAGS := -DPTHREAD -DPTHREAD_SINGLETHREADED_TIME
|
||||
libfaketimeMT.o: EXTRA_FLAGS := -DPTHREAD_SINGLETHREADED_TIME
|
||||
|
||||
${LIBS_OBJ}: libfaketime.c
|
||||
${CC} -o $@ -c ${CFLAGS} ${EXTRA_FLAGS} $<
|
||||
${CC} -o $@ -c ${CFLAGS} ${CPPFLAGS} ${EXTRA_FLAGS} $<
|
||||
|
||||
%.so.${SONAME}: %.o libfaketime.map
|
||||
${CC} -o $@ -Wl,-soname,$@ ${LDFLAGS} ${LIB_LDFLAGS} $< ${LDADD}
|
||||
|
||||
${BINS}: faketime.c
|
||||
${CC} -o $@ ${CFLAGS} ${EXTRA_FLAGS} $< ${LDFLAGS} ${LDADD}
|
||||
${CC} -o $@ ${CFLAGS} ${CPPFLAGS} ${EXTRA_FLAGS} $< ${LDFLAGS} ${BIN_LDFLAGS}
|
||||
|
||||
clean:
|
||||
@rm -f ${LIBS_OBJ} ${LIBS} ${BINS}
|
||||
|
||||
@@ -3,30 +3,41 @@
|
||||
#
|
||||
# * Compilation Defines:
|
||||
#
|
||||
# MACOS_DYLD_INTERPOSE
|
||||
# - Use dlyd interposing instead of name-based function interception
|
||||
# (required since macOS Monterey)
|
||||
#
|
||||
# FAKE_SLEEP
|
||||
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
|
||||
#
|
||||
# FAKE_SETTIME
|
||||
# - Intercept clock_settime(), settimeofday(), and adjtime()
|
||||
#
|
||||
# FAKE_PID
|
||||
# - Enable faked values for getpid() calls through FAKETIME_FAKEPID
|
||||
#
|
||||
# FAKE_RANDOM
|
||||
# - Intercept getentropy(). Dangerous for production use.
|
||||
# See README about FAKE_RANDOM.
|
||||
#
|
||||
# FAKE_STAT
|
||||
# - Enables time faking also for files' timestamps.
|
||||
#
|
||||
# NO_ATFILE
|
||||
# - Disables support for the fstatat() group of functions
|
||||
# FAKE_FILE_TIMESTAMPS, FAKE_UTIME
|
||||
# - Enables time faking for the utime* functions. If enabled via
|
||||
# FAKE_FILE_TIMESTAMPS, the faking is opt-in at runtime using
|
||||
# with the FAKE_UTIME environment variable. If enabled via
|
||||
# FAKE_UTIME, the faking is opt-out at runtime. Requires FAKE_STAT.
|
||||
#
|
||||
# PTHREAD
|
||||
# - Define this to enable multithreading support.
|
||||
#
|
||||
# PTHREAD_SINGLETHREADED_TIME
|
||||
# - Define this if you want to single-thread time() ... there ARE
|
||||
# possibile caching side-effects in a multithreaded environment
|
||||
# possible caching side-effects in a multithreaded environment
|
||||
# without this, but the performance impact may require you to
|
||||
# try it unsynchronized.
|
||||
#
|
||||
# FAKE_SLEEP
|
||||
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
|
||||
#
|
||||
# NO_CACHING
|
||||
# - Disables the caching of the fake time offset. Only disable caching
|
||||
# if you change the fake time offset during program runtime very
|
||||
# frequently. Disabling the cache may negatively influence the
|
||||
# performance.
|
||||
#
|
||||
# * Compilation addition: second libMT target added for building the pthread-
|
||||
# enabled library as a separate library
|
||||
#
|
||||
@@ -44,8 +55,8 @@ INSTALL ?= install
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
CFLAGS += -DFAKE_SLEEP -DPREFIX='"'${PREFIX}'"'
|
||||
LIB_LDFLAGS += -dynamiclib -current_version 0.9.5 -compatibility_version 0.7
|
||||
CFLAGS += -DFAKE_SLEEP -DFAKE_INTERNAL_CALLS -DPREFIX='"'${PREFIX}'"' $(FAKETIME_COMPILE_CFLAGS) -DMACOS_DYLD_INTERPOSE -DFAKE_SETTIME
|
||||
LIB_LDFLAGS += -dynamiclib -current_version 0.9.10 -compatibility_version 0.7
|
||||
|
||||
SONAME = 1
|
||||
LIBS = libfaketime.${SONAME}.dylib
|
||||
|
||||
192
src/faketime.c
192
src/faketime.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libfaketime wrapper command
|
||||
*
|
||||
* This file is part of libfaketime, version 0.9.5
|
||||
* This file is part of libfaketime, version 0.9.10
|
||||
*
|
||||
* libfaketime is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License v2 as published by the
|
||||
@@ -48,9 +48,9 @@
|
||||
|
||||
#include "faketime_common.h"
|
||||
|
||||
const char version[] = "0.9.5";
|
||||
const char version[] = "0.9.10";
|
||||
|
||||
#ifdef __APPLE__
|
||||
#if (defined __APPLE__) || (defined __sun)
|
||||
static const char *date_cmd = "gdate";
|
||||
#else
|
||||
static const char *date_cmd = "date";
|
||||
@@ -61,31 +61,35 @@ static const char *date_cmd = "date";
|
||||
/* semaphore and shared memory names */
|
||||
char sem_name[PATH_BUFSIZE] = {0}, shm_name[PATH_BUFSIZE] = {0};
|
||||
|
||||
|
||||
void usage(const char *name)
|
||||
{
|
||||
printf("\n");
|
||||
printf("Usage: %s [switches] <timestamp> <program with arguments>\n", name);
|
||||
printf("\n");
|
||||
printf("This will run the specified 'program' with the given 'arguments'.\n");
|
||||
printf("The program will be tricked into seeing the given 'timestamp' as its starting date and time.\n");
|
||||
printf("The clock will continue to run from this timestamp. Please see the manpage (man faketime)\n");
|
||||
printf("for advanced options, such as stopping the wall clock and make it run faster or slower.\n");
|
||||
printf("\n");
|
||||
printf("The optional switches are:\n");
|
||||
printf(" -m : Use the multi-threaded version of libfaketime\n");
|
||||
printf(" -f : Use the advanced timestamp specification format (see manpage)\n");
|
||||
printf("\n");
|
||||
printf("Examples:\n");
|
||||
printf("%s 'last friday 5 pm' /bin/date\n", name);
|
||||
printf("%s '2008-12-24 08:15:42' /bin/date\n", name);
|
||||
printf("%s -f '+2,5y x10,0' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n", name);
|
||||
printf("%s -f '+2,5y x0,50' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n", name);
|
||||
printf("%s -f '+2,5y i2,0' /bin/bash -c 'date; while true; do date; sleep 1 ; done'\n", name);
|
||||
printf("In this single case all spawned processes will use the same global clock\n");
|
||||
printf("without restaring it at the start of each process.\n\n");
|
||||
printf("(Please note that it depends on your locale settings whether . or , has to be used for fractions)\n");
|
||||
printf("\n");
|
||||
printf("\n"
|
||||
"Usage: %s [switches] <timestamp> <program with arguments>\n"
|
||||
"\n"
|
||||
"This will run the specified 'program' with the given 'arguments'.\n"
|
||||
"The program will be tricked into seeing the given 'timestamp' as its starting date and time.\n"
|
||||
"The clock will continue to run from this timestamp. Please see the manpage (man faketime)\n"
|
||||
"for advanced options, such as stopping the wall clock and make it run faster or slower.\n"
|
||||
"\n"
|
||||
"The optional switches are:\n"
|
||||
" -m : Use the multi-threaded version of libfaketime\n"
|
||||
" -f : Use the advanced timestamp specification format (see manpage)\n"
|
||||
" --exclude-monotonic : Prevent monotonic clock from drifting (not the raw monotonic one)\n"
|
||||
#ifdef FAKE_PID
|
||||
" -p PID : Pretend that the program's process ID is PID\n"
|
||||
#endif
|
||||
" --date-prog PROG : Use specified GNU-compatible implementation of 'date' program\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
"%s 'last friday 5 pm' /bin/date\n"
|
||||
"%s '2008-12-24 08:15:42' /bin/date\n"
|
||||
"%s -f '+2,5y x10,0' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n"
|
||||
"%s -f '+2,5y x0,50' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n"
|
||||
"%s -f '+2,5y i2,0' /bin/bash -c 'date; while true; do date; sleep 1 ; done'\n"
|
||||
"In this single case all spawned processes will use the same global clock\n"
|
||||
"without restarting it at the start of each process.\n\n"
|
||||
"(Please note that it depends on your locale settings whether . or , has to be used for fractions)\n"
|
||||
"\n", name, name, name, name, name, name);
|
||||
}
|
||||
|
||||
/** Clean up shared objects */
|
||||
@@ -93,11 +97,11 @@ static void cleanup_shobjs()
|
||||
{
|
||||
if (-1 == sem_unlink(sem_name))
|
||||
{
|
||||
perror("sem_unlink");
|
||||
perror("faketime: sem_unlink");
|
||||
}
|
||||
if (-1 == shm_unlink(shm_name))
|
||||
{
|
||||
perror("shm_unlink");
|
||||
perror("faketime: shm_unlink");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,27 +110,65 @@ int main (int argc, char **argv)
|
||||
pid_t child_pid;
|
||||
int curr_opt = 1;
|
||||
bool use_mt = false, use_direct = false;
|
||||
int pfds[2];
|
||||
long offset;
|
||||
bool fake_pid = false;
|
||||
const char *pid_val;
|
||||
|
||||
while(curr_opt < argc) {
|
||||
#ifndef SILENT
|
||||
if (getenv("FAKETIME") || getenv("FAKETIME_SHARED") || getenv("FAKETIME_FAKEPID") || getenv("FAKERANDOM_SEED")) {
|
||||
fprintf(stderr, "faketime: You appear to be running faketime within a libfaketime environment. Proceeding, but check for unexpected results...\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
while (curr_opt < argc)
|
||||
{
|
||||
if (0 == strcmp(argv[curr_opt], "-m"))
|
||||
{
|
||||
use_mt = true;
|
||||
curr_opt++;
|
||||
continue;
|
||||
}
|
||||
if (0 == strcmp(argv[curr_opt], "-p"))
|
||||
{
|
||||
fake_pid = true;
|
||||
pid_val = argv[curr_opt + 1];
|
||||
curr_opt += 2;
|
||||
#ifndef FAKE_PID
|
||||
fprintf(stderr, "faketime: -p argument probably won't work (try rebuilding with -DFAKE_PID)\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
else if (0 == strcmp(argv[curr_opt], "-f"))
|
||||
{
|
||||
use_direct = true;
|
||||
curr_opt++;
|
||||
continue;
|
||||
}
|
||||
else if (0 == strcmp(argv[curr_opt], "--exclude-monotonic"))
|
||||
{
|
||||
setenv("FAKETIME_DONT_FAKE_MONOTONIC", "1", true);
|
||||
curr_opt++;
|
||||
continue;
|
||||
}
|
||||
else if (0 == strcmp(argv[curr_opt], "--date-prog"))
|
||||
{
|
||||
curr_opt++;
|
||||
if (curr_opt > argc) {
|
||||
// At best this avoids a segfault reading beyond the argv[]
|
||||
// Realistically there would be other args (e.g. program to call)
|
||||
fprintf(stderr, "faketime: --date-prog requires a further argument\n");
|
||||
} else {
|
||||
date_cmd = argv[curr_opt];
|
||||
curr_opt++;
|
||||
//fprintf(stderr, "faketime: --date-prog assigned: %s\n", date_cmd);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if ((0 == strcmp(argv[curr_opt], "-v")) ||
|
||||
(0 == strcmp(argv[curr_opt], "--version")))
|
||||
{
|
||||
printf("\n%s: Version %s\n"
|
||||
"For usage information please use '%s --help\n'.",
|
||||
"For usage information please use '%s --help'.\n",
|
||||
argv[0], version, argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@@ -154,6 +196,7 @@ int main (int argc, char **argv)
|
||||
if (!use_direct)
|
||||
{
|
||||
// TODO get seconds
|
||||
int pfds[2];
|
||||
(void) (pipe(pfds) + 1);
|
||||
int ret = EXIT_SUCCESS;
|
||||
|
||||
@@ -162,9 +205,10 @@ int main (int argc, char **argv)
|
||||
close(1); /* close normal stdout */
|
||||
(void) (dup(pfds[1]) + 1); /* make stdout same as pfds[1] */
|
||||
close(pfds[0]); /* we don't need this */
|
||||
// fprintf(stderr, "faketime: using --date-prog: %s\n", date_cmd);
|
||||
if (EXIT_SUCCESS != execlp(date_cmd, date_cmd, "-d", argv[curr_opt], "+%s",(char *) NULL))
|
||||
{
|
||||
perror("Running (g)date failed");
|
||||
perror("faketime: Running (g)date failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
@@ -176,13 +220,14 @@ int main (int argc, char **argv)
|
||||
waitpid(child_pid, &ret, 0);
|
||||
if (ret != EXIT_SUCCESS)
|
||||
{
|
||||
printf("Error: Timestamp to fake not recognized, please re-try with a "
|
||||
printf("Error: Timestamp to fake not recognized, please re-try with a "
|
||||
"different timestamp.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
offset = atol(buf) - time(NULL);
|
||||
ret = snprintf(buf, sizeof(buf), "%s%ld", (offset >= 0)?"+":"", offset);
|
||||
setenv("FAKETIME", buf, true);
|
||||
close(pfds[0]); /* finished reading */
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -190,6 +235,10 @@ int main (int argc, char **argv)
|
||||
/* simply pass format string along */
|
||||
setenv("FAKETIME", argv[curr_opt], true);
|
||||
}
|
||||
if (fake_pid)
|
||||
setenv("FAKETIME_FAKEPID", pid_val, true);
|
||||
int keepalive_fds[2];
|
||||
(void) (pipe(keepalive_fds) + 1);
|
||||
|
||||
/* we just consumed the timestamp option */
|
||||
curr_opt++;
|
||||
@@ -199,24 +248,32 @@ int main (int argc, char **argv)
|
||||
int shm_fd;
|
||||
sem_t *sem;
|
||||
struct ft_shared_s *ft_shared;
|
||||
char shared_objs[PATH_BUFSIZE];
|
||||
char shared_objs[PATH_BUFSIZE * 2 + 1];
|
||||
|
||||
snprintf(sem_name, PATH_BUFSIZE -1 ,"/faketime_sem_%d", getpid());
|
||||
snprintf(shm_name, PATH_BUFSIZE -1 ,"/faketime_shm_%d", getpid());
|
||||
/*
|
||||
* Casting of getpid() return value to long needed to make GCC on SmartOS
|
||||
* happy, since getpid's return value's type on SmartOS is long. Since
|
||||
* getpid's return value's type is int on most other systems, and that
|
||||
* sizeof(long) always >= sizeof(int), this works on all platforms without
|
||||
* the need for crazy #ifdefs.
|
||||
*/
|
||||
snprintf(sem_name, PATH_BUFSIZE -1 ,"/faketime_sem_%ld", (long)getpid());
|
||||
snprintf(shm_name, PATH_BUFSIZE -1 ,"/faketime_shm_%ld", (long)getpid());
|
||||
|
||||
if (SEM_FAILED == (sem = sem_open(sem_name, O_CREAT|O_EXCL, S_IWUSR|S_IRUSR, 1)))
|
||||
{
|
||||
perror("sem_open");
|
||||
perror("faketime: sem_open");
|
||||
fprintf(stderr, "The faketime wrapper only works on platforms that support the sem_open()\nsystem call. However, you may LD_PRELOAD libfaketime without using this wrapper.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* create shm */
|
||||
if (-1 == (shm_fd = shm_open(shm_name, O_CREAT|O_EXCL|O_RDWR, S_IWUSR|S_IRUSR)))
|
||||
{
|
||||
perror("shm_open");
|
||||
perror("faketime: shm_open");
|
||||
if (-1 == sem_unlink(argv[2]))
|
||||
{
|
||||
perror("sem_unlink");
|
||||
perror("faketime: sem_unlink");
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -224,7 +281,7 @@ int main (int argc, char **argv)
|
||||
/* set shm size */
|
||||
if (-1 == ftruncate(shm_fd, sizeof(uint64_t)))
|
||||
{
|
||||
perror("ftruncate");
|
||||
perror("faketime: ftruncate");
|
||||
cleanup_shobjs();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -233,14 +290,14 @@ int main (int argc, char **argv)
|
||||
if (MAP_FAILED == (ft_shared = mmap(NULL, sizeof(struct ft_shared_s), PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED, shm_fd, 0)))
|
||||
{
|
||||
perror("mmap");
|
||||
perror("faketime: mmap");
|
||||
cleanup_shobjs();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (sem_wait(sem) == -1)
|
||||
{
|
||||
perror("sem_wait");
|
||||
perror("faketime: sem_wait");
|
||||
cleanup_shobjs();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -257,21 +314,21 @@ int main (int argc, char **argv)
|
||||
|
||||
if (-1 == munmap(ft_shared, (sizeof(struct ft_shared_s))))
|
||||
{
|
||||
perror("munmap");
|
||||
perror("faketime: munmap");
|
||||
cleanup_shobjs();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (sem_post(sem) == -1)
|
||||
{
|
||||
perror("semop");
|
||||
perror("faketime: semop");
|
||||
cleanup_shobjs();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
snprintf(shared_objs, PATH_BUFSIZE, "%s %s", sem_name, shm_name);
|
||||
snprintf(shared_objs, sizeof(shared_objs), "%s %s", sem_name, shm_name);
|
||||
setenv("FAKETIME_SHARED", shared_objs, true);
|
||||
|
||||
sem_close(sem);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -280,10 +337,12 @@ int main (int argc, char **argv)
|
||||
ftpl_path = PREFIX "/libfaketime.1.dylib";
|
||||
FILE *check;
|
||||
check = fopen(ftpl_path, "ro");
|
||||
if (check == NULL) {
|
||||
if (check == NULL)
|
||||
{
|
||||
ftpl_path = PREFIX "/lib/faketime/libfaketime.1.dylib";
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
fclose(check);
|
||||
}
|
||||
setenv("DYLD_INSERT_LIBRARIES", ftpl_path, true);
|
||||
@@ -298,7 +357,7 @@ int main (int argc, char **argv)
|
||||
* on MultiArch platforms, such as Debian, we put a literal $LIB into LD_PRELOAD.
|
||||
*/
|
||||
#ifndef MULTI_ARCH
|
||||
ftpl_path = PREFIX LIBDIRNAME "/libfaketimeMT.so.1";
|
||||
ftpl_path = PREFIX LIBDIRNAME "/libfaketimeMT.so.1";
|
||||
#else
|
||||
ftpl_path = PREFIX "/$LIB/faketime/libfaketimeMT.so.1";
|
||||
#endif
|
||||
@@ -306,12 +365,12 @@ int main (int argc, char **argv)
|
||||
else
|
||||
{
|
||||
#ifndef MULTI_ARCH
|
||||
ftpl_path = PREFIX LIBDIRNAME "/libfaketime.so.1";
|
||||
ftpl_path = PREFIX LIBDIRNAME "/libfaketime.so.1";
|
||||
#else
|
||||
ftpl_path = PREFIX "/$LIB/faketime/libfaketime.so.1";
|
||||
#endif
|
||||
}
|
||||
len = (ld_preload)?strlen(ld_preload):0 + 2 + strlen(ftpl_path);
|
||||
len = ((ld_preload)?strlen(ld_preload) + 1: 0) + 1 + strlen(ftpl_path);
|
||||
ld_preload_new = malloc(len);
|
||||
snprintf(ld_preload_new, len ,"%s%s%s", (ld_preload)?ld_preload:"",
|
||||
(ld_preload)?":":"", ftpl_path);
|
||||
@@ -324,17 +383,44 @@ int main (int argc, char **argv)
|
||||
/* run command and clean up shared objects */
|
||||
if (0 == (child_pid = fork()))
|
||||
{
|
||||
close(keepalive_fds[0]); /* only parent needs to read this */
|
||||
// fprintf(stderr, "faketime: Executing: %s\n", argv[curr_opt]);
|
||||
if (EXIT_SUCCESS != execvp(argv[curr_opt], &argv[curr_opt]))
|
||||
{
|
||||
perror("Running specified command failed");
|
||||
perror("faketime: Running specified command failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int ret;
|
||||
char buf;
|
||||
close(keepalive_fds[1]); /* only children need keep this open */
|
||||
waitpid(child_pid, &ret, 0);
|
||||
(void) (read(keepalive_fds[0], &buf, 1) + 1); /* reads 0B when all children exit */
|
||||
cleanup_shobjs();
|
||||
exit(ret);
|
||||
if (WIFSIGNALED(ret))
|
||||
{
|
||||
fprintf(stderr, "Caught %s\n", strsignal(WTERMSIG(ret)));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
exit(WEXITSTATUS(ret));
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 2
|
||||
* tab-width: 2
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=2 tabstop=2 expandtab:
|
||||
* :indentSize=2:tabSize=2:noTabs=true:
|
||||
*/
|
||||
|
||||
/* eof */
|
||||
|
||||
@@ -32,6 +32,10 @@ struct system_time_s
|
||||
struct timespec mon;
|
||||
/* System time according to CLOCK_MONOTONIC_RAW */
|
||||
struct timespec mon_raw;
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
/* System time according to CLOCK_BOOTTIME */
|
||||
struct timespec boot;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Data shared among faketime-spawned processes */
|
||||
@@ -41,10 +45,56 @@ struct ft_shared_s
|
||||
* When advancing time linearly with each time(), etc. call, the calls are
|
||||
* counted here */
|
||||
uint64_t ticks;
|
||||
/* Index of timstamp to be loaded from file */
|
||||
/* Index of timestamp to be loaded from file */
|
||||
uint64_t file_idx;
|
||||
/* System time Faketime started at */
|
||||
struct system_time_s start_time;
|
||||
};
|
||||
|
||||
/* These are all needed in order to properly build on OSX */
|
||||
#ifdef __APPLE__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach_host.h>
|
||||
#include <mach/mach_port.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
Variadic Argument Re-packing
|
||||
|
||||
Functions with variadic arguments typically have most arguments
|
||||
passed on the stack, but it varies across ABIs.
|
||||
|
||||
C specifies that variadic arguments that are smaller than some
|
||||
standard promotion size are promoted to "int or larger". If your
|
||||
platform's ABI only promotes to "int" and not "long" (and "int" and
|
||||
"long" differ on your platform), you should probably add
|
||||
-Dvariadic_promotion_t=int to CFLAGS.
|
||||
|
||||
Note that some ABIs do not put all the variadic arguments on the
|
||||
stack. For example, x86-64 puts float and double variadic
|
||||
arguments into floating point registers, according to
|
||||
https://www.uclibc.org/docs/psABI-x86_64.pdf
|
||||
|
||||
The only variadic function faketime cares about intercepting is
|
||||
syscall. But we don't believe that any syscalls expect float or
|
||||
double arguments, so we hope all the rest will be on the stack.
|
||||
tests/variadic/ attempts to confirm this if you are compiling
|
||||
with -DINTERCEPT_SYSCALL.
|
||||
|
||||
If libc were capable of exposing a variadic form of syscall, we
|
||||
could depend on that and drop this approach, which would be
|
||||
preferable: https://sourceware.org/bugzilla/show_bug.cgi?id=27508
|
||||
*/
|
||||
#ifndef variadic_promotion_t
|
||||
#define variadic_promotion_t long
|
||||
#endif
|
||||
|
||||
/*
|
||||
The Linux kernel appears to have baked-in 6 as the maximum number
|
||||
of arguments for a syscall beyond the syscall number itself.
|
||||
*/
|
||||
#ifndef syscall_max_args
|
||||
#define syscall_max_args 6
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
2984
src/libfaketime.c
2984
src/libfaketime.c
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,18 @@ GLIBC_2.2 {
|
||||
timer_gettime; timer_settime;
|
||||
local: timer_settime_*; timer_gettime_*;
|
||||
};
|
||||
|
||||
GLIBC_2.3.3 {
|
||||
# Changed timer_t.
|
||||
timer_gettime; timer_settime;
|
||||
} GLIBC_2.2;
|
||||
|
||||
GLIBC_2.2.5 {
|
||||
global: pthread_cond_timedwait;
|
||||
local: pthread_cond_timedwait_*; pthread_cond_init_*; pthread_cond_destroy*;
|
||||
};
|
||||
|
||||
GLIBC_2.3.2 {
|
||||
pthread_cond_timedwait; pthread_cond_init; pthread_cond_destroy;
|
||||
} GLIBC_2.2.5;
|
||||
|
||||
|
||||
12
src/sunos_endian.h
Normal file
12
src/sunos_endian.h
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
#ifndef SUN_OS_ENDIAN_H
|
||||
#define SUN_OS_ENDIAN_H
|
||||
|
||||
#include <sys/byteorder.h>
|
||||
|
||||
#define htobe64(x) BE_64(x)
|
||||
#define be64toh(x) BE_64(x)
|
||||
#define htole64(x) LE_64(x)
|
||||
#define le64toh(x) LE_64(x)
|
||||
|
||||
#endif /* SUN_OS_ENDIAN_H */
|
||||
@@ -29,43 +29,48 @@
|
||||
NOTE: `timercmp' does not work for >= or <=. */
|
||||
#define timerisset2(tvp, prefix) ((tvp)->tv_sec || (tvp)->tv_##prefix##sec)
|
||||
#define timerclear2(tvp, prefix) ((tvp)->tv_sec = (tvp)->tv_##prefix##sec = 0)
|
||||
#define timercmp2(a, b, CMP, prefix) \
|
||||
(((a)->tv_sec == (b)->tv_sec) ? \
|
||||
((a)->tv_##prefix##sec CMP (b)->tv_##prefix##sec) : \
|
||||
#define timercmp2(a, b, CMP, prefix) \
|
||||
(((a)->tv_sec == (b)->tv_sec) ? \
|
||||
((a)->tv_##prefix##sec CMP (b)->tv_##prefix##sec) : \
|
||||
((a)->tv_sec CMP (b)->tv_sec))
|
||||
#define timeradd2(a, b, result, prefix) \
|
||||
do { \
|
||||
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
|
||||
(result)->tv_##prefix##sec = (a)->tv_##prefix##sec + \
|
||||
(b)->tv_##prefix##sec; \
|
||||
if ((result)->tv_##prefix##sec >= SEC_TO_##prefix##SEC) \
|
||||
{ \
|
||||
++(result)->tv_sec; \
|
||||
(result)->tv_##prefix##sec -= SEC_TO_##prefix##SEC; \
|
||||
} \
|
||||
#define timeradd2(a, b, result, prefix) \
|
||||
do \
|
||||
{ \
|
||||
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
|
||||
(result)->tv_##prefix##sec = (a)->tv_##prefix##sec + \
|
||||
(b)->tv_##prefix##sec; \
|
||||
if ((result)->tv_##prefix##sec >= SEC_TO_##prefix##SEC) \
|
||||
{ \
|
||||
++(result)->tv_sec; \
|
||||
(result)->tv_##prefix##sec -= SEC_TO_##prefix##SEC; \
|
||||
} \
|
||||
} while (0)
|
||||
#define timersub2(a, b, result, prefix) \
|
||||
do { \
|
||||
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
|
||||
(result)->tv_##prefix##sec = (a)->tv_##prefix##sec - \
|
||||
(b)->tv_##prefix##sec; \
|
||||
if ((result)->tv_##prefix##sec < 0) { \
|
||||
--(result)->tv_sec; \
|
||||
(result)->tv_##prefix##sec += SEC_TO_##prefix##SEC; \
|
||||
} \
|
||||
#define timersub2(a, b, result, prefix) \
|
||||
do \
|
||||
{ \
|
||||
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
|
||||
(result)->tv_##prefix##sec = (a)->tv_##prefix##sec - \
|
||||
(b)->tv_##prefix##sec; \
|
||||
if ((result)->tv_##prefix##sec < 0) \
|
||||
{ \
|
||||
--(result)->tv_sec; \
|
||||
(result)->tv_##prefix##sec += SEC_TO_##prefix##SEC; \
|
||||
} \
|
||||
} while (0)
|
||||
#define timermul2(tvp, c, result, prefix) \
|
||||
do { \
|
||||
long long tmp_time; \
|
||||
tmp_time = (c) * ((tvp)->tv_sec * SEC_TO_##prefix##SEC + \
|
||||
(tvp)->tv_##prefix##sec); \
|
||||
(result)->tv_##prefix##sec = tmp_time % SEC_TO_##prefix##SEC; \
|
||||
(result)->tv_sec = (tmp_time - (result)->tv_##prefix##sec) / \
|
||||
SEC_TO_##prefix##SEC; \
|
||||
if ((result)->tv_##prefix##sec < 0) { \
|
||||
(result)->tv_##prefix##sec += SEC_TO_##prefix##SEC; \
|
||||
(result)->tv_sec -= 1; \
|
||||
} \
|
||||
#define timermul2(tvp, c, result, prefix) \
|
||||
do \
|
||||
{ \
|
||||
int64_t tmp_time; \
|
||||
tmp_time = (c) * (int64_t) ((int64_t) (tvp)->tv_sec * SEC_TO_##prefix##SEC + \
|
||||
(int64_t) (tvp)->tv_##prefix##sec); \
|
||||
(result)->tv_##prefix##sec = tmp_time % SEC_TO_##prefix##SEC; \
|
||||
(result)->tv_sec = (tmp_time - (result)->tv_##prefix##sec) / \
|
||||
SEC_TO_##prefix##SEC; \
|
||||
if ((result)->tv_##prefix##sec < 0) \
|
||||
{ \
|
||||
(result)->tv_##prefix##sec += SEC_TO_##prefix##SEC; \
|
||||
(result)->tv_sec -= 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* ops for microsecs */
|
||||
@@ -84,16 +89,28 @@
|
||||
#ifndef timersub
|
||||
#define timersub(a, b, result) timersub2(a, b, result, u)
|
||||
#endif
|
||||
#ifndef timersub
|
||||
#ifndef timermul
|
||||
#define timermul(a, c, result) timermul2(a, c, result, u)
|
||||
#endif
|
||||
|
||||
/* ops for nanosecs */
|
||||
#ifndef timespecisset
|
||||
#define timespecisset(tvp) timerisset2(tvp,n)
|
||||
#endif
|
||||
#ifndef timespecclear
|
||||
#define timespecclear(tvp) timerclear2(tvp, n)
|
||||
#endif
|
||||
#ifndef timespeccmp
|
||||
#define timespeccmp(a, b, CMP) timercmp2(a, b, CMP, n)
|
||||
#endif
|
||||
#ifndef timespecadd
|
||||
#define timespecadd(a, b, result) timeradd2(a, b, result, n)
|
||||
#endif
|
||||
#ifndef timespecsub
|
||||
#define timespecsub(a, b, result) timersub2(a, b, result, n)
|
||||
#endif
|
||||
#ifndef timespecmul
|
||||
#define timespecmul(a, c, result) timermul2(a, c, result, n)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
1208
src/uthash.h
Normal file
1208
src/uthash.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,21 @@
|
||||
CC = gcc
|
||||
|
||||
CFLAGS = -std=gnu99 -Wall -DFAKE_STAT -Werror -Wextra
|
||||
LDFLAGS = -lrt
|
||||
CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -Werror -Wextra $(FAKETIME_COMPILE_CFLAGS)
|
||||
LDFLAGS += -lrt -lpthread
|
||||
|
||||
SRC = timetest.c
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
all: timetest test
|
||||
TEST_SNIPPETS = $(notdir $(basename $(wildcard snippets/*.c)))
|
||||
EXPECTATIONS= $(notdir $(basename $(wildcard snippets/*.variable)))
|
||||
|
||||
ALL_TESTS = timetest test
|
||||
|
||||
ifneq ($(filter -DINTERCEPT_SYSCALL,${CFLAGS}),)
|
||||
ALL_TESTS += confirm_variadic_promotion
|
||||
endif
|
||||
|
||||
all: $(ALL_TESTS)
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $<
|
||||
@@ -22,10 +31,48 @@ test: timetest functest
|
||||
functest:
|
||||
./testframe.sh functests
|
||||
|
||||
%_test: %_test.c
|
||||
${CC} -o $@ ${CFLAGS} $<
|
||||
|
||||
randomtest: repeat_random
|
||||
./randomtest.sh
|
||||
|
||||
# ensure our variadic argument unpacking/repacking works as expected
|
||||
confirm_variadic_promotion: variadic_promotion
|
||||
./variadic_promotion
|
||||
variadic_promotion: variadic/main.o variadic/outer.o variadic/inner.o
|
||||
${CC} -o $@ ${CFLAGS} $^
|
||||
variadic/%.o: variadic/%.c
|
||||
${CC} -c -o $@ ${CFLAGS} $<
|
||||
|
||||
# run snippet tests
|
||||
snippets: test_variable_data test_library_constructors
|
||||
|
||||
## test snippet behavior across env var setting over time:
|
||||
test_variable_data: test_variable_data.sh $(foreach f,${EXPECTATIONS},run_${f})
|
||||
./test_variable_data.sh ${EXPECTATIONS}
|
||||
|
||||
run_%: _run_test.c snippets/%.c
|
||||
sed s/SNIPPET_NAME/$*/g < _run_test.c | ${CC} -o $@ ${CFLAGS} -x c -
|
||||
|
||||
## test snippets in other library constructors:
|
||||
test_library_constructors: $(foreach f,${TEST_SNIPPETS},test_lib_${f})
|
||||
test_lib_%: test_constructors.sh use_lib_% lib%.so
|
||||
./test_constructors.sh $*
|
||||
|
||||
lib%.so: _libtest.c snippets/%.c
|
||||
sed s/SNIPPET_NAME/$*/g < _libtest.c | ${CC} -shared -o $@ -fpic ${CFLAGS} -x c -
|
||||
|
||||
use_lib_%: _use_lib_test.c snippets/%.c lib%.so
|
||||
sed s/SNIPPET_NAME/$*/g < _use_lib_test.c | ${CC} -L. -o $@ ${CFLAGS} -x c - -l$*
|
||||
|
||||
|
||||
## cleanup and metainformation
|
||||
|
||||
clean:
|
||||
@rm -f ${OBJ} timetest
|
||||
@rm -f ${OBJ} timetest getrandom_test syscall_test $(foreach f,${TEST_SNIPPETS},use_lib_${f} lib${f}.so run_${f}) variadic_promotion variadic/*.o
|
||||
|
||||
distclean: clean
|
||||
@echo
|
||||
|
||||
.PHONY: all test clean distclean
|
||||
.PHONY: all test clean distclean randomtest snippets test_variable_data test_library_constructors
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
CC = gcc
|
||||
CC ?= clang
|
||||
|
||||
CFLAGS = -std=gnu99 -Wall -DFAKE_STAT
|
||||
LDFLAGS =
|
||||
CFLAGS += -std=gnu99 -Wall -DFAKE_STAT $(FAKETIME_COMPILE_CFLAGS)
|
||||
|
||||
SRC = timetest.c
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
@@ -35,5 +35,5 @@
|
||||
# 3. create DIR/test_XXX.sh.
|
||||
# 4. write a run function and testcase functions in DIR/test_XXX.sh.
|
||||
# 5. within the run function, call run_testcase for each testcase function.
|
||||
# 6. within each testcase funtion, call assertneq or asserteq, or do
|
||||
# 6. within each testcase function, call assertneq or asserteq, or do
|
||||
# the equivalent.
|
||||
|
||||
8
test/_libtest.c
Normal file
8
test/_libtest.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "snippets/include_headers.h"
|
||||
#define where "libSNIPPET_NAME"
|
||||
void SNIPPET_NAME_as_needed() {
|
||||
printf(" called SNIPPET_NAME_as_needed() \n");
|
||||
}
|
||||
static __attribute__((constructor)) void init_SNIPPET_NAME() {
|
||||
#include "snippets/SNIPPET_NAME.c"
|
||||
}
|
||||
5
test/_run_test.c
Normal file
5
test/_run_test.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "snippets/include_headers.h"
|
||||
#define where "run_SNIPPET_NAME"
|
||||
int main() {
|
||||
#include "snippets/SNIPPET_NAME.c"
|
||||
}
|
||||
7
test/_use_lib_test.c
Normal file
7
test/_use_lib_test.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "snippets/include_headers.h"
|
||||
extern void SNIPPET_NAME_as_needed();
|
||||
#define where "use_lib_SNIPPET_NAME"
|
||||
int main() {
|
||||
SNIPPET_NAME_as_needed();
|
||||
#include "snippets/SNIPPET_NAME.c"
|
||||
}
|
||||
@@ -9,6 +9,7 @@ platform()
|
||||
*Darwin*) echo "mac" ;;
|
||||
*Linux*) echo "linuxlike" ;;
|
||||
GNU|GNU/kFreeBSD) echo "linuxlike" ;;
|
||||
*SunOS*) echo "sunos" ;;
|
||||
*) echo 1>&2 unsupported platform, uname=\"$out\" ;;
|
||||
esac
|
||||
}
|
||||
@@ -25,11 +26,21 @@ mac_fakecmd()
|
||||
"$@"
|
||||
}
|
||||
|
||||
sunos_fakecmd()
|
||||
{
|
||||
typeset timestring="$1"; shift
|
||||
typeset fakelib=../src/libfaketime.so.1
|
||||
export LD_PRELOAD=$fakelib
|
||||
FAKETIME="$timestring" \
|
||||
"$@"
|
||||
}
|
||||
|
||||
# run faked command on linuxlike OS
|
||||
linuxlike_fakecmd()
|
||||
{
|
||||
typeset timestring="$1"; shift
|
||||
typeset fakelib=../src/libfaketime.so.1
|
||||
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
|
||||
typeset fakelib="$FTPL"
|
||||
export LD_PRELOAD=$fakelib
|
||||
FAKETIME="$timestring" \
|
||||
"$@"
|
||||
|
||||
88
test/functests/test_exclude_mono.sh
Normal file
88
test/functests/test_exclude_mono.sh
Normal file
@@ -0,0 +1,88 @@
|
||||
# Checks that setting FAKETIME_DONT_FAKE_MONOTONIC actually prevent
|
||||
# libfaketime from faking monotonic clocks.
|
||||
#
|
||||
# We do this by freezing time at a specific and arbitrary date with faketime,
|
||||
# and making sure that if we set FAKETIME_DONT_FAKE_MONOTONIC to 1, calling
|
||||
# clock_gettime(CLOCK_MONOTONIC) returns two different values.
|
||||
#
|
||||
# We also make sure that if we don't set FAKETIME_DONT_FAKE_MONOTONIC to 1,
|
||||
# in other words when we use the default behavior, two subsequent calls to
|
||||
# clock_gettime(CLOCK_MONOTONIC) do return different values.
|
||||
|
||||
init()
|
||||
{
|
||||
typeset testsuite="$1"
|
||||
PLATFORM=$(platform)
|
||||
if [ -z "$PLATFORM" ]; then
|
||||
echo "$testsuite: unknown platform! quitting"
|
||||
return 1
|
||||
fi
|
||||
echo "# PLATFORM=$PLATFORM"
|
||||
return 0
|
||||
}
|
||||
|
||||
run()
|
||||
{
|
||||
init
|
||||
|
||||
run_testcase dont_fake_mono
|
||||
# run_testcase fake_mono
|
||||
}
|
||||
|
||||
get_token()
|
||||
{
|
||||
string=$1
|
||||
token_index=$2
|
||||
separator=$3
|
||||
|
||||
echo $string | cut -d "$separator" -f $token_index
|
||||
}
|
||||
|
||||
assert_timestamps_neq()
|
||||
{
|
||||
timestamps=$1
|
||||
msg=$2
|
||||
|
||||
first_timestamp=$(get_token "${timestamps}" 1 ' ')
|
||||
second_timestamp=$(get_token "${timestamps}" 2 ' ')
|
||||
|
||||
assertneq "${first_timestamp}" "${second_timestamp}" "${msg}"
|
||||
}
|
||||
|
||||
assert_timestamps_eq()
|
||||
{
|
||||
timestamps=$1
|
||||
msg=$2
|
||||
|
||||
first_timestamp=$(get_token "${timestamps}" 1 ' ')
|
||||
second_timestamp=$(get_token "${timestamps}" 2 ' ')
|
||||
|
||||
asserteq "${first_timestamp}" "${second_timestamp}" "${msg}"
|
||||
}
|
||||
|
||||
get_monotonic_time()
|
||||
{
|
||||
dont_fake_mono=$1; shift;
|
||||
clock_id=$1; shift;
|
||||
FAKETIME_DONT_FAKE_MONOTONIC=${dont_fake_mono} \
|
||||
fakecmd "2014-07-21 09:00:00" \
|
||||
/bin/bash -c "for i in 1 2; do \
|
||||
perl -w -MTime::HiRes=clock_gettime,${clock_id} -E \
|
||||
'say clock_gettime(${clock_id})'; \
|
||||
sleep 1; \
|
||||
done"
|
||||
}
|
||||
|
||||
dont_fake_mono()
|
||||
{
|
||||
timestamps=$(get_monotonic_time 1 CLOCK_MONOTONIC)
|
||||
msg="When not faking monotonic time, timestamps should be different"
|
||||
assert_timestamps_neq "${timestamps}" "${msg}"
|
||||
}
|
||||
|
||||
fake_mono()
|
||||
{
|
||||
timestamps=$(get_monotonic_time 0 CLOCK_MONOTONIC)
|
||||
msg="When faking monotonic, timestamps should be equal"
|
||||
assert_timestamps_eq "${timestamps}" "${msg}"
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# test suite that always succeds - for testing framework
|
||||
# test suite that always succeeds - for testing framework
|
||||
|
||||
run()
|
||||
{
|
||||
|
||||
@@ -37,7 +37,15 @@ fakedate()
|
||||
#
|
||||
typeset fmt='%s'
|
||||
export FAKETIME_FMT=$fmt
|
||||
fakecmd "$1" date +$fmt
|
||||
if [ "mac" == "$PLATFORM" ]; then
|
||||
if [ -x /usr/local/bin/gdate ] ; then
|
||||
fakecmd "$1" gdate +$fmt
|
||||
else
|
||||
echo "<skip>"
|
||||
fi
|
||||
else
|
||||
fakecmd "$1" date +$fmt
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
@@ -63,5 +71,14 @@ test_with_i()
|
||||
typeset i="$1"
|
||||
typeset t=$(pow 2 $i)
|
||||
|
||||
asserteq $(fakedate $t) $t "(secs since Epoch)"
|
||||
if [ "mac" == "$PLATFORM" ]; then
|
||||
if [ -x /usr/local/bin/gdate ] ; then
|
||||
asserteq $(fakedate $t) $t "(secs since Epoch)"
|
||||
else
|
||||
asserteq $t $t "(skipping test, install gdate)"
|
||||
fi
|
||||
|
||||
else
|
||||
asserteq $(fakedate $t) $t "(secs since Epoch)"
|
||||
fi
|
||||
}
|
||||
|
||||
21
test/randomtest.sh
Executable file
21
test/randomtest.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
|
||||
|
||||
set -e
|
||||
|
||||
error=0
|
||||
|
||||
repeat3x5="$(FAKERANDOM_SEED=0xDEADBEEFDEADBEEF LD_PRELOAD="$FTPL" ./repeat_random 3 5)"
|
||||
repeat5x3="$(FAKERANDOM_SEED=0xDEADBEEFDEADBEEF LD_PRELOAD="$FTPL" ./repeat_random 5 3)"
|
||||
|
||||
if [ "$repeat3x5" != "$repeat5x3" ]; then
|
||||
error=1
|
||||
printf >&2 '5 calls of getrandom(3) got %s\n3 calls of getrandom(5) got %s\n' "$repeat3x5" "$repeat5x3"
|
||||
fi
|
||||
|
||||
if [ 0 = $error ]; then
|
||||
printf 'getrandom interception test successful.\n'
|
||||
fi
|
||||
|
||||
exit $error
|
||||
40
test/repeat_random.c
Normal file
40
test/repeat_random.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/random.h>
|
||||
|
||||
void usage(const char* name) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s REPS SIZE\n\n"
|
||||
"Gather and print REPS blocks of SIZE bytes from getrandom()\n",
|
||||
name);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
int reps, size;
|
||||
unsigned char *buf;
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
reps = atoi(argv[1]);
|
||||
size = atoi(argv[2]);
|
||||
buf = malloc(size);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "failure to allocate buffer of size %d\n", size);
|
||||
return 1;
|
||||
}
|
||||
for (int i = 0; i < reps; i++) {
|
||||
ssize_t resp = getrandom(buf, size, 0);
|
||||
if (resp != size) {
|
||||
fprintf(stderr, "tried to get %d bytes, got %zd\n", size, resp);
|
||||
free(buf);
|
||||
return 2;
|
||||
}
|
||||
for (int j = 0; j < size; j++) {
|
||||
printf("%02x", buf[j]);
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
printf("\n");
|
||||
return 0;
|
||||
};
|
||||
72
test/snippets/README
Normal file
72
test/snippets/README
Normal file
@@ -0,0 +1,72 @@
|
||||
Testing Interception with Snippets
|
||||
==================================
|
||||
|
||||
Faketime intercepts some C library functions and system calls. We
|
||||
want to make it easier to apply certain generic tests across many
|
||||
different functions. We do that with snippets of C, which each can be
|
||||
applied in multiple testing frameworks.
|
||||
|
||||
Most snippets are just a minimalist invocation of a single function or
|
||||
syscall that is likely to be intercepted by libfaketime, though it's
|
||||
possible to test more complex snippets too.
|
||||
|
||||
Including a New Snippet
|
||||
-----------------------
|
||||
|
||||
To cover a new bit of intercepted functionality, supply a C snippet in
|
||||
this directory named `FOO.c` (the name FOO should conform to C
|
||||
function names -- letters, numbers, and underscores; if you're testing
|
||||
interception of a single function, the simplest thing is to name
|
||||
snippet file after the intercepted function name).
|
||||
|
||||
This file should contain a small bit of code that exercises the
|
||||
functionality in question. It should be self-contained, and it should
|
||||
produce some kind of description of what happened to stdout. The data
|
||||
sent to stdout should include the const char* "where" value (which is
|
||||
an indication of which test framework is using the snippet). Take a
|
||||
look at getpid.c for a simple example.
|
||||
|
||||
If the snippet needs additional #include headers, please add them
|
||||
in `include_headers.h`. These #includes will be used by every snippet,
|
||||
so try to keep it minimal.
|
||||
|
||||
Snippet Testing Frameworks
|
||||
--------------------------
|
||||
|
||||
We have the following frameworks that use the snippets:
|
||||
|
||||
### Variable Data
|
||||
|
||||
Most functionality intercepted by libfaketime will normally produce
|
||||
variant output when invoked multiple times across the span of a few
|
||||
seconds by different processes. But if `FAKETIME` (or an analogous
|
||||
variable like `FAKERANDOM_SEED`) is set, the output data should remain
|
||||
constant.
|
||||
|
||||
If this describes the functionality in a new snippet `FOO.c`, please
|
||||
also drop a single-line file `FOO.variable` in this directory, where
|
||||
the first word of the line is the variable that should hold the output
|
||||
constant, and the rest of the line is the value of that variable.
|
||||
|
||||
See the `test_variable_data` target in `test/Makefile` for how this is
|
||||
implemented.
|
||||
|
||||
### Library Constructors
|
||||
|
||||
Library constructor routines are run by ld.so before the main process
|
||||
is launched. If the LD_PRELOADed libfaketime is masking a symbol from
|
||||
libc, and another library has a constructor routine that invokes that
|
||||
symbol, it might get called before libfaketime has had a chance to
|
||||
initialize its followup pointers to the actual libc functionality.
|
||||
|
||||
This framework is applied automatically to all snippets.
|
||||
|
||||
See the `test_library_constructors` target in `test/Makefile` for how
|
||||
this is implemented.
|
||||
|
||||
Adding a New Framework
|
||||
----------------------
|
||||
|
||||
If you want to add a new framework that tests across all snippets,
|
||||
implement it in a few lines of `test/Makefile` and document it in the
|
||||
section above.
|
||||
8
test/snippets/clock_gettime.c
Normal file
8
test/snippets/clock_gettime.c
Normal file
@@ -0,0 +1,8 @@
|
||||
struct timespec ts;
|
||||
clockid_t ckid = CLOCK_REALTIME;
|
||||
int ret = clock_gettime(ckid, &ts);
|
||||
if (ret == 0) {
|
||||
printf("[%s] clock_gettime(CLOCK_REALTIME[%d], &ts) -> {%lld, %ld}\n", where, ckid, (long long)ts.tv_sec, ts.tv_nsec);
|
||||
} else {
|
||||
printf("[%s] clock_gettime(CLOCK_REALTIME[%d], &ts) returned non-zero (%d), errno = %d (%s)\n", where, ckid, ret, errno, strerror(errno));
|
||||
}
|
||||
1
test/snippets/clock_gettime.variable
Normal file
1
test/snippets/clock_gettime.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME 2020-02-02 02:02:02+00:00
|
||||
8
test/snippets/clock_gettime_heap.c
Normal file
8
test/snippets/clock_gettime_heap.c
Normal file
@@ -0,0 +1,8 @@
|
||||
struct timespec *ts = malloc(sizeof(struct timespec));
|
||||
clockid_t ckid = CLOCK_REALTIME;
|
||||
int ret = clock_gettime(ckid, ts);
|
||||
if (ret == 0) {
|
||||
printf("[%s] clock_gettime_heap(CLOCK_REALTIME[%d], ts) -> {%lld, %ld}\n", where, ckid, (long long)ts->tv_sec, ts->tv_nsec);
|
||||
} else {
|
||||
printf("[%s] clock_gettime_heap(CLOCK_REALTIME[%d], ts) returned non-zero (%d), errno = %d (%s)\n", where, ckid, ret, errno, strerror(errno));
|
||||
}
|
||||
1
test/snippets/clock_gettime_heap.variable
Normal file
1
test/snippets/clock_gettime_heap.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME 2020-02-02 02:02:02+00:00
|
||||
6
test/snippets/getentropy.c
Normal file
6
test/snippets/getentropy.c
Normal file
@@ -0,0 +1,6 @@
|
||||
unsigned int targ;
|
||||
if (getentropy(&targ, sizeof(targ)) == 0) {
|
||||
printf("[%s] getentropy() yielded 0x%08x\n", where, targ);
|
||||
} else {
|
||||
printf("[%s] getentropy() failed with %d (%s)\n", where, errno, strerror(errno));
|
||||
}
|
||||
1
test/snippets/getentropy.variable
Normal file
1
test/snippets/getentropy.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKERANDOM_SEED 0x0123456789ABCDEF
|
||||
2
test/snippets/getpid.c
Normal file
2
test/snippets/getpid.c
Normal file
@@ -0,0 +1,2 @@
|
||||
pid_t pid = getpid();
|
||||
printf("[%s] getpid() yielded %d\n", where, pid);
|
||||
1
test/snippets/getpid.variable
Normal file
1
test/snippets/getpid.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME_FAKEPID 1
|
||||
7
test/snippets/getrandom.c
Normal file
7
test/snippets/getrandom.c
Normal file
@@ -0,0 +1,7 @@
|
||||
unsigned int targ;
|
||||
ssize_t ret = getrandom(&targ, sizeof(targ), 0);
|
||||
if (ret == sizeof(targ)) {
|
||||
printf("[%s] getrandom() yielded 0x%08x\n", where, targ);
|
||||
} else {
|
||||
printf("[%s] getrandom() failed with only %zd\n", where, ret);
|
||||
}
|
||||
1
test/snippets/getrandom.variable
Normal file
1
test/snippets/getrandom.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKERANDOM_SEED 0xDEADBEEFDEADBEEF
|
||||
9
test/snippets/include_headers.h
Normal file
9
test/snippets/include_headers.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
2
test/snippets/syscall.c
Normal file
2
test/snippets/syscall.c
Normal file
@@ -0,0 +1,2 @@
|
||||
long uid = syscall(__NR_getuid);
|
||||
printf("[%s] syscall(__NR_getuid) -> %ld\n", where, uid);
|
||||
8
test/snippets/syscall_clock_gettime.c
Normal file
8
test/snippets/syscall_clock_gettime.c
Normal file
@@ -0,0 +1,8 @@
|
||||
struct timespec ts;
|
||||
clockid_t ckid = CLOCK_REALTIME;
|
||||
long ret = syscall(__NR_clock_gettime, ckid, &ts);
|
||||
if (ret == 0)
|
||||
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], &ts) -> {%lld, %ld}\n", where, ckid, (long long)ts.tv_sec, ts.tv_nsec);
|
||||
else
|
||||
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], &ts) returned non-zero (%ld)\n", where, ckid, ret);
|
||||
|
||||
1
test/snippets/syscall_clock_gettime.variable
Normal file
1
test/snippets/syscall_clock_gettime.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME 2020-01-01 00:00:00
|
||||
8
test/snippets/syscall_clock_gettime_heap.c
Normal file
8
test/snippets/syscall_clock_gettime_heap.c
Normal file
@@ -0,0 +1,8 @@
|
||||
struct timespec *ts = malloc(sizeof(struct timespec));
|
||||
clockid_t ckid = CLOCK_REALTIME;
|
||||
long ret = syscall(__NR_clock_gettime, ckid, ts);
|
||||
if (ret == 0)
|
||||
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], ts) -> {%lld, %ld}\n", where, ckid, (long long)ts->tv_sec, ts->tv_nsec);
|
||||
else
|
||||
printf("[%s] syscall(__NR_gettime, CLOCK_REALTIME[%d], ts) returned non-zero (%ld)\n", where, ckid, ret);
|
||||
|
||||
1
test/snippets/syscall_clock_gettime_heap.variable
Normal file
1
test/snippets/syscall_clock_gettime_heap.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME 2020-02-02 02:02:02+00:00
|
||||
2
test/snippets/time.c
Normal file
2
test/snippets/time.c
Normal file
@@ -0,0 +1,2 @@
|
||||
time_t t = time(NULL);
|
||||
printf("[%s] time() yielded %zd\n", where, t);
|
||||
1
test/snippets/time.variable
Normal file
1
test/snippets/time.variable
Normal file
@@ -0,0 +1 @@
|
||||
FAKETIME 2020-02-02 02:02:02+00:00
|
||||
36
test/test.sh
36
test/test.sh
@@ -1,14 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
|
||||
|
||||
if [ -f /etc/faketimerc ] ; then
|
||||
echo "Running the test program with your system-wide default in /etc/faketimerc"
|
||||
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 ./timetest"
|
||||
LD_PRELOAD=../src/libfaketime.so.1 ./timetest
|
||||
echo "\$ LD_PRELOAD=$FTPL ./timetest"
|
||||
LD_PRELOAD="$FTPL" ./timetest
|
||||
echo
|
||||
else
|
||||
echo "Running the test program with no faked time specified"
|
||||
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 ./timetest"
|
||||
LD_PRELOAD=../src/libfaketime.so.1 ./timetest
|
||||
echo "\$ LD_PRELOAD=$FTPL ./timetest"
|
||||
LD_PRELOAD="$FTPL" ./timetest
|
||||
echo
|
||||
fi
|
||||
|
||||
@@ -16,48 +18,48 @@ echo "==========================================================================
|
||||
echo
|
||||
|
||||
echo "Running the test program with absolute date 2003-01-01 10:00:05 specified"
|
||||
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"2003-01-01 10:00:05\" ./timetest"
|
||||
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="2003-01-01 10:00:05" ./timetest
|
||||
echo "\$ LD_PRELOAD=$FTPL FAKETIME=\"2003-01-01 10:00:05\" ./timetest"
|
||||
LD_PRELOAD="$FTPL" FAKETIME="2003-01-01 10:00:05" ./timetest
|
||||
echo
|
||||
|
||||
echo "============================================================================="
|
||||
echo
|
||||
|
||||
echo "Running the test program with START date @2005-03-29 14:14:14 specified"
|
||||
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"@2005-03-29 14:14:14\" ./timetest"
|
||||
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="@2005-03-29 14:14:14" ./timetest
|
||||
echo "\$ LD_PRELOAD=$FTPL FAKETIME=\"@2005-03-29 14:14:14\" ./timetest"
|
||||
LD_PRELOAD="$FTPL" FAKETIME="@2005-03-29 14:14:14" ./timetest
|
||||
echo
|
||||
|
||||
echo "============================================================================="
|
||||
echo
|
||||
|
||||
echo "Running the test program with 10 days negative offset specified"
|
||||
echo "LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"-10d\" ./timetest"
|
||||
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="-10d" ./timetest
|
||||
echo "LD_PRELOAD=$FTPL FAKETIME=\"-10d\" ./timetest"
|
||||
LD_PRELOAD="$FTPL" FAKETIME="-10d" ./timetest
|
||||
echo
|
||||
|
||||
echo "============================================================================="
|
||||
echo
|
||||
|
||||
echo "Running the test program with 10 days negative offset specified, and FAKE_STAT disabled"
|
||||
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"-10d\" NO_FAKE_STAT=1 ./timetest"
|
||||
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="-10d" NO_FAKE_STAT=1 ./timetest
|
||||
echo "\$ LD_PRELOAD=$FTPL FAKETIME=\"-10d\" NO_FAKE_STAT=1 ./timetest"
|
||||
LD_PRELOAD="$FTPL" FAKETIME="-10d" NO_FAKE_STAT=1 ./timetest
|
||||
echo
|
||||
|
||||
echo "============================================================================="
|
||||
echo
|
||||
|
||||
echo "Running the test program with 10 days postive offset specified, and sped up 2 times"
|
||||
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"+10d x2\" ./timetest"
|
||||
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="+10d x2" NO_FAKE_STAT=1 ./timetest
|
||||
echo "Running the test program with 10 days positive offset specified, and speed-up factor"
|
||||
echo "\$ LD_PRELOAD=$FTPL FAKETIME=\"+10d x1\" ./timetest"
|
||||
LD_PRELOAD="$FTPL" FAKETIME="+10d x1" NO_FAKE_STAT=1 ./timetest
|
||||
echo
|
||||
|
||||
echo "============================================================================="
|
||||
echo
|
||||
|
||||
echo "Running the 'date' command with 15 days negative offset specified"
|
||||
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"-15d\" date"
|
||||
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="-15d" date
|
||||
echo "\$ LD_PRELOAD=$FTPL FAKETIME=\"-15d\" date"
|
||||
LD_PRELOAD="$FTPL" FAKETIME="-15d" date
|
||||
echo
|
||||
|
||||
echo "============================================================================="
|
||||
|
||||
@@ -28,19 +28,25 @@ echo "FAKETIME=\"-10d\" ./timetest"
|
||||
FAKETIME="-10d" ./timetest
|
||||
echo
|
||||
|
||||
echo "Running the test program with 10 days negative offset specified, and FAKE_STAT disabled"
|
||||
echo "FAKETIME=\"-10d\" NO_FAKE_STAT=1 ./timetest"
|
||||
FAKETIME="-10d" NO_FAKE_STAT=1 ./timetest
|
||||
echo
|
||||
# FAKE_STAT is disabled on macOS by default, so testing NO_FAKE_STAT is not useful
|
||||
#echo "Running the test program with 10 days negative offset specified, and FAKE_STAT disabled"
|
||||
#echo "FAKETIME=\"-10d\" NO_FAKE_STAT=1 ./timetest"
|
||||
#FAKETIME="-10d" NO_FAKE_STAT=1 ./timetest
|
||||
#echo
|
||||
|
||||
echo "Running the test program with 10 days postive offset specified, and sped up 2 times"
|
||||
echo "Running the test program with 10 days positive offset specified, and sped up 2 times"
|
||||
echo "FAKETIME=\"+10d x2\" ./timetest"
|
||||
FAKETIME="+10d x2" NO_FAKE_STAT=1 ./timetest
|
||||
echo
|
||||
|
||||
echo "Running the 'date' command with 15 days negative offset specified"
|
||||
echo "FAKETIME=\"-15d\" date"
|
||||
FAKETIME="-15d" date
|
||||
echo
|
||||
# On more recent macOS versions, the following won't work without copying gdate
|
||||
# to a different folder beforehand. We don't do that here, and since the output
|
||||
# of these tests must be reviewed manually anyway, the timetest binary should be
|
||||
# sufficient to determine whether everything works as planned.
|
||||
|
||||
#echo "Running the 'date' command with 15 days negative offset specified"
|
||||
#echo "FAKETIME=\"-15d\" date"
|
||||
#FAKETIME="-15d" date
|
||||
#echo
|
||||
|
||||
exit 0
|
||||
|
||||
10
test/test_constructors.sh
Executable file
10
test/test_constructors.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
|
||||
|
||||
function="$1"
|
||||
|
||||
printf 'Testing library init for %s (no LD_PRELOAD)\n' "$function"
|
||||
LD_LIBRARY_PATH=. "./use_lib_$function"
|
||||
printf 'Testing library init for %s (LD_PRELOAD)\n' "$function"
|
||||
LD_LIBRARY_PATH=. LD_PRELOAD="$FTPL" "./use_lib_$function"
|
||||
54
test/test_variable_data.sh
Executable file
54
test/test_variable_data.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
|
||||
DELAY="${DELAY:-2}"
|
||||
|
||||
declare -A firstunset first second delayed delayedunset
|
||||
|
||||
err=0
|
||||
for func in "$@"; do
|
||||
if ! [ -x "./run_$func" ]; then
|
||||
printf >&2 '%s does not exist, failing\n' "./run_$func"
|
||||
exit 1
|
||||
fi
|
||||
read varname value < "snippets/$func.variable"
|
||||
unset $varname
|
||||
firstunset[$func]="$(env LD_PRELOAD="$FTPL" "./run_$func")"
|
||||
first[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
|
||||
second[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
|
||||
if [ "${first[$func]}" != "${second[$func]}" ]; then
|
||||
printf >&2 '[%s] Set %s="%s", but got two different outputs:\n - %s\n - %s\n' "$func" "$varname" "$value" "${first[$func]}" "${second[$func]}"
|
||||
err=$(( $err + 1 ))
|
||||
fi
|
||||
if [ "${first[$func]}" == "${firstunset[$func]}" ]; then
|
||||
printf >&2 '[%s] Same answer when %s="%s" and when unset:\n - set: %s\n - unset: %s\n' "$func" "$varname" "$value" "${first[$func]}" "${firstunset[$func]}"
|
||||
err=$(( $err + 1 ))
|
||||
fi
|
||||
done
|
||||
|
||||
printf "Sleeping %d seconds..." "$DELAY"
|
||||
sleep "$DELAY"
|
||||
printf 'done\n'
|
||||
|
||||
for func in "$@"; do
|
||||
read varname value < "snippets/$func.variable"
|
||||
unset $varname
|
||||
delayed[$func]="$(env LD_PRELOAD="$FTPL" "$varname=$value" "./run_$func")"
|
||||
delayedunset[$func]="$(LD_PRELOAD="$FTPL" "./run_$func")"
|
||||
if [ "${first[$func]}" != "${delayed[$func]}" ]; then
|
||||
printf >&2 '[%s] Vary across delay of %d seconds (%s="%s"):\n - before: %s\n - after: %s\n' "$func" "$DELAY" "$varname" "$value" "${first[$func]}" "${delayed[$func]}"
|
||||
err=$(( $err + 1 ))
|
||||
fi
|
||||
if [ "${firstunset[$func]}" == "${delayedunset[$func]}" ]; then
|
||||
printf >&2 '[%s] Same answer when unset across delay of %d seconds:\n - before: %s\n - after: %s\n' "$func" "$DELAY" "${firstunset[$func]}" "${delayedunset[$func]}"
|
||||
err=$(( $err + 1 ))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$err" -gt 0 ]; then
|
||||
printf >&2 'Got %d errors, failing\n' "$err"
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
160
test/timetest.c
160
test/timetest.c
@@ -18,23 +18,32 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
#ifndef __APPLE__
|
||||
#ifdef FAKE_STAT
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define VERBOSE 0
|
||||
|
||||
#define SIG SIGUSR1
|
||||
|
||||
static void
|
||||
handler(int sig, siginfo_t *si, void *uc)
|
||||
{
|
||||
@@ -46,12 +55,71 @@ handler(int sig, siginfo_t *si, void *uc)
|
||||
{
|
||||
printf("Caught signal %d\n", sig);
|
||||
}
|
||||
signal(sig, SIG_IGN);
|
||||
}
|
||||
|
||||
void* pthread_test(void* args)
|
||||
{
|
||||
pthread_mutex_t fakeMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
pthread_cond_t monotonic_cond;
|
||||
pthread_condattr_t attr;
|
||||
|
||||
struct timespec timeToWait, now;
|
||||
int rt;
|
||||
|
||||
args = args; // silence compiler warning about unused argument
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
timeToWait.tv_sec = now.tv_sec+1;
|
||||
timeToWait.tv_nsec = now.tv_nsec;
|
||||
|
||||
printf("pthread_cond_timedwait: CLOCK_REALTIME test\n");
|
||||
printf("(Intentionally sleeping 1 second...)\n");
|
||||
fflush(stdout);
|
||||
|
||||
pthread_mutex_lock(&fakeMutex);
|
||||
rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait);
|
||||
if (rt != ETIMEDOUT)
|
||||
{
|
||||
printf("pthread_cond_timedwait failed\n");
|
||||
pthread_mutex_unlock(&fakeMutex);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pthread_mutex_unlock(&fakeMutex);
|
||||
|
||||
|
||||
pthread_condattr_init(&attr);
|
||||
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
||||
pthread_cond_init(&monotonic_cond, &attr);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
timeToWait.tv_sec = now.tv_sec+1;
|
||||
timeToWait.tv_nsec = now.tv_nsec;
|
||||
|
||||
printf("pthread_cond_timedwait: CLOCK_MONOTONIC test\n");
|
||||
printf("(Intentionally sleeping 1 second..., see docs about CLOCK_MONOTONIC test)\n");
|
||||
fflush(stdout);
|
||||
|
||||
pthread_mutex_lock(&fakeMutex);
|
||||
rt = pthread_cond_timedwait(&monotonic_cond, &fakeMutex, &timeToWait);
|
||||
if (rt != ETIMEDOUT)
|
||||
{
|
||||
printf("pthread_cond_timedwait failed\n");
|
||||
pthread_mutex_unlock(&fakeMutex);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pthread_mutex_unlock(&fakeMutex);
|
||||
|
||||
pthread_cond_destroy(&monotonic_cond);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
time_t now;
|
||||
struct timeb tb;
|
||||
struct timeval tv;
|
||||
@@ -63,33 +131,47 @@ int main (int argc, char **argv) {
|
||||
sigset_t mask;
|
||||
struct sigaction sa;
|
||||
#endif
|
||||
#ifndef __APPLE__
|
||||
#ifdef FAKE_STAT
|
||||
struct stat buf;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* silence compiler warnings */
|
||||
printf("%s", 0 == 1 ? argv[0] : "");
|
||||
|
||||
#ifndef __APPLE__
|
||||
pthread_t thread;
|
||||
void *ret;
|
||||
|
||||
pthread_create(&thread, NULL, pthread_test, NULL);
|
||||
pthread_join(thread, &ret);
|
||||
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
if (sigaction(SIGRTMIN, &sa, NULL) == -1) {
|
||||
if (sigaction(SIGUSR1, &sa, NULL) == -1)
|
||||
{
|
||||
perror("sigaction");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* Block timer signal temporarily */
|
||||
|
||||
printf("Blocking signal %d\n", SIGRTMIN);
|
||||
/* Block timer signal temporarily */
|
||||
printf("Blocking signal %d\n", SIGUSR1);
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGRTMIN);
|
||||
if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) {
|
||||
sigaddset(&mask, SIGUSR1);
|
||||
if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
|
||||
{
|
||||
perror("sigaction");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the timer */
|
||||
sev.sigev_notify = SIGEV_SIGNAL;
|
||||
sev.sigev_signo = SIGRTMIN;
|
||||
sev.sigev_signo = SIGUSR1;
|
||||
sev.sigev_value.sival_ptr = &timerid1;
|
||||
if (timer_create(CLOCK_REALTIME, &sev, &timerid1) == -1) {
|
||||
if (timer_create(CLOCK_REALTIME, &sev, &timerid1) == -1)
|
||||
{
|
||||
perror("timer_create");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -103,13 +185,15 @@ int main (int argc, char **argv) {
|
||||
its.it_interval.tv_sec = 0;
|
||||
its.it_interval.tv_nsec = 300000000;
|
||||
|
||||
if (timer_settime(timerid1, 0, &its, NULL) == -1) {
|
||||
if (timer_settime(timerid1, 0, &its, NULL) == -1)
|
||||
{
|
||||
perror("timer_settime");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sev.sigev_value.sival_ptr = &timerid2;
|
||||
if (timer_create(CLOCK_REALTIME, &sev, &timerid2) == -1) {
|
||||
if (timer_create(CLOCK_REALTIME, &sev, &timerid2) == -1)
|
||||
{
|
||||
perror("timer_create");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -123,7 +207,8 @@ int main (int argc, char **argv) {
|
||||
its.it_interval.tv_sec = 0;
|
||||
its.it_interval.tv_nsec = 0;
|
||||
|
||||
if (timer_settime(timerid2, TIMER_ABSTIME, &its, NULL) == -1) {
|
||||
if (timer_settime(timerid2, TIMER_ABSTIME, &its, NULL) == -1)
|
||||
{
|
||||
perror("timer_settime");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -133,7 +218,10 @@ int main (int argc, char **argv) {
|
||||
printf("time() : Current date and time: %s", ctime(&now));
|
||||
printf("time(NULL) : Seconds since Epoch : %u\n", (unsigned int)time(NULL));
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
ftime(&tb);
|
||||
#pragma GCC diagnostic pop
|
||||
printf("ftime() : Current date and time: %s", ctime(&tb.time));
|
||||
|
||||
printf("(Intentionally sleeping 2 seconds...)\n");
|
||||
@@ -148,7 +236,8 @@ int main (int argc, char **argv) {
|
||||
printf("gettimeofday() : Current date and time: %s", ctime(&tv.tv_sec));
|
||||
|
||||
#ifndef __APPLE__
|
||||
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) {
|
||||
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
|
||||
{
|
||||
perror("sigprocmask");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -157,34 +246,59 @@ int main (int argc, char **argv) {
|
||||
printf("clock_gettime(): Current date and time: %s", ctime(&ts.tv_sec));
|
||||
|
||||
int timer_getoverrun_timerid1 = timer_getoverrun(timerid1);
|
||||
if (timer_getoverrun_timerid1 != 3) {
|
||||
if (timer_getoverrun_timerid1 != 3)
|
||||
{
|
||||
#ifdef __GNU__
|
||||
printf("(Timer overruns are assumed to be fine on Hurd)\n");
|
||||
#else
|
||||
printf("timer_getoverrun(timerid1) FAILED, must be 3 but got: %d\n", timer_getoverrun_timerid1);
|
||||
#endif
|
||||
}
|
||||
|
||||
timer_gettime(timerid1, &its);
|
||||
if (VERBOSE == 1) {
|
||||
if (VERBOSE == 1)
|
||||
{
|
||||
printf("timer_gettime(timerid1, &its); its = {{%ld, %ld}, {%ld, %ld}}}\n",
|
||||
its.it_interval.tv_sec, its.it_interval.tv_nsec,
|
||||
its.it_value.tv_sec, its.it_value.tv_nsec);
|
||||
(long)its.it_interval.tv_sec, (long)its.it_interval.tv_nsec,
|
||||
(long)its.it_value.tv_sec, (long)its.it_value.tv_nsec);
|
||||
}
|
||||
|
||||
int timer_getoverrun_timerid2 = timer_getoverrun(timerid2);
|
||||
if (timer_getoverrun_timerid2 != 0) {
|
||||
if (timer_getoverrun_timerid2 != 0)
|
||||
{
|
||||
printf("timer_getoverrun(timerid2) FAILED, must be 0 but got: %d\n", timer_getoverrun_timerid2);
|
||||
}
|
||||
|
||||
timer_gettime(timerid2, &its);
|
||||
if (VERBOSE == 1) {
|
||||
if (VERBOSE == 1)
|
||||
{
|
||||
printf("timer_gettime(timerid2, &its); its = {{%ld, %ld}, {%ld, %ld}}}\n",
|
||||
its.it_interval.tv_sec, its.it_interval.tv_nsec,
|
||||
its.it_value.tv_sec, its.it_value.tv_nsec);
|
||||
(long)its.it_interval.tv_sec, (long)its.it_interval.tv_nsec,
|
||||
(long)its.it_value.tv_sec, (long)its.it_value.tv_nsec);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
#ifdef FAKE_STAT
|
||||
lstat(argv[0], &buf);
|
||||
printf("stat(): mod. time of file '%s': %s", argv[0], ctime(&buf.st_mtime));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 2
|
||||
* tab-width: 2
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=2 tabstop=2 expandtab:
|
||||
* :indentSize=2:tabSize=2:noTabs=true:
|
||||
*/
|
||||
|
||||
/* eof */
|
||||
|
||||
46
test/variadic/inner.c
Normal file
46
test/variadic/inner.c
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* round 0: c, s, wc, i, wi */
|
||||
long inner0(char *out, ...) {
|
||||
char c = 0;
|
||||
short s = 0;
|
||||
wchar_t wc = 0;
|
||||
int i = 0;
|
||||
wint_t wi = 0;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, out);
|
||||
c = va_arg(ap, int);
|
||||
s = va_arg(ap, int);
|
||||
wc = va_arg(ap, typeof(wc));
|
||||
i = va_arg(ap, typeof(i));
|
||||
wi = va_arg(ap, typeof(wi));
|
||||
va_end(ap);
|
||||
|
||||
int ret = sprintf(out, "c: 0x%x s: 0x%x wc: 0x%lx i: 0x%x wi: 0x%x\n", c, s, (long)wc, i, wi);
|
||||
return ret;
|
||||
}
|
||||
/* round 1: l, ll, ptr, pd, sz */
|
||||
long inner1(char *out, ...) {
|
||||
long l = 0;
|
||||
long long ll = 0;
|
||||
void *ptr = NULL;
|
||||
ptrdiff_t pd = 0;
|
||||
size_t sz = 0;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, out);
|
||||
l = va_arg(ap, typeof(l));
|
||||
ll = va_arg(ap, typeof(ll));
|
||||
ptr = va_arg(ap, typeof(ptr));
|
||||
pd = va_arg(ap, typeof(pd));
|
||||
sz = va_arg(ap, typeof(sz));
|
||||
va_end(ap);
|
||||
|
||||
int ret = sprintf(out, "l: 0x%lx ll: 0x%llx ptr: %p pd: 0x%tx sz: 0x%zx\n", l, ll, ptr, pd, sz);
|
||||
return ret;
|
||||
}
|
||||
70
test/variadic/main.c
Normal file
70
test/variadic/main.c
Normal file
@@ -0,0 +1,70 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <wchar.h>
|
||||
|
||||
extern long outer(long num, char *out, ...);
|
||||
extern long inner0(char *out, ...);
|
||||
extern long inner1(char *out, ...);
|
||||
|
||||
#define bufsize 2048
|
||||
|
||||
static int compare_buffers(int round,
|
||||
long ret_outer, long ret_inner,
|
||||
const char* outer, const char* inner) {
|
||||
int ret = 0;
|
||||
if (ret_outer != ret_inner) {
|
||||
printf("Round %d: return values differ (outer: %ld inner: %ld)\n", round, ret_outer, ret_inner);
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(outer, inner, bufsize)) {
|
||||
printf("Round %d strings differ:\n - outer: %s\n - inner: %s\n", round, outer, inner);
|
||||
ret++;
|
||||
}
|
||||
if (ret == 0)
|
||||
printf("Round %d success: %s\n", round, outer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main() {
|
||||
/* sizes of intrinsic types as reported by echo | cpp -dM | grep
|
||||
SIZEOF, pruned to avoid floating point types. Should work with
|
||||
both clang and gcc, not sure about other C preprocessors.
|
||||
|
||||
Note that we set bits in every high octet and every low octet to
|
||||
see that they end up in the right spot.
|
||||
*/
|
||||
char c = 0x03L;
|
||||
short s = (0x04L << ((__SIZEOF_SHORT__ - 1) * 8)) + 0xff;
|
||||
wchar_t wc = (0x05L << ((__SIZEOF_WCHAR_T__ - 1) * 8)) + 0xfe;
|
||||
int i = (0x06L << ((__SIZEOF_INT__ - 1) * 8)) + 0xfd;
|
||||
wint_t wi = (0x07L << ((__SIZEOF_WINT_T__ - 1) * 8)) + 0xfc;
|
||||
long l = (0x08L << ((__SIZEOF_LONG__ - 1) * 8) ) + 0xfb;
|
||||
long long ll = (0x09LL << ((__SIZEOF_LONG_LONG__ - 1) * 8)) + 0xfa;
|
||||
void *ptr = (void*)((0x0aL << ((__SIZEOF_POINTER__ - 1) * 8)) + 0xf9);
|
||||
ptrdiff_t pd = (0x0bL << ((__SIZEOF_PTRDIFF_T__ -1) * 8)) + 0xf9;
|
||||
size_t sz = (0x0cL << ((__SIZEOF_SIZE_T__ - 1) * 8)) + 0xf8;
|
||||
|
||||
char *buf[2];
|
||||
for (int j = 0; j < 2; j++)
|
||||
buf[j] = malloc(bufsize);
|
||||
|
||||
int ret[2];
|
||||
int errors = 0;
|
||||
|
||||
#define reset_buffers(n) for (int j = 0; j < 2; j++) memset(buf[j], n, bufsize)
|
||||
#define check_buffers(n) errors += compare_buffers(n, ret[0], ret[1], buf[0], buf[1])
|
||||
|
||||
reset_buffers(0);
|
||||
ret[0] = outer(0, buf[0], c, s, wc, i, wi);
|
||||
ret[1] = inner0(buf[1], c, s, wc, i, wi);
|
||||
check_buffers(0);
|
||||
|
||||
reset_buffers(1);
|
||||
ret[0] = outer(1, buf[0], l, ll, ptr, pd, sz);
|
||||
ret[1] = inner1(buf[1], l, ll, ptr, pd, sz);
|
||||
check_buffers(1);
|
||||
|
||||
return (int)errors;
|
||||
}
|
||||
21
test/variadic/outer.c
Normal file
21
test/variadic/outer.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include "../../src/faketime_common.h"
|
||||
|
||||
extern long inner0(char *out, ...);
|
||||
extern long inner1(char *out, ...);
|
||||
|
||||
long outer(long num, char *out, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, out);
|
||||
variadic_promotion_t a[syscall_max_args];
|
||||
for (int i = 0; i < syscall_max_args; i++)
|
||||
a[i] = va_arg(ap, variadic_promotion_t);
|
||||
va_end(ap);
|
||||
|
||||
if (num == 0)
|
||||
return inner0(out, a[0], a[1], a[2], a[3], a[4], a[5]);
|
||||
if (num == 1)
|
||||
return inner1(out, a[0], a[1], a[2], a[3], a[4], a[5]);
|
||||
else return -1;
|
||||
}
|
||||
Reference in New Issue
Block a user