506 Commits

Author SHA1 Message Date
Wolfgang Hommel
2ba77bd61b Merge pull request #540 from AbhiTheModder/android
Add Android compatibility
2026-05-03 14:15:25 +02:00
Abhi
e36ec5726e Add Android compatibility
Adds support for both cross-compilation & native compilation (on Termux)
2026-05-02 18:41:32 +05:30
Wolfgang Hommel
37c9430117 Merge pull request #537 from aquilamacedo/follow-up-535
follow-up to #535: Fix the actual dpkg-source failure path
2026-03-30 19:38:19 +02:00
Aquila Macedo
4aa0077bfc Add regression coverage for utime and utimes "now" handling
Extend timetest to exercise utime(path, NULL) and utimes(path, NULL), so
the older file timestamp wrappers are covered alongside the existing
utimensat()/futimens() "set to now" checks.
2026-03-30 10:42:47 -03:00
Aquila Macedo
097ce79771 Fix fake "now" handling for utime and utimes
Resolve utime(..., NULL) and utimes(..., NULL) through the current fake
CLOCK_REALTIME instead of deriving "now" from local timeval state.

This matches the real dpkg-source failure mode seen under
FAKETIME='@2037-01-01 00:00:00', where touching .pc/applied-patches
ended up reaching utimensat() with an invalid explicit timespec and
failing with EINVAL.

Follow-up to #535
2026-03-30 10:42:17 -03:00
Wolfgang Hommel
994b7c75ca Merge pull request #536 from aquilamacedo/fix-535-issue-einval-under-start-at
Fix utimensat/futimens fake "now" handling in start-at mode
2026-03-28 11:05:23 +01:00
Aquila Macedo
483a7a703c Add regression test for utimensat/futimens now handling
Exercise the NULL and UTIME_NOW timestamp paths in timetest so the
file-timestamp "set to now" case is covered by the test suite.
2026-03-27 19:23:49 -03:00
Aquila Macedo
e8a1c1fd3b Fix utimensat/futimens handling of fake "now"
Use fake_clock_gettime(CLOCK_REALTIME) to resolve NULL/UTIME_NOW
timestamps instead of reconstructing them from user_offset. This
avoids invalid timestamp handling in start-at faketime mode, where
"now" is derived from the configured base time plus elapsed real time.

Closes: #535
2026-03-27 19:23:35 -03:00
Wolfgang Hommel
75d91ea726 Merge pull request #533 from GeneralDisarray/implement-faketime-follow-absolute
Implement FAKETIME_FOLLOW_ABSOLUTE feature
2026-02-18 07:49:19 +01:00
Mike Rushe
6c7aa3966c Implement FAKETIME_FOLLOW_ABSOLUTE feature
See README for feature intent.
Simple regression test at test_follow_absolute.sh.
2026-02-17 12:17:48 -05:00
Wolfgang Hommel
3062fb2004 Merge pull request #530 from drolevar/fix_master
Fix several multi-arch-related issues
2026-02-01 12:17:06 +01:00
Andrij Abyzov
b687b165b2 Replace POSIX semaphore with flock() for cross-arch safety
POSIX named semaphores (sem_t) have architecture-dependent internal
layout in glibc: 32 bytes on 64-bit, 16 bytes on 32-bit. When a
64-bit faketime wrapper creates a semaphore and spawns a 32-bit child,
the child misinterprets the counter and hangs on sem_wait forever.

Extract ft_sem_* abstraction into shared ft_sem.h/ft_sem.c with three
backends: FT_POSIX (existing), FT_SYSV (existing), FT_FLOCK (new
default). The flock backend uses kernel-mediated file locking on
/dev/shm/faketime_lock_<pid>, which is architecture-independent and
auto-releases on process death.

Both libfaketime.so and the faketime wrapper now use the same shared
abstraction, ensuring protocol agreement regardless of backend.
2026-01-26 14:43:43 +01:00
Andrij Abyzov
e21bf3017a Fix cross-arch shared memory struct layout and ftruncate/munmap sizes
Replace struct timespec (arch-dependent long/time_t) with fixed-width
int64_t pairs in ft_shared_s so that 32-bit and 64-bit processes
interpret the same shared memory layout identically.

Fix ftruncate calls that allocated sizeof(uint64_t) (8 bytes) instead
of sizeof(struct ft_shared_s) (64-80 bytes) for the shared memory
region. Fix munmap in ft_cleanup using the wrong size.

Add struct layout test and cross-process shared memory functional test.
2026-01-26 13:31:55 +01:00
Wolfgang Hommel
13d47210d5 Merge pull request #528 from ppisar/gcc16
tests: Silence an unused-but-set-variable warning with GCC 16
2026-01-06 20:20:46 +01:00
Petr Písař
712733e5f0 tests: Silence an unused-but-set-variable warning with GCC 16
Compiling tests with GCC 16 results into this warning:

    gcc -shared -o libmallocintercept.so -fpic -std=gnu99 -Wall -DFAKE_STAT -Werror -Wextra  -U_FILE_OFFSET_BITS -U_TIME_BITS libmallocintercept.c
    libmallocintercept.c: In function ‘free’:
    libmallocintercept.c:79:12: error: variable ‘ptr2’ set but not used [-Werror=unused-but-set-variable=]
       79 |   long int ptr2 = (long int) ptr; ptr2 -= (long int) ptr;
	  |            ^~~~
    cc1: all warnings being treated as errors

The ptr2 variable was added in the past to silence compiler warnings,
probably for the very same reason (commits
75cbe8e507 and
2bfbe19f71). GCC 16 is smarter and
discovers that the ptr2 variables is not needed.

This patch changes the work around to "(void) unused_variable;" idiom
recommended by GCC manual and already used in print_msg().
2026-01-06 10:34:39 +01:00
Wolfgang Hommel
1e931cb4cd Merge pull request #527 from totoroyyb/master
fix: broken futex syscall when FUTEX_WAIT is used
2025-12-23 11:22:48 +01:00
Yibo Yan
026a2627af nits: remove warnings 2025-12-23 02:48:55 +00:00
Yibo Yan
7295f20288 mod: better error handling for edge cases 2025-12-23 01:26:35 +00:00
Yibo Yan
92bf909d95 fix: broken futex syscall when FUTEX_WAIT is used 2025-12-22 12:23:01 +00:00
Wolfgang Hommel
ebe76e26b0 Merge pull request #526 from rgacogne/fix-preload-hang-521
Fix: Better detection of recursive initialisation problems
2025-12-19 06:20:21 +01:00
Remi Gacogne
c0aa6189f7 Refactor ft_shm_init and ftpl_init to remove duplication
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
2025-12-16 16:30:25 +01:00
Remi Gacogne
7ba95f4cb0 Fix: Better detection of recursive initialisation problems
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
2025-12-16 11:50:40 +01:00
Wolfgang Hommel
aabe141783 Merge pull request #525 from TomasKorbar/master
Add const qualifiers to fix build with ISO C23
2025-12-15 12:51:49 +01:00
Tomas Korbar
dbe865dfdb Add const qualifiers to fix build with ISO C23
Fix https://github.com/wolfcw/libfaketime/issues/524
2025-12-15 11:03:21 +01:00
Wolfgang Hommel
1231a002e0 Merge pull request #522 from rbalint/fake-syscall-clock-nanosleep
Fake the clock_nanosleep syscall
2025-11-09 10:02:16 +01:00
Balint Reczey
3109728f45 Fake the clock_nanosleep syscall 2025-11-08 17:28:48 +01:00
Wolfgang Hommel
949b36e6a2 Merge pull request #519 from bjornfor/fix-semaphore-deletion
Only let the owner clean up semaphore and shared memory
2025-09-29 20:41:22 +02:00
Bjørn Forsman
0c76f27777 Only let the owner clean up semaphore and shared memory
I noticed a bug in the semaphore handling, when using the System V semaphore
backend:

  $ LD_PRELOAD=./src/libfaketime.so.1 bash -c "echo foo | sed s/foo/bar/"
  libfaketime: In lock_for_stat(), ft_sem_lock failed: Invalid argument
  [...exited with error...]

(Beware, the above command-line is not 100% deterministic; sometimes it
succeeds.)

Looking at the strace for the above command-line, it seems the bash echo
builtin process (or thread?) decides to remove the semaphore upon
exiting, while it's still in use by the sed process. sed then gets
EINVAL error ("Invalid argument") on its next semop call.

The root cause is a semantic difference between POSIX sem_unlink and
SysV semop(..., IPC_RMID), the two implementations for ft_sem_unlink:

* sem_unlink allows the semaphore to be used afterwards, as long as a
  process has a reference to the semaphore.
* semop(..., IPC_RMID) removes the semaphore immediately, and further
  use results in EINVAL error.

AFAICT, the simplest fix is to only let the owner of the semaphore (and
shared memory) do the clean up, which is what this patch does. Both
semaphore backends pass the tests with this change.
2025-09-29 13:41:57 +02:00
Wolfgang Hommel
7bfe6566b3 Merge pull request #516 from bjornfor/fix-dangling-pointer
Fix dangling pointer via ft_sem_t name field
2025-09-27 11:47:48 +02:00
Wolfgang Hommel
c2a9bc1878 Merge pull request #517 from bjornfor/portable-shebang
Use portable shebang
2025-09-27 11:47:19 +02:00
Bjørn Forsman
4d0f0b7426 doc: refer to commands by name, not absolute path
For simplicity and portability.

I left some instances in README.OSX as is, because I'm worried about
invalidating the docs.
2025-09-24 15:06:44 +02:00
Bjørn Forsman
9d63a80062 tests: replace /bin/bash with bash
For portability.
2025-09-24 15:03:34 +02:00
Bjørn Forsman
cccce3bf23 Replace #!/bin/bash shebangs with #!/usr/bin/env bash
For portability. E.g. /bin/bash doesn't exist on NixOS.
2025-09-24 15:02:44 +02:00
Bjørn Forsman
f33dda8022 Fix dangling pointer via ft_sem_t name field
ft_sem_create() is called with an argument located on the stack, which
means it's a bad idea to keep a reference to it in the 'name' field of
ft_sem_t -- the pointed to data goes out of scope and results in
unpredictable behaviour.

Fix it by making a copy of the semaphore name. Allocate a 256 char
buffer, to match existing code.

Fixes: 2649cdb156 ("Add semaphore abstraction layer")
2025-09-24 14:55:15 +02:00
Wolfgang Hommel
4fc06b90df Merge pull request #512 from sammytranGeo/correct-use-of-real-monotonic-clock
Use real clock monotonic when not faking
2025-08-23 19:33:26 +02:00
Sammy Tran
75e130c4f1 Use real clock monotonic when not faking 2025-08-13 15:15:12 -04:00
Wolfgang Hommel
066f38baac Merge pull request #510 from bjornfor/fix-musl-build
Only define stat64 when building with glibc
2025-08-07 13:14:29 +02:00
Bjørn Forsman
4de86c2145 Only define stat64 when building with glibc
musl defines stat64 as stat, leading to this build error:

  gcc -o libfaketime.o -c -std=gnu99 -Wall -Wextra -Werror -DFAKE_PTHREAD -DFAKE_STAT -DFAKE_UTIME -DFAKE_SLEEP -DFAKE_TIMERS -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'/nix/store/qpyvvrcas950da98mssw6ixlw7ckvyrb-libfaketime-0.9.11'"' -DLIBDIRNAME='"'/lib'"'  -Wno-nonnull-compare   libfaketime.c
  In file included from libfaketime.c:55:
  libfaketime.c:1276:5: error: redefinition of ‘stat’
   1276 | int stat64 (const char *path, struct stat64 *buf)
        |     ^~~~~~
  /nix/store/g9cgi4yyn5vrd1f9axj8gxdvwzv5ssvk-musl-1.2.5-dev/include/sys/stat.h:80:5: note: previous definition of ‘stat’ with type ‘int(const char *, struct stat *)’
     80 | int stat(const char *__restrict, struct stat *__restrict);
        |     ^~~~
  make[1]: *** [Makefile:161: libfaketime.o] Error 1

Fix it by only defining stat64 when building against glibc, since it's
not straight forward to detect musl, and it's the safest approach; there
might be other libc implementations that behave like musl.

Fixes: 53ba71e547 ("Handle stat64() call")
2025-08-07 09:19:13 +02:00
Wolfgang Hommel
ffdb51bc30 Merge pull request #507 from bjornfor/add-stat64
Handle stat64() call
2025-08-05 20:51:42 +02:00
Wolfgang Hommel
3aa2028174 Merge pull request #509 from lisanet/master
fixes issue #506 - build arch64 and arch64e separately
2025-08-03 14:27:27 +02:00
Simone Karin Lehmann
6566162e7e fix for issue #506 - build arch64 and arch64e separately and then lipo them. 2025-08-03 13:48:41 +02:00
Bjørn Forsman
53ba71e547 Handle stat64() call
This fixes missing modification of timestamps in stat() calls for
programs built with large file support (-D_FILE_OFFSET_BITS=64), both
32- and 64-bit.

Demo code:

  $ cat <<EOF >test.c
  #include <sys/stat.h>
  int main()
  {
      struct stat buf;
      return stat("/", &buf);
  }
  EOF

32-bit build:

  $ nix-shell -p gcc --argstr system i686-linux

  nix-shell$ gcc test.c && ltrace ./a.out
  __libc_start_main([ "./a.out" ] <unfinished ...>
  stat(0x804a008, 0xffa4b644, 895, 0) = 0
  +++ exited (status 0) +++

  nix-shell$ gcc -D_FILE_OFFSET_BITS=64 test.c && ltrace ./a.out
  __libc_start_main([ "./a.out" ] <unfinished ...>
  stat64(0x804a008, 0xffdcf61c, 100, 0xffdcfaeb) = 0
  +++ exited (status 0) +++

  nix-shell$ file a.out
  a.out: ELF 32-bit LSB executable, Intel 80386, [...]

64-bit build:

  $ nix-shell -p gcc

  nix-shell$ gcc test.c && ltrace ./a.out
  stat(0x402004, 0x7ffc50a9d740, 0x7ffc50a9d908, 0x403db0) = 0
  +++ exited (status 0) +++

  nix-shell$ gcc -D_FILE_OFFSET_BITS=64 test.c && ltrace ./a.out
  stat64(0x402004, 0x7ffd5cbafba0, 0x7ffd5cbafd68, 0x403db0) = 0
  +++ exited (status 0) +++

  nix-shell$ file a.out
  a.out: ELF 64-bit LSB executable, x86-64, [...]
2025-07-09 17:32:54 +02:00
Wolfgang Hommel
6404d81f63 Merge pull request #504 from bjornfor/system-v-semaphores
Add optional System V semaphores
2025-06-27 19:33:14 +02:00
Bjørn Forsman
44c578c6d6 Add optional System V semaphore backend
By building with -DFT_SEMAPHORE_BACKEND=FT_SYSV, the System V semaphore
API is unsed instead of POSIX. This works around a glibc bug[1] and
fixes https://github.com/wolfcw/libfaketime/issues/427
("libfaketime hangs forever when 32-bit process is executed within 64-bit process").
The default backend is still POSIX, in case there are regressions in the
new code.

[1] https://sourceware.org/bugzilla/show_bug.cgi?id=17980

Ref https://github.com/wolfcw/libfaketime/issues/427
2025-06-23 21:00:21 +02:00
Bjørn Forsman
2649cdb156 Add semaphore abstraction layer
Add ft_sem_*() functions that use the POSIX semaphore API.

In preparation for adding System V semaphores as an alternative to POSIX
semaphores, because glibc breaks POSIX semaphores when operating in
mixed 32- and 64-bit environments[1].

[1] https://sourceware.org/bugzilla/show_bug.cgi?id=17980
2025-06-23 16:42:49 +02:00
Bjørn Forsman
71b31e908d Add missing newline to error message 2025-06-23 16:19:26 +02:00
Wolfgang Hommel
523584abd4 Merge pull request #503 from sammytranGeo/fix-monotonic-timedwait
Fix MONOTONIC pthread_cond_timedwait when REALTIME is set
2025-06-14 13:04:11 +02:00
Sammy Tran
a2e406c669 Fix MONOTONIC pthread_cond_timedwait when REALTIME is set 2025-06-13 17:13:43 -04:00
Wolfgang Hommel
3ccdd344aa Preparations for v0.9.12 release 2025-06-09 14:31:15 +02:00
Wolfgang Hommel
f63569e422 Merge pull request #502 from usertam/patch/fix-fake-stat64buf-on-linux
Fix fake_stat64buf() again
2025-06-09 14:26:48 +02:00
usertam
d276658b74 libfaketime.c: fix fake_stat64buf() again
I got the logic wrong in PR #501 in the inner `#ifndef __APPLE__`.
This broke building on linux. This should fix it.
2025-06-09 19:19:37 +08:00
Wolfgang Hommel
cb48e454be Merge pull request #501 from usertam/patch/clean-up-and-readme
Fix compiler warnings and update README.OSX
2025-06-09 10:24:59 +02:00
usertam
77ae25f529 README.OSX: document about the new arm64e ABI 2025-06-08 23:23:50 +08:00
usertam
30d7defcf5 libfaketime.c: get rid of stat64 things on aarch64-darwin
To give more context, stat64 is a child of large-file support (LFS)
back in 1996, during the transition from 32-bit to 64-bit. People
wanted 64-bit inodes in 32-bit systems, hence stat and stat64.

Nowadays where everything is 64-bit, stat64 is mostly just an alias
to stat, as stat is already native 64-bit. On modern implementations
like musl, stat64 is even dropped entirely as a sane default. We
observe the same in darwin's stat.h:

  #if !__DARWIN_ONLY_64_BIT_INO_T
  struct stat64 __DARWIN_STRUCT_STAT64;
  #endif /* !__DARWIN_ONLY_64_BIT_INO_T */

Because struct stat64 doesn't ever exist on aarch64-darwin, and we
don't have to worry about people using stat64 calls, we can safely
remove all stat64 bloat, according to __DARWIN_ONLY_64_BIT_INO_T.

I nuked fake_stat64buf because only STAT64_HANDLER is using it, and
only non-darwin stat64 things use that handler. I didn't do more
because people might still use stat64 things on x86_64 (on glibc)
and other older 32-bit platforms, and we still need to hook those.

A loose follow up to PR #453. Fixes the remaining clang warnings on
aarch64-darwin.
2025-06-08 19:34:48 +08:00
Wolfgang Hommel
9f7b304dbe Merge pull request #500 from usertam/patch/fix-darwin-and-arm64e
Fix darwin and arm64e
2025-06-07 23:03:01 +02:00
usertam
0277016bb5 Makefile.OSX: add -fptrauth-* flags for arm64e to work properly
Particularly we need -fptrauth-calls, so when pthread_once indirectly
calls ftpl_really_init, it won't fail PAC.
2025-06-07 20:51:07 +08:00
usertam
0e2dbe4ae1 libfaketime.c: correct macro from __APPLEOSX__ to __APPLE__
This fixes the recursive pthread_once deadlock on darwin platforms.
It looks something like this:

  Trace/BPT trap: 5

  BUG IN CLIENT OF LIBPLATFORM: Trying to recursively lock an os_once_t

The macro __APPLEOSX__ is never defined, instead __APPLE__ should be used.
This mistake inadvertently caused system_time_from_system() to always take
the linux code path on darwin, leading to recursive calls during ftpl_init().

This was exposed by PR #488 which removed the ad-hoc recursion detection
that previously masked this issue.
2025-06-07 20:51:06 +08:00
Wolfgang Hommel
45d29c8256 Merge pull request #497 from usertam/patch/compile-both-arm64-arm64e
Compile for arm64 on darwin again
2025-06-03 21:48:40 +02:00
usertam
264e8efad7 Makefile.OSX: compile a fat library of both arm64e and arm64 2025-06-01 22:50:46 +08:00
usertam
3a3d1deebc Revert "Check if the user is on ARM64, add target to CFLAGS/LDFLAGS"
This reverts commit 2a2af0fcdc.
2025-06-01 01:03:58 +08:00
Wolfgang Hommel
6714b98794 Preparations for v0.9.11 release 2025-05-25 10:00:14 +02:00
Wolfgang Hommel
3e56ada3ff Merge pull request #495 from PiotrBzdrega/master
missing FUTEX_CLOCK_REALTIME declaration when build with flags -DINTERCEPT_SYSCALL -DINTERCEPT_FUTEX
2025-05-24 13:03:01 +02:00
PiotrBzdrega
2dca058f5c missing FUTEX_CLOCK_REALTIME declaration when build with flags -DINTERCEPT_SYSCALL -DINTERCEPT_FUTEX 2025-05-13 15:01:47 +02:00
Wolfgang Hommel
2e2d3eefb5 Merge pull request #493 from totoroyyb/master
[DRAFT] fix: unhandled futex-related syscall
2025-03-29 11:37:26 +01:00
Yibo Yan
fa731ed50f fix: unhandled futex wait syscall 2025-03-26 21:02:47 +00:00
Wolfgang Hommel
3f6467d421 Test different Ubuntu versions 2025-01-29 17:36:42 +01:00
Wolfgang Hommel
2dac72caba Test different Ubuntu versions 2025-01-29 17:21:51 +01:00
Wolfgang Hommel
21af5175f5 pthread.h on macOS 2025-01-28 21:30:17 +01:00
Wolfgang Hommel
b5a48c870b Merge pull request #488 from ijackson/races
Fix several data races
2025-01-28 19:59:24 +01:00
Wolfgang Hommel
52fe3cc442 Merge pull request #487 from ijackson/t64
Fake 64-bit time on 32-bit systems
2025-01-28 06:26:19 +01:00
Wolfgang Hommel
63aef51102 Merge pull request #486 from ijackson/utime
Re-disable faking utime by default
2025-01-28 06:24:32 +01:00
Ian Jackson
50e2c56914 Don't use _try_ locking calls for monotonic_conds_lock
This reverts commit 8ef74e33b6
   "Swapped out pthread_rwlock_xxlock() ..."

This could result in concurrent uses of pthread_cond_* erroneously
returning EAGAIN, which is not permitted by the spec and which the
application way well treat as a bug.  This seems to be happening in
gem2deb in ci.debian.net.

The commit message in 8ef74e33b6 says (rewrapped)

    Swapped out pthread_rwlock_xxlock(), which doesn't return if it
    can't obtain the lock, with pthread_rwlock_xxtrylock() followed by
    sched yield and error code return. The issue is sometimes a thread
    calling pthread_cond_init() or pthread_cond_destroy() can't
    acquire the lock when another thread is waiting on a condition
    variable notification via pthread_cond_timedwait(), and thus the
    thread calling pthread_cond_init() or pthread_cond_destroy() end
    up hanging indefinitely.

I don't think this is true.  The things that are done with
monotonic_conds_lock held are HASH_ADD_PTR HASH_FIND_PTR etc. on
monotonic_conds, which should all be fast and AFAICT don't in turn
take any locks.  So it shouldn't deadlock.

I conjecture that the underlying bug being experienced by the author
of "Swapped out pthread_rwlock_xxlock" was the lack of ftpl_init - ie,
access to an uninitialised pthread_rwlock_t.  That might result in a
hang.
2025-01-27 13:12:45 +00:00
Ian Jackson
b6e87c6f26 Call ftpl_init before using monotonic_conds_lock
Otherwise we can use this in an uninitialised state, which is not
allowed.

We call ftpl_init in pthread_cond_init_232, but the application might
not have called that.  For example, it might have a static condition
variable set up with PTHREAD_COND_INITIALIZER.
2025-01-27 13:12:45 +00:00
Ian Jackson
d9ba684b18 Replace data race with use of pthread_once (ft_shm_init) 2025-01-27 13:12:45 +00:00
Ian Jackson
2503b0fffc Replace data race with use of pthread_once (ftpl_init)
At the cost of no longer nicely detecting recursive initialisation
problems.

Fixes Debian bug #1093599
2025-01-27 13:12:38 +00:00
Ian Jackson
97721e5491 Interpose gettimeofday64 2025-01-27 12:27:03 +00:00
Ian Jackson
fdb5ba3f7a Interpose __time64 2025-01-27 12:27:03 +00:00
Ian Jackson
f289bf702f Fix interposition of clock_gettime64
timespec.tv_nsec is 32-bit, even though timeval.tv_usec is
64-bit (weirdly).  This doesn't matter very much in practice because
 * on little endian architectures (which is all our 32-bit release
   arches) writing to a too big integer ends up writing the
   desired value in the desired location, and
 * it doesn't affect the overall struct size on any of our actual
   architectures (which align the uint64_t to 8 so must make the
   whole struct 16 not 12), so the write overflow is harmless.

> #include <time.h>
> #include <sys/time.h>
> #include <stdio.h>
> struct timeval tv;
> struct timespec ts;
> int main(void) {
>    printf("time_t %lld\n", (unsigned long long) sizeof(time_t));
>    printf("timeval %lld %lld %lld\n",
>           (unsigned long long) sizeof(tv),
>           (unsigned long long) sizeof(tv.tv_sec),
>           (unsigned long long) sizeof(tv.tv_usec)
>           );
>    printf("timespec %lld %lld %lld\n",
>           (unsigned long long) sizeof(ts),
>           (unsigned long long) sizeof(ts.tv_sec),
>           (unsigned long long) sizeof(ts.tv_nsec)
>           );
> }
> (sid_armhf-dchroot)iwj@amdahl:~/Faketime/test$ gcc t.c
> (sid_armhf-dchroot)iwj@amdahl:~/Faketime/test$ ./a.out
> time_t 8
> timeval 16 8 8
> timespec 16 8 4
> (sid_armhf-dchroot)iwj@amdahl:~/Faketime/test$
2025-01-27 12:27:03 +00:00
Helge Deller
536889d797 Interpose clock_gettime64
Since debian generally added 64-bit time support on 32-bit
arches, now glibc sometimes calls the clock_gettime64 syscall
(and library wrapper).  This function was missing, and is added here.

Patch originally supplied here
  https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1064555
2025-01-27 12:26:40 +00:00
Ian Jackson
19b2476534 Re-disable faking utime by default
Fixes
  https://github.com/wolfcw/libfaketime/issues/483

See also
  https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1093412#35
Hopefully this will fix Debian #1093412.
2025-01-27 12:22:48 +00:00
Wolfgang Hommel
92c322507c Merge pull request #485 from LocutusOfBorg/master
test/libmallocintercept.c: fix write function unused return value
2025-01-25 13:04:34 +01:00
Gianfranco Costamagna
0516055224 test/libmallocintercept.c: fix write function unused return value
We should ignore the return value for logging function, to fix a new gcc ftbfs
libmallocintercept.c: In function ‘print_msg’:
libmallocintercept.c:27:9: error: ignoring return value of ‘write’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
   27 |         write(0, msg, strlen(msg));
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
2025-01-22 12:22:37 +01:00
Wolfgang Hommel
ba9ed5b289 Merge pull request #473 from EgnalZurc/patch-1
Preventing shared semaphore to be used again
2024-06-05 19:52:44 +02:00
Egnal Zurc
7e9d69b98f Preventing shared sem to be used again
The shared semaphore is closed but it's not assigned to null.
That's required because the logic check the semaphore status if it's not null. For this reason, we are getting a core some times.
2024-06-05 12:16:41 +02:00
Wolfgang Hommel
a04750217b ft_dlvsym() check for NULL version 2024-03-24 21:08:36 +01:00
Wolfgang Hommel
a3e91605ad Merge pull request #463 from Rob--W/issue-130-dlsym
Add FAKETIME_IGNORE_SYMBOLS to skip unneeded dlsym
2024-03-19 19:43:22 +01:00
Wolfgang Hommel
b716122cbe Merge pull request #465 from Rob--W/add-disable-shm-option
Add --disable-shm / FAKETIME_DISABLE_SHM
2024-03-19 19:15:38 +01:00
Wolfgang Hommel
23bec3882d Merge pull request #466 from joshuataylor/feature/macos-arm64
Check if the user is on ARM64, add target to CFLAGS/LDFLAGS
2024-03-18 19:26:16 +01:00
Josh Taylor
2a2af0fcdc Check if the user is on ARM64, add target to CFLAGS/LDFLAGS 2024-03-18 13:48:26 +08:00
Rob Wu
39fdbde365 Add --disable-shm / FAKETIME_DISABLE_SHM
The use of shared memory has side effects. Currently, the only way to
opt out of shared memory is by compiling with -DFAKE_STATELESS.

To allow disabling shared memory without recompiling, this patch
introduces the --disable-shm option to `faketime`, equivalent to
setting the `FAKETIME_DISABLE_SHM=1` environment variable.
2024-03-13 00:02:08 +01:00
Rob Wu
c745ab783b Add FAKETIME_IGNORE_SYMBOLS to skip unneeded dlsym 2024-03-12 02:40:56 +01:00
Wolfgang Hommel
f32986867a Merge pull request #453 from martinetd/musl
fix build on recent musl (stat64 compat)
2024-01-18 06:22:33 +01:00
Dominique Martinet
b2fe742aa7 fix build on recent musl (stat64 compat)
musl removed LFS64 compat[1] so stat64 is no longer defined by default,
but we can bring it back for now through _LARGEFILE64_SOURCE

Link: https://www.openwall.com/lists/musl/2022/09/26/1 [1]
Fixes: #446
2024-01-18 12:47:41 +09:00
Wolfgang Hommel
265651969b Merge pull request #451 from RCoeurjoly/master
sycall also watches the timestamp_file
2024-01-02 15:14:05 +01:00
Roland Coeurjoly
6a0f35dcbd sycall also watches the timestamp_file 2024-01-02 15:09:12 +01:00
Wolfgang Hommel
0af80dd593 Merge pull request #435 from kraj/master
Makefile: Detect compiler in makefile
2023-08-25 11:50:32 +02:00
Khem Raj
8908752a25 Makefile: Detect compiler in makefile
Add compiler specific options based on detected compiler gcc/clang
2023-08-24 10:09:53 -07:00
Wolfgang Hommel
27b9c83a27 Merge pull request #434 from sliquister/master
adding support for faking statx
2023-08-01 07:35:14 +02:00
Valentin Gatien-Baron
942b30e940 adding support for faking statx 2023-07-30 20:55:48 -04:00
Wolfgang Hommel
7154a3f42c Set FAKETIME_FLSHM=1 to auto-unset FAKETIME_SHARED (addresses #427) 2023-06-08 13:12:39 +02:00
Wolfgang Hommel
0c2e3d41be the missing else branch on CLOCK_MONOTONIC in clock_nanosleep (#426) 2023-06-06 20:10:31 +02:00
Wolfgang Hommel
f262b5fba7 Re-check fake_monotonic_setting in clock_nanosleep (#426) 2023-06-06 19:48:18 +02:00
Wolfgang Hommel
d17bb114c6 Honor fake_monotoic_clock setting in clock_nanosleep, addresses #426 2023-06-04 13:21:09 +02:00
Wolfgang Hommel
7df1bf7122 Fix #424 2023-04-30 20:26:07 +02:00
Wolfgang Hommel
6d072025c0 Merge pull request #422 from fixindan/dead_lock_no_return
Swapped out pthread_rwlock_xxlock(), which doesn't return if it can't…
2023-02-25 12:58:03 +01:00
Dixin Fan
8ef74e33b6 Swapped out pthread_rwlock_xxlock(), which doesn't return if it can't obtain the lock, with pthread_rwlock_xxtrylock() followed by sched yield and error code return. The issue is sometimes a thread calling pthread_cond_init() or pthread_cond_destroy() can't acquire the lock when another thread is waiting on a condition variable notification via pthread_cond_timedwait(), and thus the thread calling pthread_cond_init() or pthread_cond_destroy() end up hanging indefinitely. 2023-02-24 16:18:47 -06:00
Wolfgang Hommel
6fc4ae74f4 Merge pull request #416 from sliquister/master
ensure faketime can't be initialized more than once
2023-01-27 20:43:41 +01:00
Valentin Gatien-Baron
1997652d8e ensure faketime can't be initialized more than once
One callsite of ftpl_init wasn't protected by the "if (!initialized)"
condition, specifically:

static void ftpl_init (void) __attribute__ ((constructor));

If another "constructor" was called before this one, and that other
constructor used time or filesystem functions, ftlp_init would be
initialized by that other constructor, and then reinitialized by the
ftpl_init constructor. At that point, confusion ensues.
2023-01-16 21:26:39 -05:00
Wolfgang Hommel
de37190d40 Merge pull request #415 from usertam/master
libfaketime.c: wrap timespec_get in TIME_UTC macro
2022-12-20 19:25:59 +01:00
Samuel Tam
e0e6b79568 libfaketime.c: wrap timespec_get in TIME_UTC macro
Function `timespec_get` is not guaranteed to be declared in MacOS
since its standard library is non-conformance to modern standards.
Therefore, skip patching `timespec_get` if it is undeclared by the
standard library.

The detection of `timespec_get` is based on the conjecture that the
macro `TIME_UTC` is only defined when `timespec_get` is declared.
2022-12-20 02:08:45 +08:00
Wolfgang Hommel
df8a045597 Fix for Debian Bug#1017865 as provided by Samuel Thibault 2022-08-28 13:39:18 +02:00
Wolfgang Hommel
2adb56b07f Merge pull request #408 from daglem/short_read
Handle short reads from timestamp file
2022-08-28 13:33:51 +02:00
Dag Lem
1c80b19fe5 Handle short reads from timestamp file 2022-08-22 11:21:14 +02:00
Wolfgang Hommel
32eedc2b42 Merge pull request #406 from enr0n/master
test/snippets: fix time.c compiler error on 32-bit arches
2022-08-10 22:27:39 +02:00
Nick Rosbrook
ccc9992840 test/snippets: fix time.c compiler error on 32-bit arches
Cast t to unsigned long and use the %lu format specifier instead of %zd.
This is more portable to 32-bit arches, avoiding the following compiler
error:

 snippets/time.c:2:31: error: format ‘%zd’ expects argument of type ‘signed size_t’, but argument 3 has type ‘time_t’ {aka ‘long int’} [-Werror=format=]
     2 | printf("[%s] time() yielded %zd\n", where, t);
       |                             ~~^            ~
       |                               |            |
       |                               int          time_t {aka long int}
       |                             %ld
 cc1: all warnings being treated as errors
2022-08-10 14:40:42 -04:00
Wolfgang Hommel
a059f1294f Merge pull request #404 from perldude/perldude-issue-403
issue#403
2022-07-25 20:32:23 +02:00
Wolfgang Hommel
f4bf28356c Merge pull request #397 from j-xella/sun_compiler
Refactor to get rid of some non-standard gcc extensions
2022-07-25 20:32:02 +02:00
Michael Sullivan
5c63238544 issue#403
Disable including `sys/time.h` on ARM to prevent conflicting declarations of `gettimeofday()`.
2022-07-25 09:53:26 -07:00
Wolfgang Hommel
be4e373e63 Merge pull request #400 from sveyret/shared-mem-sync
Reset shared memory when start time is reset
2022-06-20 19:41:24 +02:00
Stéphane Veyret
431f09eb19 Reset shared memory when start time is reset 2022-06-17 16:38:41 +02:00
Aleksandr Jakusev
326c20ebb5 Refactor to get rid of some non-standard gcc extensions
Without the changes Sun studio 12.8 compiler fails, for example

Note that only the errors are fixed. On the compiler above, some
warnings still remain, so -Werror has to be removed as well from the
compiler switches in order for the compilation to succeed.
2022-05-26 23:44:39 +00:00
Wolfgang Hommel
b61fade280 honor dont_fake_monotonic in experimental sem_clockwait() (addresses #390) 2022-05-16 19:20:33 +02:00
Wolfgang Hommel
859751e2cb fix reverse user_rate in sem_clockwait() (addresses #390) 2022-05-14 23:09:03 +02:00
Wolfgang Hommel
f706373bc2 Experimental sem_clockwait() support (addresses #390) 2022-05-11 21:47:35 +02:00
Wolfgang Hommel
e7ca8378ca Merge pull request #391 from psychon/asan2
Fix another hang under ASAN
2022-05-09 19:39:43 +02:00
Uli Schlachter
3b3f80a42f Fix another hang under ASAN
We have a long-running program that we want to run under sanitizers for
extra error checking and under faketime to speed up the clock. This
program hangs after a while. Backtraces suggest that the hangs occur
because of recursion in the memory allocator, which apparently locks a
non-recursive mutex.

Specifically, what we see is that due to our use of FAKETIME_NO_CACHE=1,
libfaketime wants to reload the config file inside a (random) call to
clock_gettime(). libfaketime then uses fopen() / fclose() for reading
the config files. These function allocate / free a buffer for reading
data and specifically the call to free() that happens inside fclose()
ends up calling clock_gettime() again. At this point, libfaketime locks
up because it has a time_mutex that is locked and none-recursive.

Sadly, I did not manage to come up with a stand-alone reproducer for
this problem. Also, the above description is from memory after half a
week of vacation, so it might be (partially) wrong.

More information can be found here:

- https://github.com/wolfcw/libfaketime/issues/365#issuecomment-1115802530
- https://github.com/wolfcw/libfaketime/issues/365#issuecomment-1116178907

This commit first adds a test case. This new test uses the already
existing libmallocintercept.so to cause calls to clock_gettime() during
memory allocation routines. The difference to the already existing
version is that additionally FAKETIME_NO_CACHE and
FAKETIME_TIMESTAMP_FILE are set. This new test hung with its last output
suggesting a recursive call to malloc:

Called malloc() from libmallocintercept...successfully
Called free() on from libmallocintercept...successfully
Called malloc() from libmallocintercept...Called malloc() from libmallocintercept...

Sadly, gdb was unable to provide a meaningful backtrace for this hang.

Next, I replaced the use of fopen()/fgets()/fgets() with
open()/read()/close(). This code no longer reads the config file
line-by-line, but instead it reads all of it at once and then "filters
out" the result (ignores comment lines, removes end of line markers).

I tried to keep the behaviour of the code the same, but I know at least
one difference: Previously, the config file was read line-by-line and
lines that began with a comment character were immediately ignored. The
new code only reads the config once and then removes comment lines.
Since the buffer that is used contains only 256 characters, it is
possible that config files that were previously parsed correctly now
longer parse. A specific example: if a file begins with 500 '#'
characters in its first line and then a timestamp in the second line,
the old code was able to parse this file while the new code would only
see an empty file.

After this change, the new test no longer hangs. Sadly, I do not
actually know its effect on the "actual bug" that I wanted to fix, but
since there are no longer any calls to fclose(), there cannot be any
hangs inside fclose().

Signed-off-by: Uli Schlachter <psychon@znc.in>
2022-05-09 13:53:51 +02:00
Wolfgang Hommel
2bfbe19f71 silence minor type warning in libmallocintercept.c 2022-05-08 21:24:51 +02:00
Wolfgang Hommel
75cbe8e507 silence minor type warning in libmallocintercept.c 2022-05-08 21:20:29 +02:00
Wolfgang Hommel
e8838709ea silence minor type warning in libmallocintercept.c 2022-05-08 21:09:45 +02:00
Wolfgang Hommel
bf3a08b04d silence minor type warning in libmallocintercept.c 2022-05-08 21:05:10 +02:00
Wolfgang Hommel
141d1a7a87 Merge pull request #389 from psychon/asan
Work-around / fix libasan incompatibility
2022-05-08 20:56:16 +02:00
Uli Schlachter
0f79f21e11 Add libmallocintercept.so to make clean
Signed-off-by: Uli Schlachter <psychon@znc.in>
2022-05-08 19:20:51 +02:00
Uli Schlachter
450d5d4549 Disable FAILRE_PRE_INIT_CALLS by default
Signed-off-by: Uli Schlachter <psychon@znc.in>
2022-05-08 19:17:27 +02:00
Uli Schlachter
fff49b23fc Add FAIL_PRE_INIT_CALLS define
This commit adds a new define FAIL_PRE_INIT_CALLS. When that define is
set, calls to clock_gettime() that occur before ftpl_init() was called
(due to being marked with __attribute__((constructor))) will just fail
and return -1.

After this commit, the test case added in the previous commit no longer
hangs. To make this actually work, this new define is enabled by
default.

Fixes: https://github.com/wolfcw/libfaketime/issues/365
Signed-off-by: Uli Schlachter <psychon@znc.in>
2022-05-04 14:51:35 +02:00
Uli Schlachter
6e0f978079 Add test reproducing ASAN-like hangs
Backtraces suggest that AddressSanitizer replaces malloc() with a
function that

- locks a mutex and
- calls clock_gettime() while the mutex is held

This commit adds a test that implements a trivial malloc() that behaves
similarly. Currently, this test hangs.

Signed-off-by: Uli Schlachter <psychon@znc.in>
2022-05-04 14:25:13 +02:00
Wolfgang Hommel
f836ea3eb3 Merge pull request #388 from dkg/cleanup-random-tests
test: remember to clean up repeat_random
2022-04-16 21:17:55 +02:00
Wolfgang Hommel
642b6ee870 Merge pull request #387 from dkg/clean-syscall-tests
clean up tests related to syscall
2022-04-16 21:17:41 +02:00
Daniel Kahn Gillmor
03cb104691 test: remember to clean up repeat_random 2022-04-16 10:27:53 -07:00
Daniel Kahn Gillmor
7e86fb5419 tests: avoid testing syscall snippets if -DINTERCEPT_SYSCALL is not set
See https://bugs.debian.org/1007828
2022-04-16 10:06:23 -07:00
Daniel Kahn Gillmor
e9c74131fc tests: clean whitespace in Makefile 2022-04-16 10:05:40 -07:00
Wolfgang Hommel
8fa0530d83 Honor tv_nsec in timeouts on ppoll() calls (addresses #381) 2022-04-02 13:52:18 +02:00
Wolfgang Hommel
98e3d3f36f select(): Scale timeout parameter by user rate on return (addresses #382) 2022-04-02 13:47:04 +02:00
Wolfgang Hommel
0ca35dd8c4 Merge pull request #375 from inorton/fix_374_UFAKE_STAT
fixes #374 fix compiling without FAKE_STAT or with FAKE_UTIME
2022-03-18 19:31:35 +01:00
Ian Norton
2d941a894f fixes #374 fix compiling without FAKE_STAT 2022-03-18 12:25:55 +00:00
Wolfgang Hommel
f50664f0bd Update NEWS file about v0.9.10 changes 2022-03-04 20:33:18 +01:00
Wolfgang Hommel
d475b92594 Update release date to March 2022 for 0.9.10 (closes #366) 2022-03-04 20:28:35 +01:00
Wolfgang Hommel
40edcc7ca0 Documentation updated regarding FAKETIME_FORCE_MONOTONIC_FIX 2022-02-28 15:42:55 +01:00
Wolfgang Hommel
da348ae2dd Limit glibc auto-sensing to compilation on glibc systems (addresses #369) 2022-02-28 15:21:45 +01:00
Wolfgang Hommel
68f01e7101 Limit glibc auto-sensing to compilation on glibc systems (addresses #369) 2022-02-28 15:19:08 +01:00
Wolfgang Hommel
089a78add5 Exclude glibc versioning on macOS; bump autosense lower threshold to 2.24 2022-02-26 11:07:38 +01:00
Wolfgang Hommel
a8d6a76906 encourage forced monotonic fix issue reports during test (addresses #366) 2022-02-25 21:36:38 +01:00
Wolfgang Hommel
36090e8ceb dynamic forced monotonic fix autosense (addresses #366) 2022-02-25 21:25:58 +01:00
Wolfgang Hommel
0e61d3d191 run-time envvar FAKETIME_FORCE_MONOTONIC_FIX, autosense stub (addresses #366) 2022-02-25 20:57:38 +01:00
Wolfgang Hommel
985d666d73 Honor x/i flags also with frozen faketime stamps (closes #360) 2022-02-20 21:22:01 +01:00
Wolfgang Hommel
9dcaf53fd7 faketime wrapper complains when env vars are set unless comp/w SILENT (closes #307) 2022-02-20 20:40:19 +01:00
Wolfgang Hommel
02bc1fccae Version bump to 0.9.10 (prepares for #366) 2022-02-20 17:53:54 +01:00
Wolfgang Hommel
2c02fc08ef Further dyld interposing for macOS Monterey support (addresses #357) 2022-02-20 17:39:17 +01:00
Wolfgang Hommel
2d5126411b Merge pull request #363 from sirainen/new-calls
Add fstat(), stat() and lstat() calls
2022-02-18 20:56:42 +01:00
Wolfgang Hommel
ee4f57d8a5 Additional dyld interposing for macOS Monterey support (addresses #357) 2022-02-16 21:27:08 +01:00
Timo Sirainen
f09c98a89f Add fstat(), stat() and lstat() calls 2022-02-16 12:01:35 +02:00
Timo Sirainen
527da8441b Implement all stat-like functions with STAT_HANDLER() and STAT64_HANDLER() macros 2022-02-16 11:58:42 +02:00
Timo Sirainen
79defa361e Check missing real_* functions using CHECK_MISSING_REAL() macro 2022-02-16 11:58:05 +02:00
Timo Sirainen
6d7c42e2df Fix disabling all *stat*() faking during initialization
Only __xstat() variant was handling the dont_fake variable.
2022-02-16 11:58:04 +02:00
Timo Sirainen
a7e536bcca Rename real_*stat* variables to correspond to the actual function names 2022-02-16 11:55:30 +02:00
Wolfgang Hommel
5466cd8a5f Merge branch 'macos' 2022-02-06 21:40:50 +01:00
Wolfgang Hommel
61490dc09a Change dyld interposing for basic macOS Monterey support (addresses #357) 2022-02-06 21:39:29 +01:00
Wolfgang Hommel
db47664840 Merge pull request #368 from dkg/clean-strptime
Avoid spurious "Success" error message.
2022-02-05 09:22:53 +01:00
Daniel Kahn Gillmor
bc24e278ff Avoid spurious "Success" error message.
strptime(3) doesn't set errno, so when it was failing, calling perror()
meant producing messages like:

Failed to parse FAKETIME timestamp: Success

Rather than use perror(), just send the warning message directly to
stderr.

This was first reported in https://bugs.debian.org/939789
2022-02-04 19:04:45 -05:00
Wolfgang Hommel
b0b9432ea4 Merge pull request #367 from dkg/manpage-formatting
formatting cleanups
2022-02-04 23:23:54 +01:00
Daniel Kahn Gillmor
84fc285923 stackoverflow uses https 2022-02-04 16:47:44 -05:00
Daniel Kahn Gillmor
806c05f49d manpage: Minor cleanup to faketime.1
- close quotes correctly in "Relative time offset"
- github uses https
- e.g. and i.e. should be set off from what follows with a comma
2022-02-04 16:40:57 -05:00
Daniel Kahn Gillmor
fe6eeae423 manpage: structure source with one sentence per line
Using this structure makes diffs easier to read, when changes are due.

The underlying formatting produced by groff ends up basically the same
(though some versions of groff may adjust to have two spaces after a
sentence-ending period instead of one).
2022-02-04 16:37:27 -05:00
Wolfgang Hommel
f26242b655 Merge pull request #352 from luochunbei/master 2021-10-10 14:23:30 +02:00
luochunbei
e0ca33132d add explicit data type conversion to avoid integer overflow 2021-10-10 14:39:51 +08:00
Wolfgang Hommel
cbf1d729ed Merge pull request #350 from a1346054/fixes
Simple maintenance improvements
2021-09-22 06:26:19 +02:00
a1346054
543f6b5040 Trim excess whitespace 2021-09-21 21:03:50 +00:00
a1346054
aa9eb1006d Fix codestyle deviations 2021-09-21 21:03:14 +00:00
a1346054
14cf8d7ba8 Fix spelling 2021-09-21 20:46:28 +00:00
Wolfgang Hommel
f4ae29fb91 Merge pull request #348 from GranBurguesa/patch-1
fix do/while guard for DONT_FAKE_TIME macro
2021-09-17 19:34:53 +02:00
GranBurguesa
a9142e0e9a fix do/while guard for DONT_FAKE_TIME macro
the newer version gcc warns `this ‘while’ clause does not guard... [-Werror=misleading-indentation]`. looks like the author just omitted the `do` and the `while(0) counts as a separate statement.

in practice this isn't causing any actual problem now afaict.
2021-09-17 10:41:55 -04:00
Wolfgang Hommel
b7fff74716 Merge pull request #344 from sliquister/fake-stateless
Add a build variable to opt-out of behaviors that reduce reliability
2021-08-01 20:44:14 +02:00
Valentin Gatien-Baron
e26859e5ca add a build variable to opt-out of some behaviors
Specifically behaviors that increase the chance that a wrapped program
will not behave like an unwrapped program does, thus causing
reliability issues.
2021-08-01 08:41:17 -04:00
Valentin Gatien-Baron
3155e0ee38 try to clarify the help of a couple of compilatoin variables 2021-08-01 08:02:59 -04:00
Valentin Gatien-Baron
078a4e4060 group cpp variables according to whether they are set by default 2021-08-01 07:58:06 -04:00
Wolfgang Hommel
9043941fa9 Merge pull request #342 from sliquister/timespec_get
wrap timespec_get
2021-07-30 22:54:00 +02:00
Valentin Gatien-Baron
973111d78a wrap timespec_get 2021-07-30 13:46:24 -04:00
Wolfgang Hommel
4bab3179ce Unlock mutex before exiting in case of error (fixes #340) 2021-07-17 19:44:20 +02:00
Wolfgang Hommel
2090f5e548 Fix in __xstat regarding dont_fake handling 2021-06-22 21:51:28 +02:00
Wolfgang Hommel
f88c8d4221 Do not cache '%' in parse_ft_string (addresses #337) 2021-06-22 21:47:57 +02:00
Wolfgang Hommel
9a73db074b Merge pull request #328 from jelly/gzip_reproducible
Do not store the timestamp in the gzip
2021-05-11 18:42:09 +02:00
Jelle van der Waa
932c138112 Do not store the timestamp in the gzip
To make libfaketime reproducible don't embed the timestamp in the gzip
header.

Motivation: https://reproducible-builds.org
2021-05-11 17:03:01 +02:00
Wolfgang Hommel
9e27b2ed8b Merge pull request #320 from sliquister/master
add support for timerfd_{set,get}time
2021-03-31 20:05:02 +02:00
Valentin Gatien-Baron
c9f292ee39 add support for timerfd_{set,get}time 2021-03-30 13:02:24 -04:00
Wolfgang Hommel
d37421dbe7 Merge pull request #319 from jimklimov/install-doc
Makefile: define PREFIX same as in sub-Makefiles to install "doc" to …
2021-03-28 21:09:34 +02:00
Jim Klimov
89161a0cdf Makefile: define PREFIX same as in sub-Makefiles to install "doc" to reasonable path 2021-03-28 21:01:38 +03:00
Wolfgang Hommel
f87c2f8915 Merge pull request #318 from jimklimov/date-prog-sun
faketime.c: default to GNU date as "gdate" on Sun-related OSes
2021-03-28 19:35:41 +02:00
Wolfgang Hommel
ce1d39c98f Merge pull request #317 from jimklimov/date-prog-arg
faketime.c: allow user to select their implementation of GNU date
2021-03-28 19:35:10 +02:00
Wolfgang Hommel
262d1d574f Merge pull request #316 from jimklimov/eol
src/sunos_endian.h: No newline at end of file
2021-03-28 19:32:01 +02:00
Jim Klimov
06d49adc12 faketime.c: default to GNU date as "gdate" on Sun-related OSes 2021-03-28 20:17:07 +03:00
Jim Klimov
1686664c97 faketime.c: allow user to select their implementation of GNU date 2021-03-28 20:14:27 +03:00
Jim Klimov
5217bcd13d src/sunos_endian.h: No newline at end of file
For pedantic compilers this is actually a fatal error, since per
(older?) C standards the file should end with an EOL.
2021-03-28 18:54:26 +03:00
Wolfgang Hommel
8ae4c9bc0e Merge pull request #313 from dkg/test-variadic-promotion
Test variadic promotion
2021-03-06 09:46:07 +01:00
Daniel Kahn Gillmor
6733dc3a8d tests: Confirm variadic argument promotion assumptions when INTERCEPT_SYSCALL
The test suite should not succeed if INTERCEPT_SYSCALL is defined but
the variadic argument promotion test fails.

OTOH, if we're not asking for INTERCEPT_SYSCALL, we don't care about
the results of that test.
2021-03-05 22:48:47 -05:00
Daniel Kahn Gillmor
008d33fdf2 Test assumptions about variadic re-packing
This test uses the same style of re-packing variadic arguments through
two layers of variadic calls, and compares that call chain against one
direct variadic call.

The outer function uses the same kind of re-packing used in
src/libfaketime.c's syscall (leading to real_syscall), but the inner
functions use different assumptions about the types of each argument.

This is not an entirely comprehensive test, because we only define two
different inner function signatures.  If some particular syscall is
breaking when intercepted, consider adding something like its expected
function signature in test/variadic/inner.c, and invoke it in
test/variadic/main.c.

Note that we don't test any floating point types (those types are
typically passed in registers in x86-64, not on the stack, and are
also not used for any syscall that i'm aware of).
2021-03-05 22:48:47 -05:00
Daniel Kahn Gillmor
5a0071f952 Centralize assumptions about variadic argument re-packing
By stating these assumptions in src/faketime_common.h, we can reuse
them in the tests as well as in the code.
2021-03-05 21:46:18 -05:00
Daniel Kahn Gillmor
51f1248593 tests: use CFLAGS from the environment.
This makes the test build process use the same sort of CFLAGS as the rest of the code.
2021-03-05 21:45:23 -05:00
Daniel Kahn Gillmor
e70b143733 Prepare to add new tests depending on the definitions
We want to be able to conditionally add tests.  This sets up to be
able to do that cleanly.
2021-03-05 21:45:23 -05:00
Wolfgang Hommel
e1073c8733 Promote syscall passthrough arguments to long instead of int (#310) 2021-03-04 19:24:24 +01:00
Wolfgang Hommel
01b0b4bb56 Merge pull request #312 from dkg/avoid-diversion
Pass through syscall(__NR_clock_gettime) if FAKERANDOM is unset
2021-03-03 06:36:26 +01:00
Daniel Kahn Gillmor
5f5756ccd9 Pass through syscall(__NR_clock_gettime) if FAKERANDOM is unset
If FAKERANDOM is unset, we were still intercepting syscall() and
passing it through to clock_gettime, rather than letting it fall
through to real_syscall.

That would have the effect of diverting syscall(__NR_clock_gettime,…)
into the libc invocation of clock_gettime(…) (via real_clock_gettime).
While that probably does the same thing, it's probably a mistake to do
such a diversion when FAKETIME is unset.
2021-03-02 20:01:18 -05:00
Wolfgang Hommel
bca9f1bf90 Merge pull request #311 from dkg/more-testing
More snippet testing and better documentation
2021-03-02 21:44:56 +01:00
Daniel Kahn Gillmor
d3f3ee38c6 Add syscall_clock_gettime_heap snippet
This invokes clock_gettime, but uses a timespec from the heap instead
of the stack.

It appears to be successful for me on x86-64 GNU/Linux.

This rules out one possible cause of the error reported in #310: I was
worried that an address from the range occupied by the heap might
somehow be corrupted by the syscall variadic argument de-mangling, but
that looks like it is not the case.
2021-03-02 10:33:07 -05:00
Daniel Kahn Gillmor
a3f9410e51 Add clock_gettime_heap snippet
This invokes clock_gettime, but uses a timespec from the heap instead
of the stack.
2021-03-02 10:26:20 -05:00
Daniel Kahn Gillmor
a92d6ffe7c add snippet testing clock_gettime(CLOCK_REALTIME) 2021-03-02 10:23:11 -05:00
Daniel Kahn Gillmor
253774c8d8 added new simple snippet "time.c" 2021-03-01 21:47:18 -05:00
Daniel Kahn Gillmor
986e6e1cdc Clarify test/Makefile and snippet testing documentation
Hopefully this makes it easier for future development work to augment
the snippet-based testing.
2021-03-01 21:40:57 -05:00
Daniel Kahn Gillmor
0bfb72b627 tests: normalize "where" variable to include framework prefix and snippet name 2021-03-01 21:08:00 -05:00
Daniel Kahn Gillmor
5a1bd98979 parallelize library_contructors test 2021-03-01 21:05:22 -05:00
Daniel Kahn Gillmor
7e62881c8f Name "snippets" explicitly
Earlier, this code was conceived of to test a "function" specifically,
but some future snippet could test multiple function calls, or a
subset of a function call (e.g. snippets/syscall_clock_gettime.c
already only tests one particular syscall diversion number).

Normalizing on the name "snippet" should make it easier to understand
the code going forward.
2021-03-01 15:06:22 -05:00
Wolfgang Hommel
0e6b1b2460 Merge pull request #309 from dkg/faketime-pid
faketime: add -p option to wrapper for setting PID
2021-02-26 20:46:27 +01:00
Wolfgang Hommel
1297568caf Merge pull request #306 from dkg/cleanup-tests
Overhaul recently-added tests (new additional snippet-driven testing framework)
2021-02-26 20:28:38 +01:00
Daniel Kahn Gillmor
940502b3de Added snippet for syscall(__NR_clock_gettime)
Closes: #176
2021-02-25 23:33:30 -05:00
Daniel Kahn Gillmor
26b4b395e9 Include a check for getentropy interception
This snippet applies to both the library constructors and variable
data test frameworks.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
0b0cc29d2e test/randomtest.sh: avoid touching the filesystem 2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
a5885f1479 Drop more duplicative tests
Now that we have the snippet-driven test_variable_data suite, most of
the other longer hand-written tests are duplicative.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
0872c6c0c0 Add test_variable_data framework that reuses the snippets
Most of these snippets are likely to have some env var that causes the
data to hold constant, while the data will otherwise be likely to vary
over time.

This framework offers a way to test those snippets, by dropping the
variable and an example value in the test/snippets/FOO.variable
one-line file.

Note that the test/snippets/syscall.c snippet is *not* expected to
vary over time (or to differ when any given variable is set), so we
simply don't add any test/snippets/syscall.variable file to avoid it
being tested in this way.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
a51a38d0ae Handle when another library uses a syscall in a constructor
Without this fix, the test_library_constructors test was failing on
use_lib_syscall.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
f47223ff12 Include snippet for syscall() interception in library constructors 2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
7b1d0958b5 Drop duplicate library constructor preload tests
These tests are already taken care of with the snippet-driven library
constructor tests.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
17522c5ba1 Overhaul testing library constructors
We want to make it easier to test a bunch of different functions that
might be invoked in constructors of other libraries.

It seems conceivable that with these snippets, we could design other
tests that also work across a wide range of intercepted functions.
2021-02-25 23:17:25 -05:00
Daniel Kahn Gillmor
5e62eafcc2 faketime: add -p option to wrapper for setting PID
I had to decide what to do if FAKE_PID wasn't defined during the
build. I decided that since the wrapper can't be sure it is preloading
the same library that it was built with (someone could somehow mix and
match the library and the wrapper tool), it should just warn and pass
along the value anyway.

This reserves the option space, but shouldn't annoy people too much if
they are running it on a system that doesn't have FAKE_PID enabled.

I note that this happens regardless of whether it is a "direct"
invocation or not.  I don't fully understand all the tradeoffs here,
so I would appreciate another set of eyes reviewing this choice.

Closes: #308
2021-02-25 19:37:38 -05:00
Daniel Kahn Gillmor
01f6bc76c9 clean up after syscall_test properly 2021-02-25 18:12:04 -05:00
Daniel Kahn Gillmor
f329eee8c5 Send test output to stdout, not stderr
debian autopkgtest instances (and maybe other test systems) will
report a failure if messages are sent to stderr.

Since these messages are diagnostic messages for the test suite, and
not indicators of actual failure, they should go to stdout, not
stderr.
2021-02-25 18:11:52 -05:00
Wolfgang Hommel
c89582fc1f divert syscall() to clock_gettime() (#176 #302) 2021-02-25 21:22:41 +01:00
Wolfgang Hommel
9a38e5d775 Merge pull request #305 from dkg/fix-shm
Use real_getpid instead of getpid in ft_shm_create() under FAKE_PID
2021-02-25 19:29:11 +01:00
Daniel Kahn Gillmor
7f4e5c378a Use real_getpid instead of getpid in ft_shm_create() under FAKE_PID
This addresses part of the concerns raised in #297
2021-02-25 10:50:57 -05:00
Wolfgang Hommel
9337bccfcb Merge pull request #304 from dkg/cover-getentropy
better testing for interception of randomness from the kernel, including getentropy()
2021-02-25 06:27:35 +01:00
Wolfgang Hommel
3668fd9b0f Merge pull request #302 from dkg/syscall-interception
Intercept syscall
2021-02-25 06:15:42 +01:00
Daniel Kahn Gillmor
3a81c6becd if FAKE_RANDOM is present, try to intercept getentropy as well.
Closes: #303
2021-02-24 16:38:15 -05:00
Daniel Kahn Gillmor
3db9d20828 Test getentropy
We want to ensure that tools that call getentropy() are also
controlled appropriately.
2021-02-24 16:03:57 -05:00
Daniel Kahn Gillmor
20e74b1b02 clean up randomtest.sh, make more flexible 2021-02-24 15:58:54 -05:00
Daniel Kahn Gillmor
00d6edf90c Test repeated invocations of getrandom()
A single program that invokes getrandom() repeatedly should end up
with the same stream of bytes, regardless of how it chunks up the
reading from the entropy source.

This test already passses.  I'm including it because it seems
like a useful confirmation.
2021-02-24 15:24:45 -05:00
Daniel Kahn Gillmor
811283e683 Intercept syscall
This is an attempt at an implementation to address #301.

Some things worth noting:

 - I am not particularly confident in my reverse of the variadic C
   ABI. While the code appears to work for me on x86_64, I could
   imagine some variations between platforms that I'm not
   understanding.

 - This works to intercept the invocation of syscall as seen in
   test/syscalltest.sh, as long as it was compiled with -DFAKE_RANDOM

 - defining -DINTERCEPT_SYSCALL on non-Linux platforms should result
   in a compile-time error.

 - This does *not* work to intercept the syscall sent by `openssl
   rand`, for some reason I don't yet understand.  Perhaps openssl has
   some platform-specific syscall mechanism that doesn't route them
   through libc's syscall() shim?
2021-02-24 14:45:38 -05:00
Wolfgang Hommel
a8283c646d Merge pull request #300 from dkg/improve-tests
Test getpid() against a library that invokes getpid() in its constructor
2021-02-24 17:54:30 +01:00
Daniel Kahn Gillmor
2ca0b719e3 test getpid() against library with constructor that calls it
This is an attempt to ensure that an external library invocation of
getpid doesn't trigger a crash (e.g. #295) or an infinite loop
(e.g. #297).
2021-02-24 11:15:31 -05:00
Daniel Kahn Gillmor
f6ddc32695 Genericize build rules for testing external libraries with constructor
This paves the way for testing other interceptions like getpid() with
shared objects that do devious things in their consturctors.
2021-02-24 11:15:01 -05:00
Daniel Kahn Gillmor
8de66f799f randomtest.sh requires librandom.so to be present
In some configurations, GNU make might treat librandom.so as an
ephemeral/intermediate build artifact and destroy it before
randomtest.sh is run.  This ensures the shared object is present when
needed.
2021-02-24 11:14:37 -05:00
Wolfgang Hommel
63fe6f0be5 Merge pull request #298 from dkg/fakepid
Enable intercepting getpid()
2021-02-24 13:53:45 +01:00
Wolfgang Hommel
062abac575 Merge pull request #299 from dkg/fix-getrandom
Ensure that real_getrandom is initialized properly
2021-02-24 06:34:46 +01:00
Daniel Kahn Gillmor
004222585e Enable intercepting getpid()
I went with the runtime environment variable being FAKETIME_FAKEPID
since it seems less likely to collide with anything else.

Closes: #297
2021-02-23 22:19:08 -05:00
Daniel Kahn Gillmor
9c59e24d33 Ensure that real_getrandom is initialized properly
This avoids potential failure if another library calls getrandom()
within its constructor before we are loaded.

For me, it lets "make randomtest" succeed in tests/

Closes: #295
2021-02-23 22:15:24 -05:00
Wolfgang Hommel
46dc625642 Merge pull request #296 from dkg/test-getrandom-library-init
test getrandom() in library initialization without FAKERANDOM_SEED
2021-02-23 22:08:43 +01:00
Daniel Kahn Gillmor
8f2c856d8e test getrandom() in library initialization without FAKERANDOM_SEED
Running "make randomtest" should demonstrates the segfault described
in https://github.com/wolfcw/libfaketime/issues/295
2021-02-23 11:14:37 -05:00
Wolfgang Hommel
b4a822cd6a Merge pull request #294 from dkg/improve-FAKE_RANDOM-tests
Improve tests for FAKE_RANDOM
2021-02-23 06:24:57 +01:00
Daniel Kahn Gillmor
54994ceb0d Improve tests for FAKE_RANDOM
Previously, we had failed to test code with getrandom() against
LD_PRELOAD when FAKERANDOM_SEED was unset.

We also want to try calling getrandom twice in a single process to
make sure that works OK.
2021-02-22 22:49:05 -05:00
Wolfgang Hommel
3c0b101a84 Version bump to v0.9.9 2021-02-21 18:27:02 +01:00
Wolfgang Hommel
44a6d1f0fa Set FORCE_MONOTONIC_FIX for GitHub CI 2021-02-12 17:04:28 +01:00
Wolfgang Hommel
772d9523a7 Do not fail due to timer overrun counter mismatch on GNU/Hurd for now (#287) 2021-02-12 16:59:42 +01:00
Wolfgang Hommel
8b5519d496 Handle EINTR during sem_wait() in selected functions (addresses #291) 2021-02-09 20:16:08 +01:00
Wolfgang Hommel
3ba66842aa Make randomtest.sh use FAKETIME_TESTLIB like the rest of the test cases 2021-02-04 21:40:55 +01:00
Wolfgang Hommel
4359458c7c Merge pull request #289 from dkg/getrandom_test-cleanup
Ease build of getrandom_test
2021-02-04 21:39:02 +01:00
Wolfgang Hommel
726c4657fc Merge branch 'master' of github.com:wolfcw/libfaketime 2021-02-04 21:32:22 +01:00
Wolfgang Hommel
8853afb509 Added optional FAKETIME_TESTLIB environment variable for make test (#288) 2021-02-04 21:30:01 +01:00
Wolfgang Hommel
48f280ac86 Merge pull request #285 from dkg/fix-clobber
Try to fix warning about clobbering under optimization (Closes #284)
2021-02-04 20:07:56 +01:00
Wolfgang Hommel
47e6f5f33d Merge pull request #283 from dkg/update-version-number
fix embedded version number
2021-02-03 19:53:49 +01:00
Wolfgang Hommel
e4e5ea6211 Merge pull request #286 from dkg/speling
Fix spelling
2021-02-03 19:51:19 +01:00
Daniel Kahn Gillmor
206ae9ea80 Ease build of getrandom_test
In trying to test the experimental getrandom features, I found a few
minor problems.  These changes should make it easier to test.

After building, the developer can now just do:

    make -C test randomtest

This will do a basic verfication that the feature works as expected.

I haven't tried to integrate this with the overall "make test".  To do
that right, it should condition the test on the definition of
FAKE_RANDOM.
2021-02-03 13:12:32 -05:00
Daniel Kahn Gillmor
cce377b371 Fix spelling 2021-02-03 11:55:28 -05:00
Daniel Kahn Gillmor
5e6ed4cd2c Try to fix warning about clobbering under optimization (Closes #284)
Without this fix, when compiling with `-O1` or more, we see:

```
libfaketime.c: In function ‘fake_clock_gettime’:
libfaketime.c:2843:7: error: variable ‘ret’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Werror=clobbered]
 2843 |   int ret = INT_MAX;
      |       ^~~
cc1: all warnings being treated as errors
```

This error doesn't happen when using `-O0`.

The warning appears to happen when the compiler optimizes `ret`
because it is the return value for the function call (meaning maybe
preserved in a register, or some other more risky placement that might
break during the `goto` error cases?).  Explicitly marking it as
volatile should keep the compiler from optimizing that way, regardless
of the level of optimization the user asks for.

I got the idea to use `volatile` here from the rather confused
discussion in
https://cboard.cprogramming.com/c-programming/147829-help-me-warning-argument-fmtstring-might-clobbered-longjmp-vfork.html

I admit I don't fully understand what's going on here, and would be
grateful for review by someone who understands the machinery here at a
deeper level than I do.
2021-02-02 20:14:37 -05:00
Daniel Kahn Gillmor
55e634a6ca fix embedded version number 2021-02-02 19:23:13 -05:00
Wolfgang Hommel
532816864e Merge pull request #278 from oxan/prefix-error-messages
faketime: Prefix error messages with faketime
2020-12-08 19:14:47 +01:00
Oxan van Leeuwen
4564afb924 faketime: Prefix error messages with faketime 2020-12-08 17:27:06 +01:00
Wolfgang Hommel
5b8673df54 Updated macOS-specific documentation, especially regarding SIP issues 2020-11-16 17:05:17 +01:00
Wolfgang Hommel
e00ba47ca9 Preliminary documentation related to #275 changes 2020-11-16 16:56:47 +01:00
Wolfgang Hommel
ca2f3fefa1 Preliminary support to intercept getrandom() #275 2020-11-15 21:57:10 +01:00
Wolfgang Hommel
dacc5866a7 Merge pull request #270 from sanjaymsh/ppc64le
Travis-ci: added support for ppc64le
2020-10-07 19:52:48 +02:00
sanjay-cpu
b35e7c8ca6 Travis-ci: added support for ppc64le 2020-10-07 08:28:41 +00:00
Wolfgang Hommel
25a60d0292 Merge pull request #261 from WayneD/master
Some fixes and improvements for utime functions.
2020-07-29 08:11:58 +02:00
Wayne Davison
d90c8c26d3 Some fixes and improvements for utime functions.
- Fix the utime() and utimes() functions to work with a NULL arg
  (which is a request for "now").
- Add missing utimensat() & futimens() functions.
- Add support for a FAKE_UTIME define and enable it by default.  This
  is like defining FAKE_FILE_TIMESTAMPS except that the code defaults
  to NO utime faking unless FAKE_UTIME environment var enables it.
- When utime values are not being faked, the use of a NULL arg or a
  UTIME_NOW nsec value gives the user NOW translated into their fake
  current time.  This is because the caller's fake times are otherwise
  being preserved, so we should help their NOW request also be handled
  as a fake time.
- Mention FAKE_FILE_TIMESTAMPS & FAKE_UTIME in the src/Makefile.
- Move a sanity check in fake_clock_gettime() to where it is actually
  prior to all the pointer dereferences it should protect.
- Get rid of an errant tab in the src/Makefile's comments.
2020-07-28 18:04:11 -07:00
Wolfgang Hommel
c683c81417 Merge pull request #257 from robinlinden/deprecated-func-warning
Fix make test build failure on gcc 9.3
2020-05-29 06:35:51 +02:00
Robin Linden
f19d68ea32 Fix make test build failure on gcc 9.3
On Ubuntu 20.04 using gcc 9.3, make test fails due to a deprecated
function (ftime) warning in combination with -Werror in timetest.c.
Since the warning is from a test testing that the deprecated function
can be replaced using LD_PRELOAD, I think it's reasonable to just
silence the warning in that case.
2020-05-28 23:26:25 +02:00
Wolfgang Hommel
c36674c27f remote automake branch workflow until work on it continues 2020-05-10 13:28:30 +02:00
Wolfgang Hommel
112809f986 Merge branch 'master' of github.com:wolfcw/libfaketime 2020-04-10 13:28:05 +02:00
Wolfgang Hommel
9498b2cacc add ./configure step to action for automake branch 2020-04-10 13:27:51 +02:00
Wolfgang Hommel
c9a3b1bace Merge pull request #248 from sdettmer/fix_settime_when_using_rcfile
Fixes #247, FAKE_SETTIME has effect even if rcfile is present
2020-04-09 19:53:06 +02:00
Wolfgang Hommel
834953480e Merge pull request #249 from sdettmer/settime_update_timestamp_file
settime functions support FAKETIME_UPDATE_TIMESTAMP_FILE (for #239).
2020-04-09 19:47:06 +02:00
Steffen Dettmer
c1d10321a7 settime functions support FAKETIME_UPDATE_TIMESTAMP_FILE (for #239).
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.
2020-04-09 16:06:32 +02:00
Steffen Dettmer
58ccfb6c27 Fixes #247, FAKE_SETTIME has effect even if rcfile is present 2020-04-09 13:04:40 +02:00
Wolfgang Hommel
1e25e1f042 fix for github action for automake branch 2020-04-09 11:41:01 +02:00
Wolfgang Hommel
690ed3f158 github action for automake branch 2020-04-09 06:41:10 +02:00
Wolfgang Hommel
d2f0daf092 Merge pull request #246 from sdettmer/dev/sde/pthread_cond_init_232_lazy_init
Add lazy ftpl_init() to pthread_cond_init_232(), fixes #245.
2020-04-08 20:11:57 +02:00
Steffen Dettmer
c5b5d0b56e Add lazy ftpl_init() to pthread_cond_init_232(), fixes #245. 2020-04-08 19:57:14 +02:00
Wolfgang Hommel
f8a0ad2496 Merge pull request #244 from sdettmer/dev/sde/faketime_link_flags
Added support for FAKETIME_LINK_FLAGS for #243.
2020-04-08 19:47:46 +02:00
Steffen Dettmer
0e3269efdc Added support for FAKETIME_LINK_FLAGS for #243. 2020-04-08 19:40:31 +02:00
Wolfgang Hommel
04e78e67bf Unskip file parsing on improper initialization #240 2020-03-26 20:07:24 +01:00
Wolfgang Hommel
0e798503a4 Merge pull request #237 from FeepingCreature/fix/use-pthread-mutex-initializer-again
replace global state struct with local state struct holding a pointer to the global mutex variable
2020-03-16 13:45:37 +01:00
Mathis Beer
a7f7a54e1d replace global state struct with local state struct holding a pointer to the global mutex variable
this fixes the `{ 0 }` initializer not compiling on some platforms
fix issue 231
fix issue 235
2020-03-16 07:57:07 +01:00
Wolfgang Hommel
8075c2e250 Merge pull request #234 from FeepingCreature/fix/use-appropriate-mask-function
Fix timing issue with multiple threads
2020-03-12 21:39:17 +01:00
Mathis Beer
a12ca58dfa fix threading issue: don't assign to the global lock state struct until we're safely inside the mutex.
Otherwise, we might be overwriting the global lock state from two different
threads at once.
2020-03-12 06:49:29 +01:00
Mathis Beer
b4dea2ef9b Unlock faketime lock on all return paths from libfaketime.c.
These gymnastics are necessary because pthread_cleanup_push
and pthread_cleanup_pop must match exactly 1:1 and appear at
the same level of indentation.

This is because pthread_cleanup_push/pop are implemented in
such a way that pthread_cleanup_push opens a scope and
pthread_cleanup_pop closes it.

They're macros with unbalanced brackets.
C, ladies and gentlemen.

So instead of returning, we have to set a field indicating our
intent to return and then jump to the unlock site.
2020-03-12 06:45:43 +01:00
Mathis Beer
796b30bebf use pthread_sigmask instead of sigprocmask
pthread_sigmask is the one meant for threaded programs.
2020-03-12 06:43:33 +01:00
Wolfgang Hommel
70d26ec15c Merge pull request #230 from FeepingCreature/fix/block-signals-while-locked
Fix deadlock issues with signals: block all signals while inside mutex.
2020-03-03 19:47:49 +01:00
Mathis Beer
052239d828 Fix deadlock issues with signals: block all signals while inside mutex. 2020-03-03 17:22:52 +01:00
Wolfgang Hommel
fe8c0acee6 Merge pull request #229 from FeepingCreature/fix/dont-allocate-stack-buffers
fake_clock_gettime: avoid placing large buffers on the stack
2020-02-20 21:10:19 +01:00
Mathis Beer
c44a332e0e fake_clock_gettime: avoid placing large buffers on the stack 2020-02-20 12:14:14 +01:00
Wolfgang Hommel
a54f204209 Merge pull request #227 from wolfcw/develop
Refresh the monotonic faketime setting envvar when cache expires.
2020-02-14 19:42:23 +01:00
Wolfgang Hommel
195888434a Merge pull request #225 from tjhowse/develop
Refresh the monotonic faketime setting envar when cache expires.
2020-02-14 19:36:06 +01:00
thowse
f7de52c07b Refresh the monotonic faketime setting envar when cache expires. 2020-02-14 10:36:29 +10:00
Wolfgang Hommel
0efe7b3e3e Merge pull request #220 from aristanemi/mul_overflow_fix
timespec multiplication overflow fix
2019-12-17 18:55:20 +01:00
Abhishek Sunkum Rammurthy
b542e14959 time multiplication overflow fix
In 32 bit platforms, timespecmul2() macro function, overflow occurs during multiplication.
Size of `long` type in 32 bit platform is 4 bytes, but the size of `long` type in 64 bit platform is 8 bytes.
2019-12-17 15:16:38 +01:00
Wolfgang Hommel
78385ba8b7 Use -DFAKE_FILE_TIMESTAMPS to intercept utime[s](), by @speq, #183 2019-12-14 21:49:23 +01:00
Wolfgang Hommel
b3dcef470e fix #ifndef for timermul, @speq, #183 2019-12-14 21:30:31 +01:00
Wolfgang Hommel
90f11685b5 wrap nanosec ops in #ifndef, patch by @paul-j-lucas, #219 2019-12-14 19:49:04 +01:00
Wolfgang Hommel
d7ef17a0de Merge pull request #218 from wolfcw/revert-178-automake-branch
Revert "Automake branch"
2019-11-30 09:37:00 +01:00
Wolfgang Hommel
3123ad7fe2 Revert "Automake branch" 2019-11-30 09:36:46 +01:00
Wolfgang Hommel
af2d2e5111 Merge pull request #178 from manchicken/automake-branch
Automake branch
2019-11-30 09:36:36 +01:00
Wolfgang Hommel
11fbc2ada1 Create make-test.yml 2019-11-30 09:16:43 +01:00
Michael D. Stemle, Jr
f92d919fb0 Merged master in and cleaned up.
We no longer need the OSX-specific test. Tests are passing, too.
2019-11-27 14:32:15 -05:00
Wolfgang Hommel
22f8c3dd36 Work around race conditions when semaphore gets deleted by parent process (#217) 2019-11-20 08:43:24 +01:00
Wolfgang Hommel
a0fe6b56b0 Merge pull request #215 from wolfcw/develop
Merge changes from develop branch
2019-11-14 19:33:00 +01:00
Wolfgang Hommel
fdc3c81ae0 Merge pull request #214 from daowens01/unused_variable_compiler_error
Wrap user_per_tick_inc_set_backup declaration in ifdef
2019-11-14 19:08:44 +01:00
David Owens
10b9818c2c Wrap user_per_tick_inc_set_backup declaration in ifdef
Building without FAKE_STAT defined causes compilation errors due to
unused variable user_per_tick_inc_set_backup.  Move declaration inside
FAKE_STAT section along with the code making use of it.
2019-11-14 09:27:27 -06:00
Wolfgang Hommel
826f8b7792 Detect and bail out of endless recursive calls to clock_gettime() (#130) 2019-09-05 22:52:07 +02:00
Wolfgang Hommel
5d1e6325f2 Add FAKE_SETTIME to CFLAGS to intercept time-setting calls (#179) 2019-09-03 12:01:33 +02:00
Wolfgang Hommel
8ed946cb63 Documentation for packagers, esp. about FORCE_PTHREAD_NONVER and FORCE_MONOTONIC_FIX 2019-08-31 21:32:52 +02:00
Wolfgang Hommel
108370f850 Adds FORCE_PTHREAD_NONVER flag for platforms where pthread functions are not intercepted 2019-08-29 09:55:04 +02:00
Wolfgang Hommel
3de0d02353 Add macOS / OSX build to .travis.yml 2019-08-23 21:20:48 +02:00
Wolfgang Hommel
dc2ae5eef3 Add FORCE_MONOTONIC_FIX to .travis.yml 2019-08-23 19:34:51 +02:00
Wolfgang Hommel
1c05fdd333 Adding a simple .travis.yml file 2019-08-23 19:27:38 +02:00
Wolfgang Hommel
c60390a7e3 Updated documentation regarding compatibility, use on macOS, and contributions 2019-08-23 15:24:13 +02:00
Wolfgang Hommel
ece59abf39 Cleanup old and outdated packaging infos 2019-08-23 14:54:08 +02:00
Wolfgang Hommel
d79ed053d7 Updated documentation regarding shared memory, fixed spelling 2019-08-23 14:46:06 +02:00
Wolfgang Hommel
416c5f4708 Fix shared memory cleanup on local creation 2019-08-23 12:29:33 +02:00
Wolfgang Hommel
a238cfa2b6 Added FAKETIME_COMPILE_CFLAGS to Makefiles 2019-08-23 11:38:35 +02:00
Wolfgang Hommel
ba32d1b01c Added FORCE_MONOTONIC_FIX CFLAG to avoid hangs on timedwait (#202 #142) 2019-08-23 10:29:53 +02:00
Wolfgang Hommel
30ba0b852a Fix Makefile to run 'make src' before running 'make test' (#201) 2019-08-23 10:12:38 +02:00
Wolfgang Hommel
5932e38032 Handle platforms that do not implement semopen() (#203) 2019-08-23 10:08:32 +02:00
Wolfgang Hommel
13748ddb22 Fix building on macOS in preparation of v0.9.8 release 2019-08-22 23:39:36 +02:00
Wolfgang Hommel
5f033fe486 Intercept epoll_wait(), epoll_pwait(), and pselect() (#115) 2019-08-22 23:29:48 +02:00
Wolfgang Hommel
52108dba7a Added FAKETIME_XRESET to smoothen run-time transition between 'x' modifier values (#198) 2019-08-22 00:49:21 +02:00
Wolfgang Hommel
5ddb237842 Adjusted tests on macOS based on compilation defaults 2019-08-21 18:42:05 +02:00
Wolfgang Hommel
314b1298c9 Added support for clock_nanosleep() (#105) 2019-08-21 18:05:17 +02:00
Wolfgang Hommel
7573d20cd4 Further preparations for the upcoming v0.9.8 release 2019-08-21 11:01:24 +02:00
Wolfgang Hommel
0c8905f4ad fix stat faking when FAKETIME 'i' modifier is set (#183) 2019-08-21 10:23:01 +02:00
Wolfgang Hommel
57917c4d5a Added follow-file-timestamp mode via FAKETIME='%' and FAKETIME_FOLLOW_FILE (#156) 2019-08-20 19:43:15 +02:00
Wolfgang Hommel
e85863f671 Added note regarding leap year handling in documentation (#145) 2019-08-20 18:07:17 +02:00
Wolfgang Hommel
d5c0050684 Added environment variable FAKETIME_DONT_RESET to enable old start-at behavior (#163) 2019-08-20 15:43:29 +02:00
Wolfgang Hommel
b855b8a0d3 Updated documentation regarding offset specification on x/i modifiers 2019-08-20 13:08:36 +02:00
Wolfgang Hommel
29efeed247 don't fake time during dlsym() calls in ftpl_init (#130) 2019-08-20 10:49:01 +02:00
Wolfgang Hommel
c13e41024e Improved handling of shm/semaphores w.r.t. stale states (#199) 2019-08-20 09:53:22 +02:00
Wolfgang Hommel
65cdc7b718 Avoid hangs with clock_monotonic for pthread_cond_timedwait 2019-08-19 19:38:01 +02:00
Wolfgang Hommel
d923612c2b Improved cross-platform compatibility defaults 2019-08-19 19:16:07 +02:00
Wolfgang Hommel
59127e7514 More error details on sem_open failures 2019-08-19 14:21:47 +02:00
Wolfgang Hommel
3b494ac6c9 Safety check when creating semaphore locally 2019-08-18 19:06:52 +02:00
Wolfgang Hommel
073d185102 More detailed error messages on shm errors 2019-08-16 15:53:47 +02:00
Wolfgang Hommel
a70db9196a Shared memory cleanup when it was created locally 2019-08-13 19:48:29 +02:00
Wolfgang Hommel
7498c405ed Create shared memory if we don't have it yet (#120) 2019-08-13 19:35:45 +02:00
Wolfgang Hommel
aa091db286 Preparations for 0.9.8 release 2019-08-12 12:25:41 +02:00
Wolfgang Hommel
5e56e9a8fe addressing #190 #196 2019-08-04 18:47:30 +02:00
Wolfgang Hommel
fe42c2b4cf start-at-faketime startup fix, addresses #196 2019-08-04 17:59:33 +02:00
Wolfgang Hommel
579b908580 Merge pull request #194 from qnox/configuration_reload_fix
fixed configuration reload
2019-06-26 19:20:38 +02:00
qnox
2827a69ffe fixed configuration reload 2019-06-26 17:40:37 +02:00
Wolfgang Hommel
949183381f Merge pull request #192 from qnox/fake_pthreads_thread_safety
Fixed thread safety issue in pthread faking methods
2019-06-01 12:28:07 +02:00
qnox
ff48a007a2 fixed thread safety issue in pthread faking methods 2019-05-31 22:46:54 +02:00
Wolfgang Hommel
9846eceb10 Use absolute offset in #190, fix case 1 2019-05-03 16:03:13 +02:00
Wolfgang Hommel
7bc0d5044f Use absolute offset in #190 2019-05-03 15:45:28 +02:00
Wolfgang Hommel
ceac4c7036 Merge pull request #184 from FeepingCreature/fix-inconsistent-envvar
Rename DONT_FAKE_MONOTONIC to FAKETIME_DONT_FAKE_MONOTONIC for consistency
2019-02-05 08:11:21 +01:00
Mathis Beer
5c4fdb5173 Rename DONT_FAKE_MONOTONIC to FAKETIME_DONT_FAKE_MONOTONIC for consistency.
The old variable still works.
2019-02-05 07:45:31 +01:00
Mike Stemle
150a6cb3b2 Added a check for missing libtool. 2018-10-11 10:22:04 -04:00
Michael D. Stemle, Jr
39a85e380c Fixed a _bunch_ of autotools bugs. 2018-10-07 22:38:55 -04:00
Michael D. Stemle, Jr
825043515f Applying fixes for GNU/Linux, and the MT variant of the library. 2018-10-03 22:17:28 -04:00
Michael D. Stemle, Jr
335617c4c7 Fixed a bunch more issues, including prefix-related issues and library version breakage. 2018-10-02 23:22:51 -04:00
Michael D. Stemle, Jr
96668a9c6d Fixing a couple of issues I just found. 2018-10-02 22:20:14 -04:00
Michael D. Stemle, Jr
24fd806e6b Added GNU autotools support. 2018-10-02 22:02:30 -04:00
Michael D. Stemle, Jr
39c6872f6d Removing old makefiles. 2018-10-01 20:08:27 -04:00
Wolfgang Hommel
5c6518c597 Merge pull request #171 from ringlej/fixes
Allow specifying fractions of a second when setting FAKETIME
2018-08-01 19:29:00 +02:00
Jon Ringle
93148b3599 Allow specifying fractions of a second when setting FAKETIME
Signed-off-by: Jon Ringle <jringle@gridpoint.com>
2018-07-31 16:33:57 -04:00
Wolfgang Hommel
9a2c84d68c Merge pull request #161 from tpetazzoni/gcc8-fixes
Gcc8 fixes
2018-05-18 06:20:16 +02:00
Thomas Petazzoni
8e5af129ff faketime.c: fix shared_objs[] array size
shared_objs[] will contain the concatenation of sem_name and shm_name,
which are both 4096 bytes long, and shared_objs[] itself is only 4096
bytes long. This causes a build failure with gcc 8.x:

faketime.c: In function 'main':
faketime.c:289:45: error: '%s' directive output may be truncated writing up to 4095 bytes into a region of size between 0 and 4095 [-Werror=format-truncation=]
     snprintf(shared_objs, PATH_BUFSIZE, "%s %s", sem_name, shm_name);
                                             ^~             ~~~~~~~~
faketime.c:289:5: note: 'snprintf' output between 2 and 8192 bytes into a destination of size 4096
     snprintf(shared_objs, PATH_BUFSIZE, "%s %s", sem_name, shm_name);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This commit fixes that by enlarging the shared_objs[] array to twice
the of PATH_BUFSIZE, plus one byte for the space.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
2018-05-17 23:35:08 +02:00
Thomas Petazzoni
096c11b563 libfaketime.c: fix uninitialized 'result' use
The pthread_cond_timedwait_common() function declares a 'result'
variable, but in some code paths, it may be returned without being
initialized. This commit fixes that by initializing the variable.

Fixes:

libfaketime.c: In function 'pthread_cond_timedwait_common':
libfaketime.c:2534:7: error: 'result' may be used uninitialized in this function [-Werror=maybe-uninitialized]
   int result;
       ^~~~~~

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
2018-05-17 23:31:01 +02:00
Thomas Petazzoni
9bfae502d1 libfaketime.c: fix pthread_cleanup_push() build failure
gcc 8.x introduced stricter checking on types, and the trick to cast
pthread_mutex_unlock() into a function acceptable for
pthread_cleanup_push() no longer builds:

libfaketime.c: In function 'fake_clock_gettime':
libfaketime.c:2039:24: error: cast between incompatible function types from 'int (*)(pthread_mutex_t *)' {aka 'int (*)(union <anonymous> *)'} to 'void (*)(void *)' [-Werror=cast-function-type]
   pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, (void *)&time_mutex);
                        ^

Rather than continuing to hack around, introduce an auxilliary
function with the type expected by pthread_cleanup_push().

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
2018-05-17 23:31:01 +02:00
Thomas Petazzoni
0d964363a4 libfaketime.c: fix strncpy() issues raised by gcc 8.x
gcc 8.x introduced stricter checking on strncpy(), and causes the
following build failures:

libfaketime.c: In function 'fake_clock_gettime.part.4':
libfaketime.c:2134:7: error: 'strncpy' specified bound 256 equals destination size [-Werror=stringop-truncation]
       strncpy(user_faked_time, tmp_env, BUFFERLEN);
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfaketime.c:2134:7: error: 'strncpy' specified bound 256 equals destination size [-Werror=stringop-truncation]
       strncpy(user_faked_time, tmp_env, BUFFERLEN);
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfaketime.c: In function 'ftpl_init':
libfaketime.c:1884:12: error: 'strncpy' specified bound 1024 equals destination size [-Werror=stringop-truncation]
     (void) strncpy(ft_spawn_target, getenv("FAKETIME_SPAWN_TARGET"), 1024);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfaketime.c:1945:5: error: 'strncpy' specified bound 8192 equals destination size [-Werror=stringop-truncation]
     strncpy(user_faked_time_fmt, tmp_env, BUFSIZ);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfaketime.c: In function 'ftpl_init':
libfaketime.c:1884:12: error: 'strncpy' specified bound 1024 equals destination size [-Werror=stringop-truncation]
     (void) strncpy(ft_spawn_target, getenv("FAKETIME_SPAWN_TARGET"), 1024);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfaketime.c:1945:5: error: 'strncpy' specified bound 8192 equals destination size [-Werror=stringop-truncation]
     strncpy(user_faked_time_fmt, tmp_env, BUFSIZ);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This commit fixes that by making sure we keep one final byte for the
nul terminator, as suggested by
https://github.com/wolfcw/libfaketime/issues/150.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
2018-05-17 23:31:01 +02:00
Wolfgang Hommel
8107db7849 Improved parsing error logging 2018-05-03 19:36:47 +02:00
Wolfgang Hommel
c9473def03 Merge pull request #146 from FeepingCreature/feature/wait-ms
Add FAKETIME_WAIT_MS to force pthread_cond_timedwait to wait x ms instead of what its parameters say.
2018-02-20 06:29:18 +01:00
Wolfgang Hommel
baeed314cf Merge pull request #148 from dkg/use-CPPFLAGS
Use CPPFLAGS during compilation
2018-02-20 06:22:38 +01:00
Daniel Kahn Gillmor
90727b7d19 Use CPPFLAGS during compilation
CPPFLAGS is traditionally used to include C preprocessor flags.  While
faketime doesn't apply anything to CPPFLAGS directly, it is good form
to adopt standard settings that might be externally applied.
2018-02-19 14:20:31 -08:00
Wolfgang Hommel
8c22d91057 Merge pull request #147 from dkg/fixalpha
fix gettimeofday() on alpha (see https://bugs.debian.org/890813)
2018-02-19 20:41:23 +01:00
Michael Cree
a5d7f5b1cc fix gettimeofday() on alpha (see https://bugs.debian.org/890813)
In https://bugs.debian.org/890813, Michael Cree <mcree@orcon.net.nz>
reports:

>  The faketime package fails to work correctly on the Alpha
>  architecture. This failure of faketime to work correctly is the
>  reason for the mbedtls FTBFS, which uses faketime in its test
>  suite [1].
>
>  Consider the following test program (which I call "time-test"):
>
>  #include <stdio.h>
>  #include <sys/time.h>
>  #include <unistd.h>
>
>  int main(void)
>  {
>      struct timeval tv;
>
>      for (int j=0; j<5; j++) {
>          usleep(10000);
>          gettimeofday(&tv, NULL);
>          printf("s=%ld    us=%ld\n", tv.tv_sec, tv.tv_usec);
>      }
>      return 0;
>  }
>
>  When run it produces output like:
>
>  s=1519025990    us=838219
>  s=1519025990    us=848965
>  s=1519025990    us=859711
>  s=1519025990    us=870456
>  s=1519025990    us=881202
>
>  But when run as (with faketime built in its source directory):
>
>  LD_PRELOAD=faketime-0.9.7/src/libfaketime.so.1 FAKETIME="-1d" ./time-test
>
>  the output is:
>
>  s=2199023743604    us=0
>  s=2199023657204    us=0
>  s=2199023570804    us=0
>  s=2199023484404    us=0
>  s=2199023398004    us=0
>
>  which is definitely not correct.
>
>  The reason for the incorrect behaviour is that there are two
>  gettimeofday symbols in libc on Alpha and the dlsym() call to link
>  to the gettimeofday() is picking up the function with the wrong ABI.
>  I attach a patch to fix that.  Faketime built with the attached
>  patch works correctly and with a fixed faketime the mbedtls source
>  package builds to completion on Alpha.
2018-02-19 11:30:11 -08:00
Mathis Beer
229ce22fbc Add FAKETIME_WAIT_MS to force pthread_cond_timedwait to wait x ms instead of what its parameters say.
This prevents us from getting stuck in place when the timestamp changes.
2018-02-19 10:26:26 +01:00
Wolfgang Hommel
0487e41c34 Merge pull request #141 from dkg/speling
fix spelling :)
2018-01-16 20:25:11 +01:00
Daniel Kahn Gillmor
b3a2667e9f fix spelling :) 2018-01-16 14:21:36 -05:00
Wolfgang Hommel
6a4d1cc84e Merge pull request #140 from jprjr/musl-compat
Only use dlvsym on glibc systems
2018-01-14 19:55:09 +01:00
John Regan
87d2a67401 Only use dlvsym on glibc systems
This makes libfaketime compatible with musl libc, and likely others.
2018-01-14 12:31:39 -06:00
Wolfgang Hommel
3881dd2ebf Merge pull request #138 from mliertzer/fake_pthread
Implement fix for pthread_cond_timedwait
2018-01-02 12:23:57 +01:00
Matthias Liertzer
fb91c4fcde Implement a fix for pthread_cond_timedwait with faketime
pthread_cond_timedwait takes an absolute time as an argument, which
the function directly passes on to the kernel via the futex
syscall. In an application this absolute time argument is calculated
via the fake times provided by libfaketime. Since the kernel has no
knowledge of the fake time, pthread_cond_timedwait must be redefined
such that it converts the fake time back to real time before passing
it on.
2018-01-02 02:22:59 +01:00
Matthias Liertzer
ab7a2302f2 Rename compat library enumeration 2018-01-02 01:42:41 +01:00
Matthias Liertzer
d117ad79a2 Fix spelling of positive 2018-01-02 01:42:41 +01:00
Matthias Liertzer
5235f6f417 Make sure that DONT_FAKE_MONOTONIC=1 affects all monotonic clocks 2018-01-02 01:40:10 +01:00
Matthias Liertzer
3376334dfc Hide ftpl_init and ft_cleanup from exported functions 2018-01-02 00:16:23 +01:00
Wolfgang Hommel
bb635e4367 Treat unknown clock_ids like CLOCK_REALTIME (experimental) 2017-11-30 20:28:06 +01:00
Wolfgang Hommel
a79f5330f4 Fix #114 as suggested by @niraizik 2017-11-17 20:27:58 +01:00
Wolfgang Hommel
0dee4f88e0 Updated OSX packaging info for v0.9.7 2017-11-14 20:37:55 +01:00
Wolfgang Hommel
c9a681c3e3 Preparations for 0.9.7 release 2017-11-14 20:28:32 +01:00
Wolfgang Hommel
4ce283594f Merge pull request #122 from jasonsoooz/patch-1
Mention possibility of running java in README
2017-10-01 10:06:43 +02:00
Jason Soo
d42a2a9ec7 Mention possibility of running java in README 2017-09-30 15:51:39 +10:00
Wolfgang Hommel
5d41d41da8 Merge pull request #119 from dariaphoebe/namefix-1
fix my name
2017-07-25 07:15:29 +02:00
Daria Phoebe Brashear
46aa5773c7 fix my name 2017-07-24 16:42:38 -04:00
Wolfgang Hommel
3fe3cf1536 Updated Homebrew formula 2017-07-13 18:35:26 +02:00
Wolfgang Hommel
b23fbd5c5e Pass existing null pointers in select() 2017-06-08 19:50:34 +02:00
Wolfgang Hommel
fa88a28c4d Avoid null pointer dereference in select() 2017-06-07 20:37:12 +02:00
Wolfgang Hommel
6e4037768a early preparations for 0.9.7 release 2017-05-19 21:51:25 +02:00
Wolfgang Hommel
fa91edb0a3 Started to integrate mpareja's CLOCK_BOOTTIME patch 2017-05-19 19:14:58 +02:00
Wolfgang Hommel
725c80673c Updated for macOS Sierra 2017-05-19 19:05:12 +02:00
Wolfgang Hommel
4a9c93475e Fix macro-related compiler warnings 2017-05-19 18:55:11 +02:00
Wolfgang Hommel
842c2e4269 Merge branch 'macos-sierra' 2017-05-19 18:51:01 +02:00
Wolfgang Hommel
af0b2f85a7 Merge pull request #113 from umitanuki/support-select
Support select call
2017-05-19 18:22:14 +02:00
Hitoshi Harada
120f6898f4 Support select call 2017-05-18 17:52:03 -07:00
Wolfgang Hommel
3c0ce9c885 Merge pull request #108 from manchicken/osx-fix
Adding some code to make OSX build properly.
2017-02-28 19:19:51 +01:00
Michael D. Stemle, Jr
2c78776aaf Adding some code to make OSX build properly. 2017-02-28 10:19:32 -05:00
Balint Reczey
5dd65efa14 Merge pull request #107 from jwilk/spelling
Fix typo in README
2017-02-28 13:28:44 +01:00
Jakub Wilk
d1fdfb1950 Fix typo in README 2017-02-28 12:22:50 +01:00
Wolfgang Hommel
57b098c98a Merge pull request #103 from andir/master
Disable the non-null compare warning/error.
2016-12-20 19:46:02 +01:00
Andreas Rammhold
47e958b753 Disable the non-null compare warning/error.
We rely on the provided local library definitions for the hooked
functions which in some cases (GCC >6) carry a non-null-attribute flag
which causes compile errors on `!= NULL` checks.
2016-12-20 19:30:14 +01:00
Wolfgang Hommel
1d5976d1ab Merge pull request #102 from infinity0/patch-1
Document the faking of filesystem timestamps
2016-12-09 20:27:20 +01:00
Ximin Luo
582ae36e1d Document the faking of filesystem timestamps
It's hard to notice the tiny reference to `fstat(2)` amongst all the text about the system clock. This is a significant behaviour that is very surprising, and the default setting (on) messes with buildsystems in a counter-intuitive way. Also document how to switch it off.
2016-12-09 00:24:05 +01:00
Wolfgang Hommel
8fb6330a28 Fixes compilation issues on macOS Sierra 2016-10-30 13:25:38 +01:00
Wolfgang Hommel
da778084e5 Merge pull request #92 from hbuchsbaum/work
do not destroy environment when parsing FAKETIME_ONLY_CMDS
2016-06-27 08:54:00 +02:00
Helmut Buchsbaum
9220b5c58e do not destroy environment when parsing FAKETIME_ONLY_CMDS
Using strtok_r directly on environment string changes the environment
e.g. for subprocesses and thus changes the FAKETIME_ONLY_CMDS
setting for the subprocess to the first command only.

Avoid this by copying the environment string before parsing.
2016-06-27 08:13:33 +02:00
Wolfgang Hommel
b68f2820c4 Merge pull request #91 from jwilk/spelling
Fix spelling mistakes
2016-06-02 21:51:55 +02:00
Jakub Wilk
4786b94f8e Fix grammar in README
"allow" is a transitive verb, which requires an object,
so "allow to <verb>" is ungrammatical.
2016-06-02 21:36:54 +02:00
Jakub Wilk
0d790dabb6 Fix license name in README
There's no such thing as "GNU Public License";
GPL stands for "General Public License".
2016-06-02 21:31:43 +02:00
Jakub Wilk
6de283f621 Fix typos 2016-06-02 21:31:42 +02:00
Wolfgang Hommel
7f907c32fc Merge pull request #86 from udda/udda-patch-1
Call printf only once in usage(char*)
2016-03-15 12:34:05 +01:00
Wolfgang Hommel
0af6be50cb Merge pull request #87 from steffen-kiess/fix-init
Do not fake times during ftpl_init()
2016-03-15 12:32:56 +01:00
Steffen Kieß
b193c95475 Do not fake times during ftpl_init()
Some libc functions called by ftpl_init() might call fstat() or a similar
function which is intercepted by libfaketime. In this case, the time should
not be faked because the static variables are not yet set up properly.

See https://github.com/wolfcw/libfaketime/issues/72 for further information.
2016-03-15 10:46:05 +01:00
Mario Cianciolo
d95d96f5ea Call printf only once in usage(char*)
Replace multiple calls to printf with one single call, passing the entire string at once.
I think this is faster and more readable.
2016-03-07 17:47:23 +01:00
Wolfgang Hommel
904cc5007d Merge pull request #84 from vavrusa/master
Fixed coarse clock on platforms that don't support them
2016-01-29 17:35:15 +01:00
Marek Vavrusa
811b7916ad Fixed coarse clock on platforms that don't support them
having same number for coarse and non-coarse clock
leads to duplicate case values in switches
2016-01-29 11:20:39 +00:00
Wolfgang Hommel
74425d76e1 Updated regarding coarse clocks 2015-12-28 18:46:39 +01:00
Wolfgang Hommel
3a26d7b3bb Merge branch 'azat-coarse' into develop 2015-12-28 17:55:32 +01:00
Azat Khuzhin
4398deaa3d Raw support for COARSE clocks 2015-12-28 16:54:55 +03:00
Georg Koppen
18f5ec0671 Allow more than one command being skipped 2015-06-04 18:42:20 +02:00
Wolfgang Hommel
638a535b5f Merge pull request #65 from kilobyte/master
Fix build failure on x32 (printf warnings).
2015-03-09 18:48:37 +01:00
Adam Borowski
cc4c1c3a29 Fix build failure on x32 (printf warnings).
On x32, time_t is 64-bit to avoid Y2038 problems.  This doesn't play well
using printf("%ld"), and -Werror turns this into a build failure.
2015-03-09 08:39:06 +01:00
Wolfgang Hommel
6357820d52 Added hint about library search paths 2015-02-19 20:24:07 +01:00
Jon Ringle
64cb35857c Merge branch 'develop' (Jon Ringle's patches)
Merge pull request #55 from ringlej/feature/fix-FAKETIME-cache

Conflicts:
	src/libfaketime.c
2015-02-08 17:44:50 +01:00
Wolfgang Hommel
28d0acfedb Merge pull request #62 from dubek/fix-mt-build
Fix libfaketimeMT build to define PTHREAD
2015-01-08 11:24:03 +01:00
Dov Murik
3ed13f498c Fix libfaketimeMT build to define PTHREAD 2015-01-07 17:38:00 -05:00
Erich E. Hoover
afbb1f20c2 Fix possible infinite loop on construction. 2014-12-17 21:40:13 +01:00
Balint Reczey
68772ec36a Hide internal functions
Also remove unused fake_time().
2014-12-11 08:13:40 +01:00
Balint Reczey
3bb30f74b3 Use constructor attribute at _declaration_ 2014-12-11 08:06:28 +01:00
Erich E. Hoover
0bde083556 Make sure that the constructor has been called when the loader chose to load another constructor first. 2014-12-11 08:05:21 +01:00
Wolfgang Hommel
10b479cf29 Merge pull request #59 from mac-joker/master
New features: custom timestamp file and cache managment
2014-11-21 08:54:36 +01:00
Joker
75896bdd32 added runtime cache manipulation: change duration and active state with environment variables 2014-11-17 10:42:15 +01:00
Joker
6c207c9c68 Custom timestamp filename added: ~/.faketimerc alternative 2014-11-17 10:28:20 +01:00
Balint Reczey
527478d318 Merge pull request #58 from ltfetch/master
Wait for all transitive child processes to exit
2014-10-28 00:00:57 +01:00
ltfetch
48ef50f6c3 use pipe to block process exit until all transitive children exit 2014-10-26 20:40:24 -05:00
ltfetch
035add4eff don't leak pipe fd 2014-10-27 01:10:13 +00:00
Wolfgang Hommel
455261985d Merge pull request #55 from ringlej/feature/fix-FAKETIME-cache
Feature/fix faketime cache
2014-08-26 22:37:56 +02:00
Wolfgang Hommel
e680ca9bce Merge pull request #54 from ringlej/feature/sem_timedwait
Add support to fake sem_timedwait
2014-08-26 22:33:21 +02:00
Jon Ringle
1c5a717528 Reset ftpl_starttime when setting new relative FT_START_AT time
Signed-off-by: Jon Ringle <jringle@gridpoint.com>
2014-08-26 13:23:59 -04:00
Jon Ringle
bdd0f0aea9 Don't parse user_faked_time if it hasn't changed
Signed-off-by: Jon Ringle <jringle@gridpoint.com>
2014-08-26 11:24:18 -04:00
Jon Ringle
7c26cffac6 Re-evaluate FAKETIME environment when cache expires
When the cache expires, the FAKETIME environment does not get re-evaluated
if FAKETIME value changes. This used to work on libfaketime-0.9.1, but was
broken at some point afterwards. This fixes this problem

Signed-off-by: Jon Ringle <jringle@gridpoint.com>
2014-08-26 11:24:13 -04:00
Jon Ringle
cac3dc732a Add support to fake sem_timedwait
Signed-off-by: Jon Ringle <jringle@gridpoint.com>
2014-08-26 11:16:35 -04:00
Wolfgang Hommel
c7d7eeb49d Merge pull request #52 from joyent/man-exclude-monotonic
docs: add --exclude-monotonic to man page.
2014-08-18 09:27:03 +02:00
Julien Gilli
cae9387908 docs: add --exclude-monotonic to man page.
This was missing from PR #49.
2014-08-17 22:17:23 -07:00
Wolfgang Hommel
a6c8bb4636 Merge pull request #50 from joyent/sunos-smartos-support
Make libfaketime build, run and pass tests on SmartOS.
2014-08-07 19:46:48 +02:00
Julien Gilli
95b70c7acc Make libfaketime build, run and pass tests on SmartOS.
Since SmartOS is close to SunOS, it's possible that these changes make
libfaketime build and run on other SunOS-like platforms.

These changes were tested on MacOS X and Ubuntu 12.04, and no regression
appeared during testing.
2014-08-06 11:29:02 -07:00
Wolfgang Hommel
841b782a4c Started adding changes since v0.9.6 release 2014-07-26 09:56:41 +02:00
Wolfgang Hommel
03da54787c Merge pull request #49 from joyent/dont-fake-monotonic-clocks
Add --exclude-monotonic command line option.
2014-07-26 09:50:55 +02:00
Julien Gilli
d19da98bb4 Add --exclude-monotonic command line option.
--exclude-monotonic prevents faketime from overriding
the clock with id CLOCK_MONOTONIC when using clock_gettime.

Add DONT_FAKE_MONOTONIC env variable to libfaketime that
has the same effect.

Add functional test for DONT_FAKE_MONOTONIC support.
2014-07-25 15:43:38 -07:00
Gerardo Malazdrewicz
3bed636a41 Debian Bug#753460: Updated fix for 699599
This patch checks if __clock_gettime is available, and if not,
it uses clock_gettime instead.

Maybe this patch can be improved using dlvsym.
2014-07-19 11:07:37 +02:00
Wolfgang Hommel
70aa6b394d Preparations for 0.9.6 release 2014-06-07 17:04:02 +02:00
Antonio Terceiro
1faf137f72 fix handling of existing LD_PRELOAD in environment
This patch fixes handling of the string length when composing an updated
 LD_PRELOAD that includes both the previous value and the entry for
 libeatmydata.
2014-06-07 16:50:05 +02:00
Kees Cook
7d1a8307e1 pass through exit codes when possible, otherwise report
failure and full waitpid status and exit with a failure.
2014-06-07 16:42:46 +02:00
Wolfgang Hommel
7fdcd1adaf Merge branch 'develop' 2014-02-14 15:59:26 +01:00
Wolfgang Hommel
c3e4760338 Updated documentation for v0.9.6 & Makefile consolidation 2014-02-14 15:59:06 +01:00
Wolfgang Hommel
740e2858dc OSX autoselection in primary Makefile 2014-02-13 12:33:00 +01:00
Han Jiang
1b6cdf3d0f valgrind complains memory leak due to lack of sem_close() 2014-01-26 17:18:21 +01:00
Han Jiang
a34c2bd8c3 Typo when showing version information 2014-01-24 15:33:39 +01:00
Wolfgang Hommel
b28b5c3a5d Update of the Homebrew formula and docs 2013-11-15 23:37:31 +01:00
Wolfgang Hommel
106818614d Minor source code style fixes 2013-11-07 19:35:18 +01:00
Wolfgang Hommel
e653c388bf Minor updates to debug msgs and docs related to filter commands 2013-10-30 21:47:56 +01:00
Wolfgang Hommel
64519e28e0 Merge pull request #37 from rbalint/filter-commands
Filter commands
2013-10-30 13:31:05 -07:00
Balint Reczey
0d04c87755 Constify progname 2013-10-28 23:02:21 +01:00
Balint Reczey
c2ca839b6a Limit faking based on command name 2013-10-28 22:58:03 +01:00
Wolfgang Hommel
368f58c0f8 Added installation via Fink on OSX 2013-10-27 21:53:19 +01:00
Wolfgang Hommel
04ae576541 Packaging details, some for Linux 2013-10-27 11:33:16 +01:00
Wolfgang Hommel
2d0cc5d86b Packaging details, starting with OS X 2013-10-27 10:24:20 +01:00
Wolfgang Hommel
3a8a2b0351 fix value for kFreeBSD 2013-10-20 21:56:56 +02:00
Balint Reczey
1f938d9642 Use SIGUSR1 instead of SIGRTMIN in tests
This will probably fix compilation on Debian GNU/Hurd
2013-10-20 17:28:29 +02:00
Balint Reczey
5fb86ae178 Define CLOCK_MONOTONIC_RAW where it is not present
This fixes compilation on Debian GNU/kFreeBSD
2013-10-20 17:16:20 +02:00
Balint Reczey
27a4e3a7ad Fall back to default timer_settime() & timer_gettime() if no versioned version is present 2013-10-20 16:53:40 +02:00
Balint Reczey
23200c4321 Fix tests on libc 2.17 2013-10-20 16:43:10 +02:00
Wolfgang Hommel
76edab7837 Fix -lrt issues in Makefile 2013-10-18 17:45:57 +02:00
Wolfgang Hommel
3ac3286356 Do not use -ldl -lm when linking the wrapper 2013-10-16 20:08:57 +02:00
Balint Reczey
bb278fc159 Define config file parsing related variables in smaller scopes 2013-10-16 13:42:25 +02:00
Ray Donnelly
1bb5ee3920 Ensure late calls return correct results
.. the cache expiration would reset to using +0 as
the faketime ignoring the FAKETIME env var.
2013-10-16 11:24:26 +02:00
Balint Reczey
d1e7781db6 Add nanosecond resolution to file stat functions
Based on Ray Donnelly's idea in ddf7f4ab35
2013-10-16 10:56:45 +02:00
Balint Reczey
9c2b1a6295 Drop unused code 2013-10-16 10:19:25 +02:00
Balint Reczey
3a2d8e2ccc Enable faking internal calls on OS X
Tested on OS X 10.8 with the test suite
2013-10-16 10:00:51 +02:00
Balint Reczey
c719a977a7 Finish safe faking of internal calls 2013-10-16 09:33:50 +02:00
Balint Reczey
c1cc101f91 Fake __clock_gettime() and similar calls using __... calls
This breaks potential infinite loops.
2013-10-16 09:16:05 +02:00
Wolfgang Hommel
cd3597174c Remove second '-lrt' on linker calls to fix 32-bit building issue 2013-10-16 08:11:02 +02:00
Wolfgang Hommel
458c6d693d fix directory permissions on install 2013-10-13 18:25:52 +02:00
Wolfgang Hommel
a8f8378e77 MacPorts changeset 112093 by ryandesign 2013-10-13 12:24:52 +02:00
73 changed files with 7622 additions and 983 deletions

23
.github/workflows/make-test.yml vendored Normal file
View 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, ubuntu-22.04]
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
View File

@@ -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
View 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

View File

@@ -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

View File

@@ -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

100
NEWS
View File

@@ -1,3 +1,101 @@
List of changes for v0.9.12
===========================
Since 0.9.11:
- Improved macOS compatibility (@usertam)
Since 0.9.10:
- Fixed various cross-platform compile-time issues
- Honor nanosecond parameters/fields in relevant system calls
- Limited improvements to enhance compatibility with other
LD_PRELOAD libraries
- Added selected more intercepted system calls
- Unset FAKETIME_SHARED automatically for child processes
when enabling FAKETIME_FLSHM=1
- Disable shared memory for child processes through
FAKETIME_DISABLE_SHM=1
Since 0.9.9:
- automatically try to decide about FORCE_MONOTONIC_FIX
at run-time when not set as a compile-time flag
- 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 +139,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!

506
README
View File

@@ -1,7 +1,5 @@
=======================================================
libfaketime, version 0.9.5 (October 2013)
(previously also know as FakeTime Preload Library)
=======================================================
libfaketime, version 0.9.12 (June 2025)
=======================================
Content of this file:
@@ -18,89 +16,130 @@ 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.
If FORCE_MONOTONIC_FIX was not set as a compile-time flag, you can also
set an environment variable FAKETIME_FORCE_MONOTONIC_FIX=1 if you want
to enable the fix at run-time, or to 0 if you explicitly want to disable
it. The fix is automatically enabled if libfaketime was compiled on a
system with glibc as the underlying libc implementation, and a glibc
version is detected at run-time that is assumed to need this workaround.
Please use Github issues at https://github.com/wolfcw/libfaketime/issues
to report any observed hangs during CLOCK_MONOTONIC tests and report
your CPU architecture, libc implementation (e.g., glibc 2.30) and any
other details that might help (e.g., Linux distribution, use within, e.g.,
Docker containers etc.).
Please try to avoid compiling with FORCE_MONOTONIC_FIX on platforms that
do not need it. While it won't make a difference in most cases, depending
on the specific FAKETIME settings in use, it would cause certain
intercepted functions such as pthread_cond_timedwait() return with a
time-out too early or too late, which could break some applications.
Try compiling without FORCE_MONOTONIC_FIX first and check whether the
tests appear to hang. If they do, you can either set the
FAKETIME_FORCE_MONOTONIC_FIX environment variable to 1, or re-compile
with FORCE_MONOTONIC_FIX set.
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 +153,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 +173,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 +203,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 +240,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 \
bash -c 'while [ $SECONDS -lt 5 ]; do date; sleep 1; done'
LD_PRELOAD=src/libfaketime.so.1 FAKETIME="@2000-01-01 11:12:13" \
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 +273,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 +321,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,29 +337,33 @@ 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
LD_PRELOAD=./libfaketime.so.1 FAKETIME="+1,5y x10,0" \
/bin/bash -c 'while true; do echo $SECONDS ; sleep 1 ; done'
bash -c 'while true; do echo $SECONDS ; sleep 1 ; done'
For each second that the endless loop sleeps, the executed bash shell will
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 +377,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 +386,172 @@ 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
Setting the environment variable FAKETIME_FOLLOW_ABSOLUTE=1 enables a submode
of FAKETIME_FOLLOW_FILE behavior where fake time ONLY advances when the follow
file's timestamp advances. In this mode an application that is not subject to
libfaketime LD_PRELOAD intercept can absolutely control time for applications
that are hooked by libfaketime. For example, a host application can control the
timestamp of a follow file mapped into a container to implement (relatively)
clean pause/resume behavior for fake time applications running within the
container.
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).
Use of shared memory can be disabled by setting the FAKETIME_DISABLE_SHM
environment variable, or equivalently, passing --disable-shm to faketime.
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 +590,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 +598,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 +613,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 +663,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 +724,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 +747,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 +800,3 @@ Bug reports, feature suggestions, success reports, and patches/pull
requests are highly appreciated:
https://github.com/wolfcw/libfaketime

View File

@@ -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,84 @@ 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.
5) Working with the new arm64e system binaries in Apple Silicon
---------------------------------------------------------------
Since Apple Silicon, Apple started shipping system binaries compiled against
the `arm64e` ABI. This new ABI enforces Pointer Authentication Codes (PACs),
and enforces assembly instructions to sign and check pointer signatures to
prevent malicious control flow altering.
$ file /bin/date
/bin/date: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]
/bin/date (for architecture x86_64): Mach-O 64-bit executable x86_64
/bin/date (for architecture arm64e): Mach-O 64-bit executable arm64e
Most importantly, the new `arm64e` ABI is incompatible with the normal `arm64`
ABI we are used to; this is done so that everything `arm64e` is PAC-enforced.
As a result, this will happen when we try to hook naive `arm64` libfaketime on
system binaries (and vice versa with `arm64e` libfaketime on `arm64` binaries):
$ DYLD_INSERT_LIBRARIES=libfaketime.1.dylib /bin/date
dyld[5788]: terminating because inserted dylib 'libfaketime.1.dylib' could not be loaded:
tried: 'libfaketime.1.dylib' (mach-o file, but is an incompatible architecture (have 'arm64', need 'arm64e'))
Since PR #497, we now compile libfaketime with a fat library/binary setup, so
that we support both ABIs at the same time:
$ file libfaketime.1.dylib
libfaketime.1.dylib: Mach-O universal binary with 2 architectures: [arm64:Mach-O 64-bit dynamically linked shared library arm64] [arm64e:Mach-O 64-bit dynamically linked shared library arm64e]
libfaketime.1.dylib (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64
libfaketime.1.dylib (for architecture arm64e): Mach-O 64-bit dynamically linked shared library arm64e
Unfortunately, Apple does not support running third-party `arm64e` code yet,
since the ABI is still unstable. This means that you cannot use libfaketime
on system `arm64e` binaries out of the box, at the time of writing.
If you really need to, you may disable SIP in the recovery terminal:
(in recovery) # csrutil disable
And enable the experimental ABI after boot:
(in regular boot) $ sudo nvram boot-args=-arm64e_preview_abi
Then `arm64e` should work as-is. This use case is rather uncommon since most
userspace binaries will remain `arm64` for the time being, until Apple really
doubles down on `arm64e`. Regardless, we should be prepared for that.

View File

@@ -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
View 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
View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -1,4 +1,4 @@
.TH FAKETIME "1" "October 2013" "faketime 0.9.5" wolfcw
.TH FAKETIME "1" "June 2025" "faketime 0.9.12" 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,54 +23,80 @@ 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\--disable-shm\fR
Disable use of shared memory by libfaketime.
.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
faketime 'last Friday 5 pm' /bin/date
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.
faketime 'last Friday 5 pm' date
faketime '2008-12-24 08:15:42' date
faketime -f '+2,5y x10,0' bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'
faketime -f '+2,5y x0,50' bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'
faketime -f '+2,5y i2,0' bash -c 'while true; do date ; sleep 1 ; done'
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"

View File

@@ -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,84 @@
# 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 a few types of syscalls,
# including FUTEX (see below), clock_gettime, etc.
#
# - 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.
#
# INTERCEPT_FUTEX
# - (On GNU/Linux only) intercept glibc's syscall() for relevant FUTEX syscalls.
# If enabled, FUTEX syscalls will be intercepted and translated correspondingly.
# - when FUTEX_WAIT_BITSET (with absolute deadline) is set, the deadline will
# be adjusted based on the faketime.
# - when FUTEX_WAKE (with relative deadline) is set, the deadline will be
# adjusted based on the time rate alone.
# - for other FUTEX operations, no adjustment is made for now.
#
#
# 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
#
# FAIL_PRE_INIT_CALLS
# - If the time is queried before the library was initialised, let the
# call fail instead of trying to initialise on-the-fly. This fixes /
# works around hangs that were seen with address sanitizer.
#
# * Compilation addition: second libMT target added for building the pthread-
# enabled library as a separate library
@@ -56,8 +114,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 +124,57 @@ INSTALL ?= install
PREFIX ?= /usr/local
LIBDIRNAME ?= /lib/faketime
PLATFORM ?=$(shell uname)
ifneq ($(filter android%,$(subst -, ,$(CC))),)
IS_ANDROID := true
endif
ifeq ($(shell $(CC) -dM -E - < /dev/null | grep -c "__ANDROID__"),1)
IS_ANDROID := true
endif
ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
COMPILER := clang
else
COMPILER := gcc
endif
export COMPILER
CFLAGS += -std=gnu99 -Wall -Wextra -Werror -DFAKE_PTHREAD -DFAKE_STAT -DFAKE_UTIME -DFAKE_SLEEP -DFAKE_TIMERS -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"' -DLIBDIRNAME='"'$(LIBDIRNAME)'"' $(FAKETIME_COMPILE_CFLAGS)
ifeq ($(COMPILER),clang)
CFLAGS += -Wno-tautological-pointer-compare
endif
ifeq ($(COMPILER),gcc)
CFLAGS += -Wno-nonnull-compare
endif
ifeq ($(PLATFORM),SunOS)
CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=600
endif
ifdef IS_ANDROID
CFLAGS += -D__ANDROID__
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)
ifneq ($(PLATFORM),SunOS)
ifndef IS_ANDROID
LDFLAGS += -Wl,--version-script=libfaketime.map
endif
endif
ifdef IS_ANDROID
LDADD += -ldl -lm
BIN_LDFLAGS +=
else
LDADD += -ldl -lm -lrt -lpthread
BIN_LDFLAGS += -lrt -lpthread
endif
SRC = libfaketime.c
LIBS_OBJ = libfaketime.o libfaketimeMT.o
@@ -81,19 +185,22 @@ 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} $<
ft_sem.o: ft_sem.c ft_sem.h
${CC} -o $@ -c ${CFLAGS} ${CPPFLAGS} $<
%.so.${SONAME}: %.o libfaketime.map
${CC} -o $@ -Wl,-soname,$@ ${LDFLAGS} ${LIB_LDFLAGS} $< ${LDADD}
${LIBS_OBJ}: libfaketime.c ft_sem.h
${CC} -o $@ -c ${CFLAGS} ${CPPFLAGS} ${EXTRA_FLAGS} $<
${BINS}: faketime.c
${CC} -o $@ ${CFLAGS} ${EXTRA_FLAGS} $< ${LDFLAGS} ${LDADD}
%.so.${SONAME}: %.o ft_sem.o libfaketime.map
${CC} -o $@ -Wl,-soname,$@ ${LDFLAGS} ${LIB_LDFLAGS} $< ft_sem.o ${LDADD}
${BINS}: faketime.c ft_sem.o ft_sem.h
${CC} -o $@ ${CFLAGS} ${CPPFLAGS} ${EXTRA_FLAGS} $< ft_sem.o ${LDFLAGS} ${BIN_LDFLAGS}
clean:
@rm -f ${LIBS_OBJ} ${LIBS} ${BINS}
@rm -f ${LIBS_OBJ} ${LIBS} ${BINS} ft_sem.o
distclean: clean
@echo

View File

@@ -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,21 @@ 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.12 -compatibility_version 0.7
# From macOS 13 onwards, system binaries are compiled against the new arm64e ABI on Apple Silicon.
# These arm64e binaries enforce Pointer Authentication Code (PAC), and will refuse to run with
# "unprotected" arm64 libraries. Meanwhile, older platforms might not recognize the new arm64e ABI.
# Therefore, we now compile for two ABIs at the same time, producing a fat library of arm64e and arm64,
# so in the end the OS gets to pick which architecture it wants at runtime.
# In addition, we need to enable signing and authentication of indirect calls (-fptrauth-calls);
# otherwise in ftpl_init, pthread_once will indirectly call ftpl_really_init, which then fail PAC.
# Ideally this should be a compiler default for the arm64e ABI, but apparently not.
ARCH := $(shell uname -m)
SONAME = 1
LIBS = libfaketime.${SONAME}.dylib
@@ -53,14 +77,26 @@ BINS = faketime
all: ${LIBS} ${BINS}
ifeq ($(ARCH),arm64)
libfaketime.${SONAME}.dylib: libfaketime.c
${CC} -o libfaketime.arm64e.dylib ${CFLAGS} -arch arm64e -fptrauth-calls -fptrauth-returns ${LDFLAGS} ${LIB_LDFLAGS} -install_name ${PREFIX}/lib/faketime/$@ $<
${CC} -o libfaketime.arm64.dylib ${CFLAGS} -arch arm64 ${LDFLAGS} ${LIB_LDFLAGS} -install_name ${PREFIX}/lib/faketime/$@ $<
lipo -create -output $@ libfaketime.arm64e.dylib libfaketime.arm64.dylib
rm libfaketime.arm64e.dylib libfaketime.arm64.dylib
faketime: faketime.c
${CC} -o $@ ${CFLAGS} -arch arm64e -arch arm64 ${LDFLAGS} $<
else
libfaketime.${SONAME}.dylib: libfaketime.c
${CC} -o $@ ${CFLAGS} ${LDFLAGS} ${LIB_LDFLAGS} -install_name ${PREFIX}/lib/faketime/$@ $<
faketime: faketime.c
${CC} -o $@ ${CFLAGS} ${LDFLAGS} $<
endif
clean:
@rm -f ${OBJ} ${LIBS} ${BINS}
@rm -f ${OBJ} ${LIBS} ${BINS} libfaketime.arm64e.dylib libfaketime.arm64.dylib
distclean: clean
@echo

51
src/android_compat.h Normal file
View File

@@ -0,0 +1,51 @@
#ifndef ANDROID_COMPAT_H
#define ANDROID_COMPAT_H
#ifdef __ANDROID__
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
static inline const char *__android_shm_tmpdir(void)
{
const char *dir = getenv("FAKETIME_SHM_DIR");
if (dir == NULL)
dir = getenv("TMPDIR");
if (dir == NULL)
dir = "/data/local/tmp";
return dir;
}
static inline int __android_shm_open(const char *name, int oflag, mode_t mode)
{
char path[512];
const char *dir = __android_shm_tmpdir();
while (*name == '/') name++;
snprintf(path, sizeof(path), "%s/faketime_shm_%s", dir, name);
int fd = open(path, oflag, mode);
if (fd == -1 && (oflag & O_CREAT))
{
mkdir(dir, 0777);
fd = open(path, oflag, mode);
}
return fd;
}
static inline int __android_shm_unlink(const char *name)
{
char path[512];
const char *dir = __android_shm_tmpdir();
while (*name == '/') name++;
snprintf(path, sizeof(path), "%s/faketime_shm_%s", dir, name);
return unlink(path);
}
#define shm_open __android_shm_open
#define shm_unlink __android_shm_unlink
#endif /* __ANDROID__ */
#endif /* ANDROID_COMPAT_H */

View File

@@ -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.12
*
* 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
@@ -44,13 +44,14 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <semaphore.h>
#include "ft_sem.h"
#include "android_compat.h"
#include "faketime_common.h"
const char version[] = "0.9.5";
const char version[] = "0.9.12";
#ifdef __APPLE__
#if (defined __APPLE__) || (defined __sun)
static const char *date_cmd = "gdate";
#else
static const char *date_cmd = "date";
@@ -60,44 +61,52 @@ static const char *date_cmd = "date";
/* semaphore and shared memory names */
char sem_name[PATH_BUFSIZE] = {0}, shm_name[PATH_BUFSIZE] = {0};
static ft_sem_t wrapper_sem;
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
#ifndef FAKE_STATELESS
" --disable-shm : Disable use of shared memory by libfaketime.\n"
#endif
" --date-prog PROG : Use specified GNU-compatible implementation of 'date' program\n"
"\n"
"Examples:\n"
"%s 'last friday 5 pm' date\n"
"%s '2008-12-24 08:15:42' date\n"
"%s -f '+2,5y x10,0' bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n"
"%s -f '+2,5y x0,50' bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n"
"%s -f '+2,5y i2,0' 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 */
static void cleanup_shobjs()
{
if (-1 == sem_unlink(sem_name))
if (-1 == ft_sem_unlink(&wrapper_sem))
{
perror("sem_unlink");
perror("faketime: ft_sem_unlink");
}
if (-1 == shm_unlink(shm_name))
{
perror("shm_unlink");
perror("faketime: shm_unlink");
}
}
@@ -106,27 +115,73 @@ 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;
}
#ifndef FAKE_STATELESS
else if (0 == strcmp(argv[curr_opt], "--disable-shm"))
{
setenv("FAKETIME_DISABLE_SHM", "1", true);
curr_opt++;
continue;
}
#endif
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 +209,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 +218,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 +233,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,41 +248,49 @@ 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++;
{
/* create semaphores and shared memory */
/* create lock and shared memory */
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)))
if (-1 == ft_sem_create(sem_name, &wrapper_sem))
{
perror("sem_open");
perror("faketime: ft_sem_create");
fprintf(stderr, "The faketime wrapper failed to create its lock.\nHowever, 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");
if (-1 == sem_unlink(argv[2]))
{
perror("sem_unlink");
}
perror("faketime: shm_open");
ft_sem_unlink(&wrapper_sem);
exit(EXIT_FAILURE);
}
/* set shm size */
if (-1 == ftruncate(shm_fd, sizeof(uint64_t)))
if (-1 == ftruncate(shm_fd, sizeof(struct ft_shared_s)))
{
perror("ftruncate");
perror("faketime: ftruncate");
cleanup_shobjs();
exit(EXIT_FAILURE);
}
@@ -233,14 +299,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)
if (ft_sem_lock(&wrapper_sem) == -1)
{
perror("sem_wait");
perror("faketime: ft_sem_lock");
cleanup_shobjs();
exit(EXIT_FAILURE);
}
@@ -248,30 +314,34 @@ int main (int argc, char **argv)
/* init elapsed time ticks to zero */
ft_shared->ticks = 0;
ft_shared->file_idx = 0;
ft_shared->start_time.real.tv_sec = 0;
ft_shared->start_time.real.tv_nsec = -1;
ft_shared->start_time.mon.tv_sec = 0;
ft_shared->start_time.mon.tv_nsec = -1;
ft_shared->start_time.mon_raw.tv_sec = 0;
ft_shared->start_time.mon_raw.tv_nsec = -1;
ft_shared->start_time_real.sec = 0;
ft_shared->start_time_real.nsec = -1;
ft_shared->start_time_mon.sec = 0;
ft_shared->start_time_mon.nsec = -1;
ft_shared->start_time_mon_raw.sec = 0;
ft_shared->start_time_mon_raw.nsec = -1;
#ifdef CLOCK_BOOTTIME
ft_shared->start_time_boot.sec = 0;
ft_shared->start_time_boot.nsec = -1;
#endif
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)
if (ft_sem_unlock(&wrapper_sem) == -1)
{
perror("semop");
perror("faketime: ft_sem_unlock");
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);
ft_sem_close(&wrapper_sem);
}
{
@@ -280,10 +350,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 +370,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 +378,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 +396,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 */

View File

@@ -32,6 +32,17 @@ 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
};
/* Fixed-width time representation for shared memory (arch-independent) */
struct ft_shared_time_s
{
int64_t sec;
int64_t nsec;
};
/* Data shared among faketime-spawned processes */
@@ -41,10 +52,61 @@ 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;
/* System time Faketime started at (fixed-width for cross-arch safety) */
struct ft_shared_time_s start_time_real;
struct ft_shared_time_s start_time_mon;
struct ft_shared_time_s start_time_mon_raw;
#ifdef CLOCK_BOOTTIME
struct ft_shared_time_s start_time_boot;
#endif
};
/* 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

227
src/ft_sem.c Normal file
View File

@@ -0,0 +1,227 @@
/*
* This file is part of libfaketime, version 0.9.12
*
* 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
* Free Software Foundation.
*
* libfaketime is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License v2 along
* with the libfaketime; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "ft_sem.h"
#if FT_SEMAPHORE_BACKEND == FT_SYSV
#include <sys/sem.h>
#endif
#if FT_SEMAPHORE_BACKEND == FT_FLOCK
#include <sys/file.h>
#endif
/*
* =======================================================================
* Semaphore related functions === SEM
* =======================================================================
*/
#if FT_SEMAPHORE_BACKEND == FT_SYSV
int ft_sem_name2key(char *name)
{
key_t key;
char fullname[256];
snprintf(fullname, sizeof(fullname), "/tmp%s", name);
fullname[sizeof(fullname) - 1] = '\0';
int fd = open(fullname, O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0)
{
perror("libfaketime: open");
return -1;
}
close(fd);
if (-1 == (key = ftok(fullname, 'F')))
{
perror("libfaketime: ftok");
return -1;
}
return key;
}
#endif
#if FT_SEMAPHORE_BACKEND == FT_FLOCK
static int ft_sem_name_to_path(const char *name, char *path, size_t pathlen)
{
const char *prefix = "/faketime_sem_";
const char *p = strstr(name, prefix);
if (p == NULL)
{
return -1;
}
const char *pid_str = p + strlen(prefix);
const char *tmpdir;
#ifdef __ANDROID__
tmpdir = getenv("TMPDIR");
if (tmpdir == NULL) tmpdir = "/data/local/tmp";
#else
tmpdir = "/dev/shm";
#endif
snprintf(path, pathlen, "%s/faketime_lock_%s", tmpdir, pid_str);
path[pathlen - 1] = '\0';
return 0;
}
#endif
int ft_sem_create(char *name, ft_sem_t *ft_sem)
{
#if FT_SEMAPHORE_BACKEND == FT_POSIX
if (SEM_FAILED == (ft_sem->sem = sem_open(name, O_CREAT|O_EXCL, S_IWUSR|S_IRUSR, 1)))
{
return -1;
}
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
key_t key = ft_sem_name2key(name);
int nsems = 1;
ft_sem->semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | S_IWUSR | S_IRUSR);
if (ft_sem->semid >= 0) { /* we got here first */
struct sembuf sb = {
.sem_num = 0,
.sem_op = 1, /* number of resources the semaphore has (when decremented down to 0 the semaphore will block) */
.sem_flg = 0,
};
/* the number of semaphore operation structures (struct sembuf) passed to semop */
int nsops = 1;
/* do a semop() to "unlock" the semaphore */
if (-1 == semop(ft_sem->semid, &sb, nsops)) {
return -1;
}
} else if (errno == EEXIST) { /* someone else got here before us */
return -1;
} else {
return -1;
}
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
char path[256];
if (ft_sem_name_to_path(name, path, sizeof(path)) < 0)
{
return -1;
}
ft_sem->fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IWUSR|S_IRUSR);
if (ft_sem->fd < 0)
{
return -1;
}
#endif
strncpy(ft_sem->name, name, sizeof ft_sem->name - 1);
ft_sem->name[sizeof ft_sem->name - 1] = '\0';
return 0;
}
int ft_sem_open(char *name, ft_sem_t *ft_sem)
{
#if FT_SEMAPHORE_BACKEND == FT_POSIX
if (SEM_FAILED == (ft_sem->sem = sem_open(name, 0)))
{
return -1;
}
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
key_t key = ft_sem_name2key(name);
ft_sem->semid = semget(key, 1, S_IWUSR | S_IRUSR);
if (ft_sem->semid < 0) {
return -1;
}
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
char path[256];
if (ft_sem_name_to_path(name, path, sizeof(path)) < 0)
{
return -1;
}
ft_sem->fd = open(path, O_RDWR);
if (ft_sem->fd < 0)
{
return -1;
}
#endif
strncpy(ft_sem->name, name, sizeof ft_sem->name - 1);
ft_sem->name[sizeof ft_sem->name - 1] = '\0';
return 0;
}
int ft_sem_lock(ft_sem_t *ft_sem)
{
#if FT_SEMAPHORE_BACKEND == FT_POSIX
return sem_wait(ft_sem->sem);
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
struct sembuf sb = {
.sem_num = 0,
.sem_op = -1, /* allocate resource (lock) */
.sem_flg = 0,
};
return semop(ft_sem->semid, &sb, 1);
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
return flock(ft_sem->fd, LOCK_EX);
#endif
}
int ft_sem_unlock(ft_sem_t *ft_sem)
{
#if FT_SEMAPHORE_BACKEND == FT_POSIX
return sem_post(ft_sem->sem);
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
struct sembuf sb = {
.sem_num = 0,
.sem_op = 1, /* free resource (unlock) */
.sem_flg = 0,
};
return semop(ft_sem->semid, &sb, 1);
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
return flock(ft_sem->fd, LOCK_UN);
#endif
}
int ft_sem_close(ft_sem_t *ft_sem)
{
#if FT_SEMAPHORE_BACKEND == FT_POSIX
return sem_close(ft_sem->sem);
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
/* NOP -- there's no "close" equivalent */
(void)ft_sem;
return 0;
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
int ret = close(ft_sem->fd);
ft_sem->fd = -1;
return ret;
#endif
}
int ft_sem_unlink(ft_sem_t *ft_sem)
{
#if FT_SEMAPHORE_BACKEND == FT_POSIX
return sem_unlink(ft_sem->name);
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
return semctl(ft_sem->semid, 0, IPC_RMID);
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
char path[256];
if (ft_sem_name_to_path(ft_sem->name, path, sizeof(path)) < 0)
{
return -1;
}
return unlink(path);
#endif
}

62
src/ft_sem.h Normal file
View File

@@ -0,0 +1,62 @@
/*
* This file is part of libfaketime, version 0.9.12
*
* 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
* Free Software Foundation.
*
* libfaketime is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License v2 along
* with the libfaketime; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FT_SEM_H
#define FT_SEM_H
/* semaphore backend options */
#define FT_POSIX 1
#define FT_SYSV 2
#define FT_FLOCK 3
/* set default backend */
#ifndef FT_SEMAPHORE_BACKEND
#define FT_SEMAPHORE_BACKEND FT_FLOCK
#endif
/* validate selected backend */
#if FT_SEMAPHORE_BACKEND == FT_POSIX
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
#else
#error "Unknown FT_SEMAPHORE_BACKEND; select between FT_POSIX, FT_SYSV, and FT_FLOCK"
#endif
#if FT_SEMAPHORE_BACKEND == FT_POSIX
#include <semaphore.h>
#endif
typedef struct
{
char name[256];
#if FT_SEMAPHORE_BACKEND == FT_POSIX
sem_t *sem;
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
int semid;
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
int fd;
#endif
} ft_sem_t;
int ft_sem_create(char *name, ft_sem_t *ft_sem);
int ft_sem_open(char *name, ft_sem_t *ft_sem);
int ft_sem_lock(ft_sem_t *ft_sem);
int ft_sem_unlock(ft_sem_t *ft_sem);
int ft_sem_close(ft_sem_t *ft_sem);
int ft_sem_unlink(ft_sem_t *ft_sem);
#endif /* FT_SEM_H */

File diff suppressed because it is too large Load Diff

View File

@@ -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
View 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 */

View File

@@ -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

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
## Copyright (c) 2013, adrelanos at riseup dot net
## All rights reserved.

1208
src/uthash.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,24 @@
CC = gcc
CFLAGS = -std=gnu99 -Wall -DFAKE_STAT -Werror -Wextra
LDFLAGS = -lrt
CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -Werror -Wextra $(FAKETIME_COMPILE_CFLAGS) -U_FILE_OFFSET_BITS -U_TIME_BITS
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 shm_layout_test
ifneq ($(filter -DINTERCEPT_SYSCALL,${CFLAGS}),)
ALL_TESTS += confirm_variadic_promotion
else
TEST_SNIPPETS := $(filter-out syscall%,${TEST_SNIPPETS})
EXPECTATIONS := $(filter-out syscall%,${EXPECTATIONS})
endif
all: $(ALL_TESTS)
.c.o:
${CC} -c ${CFLAGS} $<
@@ -14,7 +26,10 @@ all: timetest test
timetest: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
test: timetest functest
shm_layout_test: shm_layout_test.c ../src/faketime_common.h
${CC} -o $@ ${CFLAGS} $<
test: timetest functest libmallocintercept.so
@echo
@./test.sh
@@ -22,10 +37,51 @@ test: timetest functest
functest:
./testframe.sh functests
%_test: %_test.c
${CC} -o $@ ${CFLAGS} $<
randomtest: repeat_random
./randomtest.sh
libmallocintercept.so: libmallocintercept.c
${CC} -shared -o $@ -fpic ${CFLAGS} $<
# 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 shm_layout_test getrandom_test syscall_test $(foreach f,${TEST_SNIPPETS},use_lib_${f} lib${f}.so run_${f}) variadic_promotion variadic/*.o repeat_random libmallocintercept.so
distclean: clean
@echo
.PHONY: all test clean distclean
.PHONY: all test clean distclean randomtest snippets test_variable_data test_library_constructors

View File

@@ -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}

View File

@@ -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
View 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
View 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
View 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"
}

View File

@@ -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" \
"$@"

View 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" \
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}"
}

View File

@@ -0,0 +1,79 @@
# Tests for FAKETIME_FOLLOW_ABSOLUTE feature.
#
# When FAKETIME_FOLLOW_ABSOLUTE=1 is set alongside FAKETIME="%" and
# FAKETIME_FOLLOW_FILE, time freezes at the follow file's mtime
# and only advances when the file's mtime changes.
FOLLOW_FILE=".follow_absolute_test_file"
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 follow_absolute_basic
run_testcase follow_absolute_freeze
run_testcase follow_absolute_tracks_mtime
rm -f "$FOLLOW_FILE"
}
# Helper to run a command with follow-absolute configuration
follow_absolute_cmd()
{
FAKETIME_FOLLOW_FILE="$FOLLOW_FILE" \
FAKETIME_FOLLOW_ABSOLUTE=1 \
fakecmd "%" "$@"
}
# Test that time matches the follow file's mtime
follow_absolute_basic()
{
touch -d "2020-03-15 10:30:00 UTC" "$FOLLOW_FILE"
typeset actual
actual=$(follow_absolute_cmd date -u +"%Y-%m-%d %H:%M:%S")
asserteq "$actual" "2020-03-15 10:30:00" \
"time should match follow file mtime"
}
# Test that time stays frozen (does not advance with real time)
follow_absolute_freeze()
{
touch -d "2020-03-15 10:30:00 UTC" "$FOLLOW_FILE"
typeset timestamps
timestamps=$(follow_absolute_cmd \
perl -e 'print time(), "\n"; sleep(2); print time(), "\n"')
typeset first second
first=$(echo "$timestamps" | head -1)
second=$(echo "$timestamps" | tail -1)
asserteq "$first" "$second" \
"time should stay frozen within a single process"
}
# Test that time tracks file mtime changes at millisecond precision
follow_absolute_tracks_mtime()
{
touch -d "2020-03-15 10:30:00.000 UTC" "$FOLLOW_FILE"
typeset first
first=$(follow_absolute_cmd \
perl -MTime::HiRes=time -e 'printf "%.3f\n", time()')
touch -d "2020-03-15 10:30:00.005 UTC" "$FOLLOW_FILE"
typeset second
second=$(follow_absolute_cmd \
perl -MTime::HiRes=time -e 'printf "%.3f\n", time()')
assertneq "$first" "$second" \
"time should advance with file mtime (ms precision)"
}

View File

@@ -0,0 +1,31 @@
# Verify that shared memory works end-to-end across processes.
# The faketime wrapper creates SHM with a known FAKETIME value,
# and the child process (via LD_PRELOAD) reads it and reports
# the faked time.
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 shm_year_check
}
shm_year_check()
{
typeset expected="2020"
typeset actual
actual=$(fakecmd "2020-06-15 12:00:00" date -u +%Y)
asserteq "$actual" "$expected" "child process should see faked year via SHM"
}

View File

@@ -1,4 +1,4 @@
# test suite that always succeds - for testing framework
# test suite that always succeeds - for testing framework
run()
{

View File

@@ -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
}

85
test/libmallocintercept.c Normal file
View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2022 be.storaged GmbH
*
* This file is part of libfaketime
*
* 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
* Free Software Foundation.
*
* libfaketime is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License v2 along
* with the libfaketime; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static void print_msg(const char *msg) {
size_t out;
out = write(0, msg, strlen(msg));
(void) out; /* unused */
}
static void* actual_malloc(size_t size) {
/* We would like to use "the real malloc", but cannot. Thus, this
* implements a trivial, allocate-only bump allocator to make things
* work.
*/
static char memory_arena[16 << 20];
static size_t allocated_index = 0;
void *result = &memory_arena[allocated_index];
allocated_index += size;
/* align to a multiple of 8 bytes */
allocated_index = (allocated_index + 7) / 8 * 8;
if (allocated_index >= sizeof(memory_arena)) {
print_msg("libmallocintercept is out of memory!");
abort();
}
return result;
}
static void poke_faketime(void) {
#ifdef FAIL_PRE_INIT_CALLS
/* To complicate things for libfaketime, this calls clock_gettime()
* while holding a lock. This should simulate problems that occurred
* with address sanitizer.
*/
static pthread_mutex_t time_mutex = PTHREAD_MUTEX_INITIALIZER;
struct timespec timespec;
pthread_mutex_lock(&time_mutex);
clock_gettime(CLOCK_REALTIME, &timespec);
pthread_mutex_unlock(&time_mutex);
#else
print_msg("FAIL_PRE_INIT_CALLS not defined, skipping poke_faketime() ");
#endif
}
void *malloc(size_t size) {
print_msg("Called malloc() from libmallocintercept...");
poke_faketime();
print_msg("successfully\n");
return actual_malloc(size);
}
void free(void *ptr) {
(void) ptr; /* unused */
print_msg("Called free() on from libmallocintercept...");
poke_faketime();
print_msg("successfully\n");
/* We cannot actually free memory */
}

21
test/randomtest.sh Executable file
View 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
View 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;
};

65
test/shm_layout_test.c Normal file
View File

@@ -0,0 +1,65 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include "../src/faketime_common.h"
static int failures = 0;
static void check_offset(const char *field, size_t actual, size_t expected)
{
if (actual != expected)
{
fprintf(stderr, "FAIL: offsetof(ft_shared_s, %s) = %zu, expected %zu\n",
field, actual, expected);
failures++;
}
else
{
printf("OK: offsetof(ft_shared_s, %s) = %zu\n", field, actual);
}
}
static void check_size(const char *name, size_t actual, size_t expected)
{
if (actual != expected)
{
fprintf(stderr, "FAIL: sizeof(%s) = %zu, expected %zu\n",
name, actual, expected);
failures++;
}
else
{
printf("OK: sizeof(%s) = %zu\n", name, actual);
}
}
int main()
{
/* ft_shared_time_s must be exactly 16 bytes: two int64_t */
check_size("ft_shared_time_s", sizeof(struct ft_shared_time_s), 16);
/* Field offsets in ft_shared_s */
check_offset("ticks", offsetof(struct ft_shared_s, ticks), 0);
check_offset("file_idx", offsetof(struct ft_shared_s, file_idx), 8);
check_offset("start_time_real", offsetof(struct ft_shared_s, start_time_real), 16);
check_offset("start_time_mon", offsetof(struct ft_shared_s, start_time_mon), 32);
check_offset("start_time_mon_raw", offsetof(struct ft_shared_s, start_time_mon_raw), 48);
#ifdef CLOCK_BOOTTIME
check_offset("start_time_boot", offsetof(struct ft_shared_s, start_time_boot), 64);
check_size("ft_shared_s", sizeof(struct ft_shared_s), 80);
#else
check_size("ft_shared_s", sizeof(struct ft_shared_s), 64);
#endif
if (failures > 0)
{
fprintf(stderr, "%d layout check(s) failed\n", failures);
return EXIT_FAILURE;
}
printf("All layout checks passed\n");
return EXIT_SUCCESS;
}

72
test/snippets/README Normal file
View 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.

View 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));
}

View File

@@ -0,0 +1 @@
FAKETIME 2020-02-02 02:02:02+00:00

View 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));
}

View File

@@ -0,0 +1 @@
FAKETIME 2020-02-02 02:02:02+00:00

View 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));
}

View File

@@ -0,0 +1 @@
FAKERANDOM_SEED 0x0123456789ABCDEF

2
test/snippets/getpid.c Normal file
View File

@@ -0,0 +1,2 @@
pid_t pid = getpid();
printf("[%s] getpid() yielded %d\n", where, pid);

View File

@@ -0,0 +1 @@
FAKETIME_FAKEPID 1

View 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);
}

View File

@@ -0,0 +1 @@
FAKERANDOM_SEED 0xDEADBEEFDEADBEEF

View 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
View File

@@ -0,0 +1,2 @@
long uid = syscall(__NR_getuid);
printf("[%s] syscall(__NR_getuid) -> %ld\n", where, uid);

View 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);

View File

@@ -0,0 +1 @@
FAKETIME 2020-01-01 00:00:00

View 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);

View File

@@ -0,0 +1 @@
FAKETIME 2020-02-02 02:02:02+00:00

View File

@@ -0,0 +1,32 @@
/* Test raw syscall(__NR_clock_nanosleep): relative and TIMER_ABSTIME */
#ifdef __NR_clock_nanosleep
struct timespec start_fake, end_fake_rel, end_fake_abs;
struct timespec req_rel = {0, 200 * 1000 * 1000}; /* 200ms fake sleep */
struct timespec req_abs;
long ret;
/* Capture starting time (fake view) */
clock_gettime(CLOCK_REALTIME, &start_fake);
/* Relative sleep via syscall */
ret = syscall(__NR_clock_nanosleep, CLOCK_REALTIME, 0, &req_rel, NULL);
clock_gettime(CLOCK_REALTIME, &end_fake_rel);
/* Absolute sleep target: 300ms after start_fake *./test_variable_data.sh */
req_abs.tv_sec = start_fake.tv_sec;
req_abs.tv_nsec = start_fake.tv_nsec + 300 * 1000 * 1000;
if (req_abs.tv_nsec >= 1000000000) { req_abs.tv_sec += 1; req_abs.tv_nsec -= 1000000000; }
/* Absolute sleep via syscall */
ret = syscall(__NR_clock_nanosleep, CLOCK_REALTIME, TIMER_ABSTIME, &req_abs, NULL);
clock_gettime(CLOCK_REALTIME, &end_fake_abs);
/* Report durations (fake view). */
long rel_ns = (end_fake_rel.tv_sec - start_fake.tv_sec) * 1000000000L + (end_fake_rel.tv_nsec - start_fake.tv_nsec);
long abs_ns = (end_fake_abs.tv_sec - start_fake.tv_sec) * 1000000000L + (end_fake_abs.tv_nsec - start_fake.tv_nsec);
printf("[%s] syscall(clock_nanosleep) relative 200ms -> ~%ld ns, absolute +300ms -> ~%ld ns\n", where, rel_ns, abs_ns);
return ret;
#else
printf("[%s] __NR_clock_nanosleep not defined on this platform\n", where);
#endif

View File

@@ -0,0 +1 @@
FAKETIME 2020-01-01 00:00:00

2
test/snippets/time.c Normal file
View File

@@ -0,0 +1,2 @@
time_t t = time(NULL);
printf("[%s] time() yielded %lu\n", where, (unsigned long)t);

View File

@@ -0,0 +1 @@
FAKETIME 2020-02-02 02:02:02+00:00

View File

@@ -1,14 +1,17 @@
#!/bin/sh
FTPL="${FAKETIME_TESTLIB:-../src/libfaketime.so.1}"
MALLOC_INTERCEPT=./libmallocintercept.so
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 +19,66 @@ 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 "============================================================================="
echo
echo "Running the test program with malloc interception"
echo "\$ LD_PRELOAD=./libmallocintercept.so:$FTPL ./timetest"
LD_PRELOAD="./libmallocintercept.so:$FTPL" ./timetest
echo
echo "============================================================================="
echo
echo "@2005-03-29 14:14:14" > .faketimerc-for-test
echo "Running the test program with malloc interception and file faketimerc"
echo "\$ FAKETIME_NO_CACHE=1 FAKETIME_TIMESTAMP_FILE=.faketimerc-for-test LD_PRELOAD=./libmallocintercept.so:$FTPL ./timetest"
FAKETIME_NO_CACHE=1 FAKETIME_TIMESTAMP_FILE=.faketimerc-for-test LD_PRELOAD="./libmallocintercept.so:$FTPL" ./timetest
rm .faketimerc-for-test
echo
echo "============================================================================="

View File

@@ -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
View 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
View File

@@ -0,0 +1,54 @@
#!/usr/bin/env 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

View File

@@ -1,4 +1,4 @@
#! /bin/bash
#!/usr/bin/env bash
# testframe.sh DIR
# bare-bones testing framework.
# run the test suites in the given DIR;

View File

@@ -18,23 +18,153 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define _GNU_SOURCE
#include <fcntl.h>
#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>
#include <string.h>
#include <utime.h>
#define MONO_FIX_TIMEOUT_SECONDS 1
#define MONO_FIX_TOLERANCE_SECONDS 0.25 // Increased tolerance slightly for CI environments
#define MONO_FIX_LOWER_BOUND (MONO_FIX_TIMEOUT_SECONDS - MONO_FIX_TOLERANCE_SECONDS)
#define MONO_FIX_UPPER_BOUND (MONO_FIX_TIMEOUT_SECONDS + MONO_FIX_TOLERANCE_SECONDS)
#define VERBOSE 0
#define SIG SIGUSR1
#ifdef __ARM_ARCH
static int fake_monotonic_clock = 0;
#else
static int fake_monotonic_clock = 1;
#endif
static void test_utime_now(void)
{
char path[] = "/tmp/libfaketime-utime-XXXXXX";
int fd;
fd = mkstemp(path);
if (fd == -1)
{
perror("mkstemp");
exit(EXIT_FAILURE);
}
if (utime(path, NULL) == -1)
{
perror("utime(NULL)");
close(fd);
unlink(path);
exit(EXIT_FAILURE);
}
if (utimes(path, NULL) == -1)
{
perror("utimes(NULL)");
close(fd);
unlink(path);
exit(EXIT_FAILURE);
}
if (close(fd) == -1)
{
perror("close");
unlink(path);
exit(EXIT_FAILURE);
}
if (unlink(path) == -1)
{
perror("unlink");
exit(EXIT_FAILURE);
}
printf("utime()/utimes(): NOW handling passed\n");
}
static void test_utimens_now(void)
{
char path[] = "/tmp/libfaketime-utimensat-XXXXXX";
struct timespec now_times[2];
int fd;
fd = mkstemp(path);
if (fd == -1)
{
perror("mkstemp");
exit(EXIT_FAILURE);
}
if (utimensat(AT_FDCWD, path, NULL, 0) == -1)
{
perror("utimensat(NULL)");
unlink(path);
exit(EXIT_FAILURE);
}
if (futimens(fd, NULL) == -1)
{
perror("futimens(NULL)");
close(fd);
unlink(path);
exit(EXIT_FAILURE);
}
now_times[0].tv_sec = now_times[1].tv_sec = 0;
now_times[0].tv_nsec = now_times[1].tv_nsec = UTIME_NOW;
if (utimensat(AT_FDCWD, path, now_times, 0) == -1)
{
perror("utimensat(UTIME_NOW)");
close(fd);
unlink(path);
exit(EXIT_FAILURE);
}
if (futimens(fd, now_times) == -1)
{
perror("futimens(UTIME_NOW)");
close(fd);
unlink(path);
exit(EXIT_FAILURE);
}
if (close(fd) == -1)
{
perror("close");
unlink(path);
exit(EXIT_FAILURE);
}
if (unlink(path) == -1)
{
perror("unlink");
exit(EXIT_FAILURE);
}
printf("utimensat()/futimens(): NOW handling passed\n");
}
static void
handler(int sig, siginfo_t *si, void *uc)
{
@@ -46,12 +176,128 @@ handler(int sig, siginfo_t *si, void *uc)
{
printf("Caught signal %d\n", sig);
}
signal(sig, SIG_IGN);
}
static void get_fake_monotonic_setting(int* current_value)
{
char *tmp_env;
if ((tmp_env = getenv("FAKETIME_DONT_FAKE_MONOTONIC")) != NULL
|| (tmp_env = getenv("DONT_FAKE_MONOTONIC")) != NULL)
{
if (0 == strcmp(tmp_env, "1"))
{
(*current_value) = 0;
}
else
{
(*current_value) = 1;
}
}
}
void* pthread_test(void* args)
{
pthread_mutex_t fake_mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t fake_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t monotonic_cond;
pthread_condattr_t attr;
struct timespec time_to_wait, now;
int rt;
args = args; // silence compiler warning about unused argument
clock_gettime(CLOCK_REALTIME, &now);
time_to_wait.tv_sec = now.tv_sec+1;
time_to_wait.tv_nsec = now.tv_nsec;
printf("pthread_cond_timedwait: CLOCK_REALTIME test\n");
printf("(Intentionally sleeping 1 second...)\n");
fflush(stdout);
pthread_mutex_lock(&fake_mtx);
rt = pthread_cond_timedwait(&fake_cond, &fake_mtx, &time_to_wait);
if (rt != ETIMEDOUT)
{
printf("pthread_cond_timedwait failed\n");
pthread_mutex_unlock(&fake_mtx);
exit(EXIT_FAILURE);
}
pthread_mutex_unlock(&fake_mtx);
pthread_condattr_init(&attr);
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
pthread_cond_init(&monotonic_cond, &attr);
clock_gettime(CLOCK_MONOTONIC, &now);
time_to_wait.tv_sec = now.tv_sec+1;
time_to_wait.tv_nsec = now.tv_nsec;
printf("pthread_cond_timedwait: CLOCK_MONOTONIC test\n");
printf("(Intentionally sleeping 1 second...)\n");
printf("(If this test hangs for more than a few seconds, please report\n your glibc version and system details as FORCE_MONOTONIC_FIX\n issue at https://github.com/wolfcw/libfaketime)\n");
fflush(stdout);
pthread_mutex_lock(&fake_mtx);
rt = pthread_cond_timedwait(&monotonic_cond, &fake_mtx, &time_to_wait);
if (rt != ETIMEDOUT)
{
printf("pthread_cond_timedwait failed\n");
pthread_mutex_unlock(&fake_mtx);
exit(EXIT_FAILURE);
}
pthread_mutex_unlock(&fake_mtx);
get_fake_monotonic_setting(&fake_monotonic_clock);
if (!fake_monotonic_clock)
{
printf("pthread_cond_timedwait: using real CLOCK_MONOTONIC test\n");
struct timespec mono_after_wait;
clock_gettime(CLOCK_MONOTONIC, &now);
time_to_wait.tv_sec = now.tv_sec + MONO_FIX_TIMEOUT_SECONDS;
time_to_wait.tv_nsec = now.tv_nsec;
struct timespec current_real_time;
clock_gettime(CLOCK_REALTIME, &current_real_time);
struct timespec new_real_time = current_real_time;
new_real_time.tv_sec += 3600; // Advance by one hour
clock_settime(CLOCK_REALTIME, &new_real_time);
pthread_mutex_lock(&fake_mtx);
rt = pthread_cond_timedwait(&monotonic_cond, &fake_mtx, &time_to_wait);
clock_gettime(CLOCK_MONOTONIC, &mono_after_wait);
pthread_mutex_unlock(&fake_mtx);
double elapsed_wall_time = (mono_after_wait.tv_sec - now.tv_sec) +
(mono_after_wait.tv_nsec - now.tv_nsec) / 1000000000.0;
if (rt == ETIMEDOUT && (elapsed_wall_time >= MONO_FIX_LOWER_BOUND && elapsed_wall_time <= MONO_FIX_UPPER_BOUND))
{
printf("pthread_cond_timedwait with real CLOCK_MONOTONIC passed: elapsed time = %.2f seconds\n", elapsed_wall_time);
}
else
{
printf("pthread_cond_timedwait with real CLOCK_MONOTONIC FAILED: elapsed time = %.2f seconds, return code = %d\n", elapsed_wall_time, rt);
exit(EXIT_FAILURE);
}
}
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 +309,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 +363,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 +385,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 +396,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 +414,10 @@ 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) {
test_utime_now();
test_utimens_now();
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
{
perror("sigprocmask");
exit(EXIT_FAILURE);
}
@@ -157,34 +426,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
View 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
View 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
View 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;
}