summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfgang Hommel <wolf@code-wizards.com>2013-08-25 10:42:36 +0200
committerWolfgang Hommel <wolf@code-wizards.com>2013-08-25 10:42:36 +0200
commit30dd22e15756c392e60366b458ee79985c2eb406 (patch)
tree5dfe2478551cc3b79ffc2e78311e6b8889f76f3e
parent03fbad9bca802e883ec445d7991ea0183ca0f62a (diff)
parentebf08018ff895db8ff6c6c33b8df3d19ccaf0bad (diff)
downloadlibfaketime-30dd22e15756c392e60366b458ee79985c2eb406.tar.gz
Merging Balint's files
-rw-r--r--src/Makefile10
-rw-r--r--src/Makefile.MacOS11
-rw-r--r--src/libfaketime.c760
-rw-r--r--src/time_ops.h99
4 files changed, 401 insertions, 479 deletions
diff --git a/src/Makefile b/src/Makefile
index 51b5100..70d405e 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -30,14 +30,6 @@
# frequently. Disabling the cache may negatively influence the
# performance.
#
-# LIMITEDFAKING
-# - Support environment variables that limit time faking to certain
-# time intervals or number of function calls.
-#
-# SPAWNSUPPORT
-# - Enable support for spawning an external process at a given
-# timestamp.
-#
# * Compilation addition: second libMT target added for building the pthread-
# enabled library as a separate library
#
@@ -52,7 +44,7 @@ INSTALL ?= install
PREFIX ?= /usr/local
-CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -DFAKE_INTERNAL_CALLS -fPIC -DPOSIX_REALTIME -DLIMITEDFAKING -DSPAWNSUPPORT -DPREFIX='"'$(PREFIX)'"'
+CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"'
LIB_LDFLAGS += -shared
LDFLAGS += -lrt
LDADD += -ldl -lm -lpthread
diff --git a/src/Makefile.MacOS b/src/Makefile.MacOS
index 98155d3..72cbb0d 100644
--- a/src/Makefile.MacOS
+++ b/src/Makefile.MacOS
@@ -30,15 +30,6 @@
# frequently. Disabling the cache may negatively influence the
# performance.
#
-# LIMITEDFAKING
-# - Support environment variables that limit time faking to certain
-# time intervals or number of function calls.
-#
-# SPAWNSUPPORT
-# - Enable support for spawning an external process at a given
-# timestamp.
-#
-#
# * Compilation addition: second libMT target added for building the pthread-
# enabled library as a separate library
#
@@ -59,7 +50,7 @@ PREFIX = /usr/local
# 10.5
#CFLAGS = -dynamiclib -DFAKE_INTERNAL_CALLS -arch i386 -arch ppc
# 10.6
-CFLAGS = -dynamiclib -DFAKE_INTERNAL_CALLS -arch i386 -arch x86_64 -DLIMITEDFAKING -DSPAWNSUPPORT -DPREFIX='"'$(PREFIX)'"'
+CFLAGS = -dynamiclib -DFAKE_INTERNAL_CALLS -arch i386 -arch x86_64 -DPREFIX='"'$(PREFIX)'"'
LIB_SRC = libfaketime.c
SONAME = 1
diff --git a/src/libfaketime.c b/src/libfaketime.c
index f709027..6f4f341 100644
--- a/src/libfaketime.c
+++ b/src/libfaketime.c
@@ -22,36 +22,23 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#include <stdbool.h>
#include <fcntl.h>
#include <time.h>
+#include <math.h>
#include <string.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include "time_ops.h"
+
/* pthread-handling contributed by David North, TDI in version 0.7 */
#ifdef PTHREAD
#include <pthread.h>
-static pthread_mutex_t once_mutex=PTHREAD_MUTEX_INITIALIZER;
-
-#define SINGLE_IF_MTX(ifcondition,mtxaddr) \
- if (ifcondition) { \
- pthread_mutex_lock(mtxaddr); \
- pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, (void *)mtxaddr); \
- if (ifcondition) {
-#define SINGLE_IF(ifcondition) SINGLE_IF_MTX(ifcondition,&once_mutex)
-#define END_SINGLE_IF \
- } \
- pthread_cleanup_pop(1); \
- }
-
#else
-#define SINGLE_IF_MTX(ifcondition,mtxaddr) if (ifcondition) {
-#define SINGLE_IF(ifcondition) if (ifcondition) {
-#define END_SINGLE_IF }
-
#endif
#include <sys/timeb.h>
@@ -59,13 +46,26 @@ static pthread_mutex_t once_mutex=PTHREAD_MUTEX_INITIALIZER;
#define BUFFERLEN 256
+/* real pointer to faked functions */
+static int (*real_stat) (int, const char *, struct stat *);
+static int (*real_fstat) (int, int, struct stat *);
+static int (*real_fstatat) (int, int, const char *, struct stat *, int);
+static int (*real_lstat)(int, const char *, struct stat *);
+static int (*real_stat64) (int, const char *, struct stat64 *);
+static int (*real_fstat64)(int, int , struct stat64 *);
+static int (*real_fstatat64)(int, int , const char *, struct stat64 *, int);
+static int (*real_lstat64) (int, const char *, struct stat64 *);
+static time_t (*real_time)(time_t *);
+static int (*real_ftime)(struct timeb *);
+static int (*real_gettimeofday)(struct timeval *, void *);
+static int (*real_clock_gettime)(clockid_t clk_id, struct timespec *tp);
+
+
/* prototypes */
time_t fake_time(time_t *time_tptr);
int fake_ftime(struct timeb *tp);
int fake_gettimeofday(struct timeval *tv, void *tz);
-#ifdef POSIX_REALTIME
int fake_clock_gettime(clockid_t clk_id, struct timespec *tp);
-#endif
/*
* Intercepted system calls:
@@ -96,6 +96,44 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp);
static sem_t *ticks_sem = NULL;
static uint64_t *ticks = NULL;
+static bool limited_faking = false;
+static long callcounter = 0;
+static long ft_start_after_secs = -1;
+static long ft_stop_after_secs = -1;
+static long ft_start_after_ncalls = -1;
+static long ft_stop_after_ncalls = -1;
+
+
+static bool spawnsupport = false;
+static int spawned = 0;
+static char ft_spawn_target[1024];
+static long ft_spawn_secs = -1;
+static long ft_spawn_ncalls = -1;
+
+/**
+ * Static time_t to store our startup time, followed by a load-time library
+ * initialization declaration.
+ */
+static struct timespec ftpl_starttime = {0, -1};
+
+static char user_faked_time_fmt[BUFSIZ] = {0};
+
+/** User supplied base time to fake */
+static struct timespec user_faked_time_timespec = {0, -1};
+/** User supplied base time is set */
+static bool user_faked_time_set = false;
+/** Fractional user offset provided through FAKETIME env. var.*/
+static struct timespec user_offset = {0, -1};
+/** Speed up or slow down clock */
+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;
+
+enum ft_mode_t {FT_FREEZE, FT_START_AT} ft_mode = FT_FREEZE;
+
+/** Time to fake is not provided through FAKETIME env. var. */
+static bool parse_config_file = true;
void ft_cleanup (void) __attribute__ ((destructor));
@@ -133,11 +171,10 @@ void ft_cleanup (void)
sem_close(ticks_sem);
}
-static time_t next_time(double ticklen)
+static void next_time(struct timespec *tp, struct timespec *ticklen)
{
- time_t ret = 0;
-
if (ticks_sem != NULL) {
+ struct timespec inc;
/* lock */
if (sem_wait(ticks_sem) == -1) {
perror("sem_wait");
@@ -145,15 +182,15 @@ static time_t next_time(double ticklen)
}
/* calculate and update elapsed time */
- ret = ticklen * (*ticks)++;
+ timespecmul(ticklen, *ticks, &inc);
+ timespecadd(&user_faked_time_timespec, &inc, tp);
+ (*ticks)++;
/* unlock */
if (sem_post(ticks_sem) == -1) {
perror("sem_post");
exit(1);
}
}
- return ret;
-
}
#ifdef FAKE_STAT
@@ -171,17 +208,7 @@ static int fake_stat_disabled = 0;
/* Contributed by Philipp Hachtmann in version 0.6 */
int __xstat (int ver, const char *path, struct stat *buf) {
- static int (*real_stat) (int, const char *, struct stat *);
- static int has_real_stat=0;
-
- SINGLE_IF(has_real_stat==0)
- real_stat = NULL;
- real_stat = dlsym(RTLD_NEXT, "__xstat");
- if (dlerror() == NULL) {
- has_real_stat = 1;
- }
- END_SINGLE_IF
- if (!has_real_stat) { /* dlsym() failed */
+ if (NULL == real_stat) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original stat() not found.\n");
#endif
@@ -206,17 +233,7 @@ int __xstat (int ver, const char *path, struct stat *buf) {
/* Contributed by Philipp Hachtmann in version 0.6 */
int __fxstat (int ver, int fildes, struct stat *buf) {
- static int (*real_fstat) (int, int, struct stat *);
- static int has_real_fstat=0;
-
- SINGLE_IF(has_real_fstat==0)
- real_fstat = NULL;
- real_fstat = dlsym(RTLD_NEXT, "__fxstat");
- if (dlerror() == NULL) {
- has_real_fstat = 1;
- }
- END_SINGLE_IF
- if (!has_real_fstat) { /* dlsym() failed */
+ if (NULL == real_fstat) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original fstat() not found.\n");
#endif
@@ -241,17 +258,8 @@ int __fxstat (int ver, int fildes, struct stat *buf) {
/* Added in v0.8 as suggested by Daniel Kahn Gillmor */
#ifndef NO_ATFILE
int __fxstatat(int ver, int fildes, const char *filename, struct stat *buf, int flag) {
- static int (*real_fstatat) (int, int, const char *, struct stat *, int);
- static int has_real_fstatat=0;
- SINGLE_IF(has_real_fstatat==0)
- real_fstatat = NULL;
- real_fstatat = dlsym(RTLD_NEXT, "__fxstatat");
- if (dlerror() == NULL) {
- has_real_fstatat = 1;
- }
- END_SINGLE_IF
- if (!has_real_fstatat) { /* dlsym() failed */
+ if (NULL == real_fstatat) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original fstatat() not found.\n");
#endif
@@ -276,17 +284,7 @@ int __fxstatat(int ver, int fildes, const char *filename, struct stat *buf, int
/* Contributed by Philipp Hachtmann in version 0.6 */
int __lxstat (int ver, const char *path, struct stat *buf) {
- static int (*real_lstat)(int, const char *, struct stat *);
- static int has_real_lstat=0;
-
- SINGLE_IF(has_real_lstat==0)
- real_lstat = NULL;
- real_lstat = dlsym(RTLD_NEXT, "__lxstat");
- if (dlerror() == NULL) {
- has_real_lstat = 1;
- }
- END_SINGLE_IF
- if (!has_real_lstat) { /* dlsym() failed */
+ if (NULL == real_lstat) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original lstat() not found.\n");
#endif
@@ -310,24 +308,14 @@ int __lxstat (int ver, const char *path, struct stat *buf) {
/* Contributed by Philipp Hachtmann in version 0.6 */
int __xstat64 (int ver, const char *path, struct stat64 *buf) {
- static int (*real_stat) (int, const char *, struct stat64 *);
- static int has_real_stat = 0;
-
- SINGLE_IF(has_real_stat==0)
- real_stat = NULL;
- real_stat = dlsym(RTLD_NEXT,"__xstat64");
- if (dlerror() == NULL) {
- has_real_stat = 1;
- }
- END_SINGLE_IF
- if (!has_real_stat) { /* dlsym() failed */
+ if (NULL == real_stat64) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original stat() not found.\n");
#endif
return -1; /* propagate error to caller */
}
- int result=real_stat(ver, path, buf);
+ int result=real_stat64(ver, path, buf);
if (result == -1) {
return -1;
}
@@ -344,24 +332,14 @@ int __xstat64 (int ver, const char *path, struct stat64 *buf) {
/* Contributed by Philipp Hachtmann in version 0.6 */
int __fxstat64 (int ver, int fildes, struct stat64 *buf) {
- static int (*real_fstat)(int, int , struct stat64 *);
- static int has_real_fstat=0;
-
- SINGLE_IF(has_real_fstat==0)
- real_fstat = NULL;
- real_fstat = dlsym(RTLD_NEXT, "__fxstat64");
- if (dlerror() == NULL) {
- has_real_fstat = 1;
- }
- END_SINGLE_IF
- if (!has_real_fstat) { /* dlsym() failed */
+ if (NULL == real_fstat64) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original fstat() not found.\n");
#endif
return -1; /* propagate error to caller */
}
- int result = real_fstat(ver, fildes, buf);
+ int result = real_fstat64(ver, fildes, buf);
if (result == -1){
return -1;
}
@@ -379,17 +357,7 @@ int __fxstat64 (int ver, int fildes, struct stat64 *buf) {
/* Added in v0.8 as suggested by Daniel Kahn Gillmor */
#ifndef NO_ATFILE
int __fxstatat64 (int ver, int fildes, const char *filename, struct stat64 *buf, int flag) {
- static int (*real_fstatat64)(int, int , const char *, struct stat64 *, int);
- static int has_real_fstatat64=0;
-
- SINGLE_IF(has_real_fstatat64==0)
- real_fstatat64 = NULL;
- real_fstatat64 = dlsym(RTLD_NEXT, "__fxstatat64");
- if (dlerror() == NULL) {
- has_real_fstatat64 = 1;
- }
- END_SINGLE_IF
- if (!has_real_fstatat64) { /* dlsym() failed */
+ if (NULL == real_fstatat64) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original fstatat64() not found.\n");
#endif
@@ -414,24 +382,14 @@ int __fxstatat64 (int ver, int fildes, const char *filename, struct stat64 *buf,
/* Contributed by Philipp Hachtmann in version 0.6 */
int __lxstat64 (int ver, const char *path, struct stat64 *buf){
- static int (*real_lstat) (int, const char *, struct stat64 *);
- static int has_real_lstat = 0;
-
- SINGLE_IF(has_real_lstat==0)
- real_lstat = NULL;
- real_lstat = dlsym(RTLD_NEXT, "__lxstat64");
- if (dlerror() == NULL) {
- has_real_lstat = 1;
- }
- END_SINGLE_IF
- if (!has_real_lstat) { /* dlsym() failed */
+ if (NULL == real_lstat64) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original lstat() not found.\n");
#endif
return -1; /* propagate error to caller */
}
- int result = real_lstat(ver, path, buf);
+ int result = real_lstat64(ver, path, buf);
if (result == -1){
return -1;
}
@@ -447,92 +405,6 @@ int __lxstat64 (int ver, const char *path, struct stat64 *buf){
}
#endif
-/*
- * On MacOS, time() internally uses gettimeofday. If we don't
- * break the cycle by just calling it directly, we double-apply
- * relative changes.
- */
-
-#ifdef __APPLE__
-static int (*real_gettimeofday)(struct timeval *, void *);
-static int has_real_gettimeofday = 0;
-#endif
-/*
- * Our version of time() allows us to return fake values, so the calling
- * program thinks it's retrieving the current date and time, while it is
- * not
- * Note that this routine is split into two parts so that the initialization
- * piece can call the 'real' time function to establish a base time.
- */
-static time_t _ftpl_time(time_t *time_tptr) {
-#ifdef __APPLE__
- struct timeval tvm, *tv = &tvm;
-#else
- static time_t (*real_time)(time_t *);
- static int has_real_time = 0;
-#endif
-
- time_t result;
-
- time_t null_dummy;
-
- /* Handle null pointers correctly, fix as suggested by Andres Ojamaa */
- if (time_tptr == NULL) {
- time_tptr = &null_dummy;
- /* (void) fprintf(stderr, "NULL pointer caught in time().\n"); */
- }
-
-#ifdef __APPLE__
- /* Check whether we've got a pointer to the real ftime() function yet */
- SINGLE_IF(has_real_gettimeofday==0)
- real_gettimeofday = NULL;
- real_gettimeofday = dlsym(RTLD_NEXT, "gettimeofday");
-
- /* check whether dlsym() worked */
- if (dlerror() == NULL) {
- has_real_gettimeofday = 1;
- }
- END_SINGLE_IF
- if (!has_real_gettimeofday) { /* dlsym() failed */
-#ifdef DEBUG
- (void) fprintf(stderr, "faketime problem: original gettimeofday() not found.\n");
-#endif
- return -1; /* propagate error to caller */
- }
-
- /* initialize our result with the real current time */
- result = (*real_gettimeofday)(tv, NULL);
- if (result == -1) return result; /* original function failed */
- if (time_tptr != NULL)
- *time_tptr = tv->tv_sec;
- result = tv->tv_sec;
-#else
- /* Check whether we've got a pointer to the real time function yet */
- SINGLE_IF(has_real_time==0)
- real_time = NULL;
- real_time = dlsym(RTLD_NEXT, "time");
-
- /* check whether dlsym() worked */
- if (dlerror() == NULL) {
- has_real_time = 1;
- }
- END_SINGLE_IF
- if (!has_real_time) { /* dlsym() failed */
-#ifdef DEBUG
- (void) fprintf(stderr, "faketime problem: original time() not found.\n");
-#endif
- if (time_tptr != NULL)
- *time_tptr = -1;
- return -1; /* propagate error to caller */
- }
-
- /* initialize our result with the real current time */
- result = (*real_time)(time_tptr);
-#endif
-
- return result;
-}
-
time_t time(time_t *time_tptr) {
time_t result;
time_t null_dummy;
@@ -540,7 +412,7 @@ time_t time(time_t *time_tptr) {
time_tptr = &null_dummy;
/* (void) fprintf(stderr, "NULL pointer caught in time().\n"); */
}
- result = _ftpl_time(time_tptr);
+ result = (*real_time)(time_tptr);
if (result == ((time_t) -1)) return result;
/* pass the real current time to our faking version, overwriting it */
@@ -552,8 +424,6 @@ time_t time(time_t *time_tptr) {
int ftime(struct timeb *tp) {
- static int (*real_ftime)(struct timeb *);
- static int has_real_ftime = 0;
int result;
/* sanity check */
@@ -561,16 +431,7 @@ int ftime(struct timeb *tp) {
return 0; /* ftime() always returns 0, see manpage */
/* Check whether we've got a pointer to the real ftime() function yet */
- SINGLE_IF(has_real_ftime==0)
- real_ftime = NULL;
- real_ftime = dlsym(RTLD_NEXT, "ftime");
-
- /* check whether dlsym() worked */
- if (dlerror() == NULL) {
- has_real_ftime = 1;
- }
- END_SINGLE_IF
- if (!has_real_ftime) { /* dlsym() failed */
+ if (NULL == real_ftime) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original ftime() not found.\n");
#endif
@@ -589,10 +450,6 @@ int ftime(struct timeb *tp) {
}
int gettimeofday(struct timeval *tv, void *tz) {
-#ifndef __APPLE__
- static int (*real_gettimeofday)(struct timeval *, void *);
- static int has_real_gettimeofday = 0;
-#endif
int result;
/* sanity check */
@@ -601,16 +458,7 @@ int gettimeofday(struct timeval *tv, void *tz) {
}
/* Check whether we've got a pointer to the real ftime() function yet */
- SINGLE_IF(has_real_gettimeofday==0)
- real_gettimeofday = NULL;
- real_gettimeofday = dlsym(RTLD_NEXT, "gettimeofday");
-
- /* check whether dlsym() worked */
- if (dlerror() == NULL) {
- has_real_gettimeofday = 1;
- }
- END_SINGLE_IF
- if (!has_real_gettimeofday) { /* dlsym() failed */
+ if (NULL == real_gettimeofday) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original gettimeofday() not found.\n");
#endif
@@ -628,10 +476,7 @@ int gettimeofday(struct timeval *tv, void *tz) {
return result;
}
-#ifdef POSIX_REALTIME
int clock_gettime(clockid_t clk_id, struct timespec *tp) {
- static int (*real_clock_gettime)(clockid_t clk_id, struct timespec *tp);
- static int has_real_clock_gettime = 0;
int result;
/* sanity check */
@@ -639,17 +484,7 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp) {
return -1;
}
- /* Check whether we've got a pointer to the real clock_gettime() function yet */
- SINGLE_IF(has_real_clock_gettime==0)
- real_clock_gettime = NULL;
- real_clock_gettime = dlsym(RTLD_NEXT, "__clock_gettime");
-
- /* check whether dlsym() worked */
- if (dlerror() == NULL) {
- has_real_clock_gettime = 1;
- }
- END_SINGLE_IF
- if (!has_real_clock_gettime) { /* dlsym() failed */
+ if (NULL == real_clock_gettime) { /* dlsym() failed */
#ifdef DEBUG
(void) fprintf(stderr, "faketime problem: original clock_gettime() not found.\n");
#endif
@@ -666,17 +501,86 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp) {
/* return the result to the caller */
return result;
}
-#endif
-/*
- * Static time_t to store our startup time, followed by a load-time library
- * initialization declaration.
- */
-static time_t ftpl_starttime = 0;
+static void parse_ft_string(const char *user_faked_time)
+{
+ struct tm user_faked_time_tm;
+ char * tmp_time_fmt;
+ /* check whether the user gave us an absolute time to fake */
+ switch (user_faked_time[0]) {
+
+ default: /* Try and interpret this as a specified time */
+ ft_mode = FT_FREEZE;
+ user_faked_time_tm.tm_isdst = -1;
+ if (NULL != strptime(user_faked_time, user_faked_time_fmt,
+ &user_faked_time_tm)) {
+ user_faked_time_timespec.tv_sec = mktime(&user_faked_time_tm);
+ user_faked_time_timespec.tv_nsec = 0;
+ user_faked_time_set = true;
+ }
+ break;
+
+ case '+':
+ case '-': /* User-specified offset */
+ ft_mode = FT_START_AT;
+ /* fractional time offsets contributed by Karl Chen in v0.8 */
+ double frac_offset = atof(user_faked_time);
+
+ /* offset is in seconds by default, but the string may contain
+ * multipliers...
+ */
+ if (strchr(user_faked_time, 'm') != NULL) frac_offset *= 60;
+ else if (strchr(user_faked_time, 'h') != NULL) frac_offset *= 60 * 60;
+ else if (strchr(user_faked_time, 'd') != NULL) frac_offset *= 60 * 60 * 24;
+ else if (strchr(user_faked_time, 'y') != NULL) frac_offset *= 60 * 60 * 24 * 365;
+
+ user_offset.tv_sec = floor(frac_offset);
+ user_offset.tv_nsec = (frac_offset - user_offset.tv_sec) * SEC_TO_nSEC;
+ timespecadd(&ftpl_starttime, &user_offset, &user_faked_time_timespec);
+ goto parse_modifiers;
+ break;
+
+ /* Contributed by David North, TDI in version 0.7 */
+ case '@': /* Specific time, but clock along relative to that starttime */
+ ft_mode = FT_START_AT;
+ user_faked_time_tm.tm_isdst = -1;
+ (void) strptime(&user_faked_time[1], user_faked_time_fmt, &user_faked_time_tm);
+
+ user_faked_time_timespec.tv_sec = mktime(&user_faked_time_tm);
+ user_faked_time_timespec.tv_nsec = 0;
+ parse_modifiers:
+ /* Speed-up / slow-down contributed by Karl Chen in v0.8 */
+ if (strchr(user_faked_time, 'x') != NULL) {
+ user_rate = atof(strchr(user_faked_time, 'x')+1);
+ user_rate_set = true;
+ } else if (NULL != (tmp_time_fmt = strchr(user_faked_time, 'i'))) {
+ double tick_inc = atof(tmp_time_fmt + 1);
+ /* increment time with every time() call*/
+ user_per_tick_inc.tv_sec = floor(tick_inc);
+ user_per_tick_inc.tv_nsec = (tick_inc - user_per_tick_inc.tv_sec) * SEC_TO_nSEC ;
+ user_per_tick_inc_set = true;
+ }
+ break;
+ }
+}
void __attribute__ ((constructor)) ftpl_init(void)
{
- time_t temp_tt;
+ char *tmp_env;
+
+ /* Look up all real_* functions. NULL will mark missing ones. */
+ real_stat = dlsym(RTLD_NEXT, "__xstat");
+ real_fstat = dlsym(RTLD_NEXT, "__fxstat");
+ real_fstatat = dlsym(RTLD_NEXT, "__fxstatat");
+ real_lstat = dlsym(RTLD_NEXT, "__lxstat");
+ real_stat64 = dlsym(RTLD_NEXT,"__xstat64");
+ real_fstat64 = dlsym(RTLD_NEXT, "__fxstat64");
+ real_fstatat64 = dlsym(RTLD_NEXT, "__fxstatat64");
+ real_lstat64 = dlsym(RTLD_NEXT, "__lxstat64");
+ real_time = dlsym(RTLD_NEXT, "time");
+ real_ftime = dlsym(RTLD_NEXT, "ftime");
+ real_gettimeofday = dlsym(RTLD_NEXT, "gettimeofday");
+ real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime");
ft_shm_init();
#ifdef FAKE_STAT
@@ -685,7 +589,65 @@ void __attribute__ ((constructor)) ftpl_init(void)
}
#endif
- ftpl_starttime = _ftpl_time(&temp_tt);
+ /* Check whether we actually should be faking the returned timestamp. */
+
+ if ((tmp_env = getenv("FAKETIME_START_AFTER_SECONDS")) != NULL) {
+ ft_start_after_secs = atol(tmp_env);
+ limited_faking = true;
+ }
+ if ((tmp_env = getenv("FAKETIME_STOP_AFTER_SECONDS")) != NULL) {
+ ft_stop_after_secs = atol(tmp_env);
+ limited_faking = true;
+ }
+ if ((tmp_env = getenv("FAKETIME_START_AFTER_NUMCALLS")) != NULL) {
+ ft_start_after_ncalls = atol(tmp_env);
+ limited_faking = true;
+ }
+ if ((tmp_env = getenv("FAKETIME_STOP_AFTER_NUMCALLS")) != NULL) {
+ ft_stop_after_ncalls = atol(tmp_env);
+ limited_faking = true;
+ }
+
+ /* check whether we should spawn an external command */
+ if ((tmp_env = getenv("FAKETIME_SPAWN_TARGET")) != NULL) {
+ spawnsupport = true;
+ (void) strncpy(ft_spawn_target, getenv("FAKETIME_SPAWN_TARGET"), 1024);
+
+ if ((tmp_env = getenv("FAKETIME_SPAWN_SECONDS")) != NULL) {
+ ft_spawn_secs = atol(tmp_env);
+ }
+ if ((tmp_env = getenv("FAKETIME_SPAWN_NUMCALLS")) != NULL) {
+ ft_spawn_ncalls = atol(tmp_env);
+ }
+ }
+
+ tmp_env = getenv("FAKETIME_FMT");
+ if (tmp_env == NULL) {
+ strcpy(user_faked_time_fmt, "%Y-%m-%d %T");
+ } else {
+ strncpy(user_faked_time_fmt, tmp_env, BUFSIZ);
+ }
+
+#ifdef __APPLE__
+ /* from http://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x */
+ clock_serv_t cclock;
+ mach_timespec_t mts;
+ host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
+ /* this is not faked */
+ clock_get_time(cclock, &mts);
+ mach_port_deallocate(mach_task_self(), cclock);
+ ftpl_starttime.tv_sec = mts.tv_sec;
+ ftpl_starttime.tv_nsec = mts.tv_sec;
+#else
+ (*real_clock_gettime)(CLOCK_REALTIME, &ftpl_starttime);
+#endif
+
+ /* fake time supplied as environment variable? */
+ if (NULL != (tmp_env = getenv("FAKETIME"))) {
+ parse_config_file = false;
+ parse_ft_string(tmp_env);
+ }
+
}
static void remove_trailing_eols(char *line)
@@ -703,48 +665,21 @@ static void remove_trailing_eols(char *line)
}
-time_t fake_time(time_t *time_tptr) {
- static char user_faked_time[BUFFERLEN]; /* changed to static for caching in v0.6 */
- struct tm user_faked_time_tm;
- time_t user_faked_time_time_t;
- long user_offset;
- double frac_user_offset;
- char filename[BUFSIZ], line[BUFFERLEN];
- FILE *faketimerc;
- static const char *user_faked_time_fmt = NULL;
- char * tmp_time_fmt;
+int fake_clock_gettime(clockid_t clk_id, struct timespec *tp) {
+
/* variables used for caching, introduced in version 0.6 */
static time_t last_data_fetch = 0; /* not fetched previously at first call */
static int cache_expired = 1; /* considered expired at first call */
static int cache_duration = 10; /* cache fake time input for 10 seconds */
-#ifdef LIMITEDFAKING
- static long callcounter = 0;
- static int limited_initialized = 0;
- char envvarbuf[32];
- static long FAKETIME_START_AFTER_SECONDS = -1;
- static long FAKETIME_STOP_AFTER_SECONDS = -1;
- static long FAKETIME_START_AFTER_NUMCALLS = -1;
- static long FAKETIME_STOP_AFTER_NUMCALLS = -1;
-#endif
-
-#ifdef SPAWNSUPPORT
- static int spawned = 0;
- static long spawn_callcounter = 0;
- static int spawn_initialized = 0;
- char spawn_envvarbuf[32];
- static char FAKETIME_SPAWN_TARGET[1024];
- static long FAKETIME_SPAWN_SECONDS = -1;
- static long FAKETIME_SPAWN_NUMCALLS = -1;
-#endif
+ /* Fake only if the call is realtime clock related */
+ if (clk_id != CLOCK_REALTIME) {
+ return 0;
+ }
-/*
- * This no longer appears to be necessary in Mac OS X 10.7 Lion
- */
-//#ifdef __APPLE__
-// static int malloc_arena = 0;
-//#endif
+ /* Sanity check by Karl Chan since v0.8 */
+ if (tp == NULL) return -1;
#ifdef PTHREAD_SINGLETHREADED_TIME
static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
@@ -752,82 +687,42 @@ static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, (void *)&time_mutex);
#endif
- /* Sanity check by Karl Chan since v0.8 */
- if (time_tptr == NULL) return -1;
-
-#ifdef LIMITEDFAKING
- /* Check whether we actually should be faking the returned timestamp. */
-
- if (ftpl_starttime > 0) {
- if (limited_initialized == 0) {
- if (getenv("FAKETIME_START_AFTER_SECONDS") != NULL) {
- (void) strncpy(envvarbuf, getenv("FAKETIME_START_AFTER_SECONDS"), 30);
- FAKETIME_START_AFTER_SECONDS = atol(envvarbuf);
- }
- if (getenv("FAKETIME_STOP_AFTER_SECONDS") != NULL) {
- (void) strncpy(envvarbuf, getenv("FAKETIME_STOP_AFTER_SECONDS"), 30);
- FAKETIME_STOP_AFTER_SECONDS = atol(envvarbuf);
- }
- if (getenv("FAKETIME_START_AFTER_NUMCALLS") != NULL) {
- (void) strncpy(envvarbuf, getenv("FAKETIME_START_AFTER_NUMCALLS"), 30);
- FAKETIME_START_AFTER_NUMCALLS = atol(envvarbuf);
- }
- if (getenv("FAKETIME_STOP_AFTER_NUMCALLS") != NULL) {
- (void) strncpy(envvarbuf, getenv("FAKETIME_STOP_AFTER_NUMCALLS"), 30);
- FAKETIME_STOP_AFTER_NUMCALLS = atol(envvarbuf);
- }
- limited_initialized = 1;
- }
- if ((callcounter + 1) >= callcounter) callcounter++;
-
- /* For debugging, output #seconds and #calls */
- /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
- if ((FAKETIME_START_AFTER_SECONDS != -1) && ((*time_tptr - ftpl_starttime) < FAKETIME_START_AFTER_SECONDS)) return *time_tptr;
- if ((FAKETIME_STOP_AFTER_SECONDS != -1) && ((*time_tptr - ftpl_starttime) >= FAKETIME_STOP_AFTER_SECONDS)) return *time_tptr;
- if ((FAKETIME_START_AFTER_NUMCALLS != -1) && (callcounter < FAKETIME_START_AFTER_NUMCALLS)) return *time_tptr;
- if ((FAKETIME_STOP_AFTER_NUMCALLS != -1) && (callcounter >= FAKETIME_STOP_AFTER_NUMCALLS)) return *time_tptr;
- /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu continues\n", (*time_tptr - ftpl_starttime), callcounter); */
+ if ((limited_faking &&
+ ((ft_start_after_ncalls != -1) || (ft_stop_after_ncalls != -1))) ||
+ (spawnsupport && ft_spawn_ncalls)) {
+ if ((callcounter + 1) >= callcounter) callcounter++;
}
-#endif
-#ifdef SPAWNSUPPORT
- /* check whether we should spawn an external command */
-
- if (ftpl_starttime > 0) {
-
- if(spawn_initialized == 0) {
- if (getenv("FAKETIME_SPAWN_TARGET") != NULL) {
- (void) strncpy(FAKETIME_SPAWN_TARGET, getenv("FAKETIME_SPAWN_TARGET"), 1024);
-
- if (getenv("FAKETIME_SPAWN_SECONDS") != NULL) {
- (void) strncpy(spawn_envvarbuf, getenv("FAKETIME_SPAWN_SECONDS"), 30);
- FAKETIME_SPAWN_SECONDS = atol(spawn_envvarbuf);
- }
-
- if (getenv("FAKETIME_SPAWN_NUMCALLS") != NULL) {
- (void) strncpy(spawn_envvarbuf, getenv("FAKETIME_SPAWN_NUMCALLS"), 30);
- FAKETIME_SPAWN_NUMCALLS = atol(spawn_envvarbuf);
- }
- }
- spawn_initialized = 1;
- }
+ if (limited_faking) {
+ /* Check whether we actually should be faking the returned timestamp. */
+ struct timespec tmp_ts;
+ /* For debugging, output #seconds and #calls */
+ /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
+ timespecsub(tp, &ftpl_starttime, &tmp_ts);
+ 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;
+ /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu continues\n", (*time_tptr - ftpl_starttime), callcounter); */
- if (spawned == 0) { /* exec external command once only */
- if ((spawn_callcounter + 1) >= spawn_callcounter) spawn_callcounter++;
- if ((((*time_tptr - ftpl_starttime) == FAKETIME_SPAWN_SECONDS) || (spawn_callcounter == FAKETIME_SPAWN_NUMCALLS)) && (spawned == 0)) {
- spawned = 1;
- system(FAKETIME_SPAWN_TARGET);
- }
+ }
- }
+ if (spawnsupport) {
+ /* check whether we should spawn an external command */
+ if (spawned == 0) { /* exec external command once only */
+ struct timespec tmp_ts;
+ timespecsub(tp, &ftpl_starttime, &tmp_ts);
+ if (((tmp_ts.tv_sec == ft_spawn_secs) || (callcounter == ft_spawn_ncalls)) && (spawned == 0)) {
+ spawned = 1;
+ system(ft_spawn_target);
+ }
+ }
}
-#endif
-
if (last_data_fetch > 0) {
- if ((*time_tptr - last_data_fetch) > cache_duration) {
+ if ((tp->tv_sec - last_data_fetch) > cache_duration) {
cache_expired = 1;
}
else {
@@ -840,8 +735,11 @@ static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
#endif
if (cache_expired == 1) {
+ static char user_faked_time[BUFFERLEN]; /* changed to static for caching in v0.6 */
+ char filename[BUFSIZ], line[BUFFERLEN];
+ FILE *faketimerc;
- last_data_fetch = *time_tptr;
+ last_data_fetch = tp->tv_sec;
/* Can be enabled for testing ...
fprintf(stderr, "***************++ Cache expired ++**************\n");
@@ -851,11 +749,7 @@ static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
snprintf(user_faked_time, BUFFERLEN, "+0");
/* fake time supplied as environment variable? */
- if (getenv("FAKETIME") != NULL) {
- (void) strncpy(user_faked_time, getenv("FAKETIME"), BUFFERLEN-2);
- user_faked_time[BUFFERLEN-1] = 0;
- }
- else {
+ if (parse_config_file) {
/* 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,
@@ -874,128 +768,76 @@ static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
}
fclose(faketimerc);
}
+ parse_ft_string(user_faked_time);
} /* read fake time from file */
-
-
- user_faked_time_fmt = getenv("FAKETIME_FMT");
- if (user_faked_time_fmt == NULL)
- user_faked_time_fmt = "%Y-%m-%d %T";
-
} /* cache had expired */
-/*
- * This no longer appears to be necessary in Mac OS X 10.7 Lion
- */
-//#ifdef __APPLE__
-// SINGLE_IF(malloc_arena==0)
-// malloc_arena = 1;
-// return *time_tptr;
-// END_SINGLE_IF
-//#endif
-
/* check whether the user gave us an absolute time to fake */
- switch (user_faked_time[0]) {
-
- default: /* Try and interpret this as a specified time */
- user_faked_time_tm.tm_isdst = -1;
- (void) strptime(user_faked_time, user_faked_time_fmt, &user_faked_time_tm);
-
- user_faked_time_time_t = mktime(&user_faked_time_tm);
- if (user_faked_time_time_t != -1) {
- if (time_tptr != NULL) /* sanity check */
- *time_tptr = user_faked_time_time_t;
- }
- break;
-
- case '+':
- case '-': /* User-specified offset */
- /* fractional time offsets contributed by Karl Chen in v0.8 */
- frac_user_offset = atof(user_faked_time);
-
- /* offset is in seconds by default, but the string may contain
- * multipliers...
- */
- if (strchr(user_faked_time, 'm') != NULL) frac_user_offset *= 60;
- else if (strchr(user_faked_time, 'h') != NULL) frac_user_offset *= 60 * 60;
- else if (strchr(user_faked_time, 'd') != NULL) frac_user_offset *= 60 * 60 * 24;
- else if (strchr(user_faked_time, 'y') != NULL) frac_user_offset *= 60 * 60 * 24 * 365;
-
- /* Speed-up / slow-down contributed by Karl Chen in v0.8 */
- if (strchr(user_faked_time, 'x') != NULL) {
- const double rate = atof(strchr(user_faked_time, 'x')+1);
- const long tdiff = (long long) *time_tptr - (long long)ftpl_starttime;
- const double timeadj = tdiff * (rate - 1.0);
- *time_tptr += (long) timeadj;
- } else if (NULL != (tmp_time_fmt = strchr(user_faked_time, 'i'))) {
- /* increment time with every time() call*/
- *time_tptr += next_time(atof(tmp_time_fmt + 1));
- }
-
- *time_tptr += (long) frac_user_offset;
-
- break;
-
- /* Contributed by David North, TDI in version 0.7 */
- case '@': /* Specific time, but clock along relative to that starttime */
- user_faked_time_tm.tm_isdst = -1;
- (void) strptime(&user_faked_time[1], user_faked_time_fmt, &user_faked_time_tm);
-
- user_faked_time_time_t = mktime(&user_faked_time_tm);
- if (user_faked_time_time_t != -1) {
- user_offset = - ( (long long int)ftpl_starttime - (long long int)user_faked_time_time_t );
-
- /* Speed-up / slow-down contributed by Karl Chen in v0.8 */
- if (strchr(user_faked_time, 'x') != NULL) {
- const double rate = atof(strchr(user_faked_time, 'x')+1);
- const long tdiff = (long long) *time_tptr - (long long)ftpl_starttime;
- const double timeadj = tdiff * (rate - 1.0);
- *time_tptr += (long) timeadj;
- } else if (NULL != (tmp_time_fmt = strchr(user_faked_time, 'i'))) {
- /* increment time with every time() call*/
- *time_tptr += next_time(atof(tmp_time_fmt + 1));
- }
-
- *time_tptr += user_offset;
- }
- break;
+ switch (ft_mode) {
+ case FT_FREEZE: /* a specified time */
+ if (user_faked_time_set) {
+ *tp = user_faked_time_timespec;
+ }
+ break;
+
+ case FT_START_AT: /* User-specified offset */
+ /* Speed-up / slow-down contributed by Karl Chen in v0.8 */
+ if (user_rate_set) {
+ struct timespec tdiff, timeadj;
+ timespecsub(tp, &ftpl_starttime, &tdiff);
+ timespecmul(&tdiff, user_rate, &timeadj);
+ timespecadd(&user_faked_time_timespec, &timeadj, tp);
+ } else if (user_per_tick_inc_set) {
+ /* increment time with every time() call*/
+ next_time(tp, &user_per_tick_inc);
+ }
+ break;
+ default:
+ return -1;
}
#ifdef PTHREAD_SINGLETHREADED_TIME
pthread_cleanup_pop(1);
#endif
-
- /* pass the possibly modified time back to caller */
- return *time_tptr;
+ return 0;
}
-int fake_ftime(struct timeb *tp) {
- time_t temp_tt = tp->time;
- tp->time = fake_time(&temp_tt);
+time_t fake_time(time_t *time_tptr) {
+ struct timespec tp;
- return 0; /* always returns 0, see manpage */
+ tp.tv_sec = *time_tptr;
+ tp.tv_nsec = 0;
+ (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
+ *time_tptr = tp.tv_sec;
+ return *time_tptr;
}
-int fake_gettimeofday(struct timeval *tv, void *tz) {
- time_t temp_tt = tv->tv_sec;
+int fake_ftime(struct timeb *tp) {
+ struct timespec ts;
+ int ret;
+ ts.tv_sec = tp->time;
+ ts.tv_nsec =tp->millitm * 1000000;
- tv->tv_sec = fake_time(&temp_tt);
+ ret = fake_clock_gettime(CLOCK_REALTIME, &ts);
+ tp->time = ts.tv_sec;
+ tp->millitm =ts.tv_nsec / 1000000;
- return 0;
+ return ret;
}
-#ifdef POSIX_REALTIME
-int fake_clock_gettime(clockid_t clk_id, struct timespec *tp) {
- time_t temp_tt = tp->tv_sec;
+int fake_gettimeofday(struct timeval *tv, void *tz) {
+ struct timespec ts;
+ int ret;
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec =tv->tv_usec * 1000;
- /* Fake only if the call is realtime clock related */
- if (clk_id == CLOCK_REALTIME) {
- tp->tv_sec = fake_time(&temp_tt);
- }
+ ret = fake_clock_gettime(CLOCK_REALTIME, &ts);
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec =ts.tv_nsec / 1000;
- return 0;
+ return ret;
}
-#endif
/*
* This causes serious issues in Mac OS X 10.7 Lion and is disabled there
@@ -1007,11 +849,9 @@ int __gettimeofday(struct timeval *tv, void *tz) {
return gettimeofday(tv, tz);
}
-#ifdef POSIX_REALTIME
int __clock_gettime(clockid_t clk_id, struct timespec *tp) {
return clock_gettime(clk_id, tp);
}
-#endif
int __ftime(struct timeb *tp) {
return ftime(tp);
diff --git a/src/time_ops.h b/src/time_ops.h
new file mode 100644
index 0000000..a12ead0
--- /dev/null
+++ b/src/time_ops.h
@@ -0,0 +1,99 @@
+/*
+ * Time operation macros based on sys/time.h
+ * Copyright 2013 Balint Reczey <balint@balintreczey.hu>
+ *
+ * This file is part of the FakeTime Preload Library.
+ *
+ * The FakeTime Preload Library 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.
+ *
+ * The FakeTime Preload Library 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 FakeTime Preload Library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TIME_OPS_H
+#define TIME_OPS_H
+#include <time.h>
+
+#define SEC_TO_uSEC 1000000
+#define SEC_TO_nSEC 1000000000
+
+/* Convenience macros for operations on timevals.
+ 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) : \
+ ((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; \
+ } \
+ } 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; \
+ } \
+ } 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; \
+ } \
+ } while (0)
+
+/* ops for microsecs */
+#ifndef timerisset
+#define timerisset(tvp) timerisset2(tvp,u)
+#endif
+#ifndef timerclear
+#define timerclear(tvp) timerclear2(tvp, u)
+#endif
+#ifndef timercmp
+#define timercmp(a, b, CMP) timercmp2(a, b, CMP, u)
+#endif
+#ifndef timeradd
+#define timeradd(a, b, result) timeradd2(a, b, result, u)
+#endif
+#ifndef timersub
+#define timersub(a, b, result) timersub2(a, b, result, u)
+#endif
+#ifndef timersub
+#define timermul(a, c, result) timermul2(a, c, result, u)
+#endif
+
+/* ops for nanosecs */
+#define timespecisset(tvp) timerisset2(tvp,n)
+#define timespecclear(tvp) timerclear2(tvp, n)
+#define timespeccmp(a, b, CMP) timercmp2(a, b, CMP, n)
+#define timespecadd(a, b, result) timeradd2(a, b, result, n)
+#define timespecsub(a, b, result) timersub2(a, b, result, n)
+#define timespecmul(a, c, result) timermul2(a, c, result, n)
+
+#endif