diff options
author | Derrick Brashear <shadow@dementia.org> | 2011-07-05 09:05:38 -0400 |
---|---|---|
committer | Derrick Brashear <shadow@dementia.org> | 2011-07-05 09:05:38 -0400 |
commit | eb59447a6d41f03f9f3bd97876a766f9164c5993 (patch) | |
tree | ad02fe9a74f014f57411fc1f6b8c9499630ab59a | |
parent | ed250849700b77d01b579fcbf58be6f129f4988b (diff) | |
download | faketime-ng-eb59447a6d41f03f9f3bd97876a766f9164c5993.tar.gz |
libfaketime macos port
port libfaketime to macos and dyld.
1) _ftpl_time calls gettimeofday since real time() does so. needed
to avoid double adjustment.
2) reduce call stack: use time tptr and call fake_time instead of
calling time for faking other time calls.
3) provide MacOS makefile and README notes.
4) make posix realtime calls under ifdef; define for base port but not
MacOS.
-rw-r--r-- | README | 6 | ||||
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/Makefile.MacOS | 78 | ||||
-rw-r--r-- | src/faketime.c | 77 |
4 files changed, 148 insertions, 15 deletions
@@ -96,6 +96,12 @@ 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 MacOS, it is necessary to compile differently, due to the different +behavior dyld has. Use the Makefile.MacOS provided to compile +libfaketime.dylib.1. Additionally, instead of using LD_PRELOAD, +the variable DYLD_INSERT_LIBRARIES should be set to the path to +libfaketime.dylib.1, and the variable DYLD_FORCE_FLAT_NAMESPACE should be +set (to anything). 4. Usage -------- diff --git a/src/Makefile b/src/Makefile index d61ebfa..702fc93 100644 --- a/src/Makefile +++ b/src/Makefile @@ -45,7 +45,7 @@ INSTALL = install PREFIX = /usr/local -CFLAGS = -std=gnu99 -Wall -DFAKE_STAT -DFAKE_INTERNAL_CALLS -fPIC +CFLAGS = -std=gnu99 -Wall -DFAKE_STAT -DFAKE_INTERNAL_CALLS -fPIC -DPOSIX_REALTIME LDFLAGS = -shared -ldl -lm -lpthread SRC = faketime.c diff --git a/src/Makefile.MacOS b/src/Makefile.MacOS new file mode 100644 index 0000000..b42f13a --- /dev/null +++ b/src/Makefile.MacOS @@ -0,0 +1,78 @@ +# +# Notes: +# +# * Compilation Defines: +# +# FAKE_STAT +# - Enables time faking also for files' timestamps. +# +# NO_ATFILE +# - Disables support for the fstatat() group of functions +# +# 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 +# without this, but the performance impact may require you to +# try it unsynchronized. +# +# FAKE_INTERNAL_CALLS +# - Also intercept libc internal __functions, e.g. not just time(), +# but also __time(). Enhances compatibility with applications +# that make use of low-level system calls, such as Java Virtual +# Machines. +# +# 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 +# +# * Compilation switch change: previous versions compiled using '-nostartfiles' +# This is no longer the case since there is a 'startup' constructor for the library +# which is used to activate the start-at times when specified. This also initializes +# the dynamic disabling of the FAKE_STAT calls. +# + +CC = gcc +INSTALL = install + +PREFIX = /usr/local + +CFLAGS = -dynamiclib -DFAKE_INTERNAL_CALLS + +SRC = faketime.c + +SONAME = 1 +LIBS = libfaketime.dylib.${SONAME} + +all: ${LIBS} + +libfaketime.dylib.${SONAME}: ${SRC} + ${CC} -o $@ ${CFLAGS} $< + +clean: + @rm -f ${OBJ} ${LIBS} + +distclean: clean + @echo + +install: ${LIBS} + @echo + @echo "Copying the faketime libraries to ${DESTDIR}${PREFIX}/lib/faketime and the faketime wrapper script to ${DESTDIR}${PREFIX}/bin ..." + $(INSTALL) -dm0755 "${DESTDIR}${PREFIX}/lib/faketime/" + $(INSTALL) -m0644 ${LIBS} "${DESTDIR}${PREFIX}/lib/faketime/" + $(INSTALL) -Dm0755 faketime "${DESTDIR}${PREFIX}/bin/faketime" + +uninstall: + for f in ${LIBS}; do rm -f "${DESTDIR}${PREFIX}/lib/faketime/$$f"; done + rmdir "${DESTDIR}${PREFIX}/lib/faketime" + rm -f "${DESTDIR}${PREFIX}/bin/faketime" + +.PHONY: all clean distclean install uninstall diff --git a/src/faketime.c b/src/faketime.c index 43a9d83..1a961a1 100644 --- a/src/faketime.c +++ b/src/faketime.c @@ -60,7 +60,9 @@ static pthread_mutex_t once_mutex=PTHREAD_MUTEX_INITIALIZER; 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: @@ -376,32 +378,70 @@ 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; @@ -415,9 +455,10 @@ static time_t _ftpl_time(time_t *time_tptr) { *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; } @@ -477,10 +518,12 @@ 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 */ if (tv == NULL) { return -1; @@ -509,11 +552,12 @@ int gettimeofday(struct timeval *tv, void *tz) { /* pass the real current time to our faking version, overwriting it */ result = fake_gettimeofday(tv, tz); - + /* return the result to the caller */ 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; @@ -551,6 +595,7 @@ 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 @@ -724,31 +769,33 @@ static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER; } int fake_ftime(struct timeb *tp) { - time_t temp_tt; + time_t temp_tt = tp->time; - tp->time = time(&temp_tt); + tp->time = fake_time(&temp_tt); return 0; /* always returns 0, see manpage */ } int fake_gettimeofday(struct timeval *tv, void *tz) { - time_t temp_tt; - - tv->tv_sec = time(&temp_tt); + time_t temp_tt = tv->tv_sec; + + tv->tv_sec = fake_time(&temp_tt); return 0; } +#ifdef POSIX_REALTIME int fake_clock_gettime(clockid_t clk_id, struct timespec *tp) { - time_t temp_tt; + time_t temp_tt = tp->tv_sec; /* Fake only if the call is realtime clock related */ if (clk_id == CLOCK_REALTIME) { - tp->tv_sec = time(&temp_tt); + tp->tv_sec = fake_time(&temp_tt); } return 0; } +#endif /* Added in v0.7 as suggested by Jamie Cameron, Google */ #ifdef FAKE_INTERNAL_CALLS @@ -756,9 +803,11 @@ 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); |