42 Commits

Author SHA1 Message Date
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
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
8 changed files with 478 additions and 69 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, macOS-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- name: make
run: make
- name: make test
run: make test

View File

@@ -4,6 +4,8 @@ matrix:
include:
- os: linux
compiler: gcc
- os: osx
osx_image: xcode11
script:
- cd ${TRAVIS_BUILD_DIR}

15
NEWS
View File

@@ -1,3 +1,18 @@
- Additional link-time LDFLAGS can be passed via the
environment variable FAKETIME_LINK_FLAGS when
running 'make'.
Since 0.9.8:
- 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)

16
README
View File

@@ -97,6 +97,12 @@ documentation whether it can be achieved by using libfaketime directly.
src/Makefile and recompile libfaketime. Do not set FORCE_MONOTONIC_FIX on
platforms where the test does not hang.
If you observe hangs on the CLOCK_REALTIME test, add the CFLAG
-DFORCE_PTHREAD_NONVER. Also set this FORCE_PTHREAD_NONVER flag in case
FORCE_MONOTONIC_FIX alone does not solve the hang on the MONOTONIC_CLOCK
test.
3. Installation
---------------
@@ -450,6 +456,16 @@ a lot of processes are started (e.g., servers handling many containers
or similar virtualization mechanisms).
Intercepting time-setting calls
-------------------------------
libfaketime can be compiled with the CFLAG "-DFAKE_SETTIME" in order
to also intercept time-setting functions, i.e., clock_settime(),
settimeofday(), and adjtime(). Instead of passing the timestamp a
program sets through to the system, only the FAKETIME environment
variable will be adjusted accordingly.
4f) Faking the date and time system-wide
----------------------------------------

63
README.packagers Normal file
View File

@@ -0,0 +1,63 @@
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.
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!

View File

@@ -30,6 +30,9 @@
# FAKE_PTHREAD
# - Intercept pthread_cond_timedwait
#
# FAKE_SETTIME
# - Intercept clock_settime(), settimeofday(), and adjtime()
#
# FORCE_MONOTONIC_FIX
# - If the test program hangs forever on
# " pthread_cond_timedwait: CLOCK_MONOTONIC test
@@ -76,7 +79,7 @@ endif
LIB_LDFLAGS += -shared
LDFLAGS += -lpthread
LDFLAGS += $(FAKETIME_LINK_FLAGS) -lpthread
ifneq ($(PLATFORM),SunOS)
LDFLAGS += -Wl,--version-script=libfaketime.map
endif

View File

@@ -53,6 +53,7 @@
/* pthread-handling contributed by David North, TDI in version 0.7 */
#if defined PTHREAD_SINGLETHREADED_TIME || defined FAKE_PTHREAD
#include <pthread.h>
#include <signal.h>
#endif
#include <sys/timeb.h>
@@ -110,6 +111,13 @@ typedef int clockid_t;
#define CLOCK_MONOTONIC_RAW (CLOCK_MONOTONIC + 1)
#endif
#ifdef FAKE_FILE_TIMESTAMPS
struct utimbuf {
time_t actime; /* access time */
time_t modtime; /* modification time */
};
#endif
/*
* Per thread variable, which we turn on inside real_* calls to avoid modifying
* time multiple times of for the whole process to prevent faking time
@@ -170,7 +178,7 @@ static int (*real_timer_gettime_233) (timer_t timerid,
#ifdef FAKE_SLEEP
static int (*real_nanosleep) (const struct timespec *req, struct timespec *rem);
#ifndef __APPLE__
static int (*real_clock_nanosleep) (clockid_t clock_id, int flags, const struct timespec *req, struct timespec *rem);
static int (*real_clock_nanosleep) (clockid_t clock_id, int flags, const struct timespec *req, struct timespec *rem);
#endif
static int (*real_usleep) (useconds_t usec);
static unsigned int (*real_sleep) (unsigned int seconds);
@@ -200,11 +208,17 @@ static int apple_clock_gettime (clockid_t clk_id, struct timespec *
static clock_serv_t clock_serv_real;
#endif
#ifdef FAKE_FILE_TIMESTAMPS
static int (*real_utimes) (const char *filename, const struct timeval times[2]);
static int (*real_utime) (const char *filename, const struct utimbuf *times);
#endif
static int initialized = 0;
/* prototypes */
static int fake_gettimeofday(struct timeval *tv);
static int fake_clock_gettime(clockid_t clk_id, struct timespec *tp);
int read_config_file();
/** Semaphore protecting shared data */
static sem_t *shared_sem = NULL;
@@ -255,6 +269,7 @@ static int fake_monotonic_clock = 1;
#endif
static int cache_enabled = 1;
static int cache_duration = 10; /* cache fake time input for 10 seconds */
static int force_cache_expiration = 0;
/*
* Static timespec to store our startup time, followed by a load-time library
@@ -285,8 +300,6 @@ static double user_rate = 1.0;
static bool user_rate_set = false;
static struct timespec user_per_tick_inc = {0, -1};
static bool user_per_tick_inc_set = false;
static bool user_per_tick_inc_set_backup = false;
enum ft_mode_t {FT_FREEZE, FT_START_AT, FT_NOOP} ft_mode = FT_FREEZE;
/* Time to fake is not provided through FAKETIME env. var. */
@@ -316,11 +329,11 @@ static void ft_shm_create(void) {
snprintf(shm_name, 255, "/faketime_shm_%ld", (long)getpid());
if (SEM_FAILED == (semN = sem_open(sem_name, O_CREAT|O_EXCL, S_IWUSR|S_IRUSR, 1)))
{ /* silently fail on platforms that do not support sem_open() */
return;
return;
}
/* create shm */
if (-1 == (shm_fdN = shm_open(shm_name, O_CREAT|O_EXCL|O_RDWR, S_IWUSR|S_IRUSR)))
{
{
perror("libfaketime: In ft_shm_create(), shm_open failed");
exit(EXIT_FAILURE);
}
@@ -329,7 +342,7 @@ static void ft_shm_create(void) {
{
perror("libfaketime: In ft_shm_create(), ftruncate failed");
exit(EXIT_FAILURE);
}
}
/* map shm */
if (MAP_FAILED == (ft_sharedN = mmap(NULL, sizeof(struct ft_shared_s), PROT_READ|PROT_WRITE,
MAP_SHARED, shm_fdN, 0)))
@@ -361,7 +374,7 @@ static void ft_shm_create(void) {
{
perror("libfaketime: In ft_shm_create(), sem_post failed");
exit(EXIT_FAILURE);
}
}
snprintf(shared_objsN, sizeof(shared_objsN), "%s %s", sem_name, shm_name);
@@ -414,6 +427,7 @@ static void ft_shm_init (void)
int ticks_shm_fd;
char sem_name[256], shm_name[256], *ft_shared_env = getenv("FAKETIME_SHARED");
sem_t *shared_semR = NULL;
static int nt=1;
/* create semaphore and shared memory locally unless it has been passed along */
if (ft_shared_env == NULL)
@@ -421,7 +435,7 @@ static void ft_shm_init (void)
ft_shm_create();
ft_shared_env = getenv("FAKETIME_SHARED");
}
/* check for stale semaphore / shared memory information */
if (ft_shared_env != NULL)
{
@@ -435,7 +449,7 @@ static void ft_shm_init (void)
ft_shm_create();
ft_shared_env = getenv("FAKETIME_SHARED");
}
else
else
{
sem_close(shared_semR);
}
@@ -452,10 +466,28 @@ static void ft_shm_init (void)
if (SEM_FAILED == (shared_sem = sem_open(sem_name, 0)))
{
perror("libfaketime: In ft_shm_init(), sem_open failed");
fprintf(stderr, "libfaketime: sem_name was %s, created locally: %s\n", sem_name, shmCreator ? "true":"false");
fprintf(stderr, "libfaketime: parsed from env: %s\n", ft_shared_env);
exit(1);
if (shmCreator)
{
perror("libfaketime: In ft_shm_init(), sem_open failed");
fprintf(stderr, "libfaketime: sem_name was %s, created locally: %s\n", sem_name, shmCreator ? "true":"false");
fprintf(stderr, "libfaketime: parsed from env: %s\n", ft_shared_env);
exit(1);
}
else
{
nt++;
if (nt > 3)
{
perror("libfaketime: In ft_shm_init(), sem_open failed and recreation attempts failed");
fprintf(stderr, "libfaketime: sem_name was %s, created locally: %s\n", sem_name, shmCreator ? "true":"false");
exit(1);
}
else{
ft_shm_init();
return;
}
}
}
if (-1 == (ticks_shm_fd = shm_open(shm_name, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)))
@@ -498,6 +530,30 @@ static void ft_cleanup (void)
}
/*
* =======================================================================
* Get monotonic faketime setting === GETENV
* =======================================================================
*/
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;
}
}
}
/*
* =======================================================================
* Internal time retrieval === INTTIME
@@ -680,6 +736,7 @@ static bool load_time(struct timespec *tp)
#include <sys/stat.h>
static int fake_stat_disabled = 0;
static bool user_per_tick_inc_set_backup = false;
void lock_for_stat()
{
@@ -1013,6 +1070,65 @@ int __lxstat64 (int ver, const char *path, struct stat64 *buf)
}
#endif
#ifdef FAKE_FILE_TIMESTAMPS
int utime(const char *filename, const struct utimbuf *times)
{
if (!initialized)
{
ftpl_init();
}
if (NULL == real_utime)
{ /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original utime() not found.\n");
#endif
return -1; /* propagate error to caller */
}
int result;
struct utimbuf ntbuf;
ntbuf.actime = times->actime - user_offset.tv_sec;
ntbuf.modtime = times->modtime - user_offset.tv_sec;
DONT_FAKE_TIME(result = real_utime(filename, &ntbuf));
if (result == -1)
{
return -1;
}
return result;
}
int utimes(const char *filename, const struct timeval times[2])
{
if (!initialized)
{
ftpl_init();
}
if (NULL == real_utimes)
{ /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original utimes() not found.\n");
#endif
return -1; /* propagate error to caller */
}
int result;
struct timeval tn[2];
struct timeval user_offset2;
user_offset2.tv_sec = user_offset.tv_sec;
user_offset2.tv_usec = 0;
timersub(&times[0], &user_offset2, &tn[0]);
timersub(&times[1], &user_offset2, &tn[1]);
DONT_FAKE_TIME(result = real_utimes(filename, tn));
if (result == -1)
{
return -1;
}
return result;
}
#endif
/*
* =======================================================================
* Faked system functions: sleep/alarm/poll/timer related === FAKE(SLEEP)
@@ -1892,10 +2008,32 @@ int gettimeofday(struct timeval *tv, void *tz)
int clock_gettime(clockid_t clk_id, struct timespec *tp)
{
int result;
static int recursion_depth = 0;
if (!initialized)
{
ftpl_init();
recursion_depth++;
if (recursion_depth == 2)
{
fprintf(stderr, "libfaketime: Unexpected recursive calls to clock_gettime() without proper initialization. Trying alternative.\n");
DONT_FAKE_TIME(ftpl_init()) ;
}
else if (recursion_depth == 3)
{
fprintf(stderr, "libfaketime: Cannot recover from unexpected recursive calls to clock_gettime().\n");
fprintf(stderr, "libfaketime: Please check whether any other libraries are in use that clash with libfaketime.\n");
fprintf(stderr, "libfaketime: Returning -1 on clock_gettime() to break recursion now... if that does not work, please check other libraries' error handling.\n");
if (tp != NULL)
{
tp->tv_sec = 0;
tp->tv_nsec = 0;
}
return -1;
}
else {
ftpl_init();
}
recursion_depth--;
}
/* sanity check */
if (tp == NULL)
@@ -2064,7 +2202,7 @@ parse_modifiers:
{
user_rate = atof(strchr(user_faked_time, 'x')+1);
user_rate_set = true;
if (NULL != getenv("FAKETIME_XRESET")) {
if (NULL != getenv("FAKETIME_XRESET")) {
if (ftpl_timecache.real.tv_nsec >= 0) {
user_faked_time_timespec.tv_sec = ftpl_faketimecache.real.tv_sec;
user_faked_time_timespec.tv_nsec = ftpl_faketimecache.real.tv_nsec;
@@ -2079,7 +2217,7 @@ parse_modifiers:
ftpl_starttime.boot.tv_nsec = ftpl_timecache.boot.tv_nsec;
#endif
}
}
}
}
else if (NULL != (tmp_time_fmt = strchr(user_faked_time, 'i')))
{
@@ -2132,6 +2270,10 @@ static void ftpl_init(void)
real_lstat64 = dlsym(RTLD_NEXT, "__lxstat64");
real_time = dlsym(RTLD_NEXT, "time");
real_ftime = dlsym(RTLD_NEXT, "ftime");
#ifdef FAKE_FILE_TIMESTAMPS
real_utimes = dlsym(RTLD_NEXT, "utimes");
real_utime = dlsym(RTLD_NEXT, "utime");
#endif
#if defined(__alpha__) && defined(__GLIBC__)
real_gettimeofday = dlvsym(RTLD_NEXT, "gettimeofday", "GLIBC_2.1");
#else
@@ -2249,14 +2391,7 @@ static void ftpl_init(void)
cache_enabled = 0;
}
}
if ((tmp_env = getenv("FAKETIME_DONT_FAKE_MONOTONIC")) != NULL
|| (tmp_env = getenv("DONT_FAKE_MONOTONIC")) != NULL)
{
if (0 == strcmp(tmp_env, "1"))
{
fake_monotonic_clock = 0;
}
}
get_fake_monotonic_setting(&fake_monotonic_clock);
/* Check whether we actually should be faking the returned timestamp. */
/* We can prevent faking time for specified commands */
@@ -2451,6 +2586,10 @@ static void ftpl_init(void)
parse_config_file = false;
parse_ft_string(tmp_env);
}
else
{
read_config_file();
}
dont_fake = dont_fake_final;
}
@@ -2486,13 +2625,62 @@ static void remove_trailing_eols(char *line)
*/
#ifdef PTHREAD_SINGLETHREADED_TIME
/*
* To avoid a deadlock if a faketime function is interrupted by a signal while
* holding the lock, we block all signals while the mutex is locked.
* The original_mask field is used to restore the previous set of signals
* after the lock has been released.
* (Prompted by issues with parallel garbage collection in D 2.090. D uses signals
* to freeze all but one thread. The frozen threads may be in faketime operations.)
*/
struct LockedState {
pthread_mutex_t *mutex;
sigset_t original_mask;
};
static void pthread_cleanup_mutex_lock(void *data)
{
pthread_mutex_t *mutex = data;
pthread_mutex_unlock(mutex);
struct LockedState *state = data;
pthread_mutex_unlock(state->mutex);
pthread_sigmask(SIG_SETMASK, &state->original_mask, NULL);
}
#endif
int read_config_file()
{
static char user_faked_time[BUFFERLEN]; /* changed to static for caching in v0.6 */
static char custom_filename[BUFSIZ];
static char filename[BUFSIZ];
FILE *faketimerc;
/* check whether there's a .faketimerc in the user's home directory, or
* a system-wide /etc/faketimerc present.
* The /etc/faketimerc handling has been contributed by David Burley,
* Jacob Moorman, and Wayne Davison of SourceForge, Inc. in version 0.6 */
(void) snprintf(custom_filename, BUFSIZ, "%s", getenv("FAKETIME_TIMESTAMP_FILE"));
(void) snprintf(filename, BUFSIZ, "%s/.faketimerc", getenv("HOME"));
if ((faketimerc = fopen(custom_filename, "rt")) != NULL ||
(faketimerc = fopen(filename, "rt")) != NULL ||
(faketimerc = fopen("/etc/faketimerc", "rt")) != NULL)
{
static char line[BUFFERLEN];
while(fgets(line, BUFFERLEN, faketimerc) != NULL)
{
if ((strlen(line) > 1) && (line[0] != ' ') &&
(line[0] != '#') && (line[0] != ';'))
{
remove_trailing_eols(line);
strncpy(user_faked_time, line, BUFFERLEN-1);
user_faked_time[BUFFERLEN-1] = 0;
break;
}
}
fclose(faketimerc);
parse_ft_string(user_faked_time);
return 1;
}
return 0;
}
int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
{
/* variables used for caching, introduced in version 0.6 */
@@ -2518,10 +2706,20 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
/* Sanity check by Karl Chan since v0.8 */
if (tp == NULL) return -1;
// {ret = value; goto abort;} to call matching pthread_cleanup_pop and return value
int ret = INT_MAX;
#ifdef PTHREAD_SINGLETHREADED_TIME
static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t time_mutex = PTHREAD_MUTEX_INITIALIZER;
// block all signals while locked. prevents deadlocks if signal interrupts in in mid-operation.
sigset_t all_signals, original_mask;
sigfillset(&all_signals);
pthread_sigmask(SIG_SETMASK, &all_signals, &original_mask);
pthread_mutex_lock(&time_mutex);
pthread_cleanup_push(pthread_cleanup_mutex_lock, &time_mutex);
struct LockedState state = { .mutex = &time_mutex, .original_mask = original_mask };
pthread_cleanup_push(pthread_cleanup_mutex_lock, &state);
#endif
if ((limited_faking &&
@@ -2566,10 +2764,14 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
{
/* Check whether we actually should be faking the returned timestamp. */
/* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
if ((ft_start_after_secs != -1) && (tmp_ts.tv_sec < ft_start_after_secs)) return 0;
if ((ft_stop_after_secs != -1) && (tmp_ts.tv_sec >= ft_stop_after_secs)) return 0;
if ((ft_start_after_ncalls != -1) && (callcounter < ft_start_after_ncalls)) return 0;
if ((ft_stop_after_ncalls != -1) && (callcounter >= ft_stop_after_ncalls)) return 0;
if (((ft_start_after_secs != -1) && (tmp_ts.tv_sec < ft_start_after_secs))
|| ((ft_stop_after_secs != -1) && (tmp_ts.tv_sec >= ft_stop_after_secs))
|| ((ft_start_after_ncalls != -1) && (callcounter < ft_start_after_ncalls))
|| ((ft_stop_after_ncalls != -1) && (callcounter >= ft_stop_after_ncalls)))
{
ret = 0;
goto abort;
}
/* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu continues\n", (*time_tptr - ftpl_starttime), callcounter); */
}
@@ -2607,6 +2809,12 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
cache_expired = 1;
}
if (force_cache_expiration != 0)
{
cache_expired = 1;
force_cache_expiration = 0;
}
if (cache_expired == 1)
{
static char user_faked_time[BUFFERLEN]; /* changed to static for caching in v0.6 */
@@ -2631,42 +2839,22 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
/* fake time supplied as environment variable? */
if (parse_config_file)
{
char custom_filename[BUFSIZ];
char filename[BUFSIZ];
FILE *faketimerc;
/* check whether there's a .faketimerc in the user's home directory, or
* a system-wide /etc/faketimerc present.
* The /etc/faketimerc handling has been contributed by David Burley,
* Jacob Moorman, and Wayne Davison of SourceForge, Inc. in version 0.6 */
(void) snprintf(custom_filename, BUFSIZ, "%s", getenv("FAKETIME_TIMESTAMP_FILE"));
(void) snprintf(filename, BUFSIZ, "%s/.faketimerc", getenv("HOME"));
if ((faketimerc = fopen(custom_filename, "rt")) != NULL ||
(faketimerc = fopen(filename, "rt")) != NULL ||
(faketimerc = fopen("/etc/faketimerc", "rt")) != NULL)
{
char line[BUFFERLEN];
while(fgets(line, BUFFERLEN, faketimerc) != NULL)
{
if ((strlen(line) > 1) && (line[0] != ' ') &&
(line[0] != '#') && (line[0] != ';'))
{
remove_trailing_eols(line);
strncpy(user_faked_time, line, BUFFERLEN-1);
user_faked_time[BUFFERLEN-1] = 0;
break;
}
}
fclose(faketimerc);
}
if (read_config_file() == 0) parse_ft_string(user_faked_time);
} /* read fake time from file */
parse_ft_string(user_faked_time);
else
{
parse_ft_string(user_faked_time);
}
/* read monotonic faketime setting from envar */
get_fake_monotonic_setting(&fake_monotonic_clock);
} /* cache had expired */
if (infile_set)
{
if (load_time(tp))
{
return 0;
ret = 0;
goto abort;
}
}
@@ -2729,12 +2917,16 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
break;
default:
return -1;
ret = -1;
goto abort;
} // end of switch(ft_mode)
abort:
#ifdef PTHREAD_SINGLETHREADED_TIME
pthread_cleanup_pop(1);
#endif
// came here via goto abort?
if (ret != INT_MAX) return ret;
save_time(tp);
/* Cache this most recent real and faked time we encountered */
@@ -2768,7 +2960,7 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
ftpl_faketimecache.boot.tv_nsec = tp->tv_nsec;
}
#endif
return 0;
}
@@ -3157,7 +3349,7 @@ int pthread_cond_timedwait_232(pthread_cond_t *cond, pthread_mutex_t *mutex, con
}
__asm__(".symver pthread_cond_timedwait_225, pthread_cond_timedwait@GLIBC_2.2.5");
#ifdef __ARM_ARCH
#if defined __ARM_ARCH || defined FORCE_PTHREAD_NONVER
__asm__(".symver pthread_cond_timedwait_232, pthread_cond_timedwait@@");
__asm__(".symver pthread_cond_init_232, pthread_cond_init@@");
__asm__(".symver pthread_cond_destroy_232, pthread_cond_destroy@@");
@@ -3169,6 +3361,89 @@ __asm__(".symver pthread_cond_destroy_232, pthread_cond_destroy@@GLIBC_2.3.2");
#endif
/*
* Intercept calls to time-setting functions if compiled with FAKE_SETTIME set.
* Based on suggestion and prototype by @ojura, see https://github.com/wolfcw/libfaketime/issues/179
*/
#ifdef FAKE_SETTIME
int clock_settime(clockid_t clk_id, const struct timespec *tp) {
/* only CLOCK_REALTIME can be set */
if (clk_id != CLOCK_REALTIME) {
errno = EPERM;
return -1;
}
/* sanity check for the pointer */
if (tp == NULL) {
errno = EFAULT;
return -1;
}
/* When setting the FAKETIME environment variable to the new timestamp,
we do not have to care about 'x' or 'i' modifiers given previously,
as they are not erased when parsing them. */
struct timespec current_time;
DONT_FAKE_TIME(clock_gettime(clk_id, &current_time))
;
time_t sec_diff = tp->tv_sec - current_time.tv_sec;
long nsec_diff = tp->tv_nsec - current_time.tv_nsec;
char newenv_string[256];
double offset = (double) sec_diff;
offset += (double) nsec_diff/SEC_TO_nSEC;
snprintf(newenv_string, 255, "%+f", offset);
setenv("FAKETIME", newenv_string, 1);
force_cache_expiration = 1; /* make sure it becomes effective immediately */
return 0;
}
int settimeofday(const struct timeval *tv, void *tz)
{
/* The use of timezone *tz is obsolete and simply ignored here. */
if (tz == NULL) tz = NULL;
if (tv == NULL)
{
errno = EFAULT;
return -1;
}
else
{
struct timespec tp;
tp.tv_sec = tv->tv_sec;
tp.tv_nsec = tv->tv_usec * 1000;
clock_settime(CLOCK_REALTIME, &tp);
}
return 0;
}
int adjtime (const struct timeval *delta, struct timeval *olddelta)
{
/* Always signal true full success when olddelta is requested. */
if (olddelta != NULL)
{
olddelta->tv_sec = 0;
olddelta->tv_usec = 0;
}
if (delta != NULL)
{
struct timespec tp;
clock_gettime(CLOCK_REALTIME, &tp);
tp.tv_sec += delta->tv_sec;
tp.tv_nsec += delta->tv_usec * 1000;
/* This actually will make the clock jump instead of gradually
adjusting it, but we fulfill the caller's intention and an
additional thread just for the gradual changes does not seem
to be worth the effort presently. */
clock_settime(CLOCK_REALTIME, &tp);
}
return 0;
}
#endif
/*
* Editor modelines

View File

@@ -60,9 +60,9 @@
#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); \
int64_t tmp_time; \
tmp_time = (c) * (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; \
@@ -89,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