Programs and patches
libfaketime
A small library for presenting programs with an artificial system time.
Last updated · 7 April 2006
Library for subverting current date and time to a given application.
Preload this library to a program that calls time(2) or gettimeofday(2) functions if you need to make it think that it's not the current date but a different one.
Usage
Set one of these environment variables:
- FAKE_TIME_START=<sec-since-epoch>
- First call to time() or gettimeofday() will return the given <sec-since-epoch>. Subsequent calls will return a time with appropriate correction, i.e. if the second call to time() occurs five seconds after the first one, it will return <sec-since-epoch>+5.
- FAKE_TIME_OFFSET=<offset_sec_from_now>
- Each call to time() or gettimeofday() returns current time + <offset_sec_from_now>.
If both variables are set, then FAKE_TIME_OFFSET has a precedence.
To convert a given time to <sec-since-epoch> use:
$ date -d "2000-01-01 12:13:14" +%s
946725194
Examples
$ date
Wed Sep 24 14:41:20 CEST 2003
$ FAKE_TIME_OFFSET=-86400 LD_PRELOAD=./libfaketime.so date
Tue Sep 23 14:41:20 CEST 2003
$ FAKE_TIME_START=946725194 LD_PRELOAD=./libfaketime.so date
Sat Jan 1 12:13:14 CET 2000
Note
On ELF systems it is possible to let the library print a help
when invoked directly from the command line, i.e.
$ ./libfaketime.so libfaketime.so - Library for subverting current time. [...]
For this to work you must know your runtime linker at the time of compilation. The approach used in my Makefile is to build a dummy program, extract its .interp section to a separate file and finally put the content of this file to ld-so.h header.
This was tested on different linux architectures with different names of runtime linkers, e.g. /lib/ld-linux.so.2 on i386, /lib64/ld-linux-x86-64.so.2 on AMD64, /lib/ld.so.1 on S390, /lib/lib64.so.1 on S390x, etc.
Please see the Makefile below for details on how is ld-so.h generated.
Source
- The main source itself:
- Read faketime.c below · Download raw faketime.c
- Makefile for successfull build:
- Read Makefile below · Download raw Makefile
Credits
Thanks to Andreas Thienemann for clock_gettime(3) support
faketime.c source
/*
* faketime.c - Main part of libfaketime.so
*
* Michal Ludvig <michal@logix.cz>, (c) 2003
* /devel/faketime
*
* Preload to a program calling time(2) or gettimeofday(2)
* functions if you need to make it think that it's not
* the current date but something different.
*
* Run ./libfaketime.so to get a more detailed help or
* check __faketime_main() function below.
*
*/
#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"
/* On ELF systems the library can print a short help
* is invoked directly. */
#define HAVE_ELF
/* Here we store pointers to orginal time() and gettimeofday()
* functions. */
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;
/* Look for and store pointers to orginal time() and gettimeofday()
* functions. */
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;
}
/* Look for FAKE_TIME_OFFSET or FAKE_TIME_START environment
* variables. */
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;
}
/* Here we go - wrapper for time(2). */
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);
}
/* Wrapper for gettimeofday (2). */
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;
}
/* Wrapper for clock_gettime(3). */
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
/* This is an entrypoint if the library is invoked as a program, i.e.
* $ ./libfaketime.so
* In this case it prints a short help.
* NOTE: This is only usable on ELF systems! */
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"
" /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 /* HAVE_ELF */
Makefile source
CC=gcc
CFLAGS=-Wall -g
LIBFAKETIME=libfaketime.so
%.so: %.c
$(CC) -fPIC $(CFLAGS) -c -o $@ $<
all: timetest $(LIBFAKETIME)
timetest: timetest.o
$(CC) $(CFLAGS) -o $@ $<
ld-so.h: dummy.c
$(CC) -o tmp-dummy dummy.c
objcopy --only-section .interp --output-target binary tmp-dummy tmp-dummy.interp
awk 'BEGIN{printf("#ifdef LD_SO\n#undef LD_SO\n#endif\n\n");} NR==1{gsub (/\000/, "", $$1); printf("#define LD_SO \"%s\"\n", $$1);}' tmp-dummy.interp > ld-so.h
rm -f tmp-dummy*
$(LIBFAKETIME): faketime.so
$(CC) -shared -o $@ -Wl,-soname,$(LIBFAKETIME) $< -ldl -e __faketime_main
faketime.so: faketime.c ld-so.h
test: all
@echo ==== Without preloaded library...
./timetest
@echo
@echo ==== Set the date to yesterday...
FAKE_TIME_OFFSET=-86400 LD_PRELOAD=./libfaketime.so ./timetest
@echo
@echo ==== Set the date to 2000/01/01 12:13:14...
FAKE_TIME_START=946725194 LD_PRELOAD=./libfaketime.so ./timetest
clean:
-rm -f *.o *.so core timetest $(LIBFAKETIME) ld-so.h tmp-dummy*