/*
* libyesterday.c
*
* Captures gettimeofday(), time() and clock_gettime() to simulate yesterday's date
*
* History:
* 01/11/2025 Creation.
*
* Documentation:
* https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/
*
* Usage examples:
* # load date program with day set to yesterday
* LD_PRELOAD=/path/to/libyesterday.so /bin/date
* # load date program with day set to a week ago
* LIBYESTERDAY=$((3600*24*7)) LD_PRELOAD=/path/to/libyesterday.so /bin/date
*
* Author: Dario Rodriguez antartica@whereismybit.com
* This program is licensed under the terms of the MIT/X license.
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
typedef time_t (*time_fn_type)(time_t *tloc);
typedef int (*gettimeofday_fn_type)(struct timeval *restrict tv, void *restrict tz);
typedef int (*clock_gettime_fn_type)(clockid_t clockid, struct timespec *tp);
static int
libyesterdaydata(time_fn_type *paramtime_fn, gettimeofday_fn_type *paramgettimeofday_fn, clock_gettime_fn_type *paramclock_gettime_fn)
{
static int init=0;
static int seconds=3600*24;
static time_fn_type realtimefn=(time_fn_type)NULL;
static gettimeofday_fn_type realgettimeofdayfn=(gettimeofday_fn_type)NULL;
static clock_gettime_fn_type realclock_gettimefn=(clock_gettime_fn_type)NULL;
if(init==0) {
char *ptr;
realtimefn = (time_fn_type)dlsym(RTLD_NEXT,"time");
realgettimeofdayfn = (gettimeofday_fn_type)dlsym(RTLD_NEXT,"gettimeofday");
realclock_gettimefn = (clock_gettime_fn_type)dlsym(RTLD_NEXT,"clock_gettime");
if((ptr=getenv("LIBYESTERDAY"))!=NULL)
seconds=atoi(ptr);
init=1;
}
if(paramtime_fn!=NULL)
*paramtime_fn=realtimefn;
if(paramgettimeofday_fn!=NULL)
*paramgettimeofday_fn=realgettimeofdayfn;
if(paramclock_gettime_fn!=NULL)
*paramclock_gettime_fn=realclock_gettimefn;
return(seconds);
}
extern time_t time(time_t *tloc)
{
time_fn_type realtimefn=(time_fn_type)NULL;
int seconds;
int res;
seconds=libyesterdaydata(&realtimefn,NULL,NULL);
res=realtimefn(NULL);
res-=seconds;
if(tloc!=NULL)
*tloc=res;
return(res);
}
extern int gettimeofday(struct timeval *restrict tv, void *restrict tz)
{
static gettimeofday_fn_type realgettimeofdayfn=(gettimeofday_fn_type)NULL;
int seconds;
int res;
seconds=libyesterdaydata(NULL,&realgettimeofdayfn,NULL);
res=realgettimeofdayfn(tv,tz);
tv->tv_sec-=seconds;
return(res);
}
extern int clock_gettime(clockid_t clockid, struct timespec *tp)
{
static clock_gettime_fn_type realclock_gettimefn=(clock_gettime_fn_type)NULL;
int seconds;
int res;
seconds=libyesterdaydata(NULL,NULL,&realclock_gettimefn);
res=realclock_gettimefn(clockid,tp);
tp->tv_sec-=seconds;
return(res);
}