#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <dlfcn.h>
#include "ld-so.h"
#define HAVE_ELF
time_t (*orig_time) (time_t *t);
int (*orig_gettimeofday) (struct timeval *tv, struct timezone *tz);
int (*orig_clock_gettime) (clockid_t clk_id, struct timespec *tp);
time_t correction = 0;
int need_parse_env = 1;
static int
open_shlib (void)
{
orig_time = dlsym (RTLD_NEXT, "time");
if (dlerror() != NULL)
return -1;
orig_gettimeofday = dlsym (RTLD_NEXT, "gettimeofday");
if (dlerror() != NULL)
return -1;
orig_clock_gettime = dlsym (RTLD_NEXT, "clock_gettime");
if (dlerror() != NULL)
return -1;
return 0;
}
static void
parse_env (time_t curr_time)
{
char *fake_env = NULL;
time_t fake_long = 0;
need_parse_env = 0;
fake_env = getenv ("FAKE_TIME_OFFSET");
if (fake_env)
{
correction = -atoll (fake_env);
return;
}
fake_env = getenv ("FAKE_TIME_START");
if (fake_env)
fake_long = atoll (fake_env);
if (fake_long)
correction = curr_time - fake_long;
}
extern time_t
time (time_t *t)
{
time_t curr_time;
if (! orig_time && open_shlib () != 0)
return -1;
curr_time = (*orig_time) (t);
if (need_parse_env)
parse_env (curr_time);
if (t)
*t -= correction;
return (curr_time - correction);
}
extern int
gettimeofday (struct timeval *tv, struct timezone *tz)
{
int ret;
if (! orig_gettimeofday && open_shlib () != 0)
return -1;
ret = (*orig_gettimeofday) (tv, tz);
if (ret == 0 && tv)
{
if (need_parse_env)
parse_env (tv->tv_sec);
tv->tv_sec -= correction;
}
return ret;
}
extern int
clock_gettime(clockid_t clk_id, struct timespec *tp)
{
int ret;
if (! orig_clock_gettime && open_shlib () != 0)
return -1;
ret = (*orig_clock_gettime) (clk_id, tp);
if (ret == 0 && tp)
{
if (need_parse_env)
parse_env (tp->tv_sec);
tp->tv_sec -= correction;
}
return ret;
}
#ifdef HAVE_ELF
extern void __faketime_main (void) __attribute__ ((noreturn));
void
__faketime_main (void)
{
char *banner = ""
" libfaketime.so - Library for subverting current time.\n"
"\n"
" Michal Ludvig <michal@logix.cz>, (c) 2003\n"
" http://www.logix.cz/michal/devel/faketime\n"
" \n"
" Preload to a program calling time(2), gettimeofday(2) \n"
" or clock_gettime(3) functions if you need to make it think \n"
" that it's not the current date but a different one.\n"
"\n"
" Usage:\n"
" \n"
" Set one of these environment variables:\n"
" \n"
" FAKE_TIME_START=<sec-since-epoch>\n"
" First call to time() or gettimeofday() will return\n"
" the given <sec-since-epoch>. Subsequent calls will\n"
" return a time with appropriate correction, i.e. if\n"
" the second call to time() occurs five seconds after\n"
" the first one, it will return <sec-since-epoch>+5.\n"
" \n"
" FAKE_TIME_OFFSET=<offset_sec_from_now>\n"
" Each call to time() or gettimeofday() returns \n"
" current time + <offset_sec_from_now>. \n"
"\n"
" If both variables are set, FAKE_TIME_OFFSET has a precedence.\n"
"\n"
" To convert a given time to <sec-since-epoch> use:\n"
" $ date -d \"2000-01-01 12:13:14\" +%s\n"
" 946725194\n"
"\n"
" Example:\n"
"\n"
" $ date\n"
" Wed Sep 24 14:41:20 CEST 2003\n"
" \n"
" $ FAKE_TIME_OFFSET=-86400 LD_PRELOAD=./libfaketime.so date\n"
" Tue Sep 23 14:41:20 CEST 2003\n"
" \n"
" $ FAKE_TIME_START=946725194 LD_PRELOAD=./libfaketime.so date\n"
" Sat Jan 1 12:13:14 CET 2000\n"
"\n";
printf ("%s", banner);
_exit (0);
}
const char __invoke_dynamic_linker__[] __attribute__ ((section (".interp")))
= LD_SO;
#endif