FAKETIME.TXT

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 */

Download raw faketime.c ↓

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*

Download raw Makefile ↓

libfaketimeUTF-8 · LOGIX.CZ

Find in Logix

Search page titles and descriptions. Esc closes.

A few handy keys

A little Borland, a little early desktop, a corner of the web to call home.

Pick a directory from the menu or tree. Use Find when you know what you’re after.

Tab / Shift+Tab
Move between controls
↑ / ↓ in menus
Choose an entry
← / → in menus
Switch directories
/
Find a page
Esc
Close menu or dialog
F1
Open this help

Prefer a different atmosphere? View has blue, grey, and green palettes.

No commands to learn. Just follow your curiosity.