summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfgang Hommel <wolfgang.hommel@unibw.de>2019-09-03 12:01:33 +0200
committerWolfgang Hommel <wolfgang.hommel@unibw.de>2019-09-03 12:01:33 +0200
commit5d1e6325f26380aea9a12d126571fcee3c30af31 (patch)
treee18ff549673e9fb0bf1cbab9098071a77ff55935
parent8ed946cb63b636d522a139119558e97a385e516d (diff)
downloadlibfaketime-5d1e6325f26380aea9a12d126571fcee3c30af31.tar.gz
Add FAKE_SETTIME to CFLAGS to intercept time-setting calls (#179)
-rw-r--r--NEWS11
-rw-r--r--README10
-rw-r--r--src/Makefile3
-rw-r--r--src/libfaketime.c90
4 files changed, 114 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index cba2534..0161eb7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,14 @@
+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)
diff --git a/README b/README
index 66cc135..d146c45 100644
--- a/README
+++ b/README
@@ -456,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
----------------------------------------
diff --git a/src/Makefile b/src/Makefile
index f13a6bb..4f67ca3 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -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
diff --git a/src/libfaketime.c b/src/libfaketime.c
index b70a3d3..119ae4d 100644
--- a/src/libfaketime.c
+++ b/src/libfaketime.c
@@ -255,6 +255,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
@@ -2607,6 +2608,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 */
@@ -3169,6 +3176,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