From 95b70c7acca97fff3116b4bbe0c4ff27717707bc Mon Sep 17 00:00:00 2001 From: Julien Gilli Date: Tue, 5 Aug 2014 16:43:34 -0700 Subject: [PATCH 1/6] Make libfaketime build, run and pass tests on SmartOS. Since SmartOS is close to SunOS, it's possible that these changes make libfaketime build and run on other SunOS-like platforms. These changes were tested on MacOS X and Ubuntu 12.04, and no regression appeared during testing. --- src/Makefile | 12 +++++++++++- src/faketime.c | 13 +++++++++++-- src/libfaketime.c | 10 +++++++++- src/sunos_endian.h | 12 ++++++++++++ test/functests/common.inc | 10 ++++++++++ 5 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 src/sunos_endian.h diff --git a/src/Makefile b/src/Makefile index 51634b0..a4d9ed6 100644 --- a/src/Makefile +++ b/src/Makefile @@ -66,10 +66,20 @@ INSTALL ?= install PREFIX ?= /usr/local LIBDIRNAME ?= /lib/faketime +PLATFORM ?=$(shell uname) CFLAGS += -std=gnu99 -Wall -Wextra -Werror -DFAKE_STAT -DFAKE_SLEEP -DFAKE_TIMERS -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"' -DLIBDIRNAME='"'$(LIBDIRNAME)'"' +ifeq ($(PLATFORM),SunOS) +CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 +endif + LIB_LDFLAGS += -shared -LDFLAGS += -Wl,--version-script=libfaketime.map -lpthread + +LDFLAGS += -lpthread +ifneq ($(PLATFORM),SunOS) +LDFLAGS += -Wl,--version-script=libfaketime.map +endif + LDADD += -ldl -lm -lrt BIN_LDFLAGS += -lrt diff --git a/src/faketime.c b/src/faketime.c index 7598145..95440a1 100644 --- a/src/faketime.c +++ b/src/faketime.c @@ -208,8 +208,15 @@ int main (int argc, char **argv) struct ft_shared_s *ft_shared; char shared_objs[PATH_BUFSIZE]; - snprintf(sem_name, PATH_BUFSIZE -1 ,"/faketime_sem_%d", getpid()); - snprintf(shm_name, PATH_BUFSIZE -1 ,"/faketime_shm_%d", getpid()); + /* + * Casting of getpid() return value to long needed to make GCC on SmartOS + * happy, since getpid's return value's type on SmartOS is long. Since + * getpid's return value's type is int on most other systems, and that + * sizeof(long) always >= sizeof(int), this works on all platforms without + * the need for crazy #ifdefs. + */ + snprintf(sem_name, PATH_BUFSIZE -1 ,"/faketime_sem_%ld", (long)getpid()); + snprintf(shm_name, PATH_BUFSIZE -1 ,"/faketime_shm_%ld", (long)getpid()); if (SEM_FAILED == (sem = sem_open(sem_name, O_CREAT|O_EXCL, S_IWUSR|S_IRUSR, 1))) { @@ -351,6 +358,8 @@ int main (int argc, char **argv) } exit(WEXITSTATUS(ret)); } + + return EXIT_SUCCESS; } /* diff --git a/src/libfaketime.c b/src/libfaketime.c index 17bef75..66b3a10 100644 --- a/src/libfaketime.c +++ b/src/libfaketime.c @@ -22,7 +22,6 @@ */ #define _GNU_SOURCE /* required to get RTLD_NEXT defined */ -#define _XOPEN_SOURCE /* required to get strptime() defined */ #include #include @@ -57,7 +56,11 @@ #ifndef __APPLE__ extern char *__progname; +#ifdef __sun +#include "sunos_endian.h" +#else #include +#endif #else /* endianness related macros */ #define htobe64(x) OSSwapHostToBigInt64(x) @@ -1437,6 +1440,10 @@ void __attribute__ ((constructor)) ftpl_init(void) real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime"); } #ifdef FAKE_TIMERS +#if defined(__sun) + real_timer_gettime_233 = dlsym(RTLD_NEXT, "timer_gettime"); + real_timer_settime_233 = dlsym(RTLD_NEXT, "timer_settime"); +#else real_timer_settime_22 = dlvsym(RTLD_NEXT, "timer_settime","GLIBC_2.2"); real_timer_settime_233 = dlvsym(RTLD_NEXT, "timer_settime","GLIBC_2.3.3"); if (NULL == real_timer_settime_233) @@ -1450,6 +1457,7 @@ void __attribute__ ((constructor)) ftpl_init(void) real_timer_gettime_233 = dlsym(RTLD_NEXT, "timer_gettime"); } #endif +#endif #endif ft_shm_init(); diff --git a/src/sunos_endian.h b/src/sunos_endian.h new file mode 100644 index 0000000..b15996a --- /dev/null +++ b/src/sunos_endian.h @@ -0,0 +1,12 @@ + +#ifndef SUN_OS_ENDIAN_H +#define SUN_OS_ENDIAN_H + +#include + +#define htobe64(x) BE_64(x) +#define be64toh(x) BE_64(x) +#define htole64(x) LE_64(x) +#define le64toh(x) LE_64(x) + +#endif /* SUN_OS_ENDIAN_H */ \ No newline at end of file diff --git a/test/functests/common.inc b/test/functests/common.inc index e1cd37c..d184ae2 100644 --- a/test/functests/common.inc +++ b/test/functests/common.inc @@ -9,6 +9,7 @@ platform() *Darwin*) echo "mac" ;; *Linux*) echo "linuxlike" ;; GNU|GNU/kFreeBSD) echo "linuxlike" ;; + *SunOS*) echo "sunos" ;; *) echo 1>&2 unsupported platform, uname=\"$out\" ;; esac } @@ -25,6 +26,15 @@ mac_fakecmd() "$@" } +sunos_fakecmd() +{ + typeset timestring="$1"; shift + typeset fakelib=../src/libfaketime.so.1 + export LD_PRELOAD=$fakelib + FAKETIME="$timestring" \ + "$@" +} + # run faked command on linuxlike OS linuxlike_fakecmd() { From cae9387908c7cd7ed1c7634ddb6fc72ed370261e Mon Sep 17 00:00:00 2001 From: Julien Gilli Date: Sun, 17 Aug 2014 22:17:23 -0700 Subject: [PATCH 2/6] docs: add --exclude-monotonic to man page. This was missing from PR #49. --- man/faketime.1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/man/faketime.1 b/man/faketime.1 index d00d80b..044da72 100644 --- a/man/faketime.1 +++ b/man/faketime.1 @@ -25,6 +25,9 @@ use the multi-threading variant of libfaketime. .TP \fB\-f\fR use the advanced timestamp specification format. +.TP +\fB\--exclude-monotonic\fR +Do not fake time when the program makes a call to clock_gettime with a CLOCK_MONOTONIC clock. .SH EXAMPLES .nf From cac3dc732a4e2be0f3c1e84ed145a57d204e6eff Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Tue, 26 Aug 2014 00:18:02 -0400 Subject: [PATCH 3/6] Add support to fake sem_timedwait Signed-off-by: Jon Ringle --- src/libfaketime.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/libfaketime.c b/src/libfaketime.c index 66b3a10..da3e077 100644 --- a/src/libfaketime.c +++ b/src/libfaketime.c @@ -148,6 +148,7 @@ static unsigned int (*real_sleep) (unsigned int seconds); static unsigned int (*real_alarm) (unsigned int seconds); static int (*real_poll) (struct pollfd *, nfds_t, int); static int (*real_ppoll) (struct pollfd *, nfds_t, const struct timespec *, const sigset_t *); +static int (*real_sem_timedwait) (sem_t*, const struct timespec*); #endif #ifdef __APPLE__ static int (*real_clock_get_time) (clock_serv_t clock_serv, mach_timespec_t *cur_timeclockid_t); @@ -929,6 +930,52 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) DONT_FAKE_TIME(ret = (*real_poll)(fds, nfds, timeout_real)); return ret; } + +int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout) +{ + int result; + struct timespec real_abs_timeout, *real_abs_timeout_pt; + + /* sanity check */ + if (abs_timeout == NULL) + { + return -1; + } + + if (NULL == real_sem_timedwait) + { /* dlsym() failed */ +#ifdef DEBUG + (void) fprintf(stderr, "faketime problem: original sem_timedwait() not found.\n"); +#endif + return -1; /* propagate error to caller */ + } + + if (!dont_fake) + { + struct timespec tdiff, timeadj; + + timespecsub(abs_timeout, &ftpl_starttime.real, &tdiff); + + if (user_rate_set) + { + timespecmul(&tdiff, user_rate, &timeadj); + } + else + { + timeadj = tdiff; + } + timespecadd(&user_faked_time_timespec, &timeadj, &real_abs_timeout); + real_abs_timeout_pt = &real_abs_timeout; + } + else + { + /* cast away constness */ + real_abs_timeout_pt = (struct timespec *)abs_timeout; + } + + DONT_FAKE_TIME(result = (*real_sem_timedwait)(sem, real_abs_timeout_pt)); + return result; +} #endif #ifndef __APPLE__ @@ -1424,6 +1471,7 @@ void __attribute__ ((constructor)) ftpl_init(void) real_alarm = dlsym(RTLD_NEXT, "alarm"); real_poll = dlsym(RTLD_NEXT, "poll"); real_ppoll = dlsym(RTLD_NEXT, "ppoll"); + real_sem_timedwait = dlsym(RTLD_NEXT, "sem_timedwait"); #endif #ifdef FAKE_INTERNAL_CALLS real___ftime = dlsym(RTLD_NEXT, "__ftime"); From 7c26cffac63b95e3999365ce1ad45a8fb6e1c49c Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Tue, 26 Aug 2014 10:50:44 -0400 Subject: [PATCH 4/6] Re-evaluate FAKETIME environment when cache expires When the cache expires, the FAKETIME environment does not get re-evaluated if FAKETIME value changes. This used to work on libfaketime-0.9.1, but was broken at some point afterwards. This fixes this problem Signed-off-by: Jon Ringle --- src/libfaketime.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/libfaketime.c b/src/libfaketime.c index 66b3a10..cb4d59c 100644 --- a/src/libfaketime.c +++ b/src/libfaketime.c @@ -1776,28 +1776,29 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp) if (cache_expired == 1) { - last_data_fetch = tp->tv_sec; + static char user_faked_time[BUFFERLEN]; /* changed to static for caching in v0.6 */ + /* initialize with default or env. variable */ + char *tmp_env; + /* Can be enabled for testing ... fprintf(stderr, "***************++ Cache expired ++**************\n"); */ + if (NULL != (tmp_env = getenv("FAKETIME"))) + { + strncpy(user_faked_time, tmp_env, BUFFERLEN); + } + else + { + snprintf(user_faked_time, BUFFERLEN, "+0"); + } + + last_data_fetch = tp->tv_sec; /* fake time supplied as environment variable? */ if (parse_config_file) { - static char user_faked_time[BUFFERLEN]; /* changed to static for caching in v0.6 */ char filename[BUFSIZ]; FILE *faketimerc; - /* initialize with default or env. variable */ - char *tmp_env; - if (NULL != (tmp_env = getenv("FAKETIME"))) - { - strncpy(user_faked_time, tmp_env, BUFFERLEN); - } - else - { - snprintf(user_faked_time, BUFFERLEN, "+0"); - } - /* 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, @@ -1820,8 +1821,8 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp) } fclose(faketimerc); } - parse_ft_string(user_faked_time); } /* read fake time from file */ + parse_ft_string(user_faked_time); } /* cache had expired */ if (infile_set) From bdd0f0aea919b906cf8beb4d8b45d6ba94e5ba80 Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Tue, 26 Aug 2014 10:51:50 -0400 Subject: [PATCH 5/6] Don't parse user_faked_time if it hasn't changed Signed-off-by: Jon Ringle --- src/libfaketime.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libfaketime.c b/src/libfaketime.c index cb4d59c..61c6631 100644 --- a/src/libfaketime.c +++ b/src/libfaketime.c @@ -216,6 +216,8 @@ static char user_faked_time_fmt[BUFSIZ] = {0}; static struct timespec user_faked_time_timespec = {0, -1}; /* User supplied base time is set */ static bool user_faked_time_set = false; +static char user_faked_time_saved[BUFFERLEN] = {0}; + /* Fractional user offset provided through FAKETIME env. var.*/ static struct timespec user_offset = {0, -1}; /* Speed up or slow down clock */ @@ -1316,6 +1318,13 @@ static void parse_ft_string(const char *user_faked_time) { struct tm user_faked_time_tm; char * tmp_time_fmt; + + if (!strncmp(user_faked_time, user_faked_time_saved, BUFFERLEN)) + { + /* No change */ + return; + } + /* check whether the user gave us an absolute time to fake */ switch (user_faked_time[0]) { @@ -1386,6 +1395,9 @@ parse_modifiers: } break; } // end of switch + + strncpy(user_faked_time_saved, user_faked_time, BUFFERLEN-1); + user_faked_time_saved[BUFFERLEN-1] = 0; } From 1c5a71752865080ed2a2427c2882a4a3ba9421fc Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Tue, 26 Aug 2014 13:23:25 -0400 Subject: [PATCH 6/6] Reset ftpl_starttime when setting new relative FT_START_AT time Signed-off-by: Jon Ringle --- src/libfaketime.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libfaketime.c b/src/libfaketime.c index 61c6631..fe37078 100644 --- a/src/libfaketime.c +++ b/src/libfaketime.c @@ -1373,6 +1373,9 @@ static void parse_ft_string(const char *user_faked_time) user_faked_time_timespec.tv_sec = mktime(&user_faked_time_tm); user_faked_time_timespec.tv_nsec = 0; + + /* Reset starttime */ + system_time_from_system(&ftpl_starttime); goto parse_modifiers; break; @@ -1398,6 +1401,9 @@ parse_modifiers: strncpy(user_faked_time_saved, user_faked_time, BUFFERLEN-1); user_faked_time_saved[BUFFERLEN-1] = 0; +#ifdef DEBUG + fprintf(stderr, "new FAKETIME: %s\n", user_faked_time_saved); +#endif }