diff options
author | Balint Reczey <balint@balintreczey.hu> | 2013-08-19 11:47:49 +0200 |
---|---|---|
committer | Balint Reczey <balint@balintreczey.hu> | 2013-08-19 13:26:17 +0200 |
commit | bfd4b9f5f39347f98fba32dd71a39627bce8ff95 (patch) | |
tree | c4f7fdc97db2a25999b04a084af45f6b17fc5729 /src/faketime.c | |
parent | ae45c5c48ee307faf3dc4b7a55c7f2db4809c0ab (diff) | |
download | libfaketime-bfd4b9f5f39347f98fba32dd71a39627bce8ff95.tar.gz |
Rewrite faketime shell script in C
Diffstat (limited to 'src/faketime.c')
-rw-r--r-- | src/faketime.c | 1089 |
1 files changed, 148 insertions, 941 deletions
diff --git a/src/faketime.c b/src/faketime.c index c374a2a..3f6fdb2 100644 --- a/src/faketime.c +++ b/src/faketime.c @@ -1,958 +1,165 @@ -/* - * This file is part of the FakeTime Preload Library, version 0.8. - * - * 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. +/** + * Faketime binary spawning commands with FTPL (faketime preload library). * - * 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. + * TODO: fill propery formated credits and license + * Converted from shell script with the following credits and comments: * - * 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 - */ + * Thanks to Daniel Kahn Gillmor for improvement suggestions. + + * It allows you to modify the date and time a program sees when using + * system library calls such as time() and fstat(). + * This wrapper exposes only a small subset of the FTPL functionality. + * Please see FTPL's README file for more details -#define _GNU_SOURCE /* required to get RTLD_NEXT defined */ -#define _XOPEN_SOURCE /* required to get strptime() defined */ + * Acknowledgment: Parts of the functionality of this wrapper have been + * inspired by Matthias Urlichs' datefudge 1.14. + + * Compile time configuration: Path where the libfaketime libraries can be found + * on Linux/UNIX . */ #include <stdio.h> +#include <unistd.h> #include <stdlib.h> -#include <time.h> +#include <stdbool.h> #include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/wait.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> -#include <dlfcn.h> - -#define BUFFERLEN 256 - -/* 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: - * - time() - * - ftime() - * - gettimeofday() - * - clock_gettime() - * - * Since version 0.7, if FAKE_INTERNAL_CALLS is defined, also calls to - * __time(), __ftime(), __gettimeofday(), and __clock_gettime() will be - * intercepted. - * - * Thanks to a contribution by Philipp Hachtmann, the following - * system calls will also be time-adjusted depending on the compile - * switches used + any environmental variables present. - * - * - stat() - * - fstat() - * - lstat() - * - the 64-bit versions of those three - * - */ - -#ifdef FAKE_STAT - -#ifndef NO_ATFILE -#ifndef _ATFILE_SOURCE -#define _ATFILE_SOURCE -#endif -#include <fcntl.h> /* Definition of AT_* constants */ -#endif - -#include <sys/stat.h> - -static int fake_stat_disabled = 0; - -/** - * When advancing time linearly with each time(), etc. call, the calls are - * counted here */ -static long int ticks = 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 */ -#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); - if (result == -1) { - return -1; - } - - if (buf != NULL) { - if (!fake_stat_disabled) { - buf->st_ctime = fake_time(&(buf->st_ctime)); - buf->st_atime = fake_time(&(buf->st_atime)); - buf->st_mtime = fake_time(&(buf->st_mtime)); - } - } - - return result; -} - -/* 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 */ -#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); - if (result == -1) { - return -1; - } - - if (buf != NULL) { - if (!fake_stat_disabled) { - buf->st_ctime = fake_time(&(buf->st_ctime)); - buf->st_atime = fake_time(&(buf->st_atime)); - buf->st_mtime = fake_time(&(buf->st_mtime)); - } - } - return result; -} - -/* 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 */ -#ifdef DEBUG - (void) fprintf(stderr, "faketime problem: original fstatat() not found.\n"); -#endif - return -1; /* propagate error to caller */ - } - - int result = real_fstatat(ver, fildes, filename, buf, flag); - if (result == -1) { - return -1; - } - - if (buf != NULL) { - if (!fake_stat_disabled) { - buf->st_ctime = fake_time(&(buf->st_ctime)); - buf->st_atime = fake_time(&(buf->st_atime)); - buf->st_mtime = fake_time(&(buf->st_mtime)); - } - } - return result; -} -#endif - -/* 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 */ -#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); - if (result == -1) { - return -1; - } - - if (buf != NULL) { - if (!fake_stat_disabled) { - buf->st_ctime = fake_time(&(buf->st_ctime)); - buf->st_atime = fake_time(&(buf->st_atime)); - buf->st_mtime = fake_time(&(buf->st_mtime)); - } - } - return result; -} - -/* 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 */ -#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); - if (result == -1) { - return -1; - } - - if (buf != NULL){ - if (!fake_stat_disabled) { - buf->st_ctime = fake_time(&(buf->st_ctime)); - buf->st_atime = fake_time(&(buf->st_atime)); - buf->st_mtime = fake_time(&(buf->st_mtime)); - } - } - return result; -} - -/* 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 */ -#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); - if (result == -1){ - return -1; - } - - if (buf != NULL){ - if (!fake_stat_disabled) { - buf->st_ctime = fake_time(&(buf->st_ctime)); - buf->st_atime = fake_time(&(buf->st_atime)); - buf->st_mtime = fake_time(&(buf->st_mtime)); - } - } - return result; -} - -/* 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 */ -#ifdef DEBUG - (void) fprintf(stderr, "faketime problem: original fstatat64() not found.\n"); -#endif - return -1; /* propagate error to caller */ - } - - int result = real_fstatat64(ver, fildes, filename, buf, flag); - if (result == -1){ - return -1; - } - - if (buf != NULL){ - if (!fake_stat_disabled) { - buf->st_ctime = fake_time(&(buf->st_ctime)); - buf->st_atime = fake_time(&(buf->st_atime)); - buf->st_mtime = fake_time(&(buf->st_mtime)); - } - } - return result; -} -#endif - -/* 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 */ -#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); - if (result == -1){ - return -1; - } - - if (buf != NULL){ - if (!fake_stat_disabled) { - buf->st_ctime = fake_time(&(buf->st_ctime)); - buf->st_atime = fake_time(&(buf->st_atime)); - buf->st_mtime = fake_time(&(buf->st_mtime)); - } - } - return result; -} -#endif - -/* - * On MacOS, time() internally uses gettimeofday. If we don't - * break the cycle by just calling it directly, we double-apply - * relative changes. - */ +const char version[] = "0.8"; #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; +static const char *date_cmd = "gdate"; #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"); */ - } - +static const char *date_cmd = "date"; +#endif + +void usage(const char *name) { + printf("\n"); + printf("Usage: %s [switches] <timestamp> <program with arguments>\n", name); + printf("\n"); + printf("This will run the specified 'program' with the given 'arguments'.\n"); + printf("The program will be tricked into seeing the given 'timestamp' as its starting date and time.\n"); + printf("The clock will continue to run from this timestamp. Please see the manpage (man faketime)\n"); + printf("for advanced options, such as stopping the wall clock and make it run faster or slower.\n"); + printf("\n"); + printf("The optional switches are:\n"); + printf(" -m : Use the multi-threaded version of libfaketime\n"); + printf(" -f : Use the advanced timestamp specification format (see manpage)\n"); + printf("\n"); + printf("Examples:\n"); + printf("%s 'last friday 5 pm' /bin/date\n", name); + printf("%s '2008-12-24 08:15:42' /bin/date\n", name); + printf("%s -f '+2,5y x10,0' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n", name); + printf("%s -f '+2,5y x0,50' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n", name); + printf("%s -f '+2,5y i2,0' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n", name); + printf("(Please note that it depends on your locale settings whether . or , has to be used for fractions)\n"); + printf("\n"); + +} + +int main (int argc, char **argv) +{ + int curr_opt = 1; + bool use_mt = false, use_direct = false; + int pfds[2]; + long offset; + + while(curr_opt < argc) { + if (0 == strcmp(argv[curr_opt], "-m")) { + use_mt = true; + curr_opt++; + continue; + } else if (0 == strcmp(argv[curr_opt], "-f")) { + use_direct = true; + curr_opt++; + continue; + } else if ((0 == strcmp(argv[curr_opt], "-v")) || + (0 == strcmp(argv[curr_opt], "--version"))) { + printf("\n%s: Version %s\n" + "For usage information please use '%s --help\n'.", + argv[0], version, argv[0]); + exit(EXIT_SUCCESS); + } else if ((0 == strcmp(argv[curr_opt], "-h")) || + (0 == strcmp(argv[curr_opt], "-?")) || + (0 == strcmp(argv[curr_opt], "--help"))) { + usage(argv[0]); + exit(EXIT_SUCCESS); + } else { + /* we parsed all options */ + break; + } + } + + /* we need at least a timestamp string and a command to run */ + if (argc - curr_opt < 2) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + if (!use_direct) { + // TODO get seconds + pipe(pfds); + pid_t pid; + int ret = EXIT_SUCCESS; + + if (0 == (pid = fork())) { + close(1); /* close normal stdout */ + dup(pfds[1]); /* make stdout same as pfds[1] */ + close(pfds[0]); /* we don't need this */ + if (EXIT_SUCCESS != execlp(date_cmd, date_cmd, "-d", argv[curr_opt], "+%s",(char *) NULL)) { + perror("Running (g)date failed"); + exit(EXIT_FAILURE); + } + } else { + char buf[256] = {0}; /* e will have way less than 256 digits */ + close(pfds[1]); /* we won't write to this */ + read(pfds[0], buf, 256); + waitpid(pid, &ret, 0); + if (ret != EXIT_SUCCESS) { + printf("Error: Timestamp to fake not recognized, please re-try with a " + "different timestamp.\n"); + exit(EXIT_FAILURE); + } + offset = atol(buf) - time(NULL); + ret = snprintf(buf, sizeof(buf), "%s%ld", (offset >= 0)?"+":"", offset); + setenv("FAKETIME", buf, true); + } + } else { + /* simply pass format string along */ + setenv("FAKETIME", argv[curr_opt], true); + } + + /* we just consumed the timestamp option */ + curr_opt++; + + { + char *ftpl_path; #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; + ftpl_path = PREFIX "/libfaketime.dylib.1"; + setenv("DYLD_INSERT_LIBRARIES", ftpl_path, true); + setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", true); #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; - if (time_tptr == NULL) { - time_tptr = &null_dummy; - /* (void) fprintf(stderr, "NULL pointer caught in time().\n"); */ - } - result = _ftpl_time(time_tptr); - if (result == ((time_t) -1)) return result; - - /* pass the real current time to our faking version, overwriting it */ - result = fake_time(time_tptr); - - /* return the result to the caller */ - return result; -} - - -int ftime(struct timeb *tp) { - static int (*real_ftime)(struct timeb *); - static int has_real_ftime = 0; - int result; - - /* sanity check */ - if (tp == NULL) - 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 */ -#ifdef DEBUG - (void) fprintf(stderr, "faketime problem: original ftime() not found.\n"); -#endif - tp = NULL; - return 0; /* propagate error to caller */ - } - - /* initialize our result with the real current time */ - result = (*real_ftime)(tp); - - /* pass the real current ftime to our faking version, overwriting it */ - result = fake_ftime(tp); - - /* return the result to the caller */ - return result; /* will always be 0 (see manpage) */ -} - -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; - } - - /* 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, tz); - if (result == -1) return result; /* original function failed */ - - /* 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; - int result; - - /* sanity check */ - if (tp == NULL) { - 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 */ -#ifdef DEBUG - (void) fprintf(stderr, "faketime problem: original clock_gettime() not found.\n"); -#endif - return -1; /* propagate error to caller */ - } - - /* initialize our result with the real current time */ - result = (*real_clock_gettime)(clk_id, tp); - if (result == -1) return result; /* original function failed */ - - /* pass the real current time to our faking version, overwriting it */ - result = fake_clock_gettime(clk_id, 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; - -void __attribute__ ((constructor)) ftpl_init(void) -{ - time_t temp_tt; - -#ifdef FAKE_STAT - if (getenv("NO_FAKE_STAT")!=NULL) { - fake_stat_disabled = 1; //Note that this is NOT re-checked - } -#endif - - ftpl_starttime = _ftpl_time(&temp_tt); -} - -static void remove_trailing_eols(char *line) -{ - char *endp = line + strlen(line); - /* - * erase the last char if it's a newline - * or carriage return, and back up. - * keep doing this, but don't back up - * past the beginning of the string. - */ -# define is_eolchar(c) ((c) == '\n' || (c) == '\r') - while (endp > line && is_eolchar(endp[-1])) - *--endp = '\0'; -} - - -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; - - /* 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 - -/* - * This no longer appears to be necessary in Mac OS X 10.7 Lion - */ -//#ifdef __APPLE__ -// static int malloc_arena = 0; -//#endif - -#ifdef PTHREAD_SINGLETHREADED_TIME -static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&time_mutex); - 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); */ - - } -#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 (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); - } - - } - + { + char *ld_preload_new, *ld_preload = getenv("LD_PRELOAD"); + size_t len; + if (use_mt) { + ftpl_path = PREFIX "/lib/faketime/libfaketimeMT.so.1"; + } else { + ftpl_path = PREFIX "/lib/faketime/libfaketime.so.1"; + } + len = (ld_preload)?strlen(ld_preload):0 + 2 + strlen(ftpl_path); + ld_preload_new = malloc(len); + snprintf(ld_preload_new, len ,"%s%s%s", (ld_preload)?ld_preload:"", + (ld_preload)?":":"", ftpl_path); + setenv("LD_PRELOAD", ld_preload_new, true); + free(ld_preload_new); } #endif - - - if (last_data_fetch > 0) { - if ((*time_tptr - last_data_fetch) > cache_duration) { - cache_expired = 1; - } - else { - cache_expired = 0; - } - } - -#ifdef NO_CACHING - cache_expired = 1; -#endif - - if (cache_expired == 1) { - - last_data_fetch = *time_tptr; - - /* Can be enabled for testing ... - fprintf(stderr, "***************++ Cache expired ++**************\n"); - */ - - /* initialize with default */ - 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 { - /* 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(filename, BUFSIZ, "%s/.faketimerc", getenv("HOME")); - if ((faketimerc = fopen(filename, "rt")) != NULL || - (faketimerc = fopen("/etc/faketimerc", "rt")) != NULL) { - 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); - } - } /* 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 = atof(tmp_time_fmt + 1) * ticks++; - } - - *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 = atof(tmp_time_fmt + 1) * ticks++; - } - - *time_tptr += user_offset; - } - break; - } - -#ifdef PTHREAD_SINGLETHREADED_TIME - pthread_cleanup_pop(1); -#endif - - /* pass the possibly modified time back to caller */ - return *time_tptr; -} - -int fake_ftime(struct timeb *tp) { - time_t temp_tt = tp->time; - - 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; - - 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 = tp->tv_sec; - - /* Fake only if the call is realtime clock related */ - if (clk_id == CLOCK_REALTIME) { - tp->tv_sec = fake_time(&temp_tt); - } - - return 0; -} -#endif - -/* - * This causes serious issues in Mac OS X 10.7 Lion and is disabled there - */ -#ifndef __APPLE__ -/* Added in v0.7 as suggested by Jamie Cameron, Google */ -#ifdef FAKE_INTERNAL_CALLS -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); -} - -time_t __time(time_t *time_tptr) { - return time(time_tptr); + } + if (EXIT_SUCCESS != execvp(argv[curr_opt], &argv[curr_opt])) { + perror("Running specified command failed"); + exit(EXIT_FAILURE); + } } -#endif -#endif - -/* eof */ |