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.
This commit is contained in:
Derrick Brashear
2011-07-05 09:05:38 -04:00
parent ed25084970
commit eb59447a6d
4 changed files with 148 additions and 15 deletions

6
README
View File

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

View File

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

78
src/Makefile.MacOS Normal file
View File

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

View File

@@ -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:
@@ -375,6 +377,16 @@ 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
@@ -382,26 +394,54 @@ int __lxstat64 (int ver, const char *path, struct stat64 *buf){
* 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);