mailarchive of the ptxdist mailing list
 help / color / mirror / Atom feed
* [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support
@ 2018-08-03 15:44 jon
  2018-08-03 15:44 ` [ptxdist] [PATCH v4 2/2] Detect changes in package patch series jon
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: jon @ 2018-08-03 15:44 UTC (permalink / raw)
  To: ptxdist; +Cc: Jon Ringle

From: Jon Ringle <jringle@gridpoint.com>

libfaketime will be used during patchin so that committer timestamps always
have a fixed value and therefore making the ${PKG}_SERIES_SHA256 value
repeatable

The minimal set of source files was picked out of libfaketime-0.9.7

Signed-off-by: Jon Ringle <jringle@gridpoint.com>
---
 Makefile.in                           |   14 +-
 scripts/libfaketime/Makefile          |  118 ++
 scripts/libfaketime/faketime.c        |  385 ++++++
 scripts/libfaketime/faketime_common.h |   61 +
 scripts/libfaketime/libfaketime.c     | 2410 +++++++++++++++++++++++++++++++++
 scripts/libfaketime/libfaketime.map   |   10 +
 scripts/libfaketime/time_ops.h        |  104 ++
 7 files changed, 3101 insertions(+), 1 deletion(-)
 create mode 100644 scripts/libfaketime/Makefile
 create mode 100644 scripts/libfaketime/faketime.c
 create mode 100644 scripts/libfaketime/faketime_common.h
 create mode 100644 scripts/libfaketime/libfaketime.c
 create mode 100644 scripts/libfaketime/libfaketime.map
 create mode 100644 scripts/libfaketime/time_ops.h

diff --git a/Makefile.in b/Makefile.in
index 40c676c..6e08377 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -22,7 +22,7 @@ export SHELL
 
 @BUILD_NCONF_TRUE@NCONF = nconf
 
-all: kconfig environment
+all: kconfig libfaketime environment
 	@touch .done
 
 kconfig:
@@ -41,6 +41,17 @@ kconfig:
 		conf mconf $(NCONF)
 	@echo "done."
 
+libfaketime:
+	@echo "building libfaketime ..."
+	@CC="$(CC)" \
+	CXX="$(CXX)" \
+	CFLAGS="$(CFLAGS)" \
+	CXXFLAGS="$(CXXFLAGS)" \
+	CPPFLAGS="$(CPPFLAGS)" \
+	LDFLAGS="$(LDFLAGS)" \
+	$(MAKE) -C "$(abs_srcdir)/scripts/libfaketime" all
+	@echo "done."
+
 environment:
 	@echo -n "preparing PTXdist environment ..."
 	@ln -sf @AWK@ "$(abs_srcdir)/bin/awk"
@@ -89,6 +100,7 @@ clean:
 	@rm -f .done
 	@find "$(abs_srcdir)/bin" -type l -print0 | xargs -0 rm -f
 	@$(MAKE) -C "$(abs_srcdir)/scripts/kconfig" clean
+	@$(MAKE) -C "$(abs_srcdir)/scripts/libfaketime" clean
 
 dirty-check:
 	@case "$(version)" in \
diff --git a/scripts/libfaketime/Makefile b/scripts/libfaketime/Makefile
new file mode 100644
index 0000000..a557c38
--- /dev/null
+++ b/scripts/libfaketime/Makefile
@@ -0,0 +1,118 @@
+#
+# Notes:
+#
+#   * Compilation Defines:
+#
+#     FAKE_STAT
+#         - Enables time faking also for files' timestamps.
+#
+#     NO_ATFILE
+#         - Disables support for the fstatat() group of functions
+#
+#     PTHREAD
+#         - Define this to enable multithreading support.
+#
+#     PTHREAD_SINGLETHREADED_TIME
+#         - Define this if you want to single-thread time() ... there ARE
+#           possibile caching side-effects in a multithreaded environment
+#           without this, but the performance impact may require you to
+#           try it unsynchronized.
+#
+#     FAKE_INTERNAL_CALLS
+#         - Also intercept libc internal __functions, e.g. not just time(),
+#           but also __time(). Enhances compatibility with applications
+#           that make use of low-level system calls, such as Java Virtual
+#           Machines.
+#
+# 	  FAKE_SLEEP
+# 	      - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
+#
+#	  FAKE_TIMERS
+#	      - Also intercept timer_settime() and timer_gettime()
+#
+#	  MULTI_ARCH
+#	  	  - If MULTI_ARCH is set, the faketime wrapper program will put a literal
+#	  	    $LIB into the LD_PRELOAD environment variable it creates, which makes
+#	  	    ld automatically choose the correct library version to use for the
+#	  	    target binary. Use for Linux platforms with Multi-Arch support only!
+#
+#   * Compilation addition: second libMT target added for building the pthread-
+#     enabled library as a separate library
+#
+#   * Compilation switch change: previous versions compiled using '-nostartfiles'
+#     This is no longer the case since there is a 'startup' constructor for the library
+#     which is used to activate the start-at times when specified. This also initializes
+#     the dynamic disabling of the FAKE_STAT calls.
+#
+# By default, libfaketime will be compiled for your system's default architecture.
+# To build 32-bit libraries and binaries, add -m32 to CFLAGS and LDFLAGS.
+#
+# Change PREFIX to where you want libfaketime (libraries and wrapper binary) installed.
+# LIBDIRNAME is relative to PREFIX. The default is to install into $PREFIX/lib/faketime,
+# but you can set LIBDIRNAME to, e.g., /lib64 if you want to install it elsewhere.
+# LIBDIRNAME has been introduced to support MultiLib systems. Please do not change the 
+# default value on MultiArch systems. 
+#
+# For testing in the current directory without installation, try make PREFIX= LIBDIRNAME='.'
+
+CC ?= gcc
+INSTALL ?= install
+
+PREFIX ?= /usr/local
+LIBDIRNAME ?= /lib/faketime
+PLATFORM ?=$(shell uname)
+
+CFLAGS += -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -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 += -lpthread
+ifneq ($(PLATFORM),SunOS)
+LDFLAGS += -Wl,--version-script=libfaketime.map
+endif
+
+LDADD += -ldl -lm -lrt
+BIN_LDFLAGS += -lrt
+
+SRC = libfaketime.c
+LIBS_OBJ = libfaketime.o libfaketimeMT.o
+BINS = faketime
+
+SONAME = 1
+LIBS = libfaketime.so.${SONAME} libfaketimeMT.so.${SONAME}
+
+all: ${LIBS} ${BINS}
+
+libfaketimeMT.o: EXTRA_FLAGS := -DPTHREAD -DPTHREAD_SINGLETHREADED_TIME
+
+${LIBS_OBJ}: libfaketime.c
+	${CC} -o $@ -c ${CFLAGS} ${EXTRA_FLAGS} $<
+
+%.so.${SONAME}: %.o libfaketime.map
+	${CC} -o $@ -Wl,-soname,$@ ${LDFLAGS} ${LIB_LDFLAGS} $< ${LDADD}
+
+${BINS}: faketime.c
+	${CC} -o $@ ${CFLAGS} ${EXTRA_FLAGS} $< ${LDFLAGS} ${BIN_LDFLAGS}
+
+clean:
+	@rm -f ${LIBS_OBJ} ${LIBS} ${BINS}
+
+distclean: clean
+	@echo
+
+install: ${LIBS} ${BINS}
+	@echo
+	@echo "Copying the faketime libraries to ${DESTDIR}${PREFIX}${LIBDIRNAME} and the faketime wrapper script to ${DESTDIR}${PREFIX}/bin ..."
+	$(INSTALL) -dm0755 "${DESTDIR}${PREFIX}${LIBDIRNAME}/"
+	$(INSTALL) -m0644 ${LIBS} "${DESTDIR}${PREFIX}${LIBDIRNAME}/"
+	$(INSTALL) -Dm0755 faketime "${DESTDIR}${PREFIX}/bin/faketime"
+
+uninstall:
+	for f in ${LIBS}; do rm -f "${DESTDIR}${PREFIX}${LIBDIRNAME}/$$f"; done
+	rmdir "${DESTDIR}${PREFIX}${LIBDIRNAME}"
+	rm -f "${DESTDIR}${PREFIX}/bin/faketime"
+
+.PHONY: all clean distclean install uninstall
diff --git a/scripts/libfaketime/faketime.c b/scripts/libfaketime/faketime.c
new file mode 100644
index 0000000..138ebbd
--- /dev/null
+++ b/scripts/libfaketime/faketime.c
@@ -0,0 +1,385 @@
+/*
+ *  libfaketime wrapper command
+ *
+ *  This file is part of libfaketime, version 0.9.7
+ *
+ *  libfaketime is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License v2 as published by the
+ *  Free Software Foundation.
+ *
+ *  libfaketime is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License v2 along
+ *  with the libfaketime; if not, write to the Free Software Foundation,
+ *  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Converted from shell script by Balint Reczey with the following credits
+ * and comments:
+ *
+ * Thanks to Daniel Kahn Gillmor for improvement suggestions.
+
+ * This wrapper exposes only a small subset of the libfaketime functionality.
+ * Please see libfaketime's README file and man page for more details.
+
+ * Acknowledgment: Parts of the functionality of this wrapper have been
+ * inspired by Matthias Urlichs' datefudge 1.14.
+
+ * Compile time configuration: Path where the libfaketime libraries can be found
+ * on Linux/UNIX
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <semaphore.h>
+
+#include "faketime_common.h"
+
+const char version[] = "0.9.7";
+
+#ifdef __APPLE__
+static const char *date_cmd = "gdate";
+#else
+static const char *date_cmd = "date";
+#endif
+
+#define PATH_BUFSIZE 4096
+
+/* semaphore and shared memory names */
+char sem_name[PATH_BUFSIZE] = {0}, shm_name[PATH_BUFSIZE] = {0};
+
+void usage(const char *name)
+{
+  printf("\n"
+  "Usage: %s [switches] <timestamp> <program with arguments>\n"
+  "\n"
+  "This will run the specified 'program' with the given 'arguments'.\n"
+  "The program will be tricked into seeing the given 'timestamp' as its starting date and time.\n"
+  "The clock will continue to run from this timestamp. Please see the manpage (man faketime)\n"
+  "for advanced options, such as stopping the wall clock and make it run faster or slower.\n"
+  "\n"
+  "The optional switches are:\n"
+  "  -m                  : Use the multi-threaded version of libfaketime\n"
+  "  -f                  : Use the advanced timestamp specification format (see manpage)\n"
+  "  --exclude-monotonic : Prevent monotonic clock from drifting (not the raw monotonic one)\n"
+  "\n"
+  "Examples:\n"
+  "%s 'last friday 5 pm' /bin/date\n"
+  "%s '2008-12-24 08:15:42' /bin/date\n"
+  "%s -f '+2,5y x10,0' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n"
+  "%s -f '+2,5y x0,50' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n"
+  "%s -f '+2,5y i2,0' /bin/bash -c 'date; while true; do date; sleep 1 ; done'\n"
+  "In this single case all spawned processes will use the same global clock\n"
+  "without restarting it at the start of each process.\n\n"
+  "(Please note that it depends on your locale settings whether . or , has to be used for fractions)\n"
+  "\n", name, name, name, name, name, name);
+}
+
+/** Clean up shared objects */
+static void cleanup_shobjs()
+{
+  if (-1 == sem_unlink(sem_name))
+  {
+    perror("sem_unlink");
+  }
+  if (-1 == shm_unlink(shm_name))
+  {
+    perror("shm_unlink");
+  }
+}
+
+int main (int argc, char **argv)
+{
+  pid_t child_pid;
+  int curr_opt = 1;
+  bool use_mt = false, use_direct = false;
+  long offset;
+
+  while(curr_opt < argc)
+  {
+    if (0 == strcmp(argv[curr_opt], "-m"))
+    {
+      use_mt = true;
+      curr_opt++;
+      continue;
+    }
+    else if (0 == strcmp(argv[curr_opt], "-f"))
+    {
+      use_direct = true;
+      curr_opt++;
+      continue;
+    }
+    else if (0 == strcmp(argv[curr_opt], "--exclude-monotonic"))
+    {
+      setenv("DONT_FAKE_MONOTONIC", "1", true);
+      curr_opt++;
+      continue;
+    }
+    else if ((0 == strcmp(argv[curr_opt], "-v")) ||
+             (0 == strcmp(argv[curr_opt], "--version")))
+    {
+      printf("\n%s: Version %s\n"
+         "For usage information please use '%s --help'.\n",
+         argv[0], version, argv[0]);
+      exit(EXIT_SUCCESS);
+    }
+    else if ((0 == strcmp(argv[curr_opt], "-h")) ||
+             (0 == strcmp(argv[curr_opt], "-?")) ||
+             (0 == strcmp(argv[curr_opt], "--help")))
+    {
+      usage(argv[0]);
+      exit(EXIT_SUCCESS);
+    }
+    else
+    {
+      /* we parsed all options */
+      break;
+    }
+  }
+
+  /* we need at least a timestamp string and a command to run */
+  if (argc - curr_opt < 2)
+  {
+    usage(argv[0]);
+    exit(EXIT_FAILURE);
+  }
+
+  if (!use_direct)
+  {
+    // TODO get seconds
+    int pfds[2];
+    (void) (pipe(pfds) + 1);
+    int ret = EXIT_SUCCESS;
+
+    if (0 == (child_pid = fork()))
+    {
+      close(1);       /* close normal stdout */
+      (void) (dup(pfds[1]) + 1);   /* make stdout same as pfds[1] */
+      close(pfds[0]); /* we don't need this */
+      if (EXIT_SUCCESS != execlp(date_cmd, date_cmd, "-d", argv[curr_opt], "+%s",(char *) NULL))
+      {
+        perror("Running (g)date failed");
+        exit(EXIT_FAILURE);
+      }
+    }
+    else
+    {
+      char buf[256] = {0}; /* e will have way less than 256 digits */
+      close(pfds[1]);   /* we won't write to this */
+      (void) (read(pfds[0], buf, 256) + 1);
+      waitpid(child_pid, &ret, 0);
+      if (ret != EXIT_SUCCESS)
+      {
+        printf("Error: Timestamp to fake not recognized, please re-try with a "
+               "different timestamp.\n");
+        exit(EXIT_FAILURE);
+      }
+      offset = atol(buf) - time(NULL);
+      ret = snprintf(buf, sizeof(buf), "%s%ld", (offset >= 0)?"+":"", offset);
+      setenv("FAKETIME", buf, true);
+      close(pfds[0]); /* finished reading */
+    }
+  }
+  else
+  {
+    /* simply pass format string along */
+    setenv("FAKETIME", argv[curr_opt], true);
+  }
+  int keepalive_fds[2];
+  (void) (pipe(keepalive_fds) + 1);
+
+  /* we just consumed the timestamp option */
+  curr_opt++;
+
+  {
+    /* create semaphores and shared memory */
+    int shm_fd;
+    sem_t *sem;
+    struct ft_shared_s *ft_shared;
+    char shared_objs[PATH_BUFSIZE];
+
+    /*
+     * 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)))
+    {
+      perror("sem_open");
+      exit(EXIT_FAILURE);
+    }
+
+    /* create shm */
+    if (-1 == (shm_fd = shm_open(shm_name, O_CREAT|O_EXCL|O_RDWR, S_IWUSR|S_IRUSR)))
+    {
+      perror("shm_open");
+      if (-1 == sem_unlink(argv[2]))
+      {
+        perror("sem_unlink");
+      }
+      exit(EXIT_FAILURE);
+    }
+
+    /* set shm size */
+    if (-1 == ftruncate(shm_fd, sizeof(uint64_t)))
+    {
+      perror("ftruncate");
+      cleanup_shobjs();
+      exit(EXIT_FAILURE);
+    }
+
+    /* map shm */
+    if (MAP_FAILED == (ft_shared = mmap(NULL, sizeof(struct ft_shared_s), PROT_READ|PROT_WRITE,
+                        MAP_SHARED, shm_fd, 0)))
+    {
+      perror("mmap");
+      cleanup_shobjs();
+      exit(EXIT_FAILURE);
+    }
+
+    if (sem_wait(sem) == -1)
+    {
+      perror("sem_wait");
+      cleanup_shobjs();
+      exit(EXIT_FAILURE);
+    }
+
+    /* init elapsed time ticks to zero */
+    ft_shared->ticks = 0;
+    ft_shared->file_idx = 0;
+    ft_shared->start_time.real.tv_sec = 0;
+    ft_shared->start_time.real.tv_nsec = -1;
+    ft_shared->start_time.mon.tv_sec = 0;
+    ft_shared->start_time.mon.tv_nsec = -1;
+    ft_shared->start_time.mon_raw.tv_sec = 0;
+    ft_shared->start_time.mon_raw.tv_nsec = -1;
+
+    if (-1 == munmap(ft_shared, (sizeof(struct ft_shared_s))))
+    {
+      perror("munmap");
+      cleanup_shobjs();
+      exit(EXIT_FAILURE);
+    }
+
+    if (sem_post(sem) == -1)
+    {
+      perror("semop");
+      cleanup_shobjs();
+      exit(EXIT_FAILURE);
+    }
+
+    snprintf(shared_objs, PATH_BUFSIZE, "%s %s", sem_name, shm_name);
+    setenv("FAKETIME_SHARED", shared_objs, true);
+    sem_close(sem);
+  }
+
+  {
+    char *ftpl_path;
+#ifdef __APPLE__
+    ftpl_path = PREFIX "/libfaketime.1.dylib";
+    FILE *check;
+    check = fopen(ftpl_path, "ro");
+    if (check == NULL)
+    {
+      ftpl_path = PREFIX "/lib/faketime/libfaketime.1.dylib";
+    }
+    else
+    {
+      fclose(check);
+    }
+    setenv("DYLD_INSERT_LIBRARIES", ftpl_path, true);
+    setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", true);
+#else
+    {
+      char *ld_preload_new, *ld_preload = getenv("LD_PRELOAD");
+      size_t len;
+      if (use_mt)
+      {
+        /*
+         * on MultiArch platforms, such as Debian, we put a literal $LIB into LD_PRELOAD.
+         */
+#ifndef MULTI_ARCH
+        ftpl_path = PREFIX LIBDIRNAME "/libfaketimeMT.so.1";
+#else
+        ftpl_path = PREFIX "/$LIB/faketime/libfaketimeMT.so.1";
+#endif
+      }
+      else
+      {
+#ifndef MULTI_ARCH
+        ftpl_path = PREFIX LIBDIRNAME "/libfaketime.so.1";
+#else
+        ftpl_path = PREFIX "/$LIB/faketime/libfaketime.so.1";
+#endif
+      }
+      len = ((ld_preload)?strlen(ld_preload) + 1: 0) + 1 + strlen(ftpl_path);
+      ld_preload_new = malloc(len);
+      snprintf(ld_preload_new, len ,"%s%s%s", (ld_preload)?ld_preload:"",
+              (ld_preload)?":":"", ftpl_path);
+      setenv("LD_PRELOAD", ld_preload_new, true);
+      free(ld_preload_new);
+    }
+#endif
+  }
+
+  /* run command and clean up shared objects */
+  if (0 == (child_pid = fork()))
+  {
+    close(keepalive_fds[0]); /* only parent needs to read this */
+    if (EXIT_SUCCESS != execvp(argv[curr_opt], &argv[curr_opt]))
+    {
+      perror("Running specified command failed");
+      exit(EXIT_FAILURE);
+    }
+  }
+  else
+  {
+    int ret;
+    char buf;
+    close(keepalive_fds[1]); /* only children need keep this open */
+    waitpid(child_pid, &ret, 0);
+    (void) (read(keepalive_fds[0], &buf, 1) + 1); /* reads 0B when all children exit */
+    cleanup_shobjs();
+    if (WIFSIGNALED(ret))
+    {
+      fprintf(stderr, "Caught %s\n", strsignal(WTERMSIG(ret)));
+      exit(EXIT_FAILURE);
+    }
+    exit(WEXITSTATUS(ret));
+  }
+
+  return EXIT_SUCCESS;
+}
+
+/*
+ * Editor modelines
+ *
+ * Local variables:
+ * c-basic-offset: 2
+ * tab-width: 2
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=2 tabstop=2 expandtab:
+ * :indentSize=2:tabSize=2:noTabs=true:
+ */
+
+/* eof */
diff --git a/scripts/libfaketime/faketime_common.h b/scripts/libfaketime/faketime_common.h
new file mode 100644
index 0000000..9fda6a7
--- /dev/null
+++ b/scripts/libfaketime/faketime_common.h
@@ -0,0 +1,61 @@
+/*
+ * Faketime's common definitions
+ *
+ * Copyright 2013 Balint Reczey <balint@balintreczey.hu>
+ *
+ * This file is part of the libfaketime.
+ *
+ * libfaketime is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License v2 as published by the Free
+ * Software Foundation.
+ *
+ * libfaketime is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License v2 along
+ * with libfaketime; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef FAKETIME_COMMON_H
+#define FAKETIME_COMMON_H
+
+#include <stdint.h>
+
+struct system_time_s
+{
+  /* System time according to CLOCK_REALTIME */
+  struct timespec real;
+  /* System time according to CLOCK_MONOTONIC */
+  struct timespec mon;
+  /* System time according to CLOCK_MONOTONIC_RAW */
+  struct timespec mon_raw;
+#ifdef CLOCK_BOOTTIME
+  /* System time according to CLOCK_BOOTTIME */
+  struct timespec boot;
+#endif
+};
+
+/* Data shared among faketime-spawned processes */
+struct ft_shared_s
+{
+  /*
+   * When advancing time linearly with each time(), etc. call, the calls are
+   * counted here */
+  uint64_t ticks;
+  /* Index of timstamp to be loaded from file */
+  uint64_t file_idx;
+  /* System time Faketime started at */
+  struct system_time_s start_time;
+};
+
+/* These are all needed in order to properly build on OSX */
+#ifdef __APPLE__
+#include <mach/clock.h>
+#include <mach/mach_host.h>
+#include <mach/mach_port.h>
+#endif
+
+#endif
diff --git a/scripts/libfaketime/libfaketime.c b/scripts/libfaketime/libfaketime.c
new file mode 100644
index 0000000..eb2d01b
--- /dev/null
+++ b/scripts/libfaketime/libfaketime.c
@@ -0,0 +1,2410 @@
+/*
+ *  This file is part of libfaketime, version 0.9.7
+ *
+ *  libfaketime is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License v2 as published by the
+ *  Free Software Foundation.
+ *
+ *  libfaketime is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License v2 along
+ *  with the libfaketime; if not, write to the Free Software Foundation,
+ *  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *      =======================================================================
+ *      Global settings, includes, and macros                          === HEAD
+ *      =======================================================================
+ */
+
+#define _GNU_SOURCE             /* required to get RTLD_NEXT defined */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <time.h>
+#include <math.h>
+#include <errno.h>
+#include <string.h>
+#include <semaphore.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <limits.h>
+
+#include "time_ops.h"
+#include "faketime_common.h"
+
+/* pthread-handling contributed by David North, TDI in version 0.7 */
+#ifdef PTHREAD
+#include <pthread.h>
+#endif
+
+#include <sys/timeb.h>
+#include <dlfcn.h>
+
+#define BUFFERLEN   256
+
+#ifndef __APPLE__
+extern char *__progname;
+#ifdef __sun
+#include "sunos_endian.h"
+#else
+#include <endian.h>
+#endif
+#else
+/* endianness related macros */
+#ifndef OSSwapHostToBigInt64
+#define OSSwapHostToBigInt64(x) ((uint64_t)(x))
+#endif
+#define htobe64(x) OSSwapHostToBigInt64(x)
+#ifndef OSSwapHostToLittleInt64
+#define OSSwapHostToLittleInt64(x) OSSwapInt64(x)
+#endif
+#define htole64(x) OSSwapHostToLittleInt64(x)
+#ifndef OSSwapBigToHostInt64
+#define OSSwapBigToHostInt64(x) ((uint64_t)(x))
+#endif
+#define be64toh(x) OSSwapBigToHostInt64(x)
+#ifndef OSSwapLittleToHostInt64
+#define OSSwapLittleToHostInt64(x) OSSwapInt64(x)
+#endif
+#define le64toh(x) OSSwapLittleToHostInt64(x)
+
+/* clock_gettime() and related clock definitions are missing on __APPLE__ */
+#ifndef CLOCK_REALTIME
+/* from GNU C Library time.h */
+/* Identifier for system-wide realtime clock. ( == 1) */
+#define CLOCK_REALTIME               CALENDAR_CLOCK
+/* Monotonic system-wide clock. (== 0) */
+#define CLOCK_MONOTONIC              SYSTEM_CLOCK
+/* High-resolution timer from the CPU.  */
+#define CLOCK_PROCESS_CPUTIME_ID     2
+/* Thread-specific CPU-time clock.  */
+#define CLOCK_THREAD_CPUTIME_ID      3
+/* Monotonic system-wide clock, not adjusted for frequency scaling.  */
+#define CLOCK_MONOTONIC_RAW          4
+typedef int clockid_t;
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif
+#endif
+
+/* some systems lack raw clock */
+#ifndef CLOCK_MONOTONIC_RAW
+#define CLOCK_MONOTONIC_RAW (CLOCK_MONOTONIC + 1)
+#endif
+
+/*
+ * Per thread variable, which we turn on inside real_* calls to avoid modifying
+ * time multiple times of for the whole process to prevent faking time
+ */
+static __thread bool dont_fake = false;
+
+/* Wrapper for function calls, which we want to return system time */
+#define DONT_FAKE_TIME(call)          \
+  {                                   \
+    bool dont_fake_orig = dont_fake;  \
+    if (!dont_fake)                   \
+    {                                 \
+      dont_fake = true;               \
+    }                                 \
+    call;                             \
+    dont_fake = dont_fake_orig;       \
+  } while (0)
+
+/* pointers to real (not faked) functions */
+static int          (*real_stat)            (int, const char *, struct stat *);
+static int          (*real_fstat)           (int, int, struct stat *);
+static int          (*real_fstatat)         (int, int, const char *, struct stat *, int);
+static int          (*real_lstat)           (int, const char *, struct stat *);
+static int          (*real_stat64)          (int, const char *, struct stat64 *);
+static int          (*real_fstat64)         (int, int , struct stat64 *);
+static int          (*real_fstatat64)       (int, int , const char *, struct stat64 *, int);
+static int          (*real_lstat64)         (int, const char *, struct stat64 *);
+static time_t       (*real_time)            (time_t *);
+static int          (*real_ftime)           (struct timeb *);
+static int          (*real_gettimeofday)    (struct timeval *, void *);
+static int          (*real_clock_gettime)   (clockid_t clk_id, struct timespec *tp);
+#ifdef FAKE_INTERNAL_CALLS
+static int          (*real___ftime)           (struct timeb *);
+static int          (*real___gettimeofday)    (struct timeval *, void *);
+static int          (*real___clock_gettime)   (clockid_t clk_id, struct timespec *tp);
+#endif
+#ifndef __APPLEOSX__
+#ifdef FAKE_TIMERS
+static int          (*real_timer_settime_22)   (int timerid, int flags, const struct itimerspec *new_value,
+                                                struct itimerspec * old_value);
+static int          (*real_timer_settime_233)  (timer_t timerid, int flags,
+                                                const struct itimerspec *new_value,
+                                                struct itimerspec * old_value);
+static int          (*real_timer_gettime_22)   (int timerid,
+                                                struct itimerspec *curr_value);
+static int          (*real_timer_gettime_233)  (timer_t timerid,
+                                                struct itimerspec *curr_value);
+#endif
+#endif
+#ifdef FAKE_SLEEP
+static int          (*real_nanosleep)       (const struct timespec *req, struct timespec *rem);
+static int          (*real_usleep)          (useconds_t usec);
+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_select)          (int nfds, fd_set *restrict readfds,
+                                             fd_set *restrict writefds,
+                                             fd_set *restrict errorfds,
+                                             struct timeval *restrict timeout);
+static int          (*real_sem_timedwait)   (sem_t*, const struct timespec*);
+#endif
+#ifdef __APPLEOSX__
+static int          (*real_clock_get_time)  (clock_serv_t clock_serv, mach_timespec_t *cur_timeclockid_t);
+static int          apple_clock_gettime     (clockid_t clk_id, struct timespec *tp);
+static clock_serv_t clock_serv_real;
+#endif
+
+static int initialized = 0;
+
+/* prototypes */
+static int    fake_gettimeofday(struct timeval *tv);
+static int    fake_clock_gettime(clockid_t clk_id, struct timespec *tp);
+
+/** Semaphore protecting shared data */
+static sem_t *shared_sem = NULL;
+
+/** Data shared among faketime-spawned processes */
+static struct ft_shared_s *ft_shared = NULL;
+
+/** Storage format for timestamps written to file. Big endian.*/
+struct saved_timestamp
+{
+  int64_t sec;
+  uint64_t nsec;
+};
+
+static inline void timespec_from_saved (struct timespec *tp,
+  struct saved_timestamp *saved)
+{
+  /* read as big endian */
+  tp->tv_sec = be64toh(saved->sec);
+  tp->tv_nsec = be64toh(saved->nsec);
+}
+
+/** Saved timestamps */
+static struct saved_timestamp *stss = NULL;
+static size_t infile_size;
+static bool infile_set = false;
+
+/** File fd to save timestamps to */
+static int outfile = -1;
+
+static bool limited_faking = false;
+static long callcounter = 0;
+static long ft_start_after_secs = -1;
+static long ft_stop_after_secs = -1;
+static long ft_start_after_ncalls = -1;
+static long ft_stop_after_ncalls = -1;
+
+static bool spawnsupport = false;
+static int spawned = 0;
+static char ft_spawn_target[1024];
+static long ft_spawn_secs = -1;
+static long ft_spawn_ncalls = -1;
+
+static int fake_monotonic_clock = 1;
+static int cache_enabled = 1;
+static int cache_duration = 10;     /* cache fake time input for 10 seconds */
+
+/*
+ * Static timespec to store our startup time, followed by a load-time library
+ * initialization declaration.
+ */
+#ifndef CLOCK_BOOTTIME
+static struct system_time_s ftpl_starttime = {{0, -1}, {0, -1}, {0, -1}};
+#else
+static struct system_time_s ftpl_starttime = {{0, -1}, {0, -1}, {0, -1}, {0, -1}};
+#endif
+
+static char user_faked_time_fmt[BUFSIZ] = {0};
+
+/* User supplied base time to fake */
+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 */
+static double user_rate = 1.0;
+static bool user_rate_set = false;
+static struct timespec user_per_tick_inc = {0, -1};
+static bool user_per_tick_inc_set = false;
+
+enum ft_mode_t {FT_FREEZE, FT_START_AT, FT_NOOP} ft_mode = FT_FREEZE;
+
+/* Time to fake is not provided through FAKETIME env. var. */
+static bool parse_config_file = true;
+
+void ft_cleanup (void) __attribute__ ((destructor));
+void ftpl_init (void) __attribute__ ((constructor));
+
+
+/*
+ *      =======================================================================
+ *      Shared memory related functions                                 === SHM
+ *      =======================================================================
+ */
+
+static void ft_shm_init (void)
+{
+  int ticks_shm_fd;
+  char sem_name[256], shm_name[256], *ft_shared_env = getenv("FAKETIME_SHARED");
+
+  if (ft_shared_env != NULL)
+  {
+    if (sscanf(ft_shared_env, "%255s %255s", sem_name, shm_name) < 2)
+    {
+      printf("Error parsing semaphore name and shared memory id from string: %s", ft_shared_env);
+      exit(1);
+    }
+
+    if (SEM_FAILED == (shared_sem = sem_open(sem_name, 0)))
+    {
+      perror("sem_open");
+      exit(1);
+    }
+
+    if (-1 == (ticks_shm_fd = shm_open(shm_name, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)))
+    {
+      perror("shm_open");
+      exit(1);
+    }
+
+    if (MAP_FAILED == (ft_shared = mmap(NULL, sizeof(struct ft_shared_s), PROT_READ|PROT_WRITE,
+            MAP_SHARED, ticks_shm_fd, 0)))
+    {
+      perror("mmap");
+      exit(1);
+    }
+  }
+}
+
+void ft_cleanup (void)
+{
+  /* detach from shared memory */
+  if (ft_shared != NULL)
+  {
+    munmap(ft_shared, sizeof(uint64_t));
+  }
+  if (stss != NULL)
+  {
+    munmap(stss, infile_size);
+  }
+  if (shared_sem != NULL)
+  {
+    sem_close(shared_sem);
+  }
+}
+
+
+/*
+ *      =======================================================================
+ *      Internal time retrieval                                     === INTTIME
+ *      =======================================================================
+ */
+
+/* Get system time from system for all clocks */
+static void system_time_from_system (struct system_time_s * systime)
+{
+#ifdef __APPLEOSX__
+  /* from http://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x */
+  clock_serv_t cclock;
+  mach_timespec_t mts;
+  host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clock_serv_real);
+  (*real_clock_get_time)(clock_serv_real, &mts);
+  systime->real.tv_sec = mts.tv_sec;
+  systime->real.tv_nsec = mts.tv_nsec;
+  host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+  (*real_clock_get_time)(cclock, &mts);
+  mach_port_deallocate(mach_task_self(), cclock);
+  systime->mon.tv_sec = mts.tv_sec;
+  systime->mon.tv_nsec = mts.tv_nsec;
+  systime->mon_raw.tv_sec = mts.tv_sec;
+  systime->mon_raw.tv_nsec = mts.tv_nsec;
+#else
+  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_REALTIME, &systime->real))
+   ;
+  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_MONOTONIC, &systime->mon))
+   ;
+  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_MONOTONIC_RAW, &systime->mon_raw))
+   ;
+#ifdef CLOCK_BOOTTIME
+  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_BOOTTIME, &systime->boot))
+   ;
+#endif
+#endif
+}
+
+static void next_time(struct timespec *tp, struct timespec *ticklen)
+{
+  if (shared_sem != NULL)
+  {
+    struct timespec inc;
+    /* lock */
+    if (sem_wait(shared_sem) == -1)
+    {
+      perror("sem_wait");
+      exit(1);
+    }
+    /* calculate and update elapsed time */
+    timespecmul(ticklen, ft_shared->ticks, &inc);
+    timespecadd(&user_faked_time_timespec, &inc, tp);
+    (ft_shared->ticks)++;
+    /* unlock */
+    if (sem_post(shared_sem) == -1)
+    {
+      perror("sem_post");
+      exit(1);
+    }
+  }
+}
+
+
+/*
+ *      =======================================================================
+ *      Saving & loading time                                          === SAVE
+ *      =======================================================================
+ */
+
+static void save_time(struct timespec *tp)
+{
+  if ((shared_sem != NULL) && (outfile != -1))
+  {
+    struct saved_timestamp time_write;
+    ssize_t written;
+    size_t n = 0;
+
+    time_write.sec = htobe64(tp->tv_sec);
+    time_write.nsec = htobe64(tp->tv_nsec);
+
+    /* lock */
+    if (sem_wait(shared_sem) == -1)
+    {
+      perror("sem_wait");
+      exit(1);
+    }
+
+    lseek(outfile, 0, SEEK_END);
+    do
+    {
+      written = write(outfile, &(((char*)&time_write)[n]), sizeof(time_write) - n);
+    }
+    while (((written == -1) && (errno == EINTR)) ||
+            (sizeof(time_write) < (n += written)));
+
+    if ((written == -1) || (n < sizeof(time_write)))
+    {
+      perror("Saving timestamp to file failed");
+    }
+
+    /* unlock */
+    if (sem_post(shared_sem) == -1)
+    {
+      perror("sem_post");
+      exit(1);
+    }
+  }
+}
+
+/*
+ * Provide faked time from file.
+ * @return time is set from filen
+ */
+static bool load_time(struct timespec *tp)
+{
+  bool ret = false;
+  if ((shared_sem != NULL) && (infile_set))
+  {
+    /* lock */
+    if (sem_wait(shared_sem) == -1)
+    {
+      perror("sem_wait");
+      exit(1);
+    }
+
+    if ((sizeof(stss[0]) * (ft_shared->file_idx + 1)) > infile_size)
+    {
+      /* we are out of timstamps to replay, return to faking time by rules
+       * using last timestamp from file as the user provided timestamp */
+      timespec_from_saved(&user_faked_time_timespec, &stss[(infile_size / sizeof(stss[0])) - 1 ]);
+
+      if (ft_shared->ticks == 0)
+      {
+        /* we set shared memory to stop using infile */
+        ft_shared->ticks = 1;
+        system_time_from_system(&ftpl_starttime);
+        ft_shared->start_time = ftpl_starttime;
+      }
+      else
+      {
+        ftpl_starttime = ft_shared->start_time;
+      }
+
+      munmap(stss, infile_size);
+      infile_set = false;
+    }
+    else
+    {
+      timespec_from_saved(tp, &stss[ft_shared->file_idx]);
+      ft_shared->file_idx++;
+      ret = true;
+    }
+
+    /* unlock */
+    if (sem_post(shared_sem) == -1)
+    {
+      perror("sem_post");
+      exit(1);
+    }
+  }
+  return ret;
+}
+
+
+/*
+ *      =======================================================================
+ *      Faked system functions: file related                     === FAKE(FILE)
+ *      =======================================================================
+ */
+
+#ifdef FAKE_STAT
+
+#ifndef NO_ATFILE
+#ifndef _ATFILE_SOURCE
+#define _ATFILE_SOURCE
+#endif
+#include <fcntl.h> /* Definition of AT_* constants */
+#endif
+
+#include <sys/stat.h>
+
+static int fake_stat_disabled = 0;
+
+#define FAKE_STRUCT_STAT_TIME(which) {                \
+    struct timespec t = {buf->st_##which##time,       \
+                         buf->st_##which##timensec};  \
+    fake_clock_gettime(CLOCK_REALTIME, &t);           \
+    buf->st_##which##time = t.tv_sec;                 \
+    buf->st_##which##timensec = t.tv_nsec;            \
+  } while (0)
+
+static inline void fake_statbuf (struct stat *buf) {
+#ifndef st_atime
+  FAKE_STRUCT_STAT_TIME(c);
+  FAKE_STRUCT_STAT_TIME(a);
+  FAKE_STRUCT_STAT_TIME(m);
+#else
+  fake_clock_gettime(CLOCK_REALTIME, &buf->st_ctim);
+  fake_clock_gettime(CLOCK_REALTIME, &buf->st_atim);
+  fake_clock_gettime(CLOCK_REALTIME, &buf->st_mtim);
+#endif
+}
+
+static inline void fake_stat64buf (struct stat64 *buf) {
+#ifndef st_atime
+  FAKE_STRUCT_STAT_TIME(c);
+  FAKE_STRUCT_STAT_TIME(a);
+  FAKE_STRUCT_STAT_TIME(m);
+#else
+  fake_clock_gettime(CLOCK_REALTIME, &buf->st_ctim);
+  fake_clock_gettime(CLOCK_REALTIME, &buf->st_atim);
+  fake_clock_gettime(CLOCK_REALTIME, &buf->st_mtim);
+#endif
+}
+
+/* Contributed by Philipp Hachtmann in version 0.6 */
+int __xstat (int ver, const char *path, struct stat *buf)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (NULL == real_stat)
+  { /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original stat() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  int result;
+  DONT_FAKE_TIME(result = real_stat(ver, path, buf));
+  if (result == -1)
+  {
+    return -1;
+  }
+
+   if (buf != NULL)
+   {
+     if (!fake_stat_disabled)
+     {
+       fake_statbuf(buf);
+     }
+   }
+
+  return result;
+}
+
+/* Contributed by Philipp Hachtmann in version 0.6 */
+int __fxstat (int ver, int fildes, struct stat *buf)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (NULL == real_fstat)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original fstat() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  int result;
+  DONT_FAKE_TIME(result = real_fstat(ver, fildes, buf));
+  if (result == -1)
+  {
+    return -1;
+  }
+
+  if (buf != NULL)
+  {
+    if (!fake_stat_disabled)
+    {
+      fake_statbuf(buf);
+    }
+  }
+  return result;
+}
+
+/* Added in v0.8 as suggested by Daniel Kahn Gillmor */
+#ifndef NO_ATFILE
+int __fxstatat(int ver, int fildes, const char *filename, struct stat *buf, int flag)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (NULL == real_fstatat)
+  { /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original fstatat() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  int result;
+  DONT_FAKE_TIME(result = real_fstatat(ver, fildes, filename, buf, flag));
+  if (result == -1)
+  {
+    return -1;
+  }
+
+  if (buf != NULL)
+  {
+    if (!fake_stat_disabled)
+    {
+      fake_statbuf(buf);
+    }
+  }
+  return result;
+}
+#endif
+
+/* Contributed by Philipp Hachtmann in version 0.6 */
+int __lxstat (int ver, const char *path, struct stat *buf)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (NULL == real_lstat)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original lstat() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  int result;
+  DONT_FAKE_TIME(result = real_lstat(ver, path, buf));
+  if (result == -1)
+  {
+    return -1;
+  }
+
+  if (buf != NULL)
+  {
+    if (!fake_stat_disabled)
+    {
+      fake_statbuf(buf);
+    }
+  }
+  return result;
+}
+
+/* Contributed by Philipp Hachtmann in version 0.6 */
+int __xstat64 (int ver, const char *path, struct stat64 *buf)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (NULL == real_stat64)
+  { /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original stat() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  int result;
+  DONT_FAKE_TIME(result = real_stat64(ver, path, buf));
+  if (result == -1)
+  {
+    return -1;
+  }
+
+  if (buf != NULL)
+  {
+    if (!fake_stat_disabled)
+    {
+      fake_stat64buf(buf);
+    }
+  }
+  return result;
+}
+
+/* Contributed by Philipp Hachtmann in version 0.6 */
+int __fxstat64 (int ver, int fildes, struct stat64 *buf)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (NULL == real_fstat64)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original fstat() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  int result;
+  DONT_FAKE_TIME(result = real_fstat64(ver, fildes, buf));
+  if (result == -1)
+  {
+    return -1;
+  }
+
+  if (buf != NULL)
+  {
+    if (!fake_stat_disabled)
+    {
+      fake_stat64buf(buf);
+    }
+  }
+  return result;
+}
+
+/* Added in v0.8 as suggested by Daniel Kahn Gillmor */
+#ifndef NO_ATFILE
+int __fxstatat64 (int ver, int fildes, const char *filename, struct stat64 *buf, int flag)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (NULL == real_fstatat64)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original fstatat64() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  int result;
+  DONT_FAKE_TIME(result = real_fstatat64(ver, fildes, filename, buf, flag));
+  if (result == -1)
+  {
+    return -1;
+  }
+
+  if (buf != NULL)
+  {
+    if (!fake_stat_disabled)
+    {
+      fake_stat64buf(buf);
+    }
+  }
+  return result;
+}
+#endif
+
+/* Contributed by Philipp Hachtmann in version 0.6 */
+int __lxstat64 (int ver, const char *path, struct stat64 *buf)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (NULL == real_lstat64)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original lstat() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  int result;
+  DONT_FAKE_TIME(result = real_lstat64(ver, path, buf));
+  if (result == -1)
+  {
+    return -1;
+  }
+
+  if (buf != NULL)
+  {
+    if (!fake_stat_disabled)
+    {
+      fake_stat64buf(buf);
+    }
+  }
+  return result;
+}
+#endif
+
+/*
+ *      =======================================================================
+ *      Faked system functions: sleep/alarm/poll/timer related  === FAKE(SLEEP)
+ *      =======================================================================
+ *      Contributed by Balint Reczey in v0.9.5
+ */
+
+#ifdef FAKE_SLEEP
+/*
+ * Faked nanosleep()
+ */
+int nanosleep(const struct timespec *req, struct timespec *rem)
+{
+  int result;
+  struct timespec real_req;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (real_nanosleep == NULL)
+  {
+    return -1;
+  }
+  if (req != NULL)
+  {
+    if (user_rate_set && !dont_fake)
+    {
+      timespecmul(req, 1.0 / user_rate, &real_req);
+    }
+    else
+    {
+      real_req = *req;
+    }
+  }
+  else
+  {
+    return -1;
+  }
+
+  DONT_FAKE_TIME(result = (*real_nanosleep)(&real_req, rem));
+  if (result == -1)
+  {
+    return result;
+  }
+
+  /* fake returned parts */
+  if ((rem != NULL) && ((rem->tv_sec != 0) || (rem->tv_nsec != 0)))
+  {
+    if (user_rate_set && !dont_fake)
+    {
+      timespecmul(rem, user_rate, rem);
+    }
+  }
+  /* return the result to the caller */
+  return result;
+}
+
+/*
+ * Faked usleep()
+ */
+int usleep(useconds_t usec)
+{
+  int result;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (user_rate_set && !dont_fake)
+  {
+    struct timespec real_req;
+
+    if (real_nanosleep == NULL)
+    {
+      /* fall back to usleep() */
+      if (real_usleep == NULL)
+      {
+        return -1;
+      }
+      DONT_FAKE_TIME(result = (*real_usleep)((1.0 / user_rate) * usec));
+      return result;
+    }
+
+    real_req.tv_sec = usec / 1000000;
+    real_req.tv_nsec = (usec % 1000000) * 1000;
+    timespecmul(&real_req, 1.0 / user_rate, &real_req);
+    DONT_FAKE_TIME(result = (*real_nanosleep)(&real_req, NULL));
+  }
+  else
+  {
+    DONT_FAKE_TIME(result = (*real_usleep)(usec));
+  }
+  return result;
+}
+
+/*
+ * Faked sleep()
+ */
+unsigned int sleep(unsigned int seconds)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (user_rate_set && !dont_fake)
+  {
+    if (real_nanosleep == NULL)
+    {
+      /* fall back to sleep */
+      unsigned int ret;
+      if (real_sleep == NULL)
+      {
+        return 0;
+      }
+      DONT_FAKE_TIME(ret = (*real_sleep)((1.0 / user_rate) * seconds));
+      return (user_rate_set && !dont_fake)?(user_rate * ret):ret;
+    }
+    else
+    {
+      int result;
+      struct timespec real_req = {seconds, 0}, rem;
+      timespecmul(&real_req, 1.0 / user_rate, &real_req);
+      DONT_FAKE_TIME(result = (*real_nanosleep)(&real_req, &rem));
+      if (result == -1)
+      {
+        return 0;
+      }
+
+      /* fake returned parts */
+      if ((rem.tv_sec != 0) || (rem.tv_nsec != 0))
+      {
+        timespecmul(&rem, user_rate, &rem);
+      }
+      /* return the result to the caller */
+      return rem.tv_sec;
+    }
+  }
+  else
+  {
+    /* no need to fake anything */
+    unsigned int ret;
+    DONT_FAKE_TIME(ret = (*real_sleep)(seconds));
+    return ret;
+  }
+}
+
+/*
+ * Faked alarm()
+ * @note due to rounding alarm(2) with faketime -f '+0 x7' won't wait 2/7
+ * wall clock seconds but 0 seconds
+ */
+unsigned int alarm(unsigned int seconds)
+{
+  unsigned int ret;
+  unsigned int seconds_real = (user_rate_set && !dont_fake)?((1.0 / user_rate) * seconds):seconds;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (real_alarm == NULL)
+  {
+    return -1;
+  }
+
+  DONT_FAKE_TIME(ret = (*real_alarm)(seconds_real));
+  return (user_rate_set && !dont_fake)?(user_rate * ret):ret;
+}
+
+/*
+ * Faked ppoll()
+ */
+int ppoll(struct pollfd *fds, nfds_t nfds,
+    const struct timespec *timeout_ts, const sigset_t *sigmask)
+{
+  struct timespec real_timeout, *real_timeout_pt;
+  int ret;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (real_ppoll == NULL)
+  {
+    return -1;
+  }
+  if (timeout_ts != NULL)
+  {
+    if (user_rate_set && !dont_fake && (timeout_ts->tv_sec > 0))
+    {
+      timespecmul(timeout_ts, 1.0 / user_rate, &real_timeout);
+      real_timeout_pt = &real_timeout;
+    }
+    else
+    {
+      /* cast away constness */
+      real_timeout_pt = (struct timespec *)timeout_ts;
+    }
+  }
+  else
+  {
+    real_timeout_pt = NULL;
+  }
+
+  DONT_FAKE_TIME(ret = (*real_ppoll)(fds, nfds, real_timeout_pt, sigmask));
+  return ret;
+}
+
+/*
+ * Faked poll()
+ */
+int poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+  int ret, timeout_real = (user_rate_set && !dont_fake && (timeout > 0))?(timeout / user_rate):timeout;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (real_poll == NULL)
+  {
+    return -1;
+  }
+
+  DONT_FAKE_TIME(ret = (*real_poll)(fds, nfds, timeout_real));
+  return ret;
+}
+
+/*
+ * Faked select()
+ */
+int select(int nfds, fd_set *readfds,
+           fd_set *writefds,
+           fd_set *errorfds,
+           struct timeval *timeout)
+{
+  int ret;
+  struct timeval timeout_real;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+
+  if (real_select == NULL)
+  {
+    return -1;
+  }
+
+  if (timeout != NULL)
+  {
+    if (user_rate_set && !dont_fake && (timeout->tv_sec > 0 || timeout->tv_usec > 0))
+    {
+      struct timespec ts;
+
+      ts.tv_sec = timeout->tv_sec;
+      ts.tv_nsec = timeout->tv_usec * 1000;
+
+      timespecmul(&ts, 1.0 / user_rate, &ts);
+
+      timeout_real.tv_sec = ts.tv_sec;
+      timeout_real.tv_usec = ts.tv_nsec / 1000;
+    }
+    else
+    {
+      timeout_real.tv_sec = timeout->tv_sec;
+      timeout_real.tv_usec = timeout->tv_usec;
+    }
+  }
+
+  DONT_FAKE_TIME(ret = (*real_select)(nfds, readfds, writefds, errorfds, timeout == NULL ? timeout : &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__
+#ifdef FAKE_TIMERS
+
+/* timer related functions and structures */
+typedef union {
+  int int_member;
+  timer_t timer_t_member;
+} timer_t_or_int;
+
+/*
+ * Faketime's function implementation's compatibility mode
+ */
+typedef enum {FT_COMPAT_GLIBC_2_2, FT_COMPAT_GLIBC_2_3_3} ft_lib_compat;
+
+
+/*
+ * Faked timer_settime()
+ * Does not affect timer speed when stepping clock with each time() call.
+ */
+static int
+timer_settime_common(timer_t_or_int timerid, int flags,
+         const struct itimerspec *new_value,
+         struct itimerspec *old_value, ft_lib_compat compat)
+{
+  int result;
+  struct itimerspec new_real;
+  struct itimerspec *new_real_pt = &new_real;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (new_value == NULL)
+  {
+    new_real_pt = NULL;
+  }
+  else if (dont_fake)
+  {
+    /* cast away constness*/
+    new_real_pt = (struct itimerspec *)new_value;
+  }
+  else
+  {
+    /* set it_value */
+    if ((new_value->it_value.tv_sec != 0) ||
+        (new_value->it_value.tv_nsec != 0))
+    {
+      if (flags & TIMER_ABSTIME)
+      {
+        struct timespec tdiff, timeadj;
+        timespecsub(&new_value->it_value, &user_faked_time_timespec, &timeadj);
+        if (user_rate_set)
+        {
+          timespecmul(&timeadj, 1.0/user_rate, &tdiff);
+        }
+        else
+        {
+          tdiff = timeadj;
+        }
+        /* only CLOCK_REALTIME is handled */
+        timespecadd(&ftpl_starttime.real, &tdiff, &new_real.it_value);
+      }
+      else
+      {
+        if (user_rate_set)
+        {
+          timespecmul(&new_value->it_value, 1.0/user_rate, &new_real.it_value);
+        }
+        else
+        {
+          new_real.it_value = new_value->it_value;
+        }
+      }
+    }
+    else
+    {
+      new_real.it_value = new_value->it_value;
+    }
+    /* set it_interval */
+    if (user_rate_set && ((new_value->it_interval.tv_sec != 0) ||
+       (new_value->it_interval.tv_nsec != 0)))
+    {
+      timespecmul(&new_value->it_interval, 1.0/user_rate, &new_real.it_interval);
+    }
+    else
+    {
+      new_real.it_interval = new_value->it_interval;
+    }
+  }
+
+  switch (compat)
+  {
+    case FT_COMPAT_GLIBC_2_2:
+      DONT_FAKE_TIME(result = (*real_timer_settime_22)(timerid.int_member, flags,
+                    new_real_pt, old_value));
+      break;
+    case FT_COMPAT_GLIBC_2_3_3:
+       DONT_FAKE_TIME(result = (*real_timer_settime_233)(timerid.timer_t_member,
+                    flags, new_real_pt, old_value));
+       break;
+    default:
+      result = -1;
+      break;
+  }
+
+  if (result == -1)
+  {
+    return result;
+  }
+
+  /* fake returned parts */
+  if ((old_value != NULL) && !dont_fake)
+  {
+    if ((old_value->it_value.tv_sec != 0) ||
+        (old_value->it_value.tv_nsec != 0))
+    {
+      result = fake_clock_gettime(CLOCK_REALTIME, &old_value->it_value);
+    }
+    if (user_rate_set && ((old_value->it_interval.tv_sec != 0) ||
+       (old_value->it_interval.tv_nsec != 0)))
+    {
+      timespecmul(&old_value->it_interval, user_rate, &old_value->it_interval);
+    }
+  }
+
+  /* return the result to the caller */
+  return result;
+}
+
+/*
+ * Faked timer_settime() compatible with implementation in GLIBC 2.2
+ */
+int timer_settime_22(int timerid, int flags,
+         const struct itimerspec *new_value,
+         struct itimerspec *old_value)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (real_timer_settime_22 == NULL)
+  {
+    return -1;
+  }
+  else
+  {
+    return (timer_settime_common((timer_t_or_int)timerid, flags, new_value, old_value,
+            FT_COMPAT_GLIBC_2_2));
+  }
+}
+
+/*
+ * Faked timer_settime() compatible with implementation in GLIBC 2.3.3
+ */
+int timer_settime_233(timer_t timerid, int flags,
+      const struct itimerspec *new_value,
+      struct itimerspec *old_value)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (real_timer_settime_233 == NULL)
+  {
+    return -1;
+  }
+  else
+  {
+    return (timer_settime_common((timer_t_or_int)timerid, flags, new_value, old_value,
+            FT_COMPAT_GLIBC_2_3_3));
+  }
+}
+
+/*
+ * Faked timer_gettime()
+ * Does not affect timer speed when stepping clock with each time() call.
+ */
+int timer_gettime_common(timer_t_or_int timerid, struct itimerspec *curr_value, ft_lib_compat compat)
+{
+  int result;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (real_timer_gettime_233 == NULL)
+  {
+    return -1;
+  }
+
+  switch (compat)
+  {
+    case FT_COMPAT_GLIBC_2_2:
+      DONT_FAKE_TIME(result = (*real_timer_gettime_22)(timerid.int_member, curr_value));
+      break;
+    case FT_COMPAT_GLIBC_2_3_3:
+      DONT_FAKE_TIME(result = (*real_timer_gettime_233)(timerid.timer_t_member, curr_value));
+      break;
+    default:
+      result = -1;
+      break;
+  }
+
+  if (result == -1)
+  {
+    return result;
+  }
+
+  /* fake returned parts */
+  if (curr_value != NULL)
+  {
+    if (user_rate_set && !dont_fake)
+    {
+      timespecmul(&curr_value->it_interval, user_rate, &curr_value->it_interval);
+      timespecmul(&curr_value->it_value, user_rate, &curr_value->it_value);
+    }
+  }
+  /* return the result to the caller */
+  return result;
+}
+
+/*
+ * Faked timer_gettime() compatible with implementation in GLIBC 2.2
+ */
+int timer_gettime_22(timer_t timerid, struct itimerspec *curr_value)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (real_timer_gettime_22 == NULL)
+  {
+    return -1;
+  }
+  else
+  {
+    return (timer_gettime_common((timer_t_or_int)timerid, curr_value,
+         FT_COMPAT_GLIBC_2_2));
+  }
+}
+
+/*
+ * Faked timer_gettime() compatible with implementation in GLIBC 2.3.3
+ */
+int timer_gettime_233(timer_t timerid, struct itimerspec *curr_value)
+{
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  if (real_timer_gettime_233 == NULL)
+  {
+    return -1;
+  }
+  else
+  {
+    return (timer_gettime_common((timer_t_or_int)timerid, curr_value,
+            FT_COMPAT_GLIBC_2_3_3));
+  }
+}
+
+__asm__(".symver timer_gettime_22, timer_gettime@GLIBC_2.2");
+__asm__(".symver timer_gettime_233, timer_gettime@@GLIBC_2.3.3");
+__asm__(".symver timer_settime_22, timer_settime@GLIBC_2.2");
+__asm__(".symver timer_settime_233, timer_settime@@GLIBC_2.3.3");
+
+#endif
+#endif
+
+
+/*
+ *      =======================================================================
+ *      Faked system functions: basic time functions             === FAKE(TIME)
+ *      =======================================================================
+ */
+
+/*
+ * time() implementation using clock_gettime()
+ * @note Does not check for EFAULT, see man 2 time
+ */
+time_t time(time_t *time_tptr)
+{
+  struct timespec tp;
+  time_t result;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
+  if (result == -1) return -1;
+
+  /* pass the real current time to our faking version, overwriting it */
+  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
+
+  if (time_tptr != NULL)
+  {
+    *time_tptr = tp.tv_sec;
+  }
+  return tp.tv_sec;
+}
+
+int ftime(struct timeb *tb)
+{
+  struct timespec tp;
+  int result;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  /* sanity check */
+  if (tb == NULL)
+    return 0;               /* ftime() always returns 0, see manpage */
+
+  /* Check whether we've got a pointer to the real ftime() function yet */
+  if (NULL == real_ftime)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original ftime() not found.\n");
+#endif
+    return 0; /* propagate error to caller */
+  }
+
+  /* initialize our TZ result with the real current time */
+  DONT_FAKE_TIME(result = (*real_ftime)(tb));
+  if (result == -1)
+  {
+    return result;
+  }
+
+  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
+  if (result == -1) return -1;
+
+  /* pass the real current time to our faking version, overwriting it */
+  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
+
+  tb->time = tp.tv_sec;
+  tb->millitm = tp.tv_nsec / 1000000;
+
+  /* return the result to the caller */
+  return result; /* will always be 0 (see manpage) */
+}
+
+int gettimeofday(struct timeval *tv, void *tz)
+{
+  int result;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  /* sanity check */
+  if (tv == NULL)
+  {
+    return -1;
+  }
+
+  /* Check whether we've got a pointer to the real ftime() function yet */
+  if (NULL == real_gettimeofday)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original gettimeofday() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  /* initialize our result with the real current time */
+  DONT_FAKE_TIME(result = (*real_gettimeofday)(tv, tz));
+  if (result == -1) return result; /* original function failed */
+
+  /* pass the real current time to our faking version, overwriting it */
+  result = fake_gettimeofday(tv);
+
+  /* return the result to the caller */
+  return result;
+}
+
+int clock_gettime(clockid_t clk_id, struct timespec *tp)
+{
+  int result;
+
+  if (!initialized)
+  {
+    ftpl_init();
+  }
+  /* sanity check */
+  if (tp == NULL)
+  {
+    return -1;
+  }
+
+  if (NULL == real_clock_gettime)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original clock_gettime() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  /* initialize our result with the real current time */
+  DONT_FAKE_TIME(result = (*real_clock_gettime)(clk_id, tp));
+  if (result == -1) return result; /* original function failed */
+
+  /* pass the real current time to our faking version, overwriting it */
+  if (fake_monotonic_clock || clk_id != CLOCK_MONOTONIC)
+  {
+    result = fake_clock_gettime(clk_id, tp);
+  }
+
+  /* return the result to the caller */
+  return result;
+}
+
+
+/*
+ *      =======================================================================
+ *      Parsing the user's faketime requests                          === PARSE
+ *      =======================================================================
+ */
+
+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])
+  {
+
+    default:  /* Try and interpret this as a specified time */
+      if (ft_mode != FT_NOOP) ft_mode = FT_FREEZE;
+      user_faked_time_tm.tm_isdst = -1;
+      if (NULL != strptime(user_faked_time, user_faked_time_fmt, &user_faked_time_tm))
+      {
+        user_faked_time_timespec.tv_sec = mktime(&user_faked_time_tm);
+        user_faked_time_timespec.tv_nsec = 0;
+        user_faked_time_set = true;
+      }
+      else
+      {
+        perror("Failed to parse FAKETIME timestamp");
+        exit(EXIT_FAILURE);
+      }
+      break;
+
+    case '+':
+    case '-': /* User-specified offset */
+      if (ft_mode != FT_NOOP) ft_mode = FT_START_AT;
+      /* fractional time offsets contributed by Karl Chen in v0.8 */
+      double frac_offset = atof(user_faked_time);
+
+      /* offset is in seconds by default, but the string may contain
+       * multipliers...
+       */
+      if (strchr(user_faked_time, 'm') != NULL) frac_offset *= 60;
+      else if (strchr(user_faked_time, 'h') != NULL) frac_offset *= 60 * 60;
+      else if (strchr(user_faked_time, 'd') != NULL) frac_offset *= 60 * 60 * 24;
+      else if (strchr(user_faked_time, 'y') != NULL) frac_offset *= 60 * 60 * 24 * 365;
+
+      user_offset.tv_sec = floor(frac_offset);
+      user_offset.tv_nsec = (frac_offset - user_offset.tv_sec) * SEC_TO_nSEC;
+      timespecadd(&ftpl_starttime.real, &user_offset, &user_faked_time_timespec);
+      goto parse_modifiers;
+      break;
+
+      /* Contributed by David North, TDI in version 0.7 */
+    case '@': /* Specific time, but clock along relative to that starttime */
+      ft_mode = FT_START_AT;
+      user_faked_time_tm.tm_isdst = -1;
+      (void) strptime(&user_faked_time[1], user_faked_time_fmt, &user_faked_time_tm);
+
+      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;
+
+    case 'i':
+    case 'x': /* Only modifiers are passed, don't fall back to strptime */
+parse_modifiers:
+      /* Speed-up / slow-down contributed by Karl Chen in v0.8 */
+      if (strchr(user_faked_time, 'x') != NULL)
+      {
+        user_rate = atof(strchr(user_faked_time, 'x')+1);
+        user_rate_set = true;
+      }
+      else if (NULL != (tmp_time_fmt = strchr(user_faked_time, 'i')))
+      {
+        double tick_inc = atof(tmp_time_fmt + 1);
+        /* increment time with every time() call*/
+        user_per_tick_inc.tv_sec = floor(tick_inc);
+        user_per_tick_inc.tv_nsec = (tick_inc - user_per_tick_inc.tv_sec) * SEC_TO_nSEC ;
+        user_per_tick_inc_set = true;
+      }
+      break;
+  } // end of switch
+
+  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
+}
+
+
+/*
+ *      =======================================================================
+ *      Initialization                                                 === INIT
+ *      =======================================================================
+ */
+
+void ftpl_init(void)
+{
+  char *tmp_env;
+  bool dont_fake_final;
+
+#ifdef __APPLE__
+  const char *progname = getprogname();
+#else
+  const char *progname = __progname;
+#endif
+
+  /* Look up all real_* functions. NULL will mark missing ones. */
+  real_stat =               dlsym(RTLD_NEXT, "__xstat");
+  real_fstat =              dlsym(RTLD_NEXT, "__fxstat");
+  real_fstatat =            dlsym(RTLD_NEXT, "__fxstatat");
+  real_lstat =              dlsym(RTLD_NEXT, "__lxstat");
+  real_stat64 =             dlsym(RTLD_NEXT,"__xstat64");
+  real_fstat64 =            dlsym(RTLD_NEXT, "__fxstat64");
+  real_fstatat64 =          dlsym(RTLD_NEXT, "__fxstatat64");
+  real_lstat64 =            dlsym(RTLD_NEXT, "__lxstat64");
+  real_time =               dlsym(RTLD_NEXT, "time");
+  real_ftime =              dlsym(RTLD_NEXT, "ftime");
+  real_gettimeofday =       dlsym(RTLD_NEXT, "gettimeofday");
+#ifdef FAKE_SLEEP
+  real_nanosleep =          dlsym(RTLD_NEXT, "nanosleep");
+  real_usleep =             dlsym(RTLD_NEXT, "usleep");
+  real_sleep =              dlsym(RTLD_NEXT, "sleep");
+  real_alarm =              dlsym(RTLD_NEXT, "alarm");
+  real_poll =               dlsym(RTLD_NEXT, "poll");
+  real_ppoll =              dlsym(RTLD_NEXT, "ppoll");
+  real_select =             dlsym(RTLD_NEXT, "select");
+  real_sem_timedwait =      dlsym(RTLD_NEXT, "sem_timedwait");
+#endif
+#ifdef FAKE_INTERNAL_CALLS
+  real___ftime =              dlsym(RTLD_NEXT, "__ftime");
+  real___gettimeofday =       dlsym(RTLD_NEXT, "__gettimeofday");
+  real___clock_gettime  =     dlsym(RTLD_NEXT, "__clock_gettime");
+#endif
+#ifdef __APPLEOSX__
+  real_clock_get_time =     dlsym(RTLD_NEXT, "clock_get_time");
+  real_clock_gettime  =     apple_clock_gettime;
+#else
+  real_clock_gettime  =     dlsym(RTLD_NEXT, "__clock_gettime");
+  if (NULL == real_clock_gettime)
+  {
+    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)
+  {
+    real_timer_settime_233 =  dlsym(RTLD_NEXT, "timer_settime");
+  }
+  real_timer_gettime_22 =   dlvsym(RTLD_NEXT, "timer_gettime","GLIBC_2.2");
+  real_timer_gettime_233 =  dlvsym(RTLD_NEXT, "timer_gettime","GLIBC_2.3.3");
+  if (NULL == real_timer_gettime_233)
+  {
+    real_timer_gettime_233 =  dlsym(RTLD_NEXT, "timer_gettime");
+  }
+#endif
+#endif
+#endif
+
+  dont_fake = true; // Do not fake times during initialization
+  dont_fake_final = false;
+  initialized = 1;
+
+  ft_shm_init();
+#ifdef FAKE_STAT
+  if (getenv("NO_FAKE_STAT")!=NULL)
+  {
+    fake_stat_disabled = 1;  //Note that this is NOT re-checked
+  }
+#endif
+
+  if ((tmp_env = getenv("FAKETIME_CACHE_DURATION")) != NULL)
+  {
+    cache_duration = atoi(tmp_env);
+  }
+  if ((tmp_env = getenv("FAKETIME_NO_CACHE")) != NULL)
+  {
+    if (0 == strcmp(tmp_env, "1"))
+    {
+      cache_enabled = 0;
+    }
+  }
+  if ((tmp_env = getenv("DONT_FAKE_MONOTONIC")) != NULL)
+  {
+    if (0 == strcmp(tmp_env, "1"))
+    {
+      fake_monotonic_clock = 0;
+    }
+  }
+  /* Check whether we actually should be faking the returned timestamp. */
+
+  /* We can prevent faking time for specified commands */
+  if ((tmp_env = getenv("FAKETIME_SKIP_CMDS")) != NULL)
+  {
+    char *skip_cmd, *saveptr, *tmpvar;
+    /* Don't mess with the env variable directly. */
+    tmpvar = strdup(tmp_env);
+    if (tmpvar != NULL)
+    {
+      skip_cmd = strtok_r(tmpvar, ",", &saveptr);
+      while (skip_cmd != NULL)
+      {
+        if (0 == strcmp(progname, skip_cmd))
+        {
+          ft_mode = FT_NOOP;
+          dont_fake_final = true;
+          break;
+        }
+        skip_cmd = strtok_r(NULL, ",", &saveptr);
+      }
+      free(tmpvar);
+      tmpvar = NULL;
+    }
+    else
+    {
+      fprintf(stderr, "Error: Could not copy the environment variable value.\n");
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  /* We can limit faking time to specified commands */
+  if ((tmp_env = getenv("FAKETIME_ONLY_CMDS")) != NULL)
+  {
+    char *only_cmd, *saveptr, *tmpvar;
+    bool cmd_matched = false;
+
+    if (getenv("FAKETIME_SKIP_CMDS") != NULL)
+    {
+      fprintf(stderr, "Error: Both FAKETIME_SKIP_CMDS and FAKETIME_ONLY_CMDS can't be set.\n");
+      exit(EXIT_FAILURE);
+    }
+
+    /* Don't mess with the env variable directly. */
+    tmpvar = strdup(tmp_env);
+    if (tmpvar != NULL) {
+      only_cmd = strtok_r(tmpvar, ",", &saveptr);
+      while (only_cmd != NULL)
+      {
+        if (0 == strcmp(progname, only_cmd))
+        {
+          cmd_matched = true;
+          break;
+        }
+        only_cmd = strtok_r(NULL, ",", &saveptr);
+      }
+
+      if (!cmd_matched)
+      {
+        ft_mode = FT_NOOP;
+        dont_fake_final = true;
+      }
+      free(tmpvar);
+    } else {
+      fprintf(stderr, "Error: Could not copy the environment variable value.\n");
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  if ((tmp_env = getenv("FAKETIME_START_AFTER_SECONDS")) != NULL)
+  {
+    ft_start_after_secs = atol(tmp_env);
+    limited_faking = true;
+  }
+  if ((tmp_env = getenv("FAKETIME_STOP_AFTER_SECONDS")) != NULL)
+  {
+    ft_stop_after_secs = atol(tmp_env);
+    limited_faking = true;
+  }
+  if ((tmp_env = getenv("FAKETIME_START_AFTER_NUMCALLS")) != NULL)
+  {
+    ft_start_after_ncalls = atol(tmp_env);
+    limited_faking = true;
+  }
+  if ((tmp_env = getenv("FAKETIME_STOP_AFTER_NUMCALLS")) != NULL)
+  {
+    ft_stop_after_ncalls = atol(tmp_env);
+    limited_faking = true;
+  }
+
+  /* check whether we should spawn an external command */
+  if ((tmp_env = getenv("FAKETIME_SPAWN_TARGET")) != NULL)
+  {
+    spawnsupport = true;
+    (void) strncpy(ft_spawn_target, getenv("FAKETIME_SPAWN_TARGET"), 1024);
+    if ((tmp_env = getenv("FAKETIME_SPAWN_SECONDS")) != NULL)
+    {
+      ft_spawn_secs = atol(tmp_env);
+    }
+    if ((tmp_env = getenv("FAKETIME_SPAWN_NUMCALLS")) != NULL)
+    {
+      ft_spawn_ncalls = atol(tmp_env);
+    }
+  }
+
+  if ((tmp_env = getenv("FAKETIME_SAVE_FILE")) != NULL)
+  {
+    if (-1 == (outfile = open(tmp_env, O_RDWR | O_APPEND | O_CLOEXEC | O_CREAT,
+                              S_IWUSR | S_IRUSR)))
+    {
+      perror("Opening file for saving timestamps failed");
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  /* load file only if reading timstamps from it is not finished yet */
+  if ((tmp_env = getenv("FAKETIME_LOAD_FILE")) != NULL)
+  {
+    int infile = -1;
+    struct stat sb;
+    if (-1 == (infile = open(tmp_env, O_RDONLY|O_CLOEXEC)))
+    {
+      perror("Opening file for loading timestamps failed");
+      exit(EXIT_FAILURE);
+    }
+
+    fstat(infile, &sb);
+    if (sizeof(stss[0]) > (infile_size = sb.st_size))
+    {
+      printf("There are no timestamps in the provided file to load timestamps from");
+      exit(EXIT_FAILURE);
+    }
+
+    if ((infile_size % sizeof(stss[0])) != 0)
+    {
+      printf("File size is not multiple of timestamp size. It is probably damaged.");
+      exit(EXIT_FAILURE);
+    }
+
+    stss = mmap(NULL, infile_size, PROT_READ, MAP_SHARED, infile, 0);
+    if (stss == MAP_FAILED)
+    {
+      perror("Mapping file for loading timestamps failed");
+      exit(EXIT_FAILURE);
+    }
+    infile_set = true;
+  }
+
+  tmp_env = getenv("FAKETIME_FMT");
+  if (tmp_env == NULL)
+  {
+    strcpy(user_faked_time_fmt, "%Y-%m-%d %T");
+  }
+  else
+  {
+    strncpy(user_faked_time_fmt, tmp_env, BUFSIZ);
+  }
+
+  if (shared_sem != 0)
+  {
+    if (sem_wait(shared_sem) == -1)
+    {
+      perror("sem_wait");
+      exit(1);
+    }
+    if (ft_shared->start_time.real.tv_nsec == -1)
+    {
+      /* set up global start time */
+      system_time_from_system(&ftpl_starttime);
+      ft_shared->start_time = ftpl_starttime;
+    }
+    else
+    {
+      /** get preset start time */
+      ftpl_starttime = ft_shared->start_time;
+    }
+    if (sem_post(shared_sem) == -1)
+    {
+      perror("sem_post");
+      exit(1);
+    }
+  }
+  else
+  {
+    system_time_from_system(&ftpl_starttime);
+  }
+  /* fake time supplied as environment variable? */
+  if (NULL != (tmp_env = getenv("FAKETIME")))
+  {
+    parse_config_file = false;
+    parse_ft_string(tmp_env);
+  }
+
+  dont_fake = dont_fake_final;
+}
+
+
+/*
+ *      =======================================================================
+ *      Helper functions                                             === HELPER
+ *      =======================================================================
+ */
+
+static void remove_trailing_eols(char *line)
+{
+  char *endp = line + strlen(line);
+  /*
+   * erase the last char if it's a newline
+   * or carriage return, and back up.
+   * keep doing this, but don't back up
+   * past the beginning of the string.
+   */
+# define is_eolchar(c) ((c) == '\n' || (c) == '\r')
+  while (endp > line && is_eolchar(endp[-1]))
+  {
+    *--endp = '\0';
+  }
+}
+
+
+/*
+ *      =======================================================================
+ *      Implementation of faked functions                        === FAKE(FAKE)
+ *      =======================================================================
+ */
+
+int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
+{
+  /* variables used for caching, introduced in version 0.6 */
+  static time_t last_data_fetch = 0;  /* not fetched previously at first call */
+  static int cache_expired = 1;       /* considered expired at first call */
+
+  if (dont_fake) return 0;
+  /* Per process timers are only sped up or slowed down */
+  if ((clk_id == CLOCK_PROCESS_CPUTIME_ID ) || (clk_id == CLOCK_THREAD_CPUTIME_ID))
+  {
+    if (user_rate_set)
+    {
+      timespecmul(tp, user_rate, tp);
+    }
+    return 0;
+  }
+
+  /* Sanity check by Karl Chan since v0.8 */
+  if (tp == NULL) return -1;
+
+#ifdef PTHREAD_SINGLETHREADED_TIME
+  static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
+  pthread_mutex_lock(&time_mutex);
+  pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, (void *)&time_mutex);
+#endif
+
+  if ((limited_faking &&
+     ((ft_start_after_ncalls != -1) || (ft_stop_after_ncalls != -1))) ||
+     (spawnsupport && ft_spawn_ncalls))
+  {
+    if (callcounter < LONG_MAX) callcounter++;
+  }
+
+  if (limited_faking || spawnsupport)
+  {
+    struct timespec tmp_ts;
+    /* For debugging, output #seconds and #calls */
+    switch (clk_id)
+    {
+      case CLOCK_REALTIME:
+#ifdef CLOCK_REALTIME_COARSE
+      case CLOCK_REALTIME_COARSE:
+#endif
+        timespecsub(tp, &ftpl_starttime.real, &tmp_ts);
+        break;
+      case CLOCK_MONOTONIC:
+#ifdef CLOCK_MONOTONIC_COARSE
+      case CLOCK_MONOTONIC_COARSE:
+#endif
+        timespecsub(tp, &ftpl_starttime.mon, &tmp_ts);
+        break;
+      case CLOCK_MONOTONIC_RAW:
+        timespecsub(tp, &ftpl_starttime.mon_raw, &tmp_ts);
+        break;
+#ifdef CLOCK_BOOTTIME
+      case CLOCK_BOOTTIME:
+        timespecsub(tp, &ftpl_starttime.boot, &tmp_ts);
+        break;
+#endif
+      default:
+        printf("Invalid clock_id for clock_gettime: %d", clk_id);
+        exit(EXIT_FAILURE);
+    }
+
+    if (limited_faking)
+    {
+      /* Check whether we actually should be faking the returned timestamp. */
+      /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
+      if ((ft_start_after_secs != -1)   && (tmp_ts.tv_sec < ft_start_after_secs)) return 0;
+      if ((ft_stop_after_secs != -1)    && (tmp_ts.tv_sec >= ft_stop_after_secs)) return 0;
+      if ((ft_start_after_ncalls != -1) && (callcounter < ft_start_after_ncalls)) return 0;
+      if ((ft_stop_after_ncalls != -1)  && (callcounter >= ft_stop_after_ncalls)) return 0;
+      /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu continues\n", (*time_tptr - ftpl_starttime), callcounter); */
+    }
+
+    if (spawnsupport)
+    {
+      /* check whether we should spawn an external command */
+      if (spawned == 0)
+      { /* exec external command once only */
+        if (((tmp_ts.tv_sec == ft_spawn_secs) || (callcounter == ft_spawn_ncalls)) && (spawned == 0))
+        {
+          spawned = 1;
+          (void) (system(ft_spawn_target) + 1);
+        }
+      }
+    }
+  }
+
+  if (last_data_fetch > 0)
+  {
+    if ((tp->tv_sec - last_data_fetch) > cache_duration)
+    {
+      cache_expired = 1;
+    }
+    else
+    {
+      cache_expired = 0;
+    }
+  }
+
+  if (cache_enabled == 0)
+  {
+    cache_expired = 1;
+  }
+
+  if (cache_expired == 1)
+  {
+    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)
+    {
+      char custom_filename[BUFSIZ];
+      char filename[BUFSIZ];
+      FILE *faketimerc;
+      /* 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,
+       * Jacob Moorman, and Wayne Davison of SourceForge, Inc. in version 0.6 */
+      (void) snprintf(custom_filename, BUFSIZ, "%s", getenv("FAKETIME_TIMESTAMP_FILE"));
+      (void) snprintf(filename, BUFSIZ, "%s/.faketimerc", getenv("HOME"));
+      if ((faketimerc = fopen(custom_filename, "rt")) != NULL ||
+          (faketimerc = fopen(filename, "rt")) != NULL ||
+          (faketimerc = fopen("/etc/faketimerc", "rt")) != NULL)
+      {
+        char line[BUFFERLEN];
+        while(fgets(line, BUFFERLEN, faketimerc) != NULL)
+        {
+          if ((strlen(line) > 1) && (line[0] != ' ') &&
+              (line[0] != '#') && (line[0] != ';'))
+          {
+            remove_trailing_eols(line);
+            strncpy(user_faked_time, line, BUFFERLEN-1);
+            user_faked_time[BUFFERLEN-1] = 0;
+            break;
+          }
+        }
+        fclose(faketimerc);
+      }
+    } /* read fake time from file */
+    parse_ft_string(user_faked_time);
+  } /* cache had expired */
+
+  if (infile_set)
+  {
+    if (load_time(tp))
+    {
+      return 0;
+    }
+  }
+
+  /* check whether the user gave us an absolute time to fake */
+  switch (ft_mode)
+  {
+    case FT_FREEZE:  /* a specified time */
+      if (user_faked_time_set)
+      {
+        *tp = user_faked_time_timespec;
+      }
+      break;
+
+    case FT_START_AT: /* User-specified offset */
+      if (user_per_tick_inc_set)
+      {
+        /* increment time with every time() call*/
+        next_time(tp, &user_per_tick_inc);
+      }
+      else
+      {
+        /* Speed-up / slow-down contributed by Karl Chen in v0.8 */
+        struct timespec tdiff, timeadj;
+        switch (clk_id)
+        {
+          case CLOCK_REALTIME:
+#ifdef CLOCK_REALTIME_COARSE
+          case CLOCK_REALTIME_COARSE:
+#endif
+            timespecsub(tp, &ftpl_starttime.real, &tdiff);
+            break;
+          case CLOCK_MONOTONIC:
+#ifdef CLOCK_MONOTONIC_COARSE
+          case CLOCK_MONOTONIC_COARSE:
+#endif
+            timespecsub(tp, &ftpl_starttime.mon, &tdiff);
+            break;
+          case CLOCK_MONOTONIC_RAW:
+            timespecsub(tp, &ftpl_starttime.mon_raw, &tdiff);
+            break;
+#ifdef CLOCK_BOOTTIME
+          case CLOCK_BOOTTIME:
+            timespecsub(tp, &ftpl_starttime.boot, &tdiff);
+            break;
+#endif
+          default:
+            printf("Invalid clock_id for clock_gettime: %d", clk_id);
+            exit(EXIT_FAILURE);
+        } // end of switch (clk_id)
+        if (user_rate_set)
+        {
+          timespecmul(&tdiff, user_rate, &timeadj);
+        }
+        else
+        {
+          timeadj = tdiff;
+        }
+        timespecadd(&user_faked_time_timespec, &timeadj, tp);
+      }
+      break;
+
+    default:
+      return -1;
+  } // end of switch(ft_mode)
+
+#ifdef PTHREAD_SINGLETHREADED_TIME
+  pthread_cleanup_pop(1);
+#endif
+  save_time(tp);
+  return 0;
+}
+
+int fake_gettimeofday(struct timeval *tv)
+{
+  struct timespec ts;
+  int ret;
+  ts.tv_sec = tv->tv_sec;
+  ts.tv_nsec = tv->tv_usec * 1000  + ftpl_starttime.real.tv_nsec % 1000;
+
+  ret = fake_clock_gettime(CLOCK_REALTIME, &ts);
+  tv->tv_sec = ts.tv_sec;
+  tv->tv_usec =ts.tv_nsec / 1000;
+
+  return ret;
+}
+
+
+/*
+ *      =======================================================================
+ *      Faked system functions: Apple Mac OS X specific           === FAKE(OSX)
+ *      =======================================================================
+ */
+
+#ifdef __APPLEOSX__
+/*
+ * clock_gettime implementation for __APPLE__
+ * @note It always behave like being called with CLOCK_REALTIME.
+ */
+static int apple_clock_gettime(clockid_t clk_id, struct timespec *tp)
+{
+  int result;
+  mach_timespec_t cur_timeclockid_t;
+  (void) clk_id; /* unused */
+
+  if (NULL == real_clock_get_time)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original clock_get_time() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  DONT_FAKE_TIME(result = (*real_clock_get_time)(clock_serv_real, &cur_timeclockid_t));
+  tp->tv_sec =  cur_timeclockid_t.tv_sec;
+  tp->tv_nsec = cur_timeclockid_t.tv_nsec;
+  return result;
+}
+
+int clock_get_time(clock_serv_t clock_serv, mach_timespec_t *cur_timeclockid_t)
+{
+  int result;
+  struct timespec ts;
+
+  /*
+   * Initialize our result with the real current time from CALENDAR_CLOCK.
+   * This is a bit of cheating, but we don't keep track of obtained clock
+   * services.
+   */
+  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &ts));
+  if (result == -1) return result; /* original function failed */
+
+  /* pass the real current time to our faking version, overwriting it */
+  result = fake_clock_gettime(CLOCK_REALTIME, &ts);
+  cur_timeclockid_t->tv_sec = ts.tv_sec;
+  cur_timeclockid_t->tv_nsec = ts.tv_nsec;
+
+  /* return the result to the caller */
+  return result;
+}
+#endif
+
+
+/*
+ *      =======================================================================
+ *      Faked system-internal functions                           === FAKE(INT)
+ *      =======================================================================
+ */
+
+#ifdef FAKE_INTERNAL_CALLS
+int __gettimeofday(struct timeval *tv, void *tz)
+{
+  int result;
+
+  /* sanity check */
+  if (tv == NULL)
+  {
+    return -1;
+  }
+
+  /* Check whether we've got a pointer to the real ftime() function yet */
+  if (NULL == real___gettimeofday)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original __gettimeofday() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  /* initialize our result with the real current time */
+  DONT_FAKE_TIME(result = (*real___gettimeofday)(tv, tz));
+  if (result == -1) return result; /* original function failed */
+
+  /* pass the real current time to our faking version, overwriting it */
+  result = fake_gettimeofday(tv);
+
+  /* return the result to the caller */
+  return result;
+}
+
+int __clock_gettime(clockid_t clk_id, struct timespec *tp)
+{
+  int result;
+
+  /* sanity check */
+  if (tp == NULL)
+  {
+    return -1;
+  }
+
+  if (NULL == real___clock_gettime)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original __clock_gettime() not found.\n");
+#endif
+    return -1; /* propagate error to caller */
+  }
+
+  /* initialize our result with the real current time */
+  DONT_FAKE_TIME(result = (*real___clock_gettime)(clk_id, tp));
+  if (result == -1) return result; /* original function failed */
+
+  /* pass the real current time to our faking version, overwriting it */
+  if (fake_monotonic_clock || clk_id != CLOCK_MONOTONIC)
+  {
+    result = fake_clock_gettime(clk_id, tp);
+  }
+
+  /* return the result to the caller */
+  return result;
+}
+
+time_t __time(time_t *time_tptr)
+{
+  struct timespec tp;
+  time_t result;
+
+  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
+  if (result == -1) return -1;
+
+  /* pass the real current time to our faking version, overwriting it */
+  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
+
+  if (time_tptr != NULL)
+  {
+    *time_tptr = tp.tv_sec;
+  }
+  return tp.tv_sec;
+}
+
+int __ftime(struct timeb *tb)
+{
+  struct timespec tp;
+  int result;
+
+  /* sanity check */
+  if (tb == NULL)
+    return 0;               /* ftime() always returns 0, see manpage */
+
+  /* Check whether we've got a pointer to the real ftime() function yet */
+  if (NULL == real___ftime)
+  {  /* dlsym() failed */
+#ifdef DEBUG
+    (void) fprintf(stderr, "faketime problem: original ftime() not found.\n");
+#endif
+    return 0; /* propagate error to caller */
+  }
+
+  /* initialize our TZ result with the real current time */
+  DONT_FAKE_TIME(result = (*real___ftime)(tb));
+  if (result == -1)
+  {
+    return result;
+  }
+
+  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
+  if (result == -1) return -1;
+
+  /* pass the real current time to our faking version, overwriting it */
+  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
+
+  tb->time = tp.tv_sec;
+  tb->millitm = tp.tv_nsec / 1000000;
+
+  /* return the result to the caller */
+  return result; /* will always be 0 (see manpage) */
+}
+
+#endif
+
+/*
+ * Editor modelines
+ *
+ * Local variables:
+ * c-basic-offset: 2
+ * tab-width: 2
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=2 tabstop=2 expandtab:
+ * :indentSize=2:tabSize=2:noTabs=true:
+ */
+
+/* eof */
diff --git a/scripts/libfaketime/libfaketime.map b/scripts/libfaketime/libfaketime.map
new file mode 100644
index 0000000..6e008cf
--- /dev/null
+++ b/scripts/libfaketime/libfaketime.map
@@ -0,0 +1,10 @@
+GLIBC_2.2 {
+  global:
+
+  timer_gettime; timer_settime;
+  local: timer_settime_*; timer_gettime_*;
+};
+GLIBC_2.3.3 {
+  # Changed timer_t.
+  timer_gettime; timer_settime;
+} GLIBC_2.2;
diff --git a/scripts/libfaketime/time_ops.h b/scripts/libfaketime/time_ops.h
new file mode 100644
index 0000000..59ab1ee
--- /dev/null
+++ b/scripts/libfaketime/time_ops.h
@@ -0,0 +1,104 @@
+/*
+ * Time operation macros based on sys/time.h
+ * Copyright 2013 Balint Reczey <balint@balintreczey.hu>
+ *
+ * This file is part of libfaketime.
+ *
+ * libfaketime is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License v2 as published by the Free
+ * Software Foundation.
+ *
+ * libfaketime is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License v2 along
+ * with libfaketime; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef TIME_OPS_H
+#define TIME_OPS_H
+#include <time.h>
+
+#define SEC_TO_uSEC 1000000
+#define SEC_TO_nSEC 1000000000
+
+/* Convenience macros for operations on timevals.
+   NOTE: `timercmp' does not work for >= or <=.  */
+#define timerisset2(tvp, prefix) ((tvp)->tv_sec || (tvp)->tv_##prefix##sec)
+#define timerclear2(tvp, prefix) ((tvp)->tv_sec = (tvp)->tv_##prefix##sec = 0)
+#define timercmp2(a, b, CMP, prefix)                                \
+  (((a)->tv_sec == (b)->tv_sec) ?                                   \
+   ((a)->tv_##prefix##sec CMP (b)->tv_##prefix##sec) :              \
+   ((a)->tv_sec CMP (b)->tv_sec))
+#define timeradd2(a, b, result, prefix)                             \
+  do                                                                \
+  {                                                                 \
+    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                   \
+    (result)->tv_##prefix##sec = (a)->tv_##prefix##sec +            \
+      (b)->tv_##prefix##sec;                                        \
+    if ((result)->tv_##prefix##sec >= SEC_TO_##prefix##SEC)         \
+      {                                                             \
+        ++(result)->tv_sec;                                         \
+        (result)->tv_##prefix##sec -= SEC_TO_##prefix##SEC;         \
+      }                                                             \
+  } while (0)
+#define timersub2(a, b, result, prefix)                             \
+  do                                                                \
+  {                                                                 \
+    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                   \
+    (result)->tv_##prefix##sec = (a)->tv_##prefix##sec -            \
+      (b)->tv_##prefix##sec;                                        \
+    if ((result)->tv_##prefix##sec < 0)                             \
+    {                                                               \
+      --(result)->tv_sec;                                           \
+      (result)->tv_##prefix##sec += SEC_TO_##prefix##SEC;           \
+    }                                                               \
+  } while (0)
+#define timermul2(tvp, c, result, prefix)                           \
+  do                                                                \
+  {                                                                 \
+    long long tmp_time;                                             \
+    tmp_time = (c) * ((tvp)->tv_sec * SEC_TO_##prefix##SEC +        \
+               (tvp)->tv_##prefix##sec);                            \
+    (result)->tv_##prefix##sec = tmp_time % SEC_TO_##prefix##SEC;   \
+    (result)->tv_sec = (tmp_time - (result)->tv_##prefix##sec) /    \
+      SEC_TO_##prefix##SEC;                                         \
+    if ((result)->tv_##prefix##sec < 0)                             \
+    {                                                               \
+      (result)->tv_##prefix##sec +=  SEC_TO_##prefix##SEC;          \
+      (result)->tv_sec -= 1;                                        \
+    }                                                               \
+  } while (0)
+
+/* ops for microsecs */
+#ifndef timerisset
+#define timerisset(tvp) timerisset2(tvp,u)
+#endif
+#ifndef timerclear
+#define timerclear(tvp) timerclear2(tvp, u)
+#endif
+#ifndef timercmp
+#define timercmp(a, b, CMP) timercmp2(a, b, CMP, u)
+#endif
+#ifndef timeradd
+#define timeradd(a, b, result) timeradd2(a, b, result, u)
+#endif
+#ifndef timersub
+#define timersub(a, b, result) timersub2(a, b, result, u)
+#endif
+#ifndef timersub
+#define timermul(a, c, result) timermul2(a, c, result, u)
+#endif
+
+/* ops for nanosecs */
+#define timespecisset(tvp) timerisset2(tvp,n)
+#define timespecclear(tvp) timerclear2(tvp, n)
+#define timespeccmp(a, b, CMP) timercmp2(a, b, CMP, n)
+#define timespecadd(a, b, result) timeradd2(a, b, result, n)
+#define timespecsub(a, b, result) timersub2(a, b, result, n)
+#define timespecmul(a, c, result) timermul2(a, c, result, n)
+
+#endif
-- 
1.9.1


_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ptxdist] [PATCH v4 2/2] Detect changes in package patch series
  2018-08-03 15:44 [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support jon
@ 2018-08-03 15:44 ` jon
  2018-08-08  9:50 ` [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support Roland Hieber
  2018-08-27 16:27 ` Michael Olbrich
  2 siblings, 0 replies; 6+ messages in thread
From: jon @ 2018-08-03 15:44 UTC (permalink / raw)
  To: ptxdist; +Cc: Jon Ringle

From: Jon Ringle <jringle@gridpoint.com>

For a long time it has bothered me that if a package's patches were changed
ptxdist would not detect this change and I would often have old versions of
*-dev.tar.gz packages that got used because the packages patches were
updated.

This commit solves this problem.

Here's how it works:
1) In the package rule makefile add `${PKG}_SERIES_SHA256 :=`
2) extract the package. libfaketime is used to keep the committer timestamp
   to a fixed timestamp in order to keep the git SHA1 tree repeatable.
3) from the packages src dir do `git ptx-patches`
   This will populate the rule makefile _SERIES_SHA256 value
4) Anytime you make a patch change to a package and do `git ptx-patches`
   the series file gets updated with the `git rev-parse HEAD` value which
   causes the series file to have a new sha256 value and therefore a new
   value gets populated in the rule makefile, which then causes the package
   to be rebuilt and the *-dev.tar.gz package will have a different cfghash
   in the filename

Signed-off-by: Jon Ringle <jringle@gridpoint.com>
---
 scripts/git-ptx-patches                | 38 +++++++++++++++++++++++++++-------
 scripts/lib/ptxd_make_world_patchin.sh | 28 ++++++++++++++++++++++++-
 2 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/scripts/git-ptx-patches b/scripts/git-ptx-patches
index f2568f9..d37c936 100755
--- a/scripts/git-ptx-patches
+++ b/scripts/git-ptx-patches
@@ -2,9 +2,31 @@
 
 PTX_PATCHES_HEADER="# generated by git-ptx-patches"
 
-function _md5sum() {
-	local sum=$(md5sum)
-	echo "# $sum git-ptx-patches magic"
+function _gitsha1sum() {
+	local sha1=$(git rev-parse HEAD)
+	echo "# $sha1 git-ptx-patches magic"
+}
+
+update_series_sha256() {
+	local makefile="$(readlink -f .ptxdist/rule.make)"
+	source .ptxdist/rule.env
+	set -- $(sha256sum .ptxdist/series)
+	local sha256="${1}"
+
+	local count=$(grep "^${PKG}_SERIES_SHA256[	 ]*:=" "${makefile}" 2> /dev/null | wc -l)
+	if [ "${count}" -gt 1 ]; then
+		echo "Error: Could not update patch series sha256sum for '${pkg_label}': ${PKG}_SERIES_SHA256 found ${count} times in '${makefile}'."
+		exit 1
+	fi
+	local current_sha256=$(grep "^${PKG}_SERIES_SHA256[	 ]*:= " "${makefile}" |cut -f2 -d=|xargs)
+	if [ "${current_sha256}" != "${sha256}" ]; then
+		sed -i "s/^\(\<${PKG}_SERIES_SHA256[	]*:=\) *[a-f0-9]*\$/\1 ${sha256}/" "${makefile}"
+		if ! grep -q "${sha256}\$" "${makefile}"; then
+			echo "Warning: ${PKG}_SERIES_SHA256 is missing from '${makefile}'."
+		else
+			echo "New patch series checksum for '${pkg_label}': ${sha256} in '${makefile}'."
+		fi
+	fi
 }
 
 if [ ! -L .ptxdist/patches ]; then
@@ -22,10 +44,8 @@ tag=base
 
 if grep -q "$PTX_PATCHES_HEADER" .ptxdist/series; then
 	echo "Found series file generated by git-ptx-patches."
-	lines=$(wc -l < .ptxdist/series)
-	lines=$[lines-1]
-	magic=$(head -n$lines .ptxdist/series | _md5sum)
-	if grep -q "^$magic" .ptxdist/series; then
+	magic=$(git rev-parse HEAD)
+	if grep -q "^# $magic" .ptxdist/series; then
 		remove_old=yes
 	else
 		echo "Warning: .ptxdist/series was modified."
@@ -132,7 +152,9 @@ cat .ptxdist/series.0 > .ptxdist/series
 git format-patch -M -N $GIT_EXTRA_ARGS ${tagopt} -o .ptxdist/patches/ ${range} | sed -e 's,^.ptxdist/patches/,,' > .ptxdist/series.auto
 cat .ptxdist/series.auto >> .ptxdist/series
 cat .ptxdist/series.1 >> .ptxdist/series
-cat .ptxdist/series | _md5sum >> .ptxdist/series
+cat .ptxdist/series | _gitsha1sum >> .ptxdist/series
+
+update_series_sha256
 
 # The first line of the patch is 'From <some-git-hash> ...'
 # remove it to avoid unnecessary changes in the patch files.
diff --git a/scripts/lib/ptxd_make_world_patchin.sh b/scripts/lib/ptxd_make_world_patchin.sh
index e57da64..cb31244 100644
--- a/scripts/lib/ptxd_make_world_patchin.sh
+++ b/scripts/lib/ptxd_make_world_patchin.sh
@@ -221,6 +221,8 @@ ptxd_make_world_patchin_apply()
 	pkg_patch_series \
 	pkg_patch_tool
 
+    local PKG="$(ptxd_name_to_NAME "${pkg_label}")"
+
     if [[ "${pkg_url}" =~ ^file:// ]]; then
 	local url="$(ptxd_file_url_path "${pkg_url}")"
 	# local directories are not intended to be patched
@@ -255,6 +257,16 @@ ptxd_make_world_patchin_apply()
     mkdir "${pkg_patchin_dir}/.ptxdist" &&
 
     #
+    # create a ".ptxdist/rule.make" link pointing to the packages rule makefile
+    #
+    ln -s "${pkg_makefile}" "${pkg_patchin_dir}/.ptxdist/rule.make" &&
+    (
+	cat <<-EOF
+	PKG=${PKG}
+	pkg_label=${pkg_label}
+	EOF
+    ) > "${pkg_patchin_dir}/.ptxdist/rule.env" &&
+    #
     # create a ".ptxdist/patches" link pointing to the directory
     # containing the patches
     #
@@ -341,6 +353,7 @@ ptxd_make_world_patchin_apply()
     echo
     echo "pkg_patch_dir:     '$(ptxd_print_path "${pkg_patch_dir:-<none>}")'"
     echo "pkg_patch_series:  '$(ptxd_print_path "${pkg_patch_series:-<none>}")'"
+    echo "pkg_makefile:    '$(ptxd_print_path "${pkg_makefile:-<none>}")'"
     echo
 
     # apply patches if series file is available
@@ -437,6 +450,7 @@ export -f ptxd_make_world_autogen
 # pkg_patchin_dir	where to apply the patches
 # pkg_patch_dir		path to dir that contains the patches
 #			empty if no patches should be applied
+# pkg_makefile		the package's rule makefile
 #
 ptxd_make_world_patchin_init()
 {
@@ -463,6 +477,14 @@ ptxd_make_world_patchin_init()
 	return
     fi
     pkg_patch_dir="${ptxd_reply}"
+
+    #
+    # find rules make
+    #
+    if ! ptxd_find_pkg_makefile "${pkg_label}" ; then
+	return
+    fi
+    pkg_makefile="$(readlink -f "${ptxd_reply}")"
 }
 export -f ptxd_make_world_patchin_init
 
@@ -471,8 +493,12 @@ ptxd_make_world_patchin()
     ptxd_make_world_patchin_init || return
 
     if [ -n "${pkg_patch_dir}" ]; then (
+	local libfaketime="${PTXDIST_TOPDIR}/scripts/libfaketime/libfaketime.so.1"
 	cd "${pkg_patchin_dir}" &&
-	ptxd_make_world_patchin_apply
+	( LD_PRELOAD="${libfaketime}" \
+	  FAKETIME="2002-01-15 13:30:00" \
+	  ptxd_make_world_patchin_apply
+	)
      ) else
 	echo -e "patchin: no patches found"
     fi
-- 
1.9.1


_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support
  2018-08-03 15:44 [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support jon
  2018-08-03 15:44 ` [ptxdist] [PATCH v4 2/2] Detect changes in package patch series jon
@ 2018-08-08  9:50 ` Roland Hieber
  2018-08-08 10:58   ` Jon Ringle
  2018-08-27 16:27 ` Michael Olbrich
  2 siblings, 1 reply; 6+ messages in thread
From: Roland Hieber @ 2018-08-08  9:50 UTC (permalink / raw)
  To: ptxdist; +Cc: ptxdist, Jon Ringle

On Fri, Aug 03, 2018 at 11:44:55AM -0400, jon@ringle.org wrote:
> From: Jon Ringle <jringle@gridpoint.com>
> 
> libfaketime will be used during patchin so that committer timestamps always
> have a fixed value and therefore making the ${PKG}_SERIES_SHA256 value
> repeatable
> 
> The minimal set of source files was picked out of libfaketime-0.9.7
> 
> Signed-off-by: Jon Ringle <jringle@gridpoint.com>
> ---
>  Makefile.in                           |   14 +-
>  scripts/libfaketime/Makefile          |  118 ++
>  scripts/libfaketime/faketime.c        |  385 ++++++
>  scripts/libfaketime/faketime_common.h |   61 +
>  scripts/libfaketime/libfaketime.c     | 2410 +++++++++++++++++++++++++++++++++
>  scripts/libfaketime/libfaketime.map   |   10 +
>  scripts/libfaketime/time_ops.h        |  104 ++

Uh. Does it really make more sense to vendor libfaketime instead of
using the package from the host system, like we do it with python, bash,
etc.?

 - Roland

>  7 files changed, 3101 insertions(+), 1 deletion(-)
>  create mode 100644 scripts/libfaketime/Makefile
>  create mode 100644 scripts/libfaketime/faketime.c
>  create mode 100644 scripts/libfaketime/faketime_common.h
>  create mode 100644 scripts/libfaketime/libfaketime.c
>  create mode 100644 scripts/libfaketime/libfaketime.map
>  create mode 100644 scripts/libfaketime/time_ops.h
> 
> diff --git a/Makefile.in b/Makefile.in
> index 40c676c..6e08377 100644
> --- a/Makefile.in
> +++ b/Makefile.in
> @@ -22,7 +22,7 @@ export SHELL
>  
>  @BUILD_NCONF_TRUE@NCONF = nconf
>  
> -all: kconfig environment
> +all: kconfig libfaketime environment
>  	@touch .done
>  
>  kconfig:
> @@ -41,6 +41,17 @@ kconfig:
>  		conf mconf $(NCONF)
>  	@echo "done."
>  
> +libfaketime:
> +	@echo "building libfaketime ..."
> +	@CC="$(CC)" \
> +	CXX="$(CXX)" \
> +	CFLAGS="$(CFLAGS)" \
> +	CXXFLAGS="$(CXXFLAGS)" \
> +	CPPFLAGS="$(CPPFLAGS)" \
> +	LDFLAGS="$(LDFLAGS)" \
> +	$(MAKE) -C "$(abs_srcdir)/scripts/libfaketime" all
> +	@echo "done."
> +
>  environment:
>  	@echo -n "preparing PTXdist environment ..."
>  	@ln -sf @AWK@ "$(abs_srcdir)/bin/awk"
> @@ -89,6 +100,7 @@ clean:
>  	@rm -f .done
>  	@find "$(abs_srcdir)/bin" -type l -print0 | xargs -0 rm -f
>  	@$(MAKE) -C "$(abs_srcdir)/scripts/kconfig" clean
> +	@$(MAKE) -C "$(abs_srcdir)/scripts/libfaketime" clean
>  
>  dirty-check:
>  	@case "$(version)" in \
> diff --git a/scripts/libfaketime/Makefile b/scripts/libfaketime/Makefile
> new file mode 100644
> index 0000000..a557c38
> --- /dev/null
> +++ b/scripts/libfaketime/Makefile
> @@ -0,0 +1,118 @@
> +#
> +# Notes:
> +#
> +#   * Compilation Defines:
> +#
> +#     FAKE_STAT
> +#         - Enables time faking also for files' timestamps.
> +#
> +#     NO_ATFILE
> +#         - Disables support for the fstatat() group of functions
> +#
> +#     PTHREAD
> +#         - Define this to enable multithreading support.
> +#
> +#     PTHREAD_SINGLETHREADED_TIME
> +#         - Define this if you want to single-thread time() ... there ARE
> +#           possibile caching side-effects in a multithreaded environment
> +#           without this, but the performance impact may require you to
> +#           try it unsynchronized.
> +#
> +#     FAKE_INTERNAL_CALLS
> +#         - Also intercept libc internal __functions, e.g. not just time(),
> +#           but also __time(). Enhances compatibility with applications
> +#           that make use of low-level system calls, such as Java Virtual
> +#           Machines.
> +#
> +# 	  FAKE_SLEEP
> +# 	      - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
> +#
> +#	  FAKE_TIMERS
> +#	      - Also intercept timer_settime() and timer_gettime()
> +#
> +#	  MULTI_ARCH
> +#	  	  - If MULTI_ARCH is set, the faketime wrapper program will put a literal
> +#	  	    $LIB into the LD_PRELOAD environment variable it creates, which makes
> +#	  	    ld automatically choose the correct library version to use for the
> +#	  	    target binary. Use for Linux platforms with Multi-Arch support only!
> +#
> +#   * Compilation addition: second libMT target added for building the pthread-
> +#     enabled library as a separate library
> +#
> +#   * Compilation switch change: previous versions compiled using '-nostartfiles'
> +#     This is no longer the case since there is a 'startup' constructor for the library
> +#     which is used to activate the start-at times when specified. This also initializes
> +#     the dynamic disabling of the FAKE_STAT calls.
> +#
> +# By default, libfaketime will be compiled for your system's default architecture.
> +# To build 32-bit libraries and binaries, add -m32 to CFLAGS and LDFLAGS.
> +#
> +# Change PREFIX to where you want libfaketime (libraries and wrapper binary) installed.
> +# LIBDIRNAME is relative to PREFIX. The default is to install into $PREFIX/lib/faketime,
> +# but you can set LIBDIRNAME to, e.g., /lib64 if you want to install it elsewhere.
> +# LIBDIRNAME has been introduced to support MultiLib systems. Please do not change the 
> +# default value on MultiArch systems. 
> +#
> +# For testing in the current directory without installation, try make PREFIX= LIBDIRNAME='.'
> +
> +CC ?= gcc
> +INSTALL ?= install
> +
> +PREFIX ?= /usr/local
> +LIBDIRNAME ?= /lib/faketime
> +PLATFORM ?=$(shell uname)
> +
> +CFLAGS += -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -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 += -lpthread
> +ifneq ($(PLATFORM),SunOS)
> +LDFLAGS += -Wl,--version-script=libfaketime.map
> +endif
> +
> +LDADD += -ldl -lm -lrt
> +BIN_LDFLAGS += -lrt
> +
> +SRC = libfaketime.c
> +LIBS_OBJ = libfaketime.o libfaketimeMT.o
> +BINS = faketime
> +
> +SONAME = 1
> +LIBS = libfaketime.so.${SONAME} libfaketimeMT.so.${SONAME}
> +
> +all: ${LIBS} ${BINS}
> +
> +libfaketimeMT.o: EXTRA_FLAGS := -DPTHREAD -DPTHREAD_SINGLETHREADED_TIME
> +
> +${LIBS_OBJ}: libfaketime.c
> +	${CC} -o $@ -c ${CFLAGS} ${EXTRA_FLAGS} $<
> +
> +%.so.${SONAME}: %.o libfaketime.map
> +	${CC} -o $@ -Wl,-soname,$@ ${LDFLAGS} ${LIB_LDFLAGS} $< ${LDADD}
> +
> +${BINS}: faketime.c
> +	${CC} -o $@ ${CFLAGS} ${EXTRA_FLAGS} $< ${LDFLAGS} ${BIN_LDFLAGS}
> +
> +clean:
> +	@rm -f ${LIBS_OBJ} ${LIBS} ${BINS}
> +
> +distclean: clean
> +	@echo
> +
> +install: ${LIBS} ${BINS}
> +	@echo
> +	@echo "Copying the faketime libraries to ${DESTDIR}${PREFIX}${LIBDIRNAME} and the faketime wrapper script to ${DESTDIR}${PREFIX}/bin ..."
> +	$(INSTALL) -dm0755 "${DESTDIR}${PREFIX}${LIBDIRNAME}/"
> +	$(INSTALL) -m0644 ${LIBS} "${DESTDIR}${PREFIX}${LIBDIRNAME}/"
> +	$(INSTALL) -Dm0755 faketime "${DESTDIR}${PREFIX}/bin/faketime"
> +
> +uninstall:
> +	for f in ${LIBS}; do rm -f "${DESTDIR}${PREFIX}${LIBDIRNAME}/$$f"; done
> +	rmdir "${DESTDIR}${PREFIX}${LIBDIRNAME}"
> +	rm -f "${DESTDIR}${PREFIX}/bin/faketime"
> +
> +.PHONY: all clean distclean install uninstall
> diff --git a/scripts/libfaketime/faketime.c b/scripts/libfaketime/faketime.c
> new file mode 100644
> index 0000000..138ebbd
> --- /dev/null
> +++ b/scripts/libfaketime/faketime.c
> @@ -0,0 +1,385 @@
> +/*
> + *  libfaketime wrapper command
> + *
> + *  This file is part of libfaketime, version 0.9.7
> + *
> + *  libfaketime is free software; you can redistribute it and/or modify it
> + *  under the terms of the GNU General Public License v2 as published by the
> + *  Free Software Foundation.
> + *
> + *  libfaketime is distributed in the hope that it will be useful, but WITHOUT
> + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + *  more details.
> + *
> + *  You should have received a copy of the GNU General Public License v2 along
> + *  with the libfaketime; if not, write to the Free Software Foundation,
> + *  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + *
> + * Converted from shell script by Balint Reczey with the following credits
> + * and comments:
> + *
> + * Thanks to Daniel Kahn Gillmor for improvement suggestions.
> +
> + * This wrapper exposes only a small subset of the libfaketime functionality.
> + * Please see libfaketime's README file and man page for more details.
> +
> + * Acknowledgment: Parts of the functionality of this wrapper have been
> + * inspired by Matthias Urlichs' datefudge 1.14.
> +
> + * Compile time configuration: Path where the libfaketime libraries can be found
> + * on Linux/UNIX
> + *
> + */
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <time.h>
> +#include <fcntl.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include <sys/mman.h>
> +#include <semaphore.h>
> +
> +#include "faketime_common.h"
> +
> +const char version[] = "0.9.7";
> +
> +#ifdef __APPLE__
> +static const char *date_cmd = "gdate";
> +#else
> +static const char *date_cmd = "date";
> +#endif
> +
> +#define PATH_BUFSIZE 4096
> +
> +/* semaphore and shared memory names */
> +char sem_name[PATH_BUFSIZE] = {0}, shm_name[PATH_BUFSIZE] = {0};
> +
> +void usage(const char *name)
> +{
> +  printf("\n"
> +  "Usage: %s [switches] <timestamp> <program with arguments>\n"
> +  "\n"
> +  "This will run the specified 'program' with the given 'arguments'.\n"
> +  "The program will be tricked into seeing the given 'timestamp' as its starting date and time.\n"
> +  "The clock will continue to run from this timestamp. Please see the manpage (man faketime)\n"
> +  "for advanced options, such as stopping the wall clock and make it run faster or slower.\n"
> +  "\n"
> +  "The optional switches are:\n"
> +  "  -m                  : Use the multi-threaded version of libfaketime\n"
> +  "  -f                  : Use the advanced timestamp specification format (see manpage)\n"
> +  "  --exclude-monotonic : Prevent monotonic clock from drifting (not the raw monotonic one)\n"
> +  "\n"
> +  "Examples:\n"
> +  "%s 'last friday 5 pm' /bin/date\n"
> +  "%s '2008-12-24 08:15:42' /bin/date\n"
> +  "%s -f '+2,5y x10,0' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n"
> +  "%s -f '+2,5y x0,50' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n"
> +  "%s -f '+2,5y i2,0' /bin/bash -c 'date; while true; do date; sleep 1 ; done'\n"
> +  "In this single case all spawned processes will use the same global clock\n"
> +  "without restarting it at the start of each process.\n\n"
> +  "(Please note that it depends on your locale settings whether . or , has to be used for fractions)\n"
> +  "\n", name, name, name, name, name, name);
> +}
> +
> +/** Clean up shared objects */
> +static void cleanup_shobjs()
> +{
> +  if (-1 == sem_unlink(sem_name))
> +  {
> +    perror("sem_unlink");
> +  }
> +  if (-1 == shm_unlink(shm_name))
> +  {
> +    perror("shm_unlink");
> +  }
> +}
> +
> +int main (int argc, char **argv)
> +{
> +  pid_t child_pid;
> +  int curr_opt = 1;
> +  bool use_mt = false, use_direct = false;
> +  long offset;
> +
> +  while(curr_opt < argc)
> +  {
> +    if (0 == strcmp(argv[curr_opt], "-m"))
> +    {
> +      use_mt = true;
> +      curr_opt++;
> +      continue;
> +    }
> +    else if (0 == strcmp(argv[curr_opt], "-f"))
> +    {
> +      use_direct = true;
> +      curr_opt++;
> +      continue;
> +    }
> +    else if (0 == strcmp(argv[curr_opt], "--exclude-monotonic"))
> +    {
> +      setenv("DONT_FAKE_MONOTONIC", "1", true);
> +      curr_opt++;
> +      continue;
> +    }
> +    else if ((0 == strcmp(argv[curr_opt], "-v")) ||
> +             (0 == strcmp(argv[curr_opt], "--version")))
> +    {
> +      printf("\n%s: Version %s\n"
> +         "For usage information please use '%s --help'.\n",
> +         argv[0], version, argv[0]);
> +      exit(EXIT_SUCCESS);
> +    }
> +    else if ((0 == strcmp(argv[curr_opt], "-h")) ||
> +             (0 == strcmp(argv[curr_opt], "-?")) ||
> +             (0 == strcmp(argv[curr_opt], "--help")))
> +    {
> +      usage(argv[0]);
> +      exit(EXIT_SUCCESS);
> +    }
> +    else
> +    {
> +      /* we parsed all options */
> +      break;
> +    }
> +  }
> +
> +  /* we need at least a timestamp string and a command to run */
> +  if (argc - curr_opt < 2)
> +  {
> +    usage(argv[0]);
> +    exit(EXIT_FAILURE);
> +  }
> +
> +  if (!use_direct)
> +  {
> +    // TODO get seconds
> +    int pfds[2];
> +    (void) (pipe(pfds) + 1);
> +    int ret = EXIT_SUCCESS;
> +
> +    if (0 == (child_pid = fork()))
> +    {
> +      close(1);       /* close normal stdout */
> +      (void) (dup(pfds[1]) + 1);   /* make stdout same as pfds[1] */
> +      close(pfds[0]); /* we don't need this */
> +      if (EXIT_SUCCESS != execlp(date_cmd, date_cmd, "-d", argv[curr_opt], "+%s",(char *) NULL))
> +      {
> +        perror("Running (g)date failed");
> +        exit(EXIT_FAILURE);
> +      }
> +    }
> +    else
> +    {
> +      char buf[256] = {0}; /* e will have way less than 256 digits */
> +      close(pfds[1]);   /* we won't write to this */
> +      (void) (read(pfds[0], buf, 256) + 1);
> +      waitpid(child_pid, &ret, 0);
> +      if (ret != EXIT_SUCCESS)
> +      {
> +        printf("Error: Timestamp to fake not recognized, please re-try with a "
> +               "different timestamp.\n");
> +        exit(EXIT_FAILURE);
> +      }
> +      offset = atol(buf) - time(NULL);
> +      ret = snprintf(buf, sizeof(buf), "%s%ld", (offset >= 0)?"+":"", offset);
> +      setenv("FAKETIME", buf, true);
> +      close(pfds[0]); /* finished reading */
> +    }
> +  }
> +  else
> +  {
> +    /* simply pass format string along */
> +    setenv("FAKETIME", argv[curr_opt], true);
> +  }
> +  int keepalive_fds[2];
> +  (void) (pipe(keepalive_fds) + 1);
> +
> +  /* we just consumed the timestamp option */
> +  curr_opt++;
> +
> +  {
> +    /* create semaphores and shared memory */
> +    int shm_fd;
> +    sem_t *sem;
> +    struct ft_shared_s *ft_shared;
> +    char shared_objs[PATH_BUFSIZE];
> +
> +    /*
> +     * 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)))
> +    {
> +      perror("sem_open");
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    /* create shm */
> +    if (-1 == (shm_fd = shm_open(shm_name, O_CREAT|O_EXCL|O_RDWR, S_IWUSR|S_IRUSR)))
> +    {
> +      perror("shm_open");
> +      if (-1 == sem_unlink(argv[2]))
> +      {
> +        perror("sem_unlink");
> +      }
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    /* set shm size */
> +    if (-1 == ftruncate(shm_fd, sizeof(uint64_t)))
> +    {
> +      perror("ftruncate");
> +      cleanup_shobjs();
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    /* map shm */
> +    if (MAP_FAILED == (ft_shared = mmap(NULL, sizeof(struct ft_shared_s), PROT_READ|PROT_WRITE,
> +                        MAP_SHARED, shm_fd, 0)))
> +    {
> +      perror("mmap");
> +      cleanup_shobjs();
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    if (sem_wait(sem) == -1)
> +    {
> +      perror("sem_wait");
> +      cleanup_shobjs();
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    /* init elapsed time ticks to zero */
> +    ft_shared->ticks = 0;
> +    ft_shared->file_idx = 0;
> +    ft_shared->start_time.real.tv_sec = 0;
> +    ft_shared->start_time.real.tv_nsec = -1;
> +    ft_shared->start_time.mon.tv_sec = 0;
> +    ft_shared->start_time.mon.tv_nsec = -1;
> +    ft_shared->start_time.mon_raw.tv_sec = 0;
> +    ft_shared->start_time.mon_raw.tv_nsec = -1;
> +
> +    if (-1 == munmap(ft_shared, (sizeof(struct ft_shared_s))))
> +    {
> +      perror("munmap");
> +      cleanup_shobjs();
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    if (sem_post(sem) == -1)
> +    {
> +      perror("semop");
> +      cleanup_shobjs();
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    snprintf(shared_objs, PATH_BUFSIZE, "%s %s", sem_name, shm_name);
> +    setenv("FAKETIME_SHARED", shared_objs, true);
> +    sem_close(sem);
> +  }
> +
> +  {
> +    char *ftpl_path;
> +#ifdef __APPLE__
> +    ftpl_path = PREFIX "/libfaketime.1.dylib";
> +    FILE *check;
> +    check = fopen(ftpl_path, "ro");
> +    if (check == NULL)
> +    {
> +      ftpl_path = PREFIX "/lib/faketime/libfaketime.1.dylib";
> +    }
> +    else
> +    {
> +      fclose(check);
> +    }
> +    setenv("DYLD_INSERT_LIBRARIES", ftpl_path, true);
> +    setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", true);
> +#else
> +    {
> +      char *ld_preload_new, *ld_preload = getenv("LD_PRELOAD");
> +      size_t len;
> +      if (use_mt)
> +      {
> +        /*
> +         * on MultiArch platforms, such as Debian, we put a literal $LIB into LD_PRELOAD.
> +         */
> +#ifndef MULTI_ARCH
> +        ftpl_path = PREFIX LIBDIRNAME "/libfaketimeMT.so.1";
> +#else
> +        ftpl_path = PREFIX "/$LIB/faketime/libfaketimeMT.so.1";
> +#endif
> +      }
> +      else
> +      {
> +#ifndef MULTI_ARCH
> +        ftpl_path = PREFIX LIBDIRNAME "/libfaketime.so.1";
> +#else
> +        ftpl_path = PREFIX "/$LIB/faketime/libfaketime.so.1";
> +#endif
> +      }
> +      len = ((ld_preload)?strlen(ld_preload) + 1: 0) + 1 + strlen(ftpl_path);
> +      ld_preload_new = malloc(len);
> +      snprintf(ld_preload_new, len ,"%s%s%s", (ld_preload)?ld_preload:"",
> +              (ld_preload)?":":"", ftpl_path);
> +      setenv("LD_PRELOAD", ld_preload_new, true);
> +      free(ld_preload_new);
> +    }
> +#endif
> +  }
> +
> +  /* run command and clean up shared objects */
> +  if (0 == (child_pid = fork()))
> +  {
> +    close(keepalive_fds[0]); /* only parent needs to read this */
> +    if (EXIT_SUCCESS != execvp(argv[curr_opt], &argv[curr_opt]))
> +    {
> +      perror("Running specified command failed");
> +      exit(EXIT_FAILURE);
> +    }
> +  }
> +  else
> +  {
> +    int ret;
> +    char buf;
> +    close(keepalive_fds[1]); /* only children need keep this open */
> +    waitpid(child_pid, &ret, 0);
> +    (void) (read(keepalive_fds[0], &buf, 1) + 1); /* reads 0B when all children exit */
> +    cleanup_shobjs();
> +    if (WIFSIGNALED(ret))
> +    {
> +      fprintf(stderr, "Caught %s\n", strsignal(WTERMSIG(ret)));
> +      exit(EXIT_FAILURE);
> +    }
> +    exit(WEXITSTATUS(ret));
> +  }
> +
> +  return EXIT_SUCCESS;
> +}
> +
> +/*
> + * Editor modelines
> + *
> + * Local variables:
> + * c-basic-offset: 2
> + * tab-width: 2
> + * indent-tabs-mode: nil
> + * End:
> + *
> + * vi: set shiftwidth=2 tabstop=2 expandtab:
> + * :indentSize=2:tabSize=2:noTabs=true:
> + */
> +
> +/* eof */
> diff --git a/scripts/libfaketime/faketime_common.h b/scripts/libfaketime/faketime_common.h
> new file mode 100644
> index 0000000..9fda6a7
> --- /dev/null
> +++ b/scripts/libfaketime/faketime_common.h
> @@ -0,0 +1,61 @@
> +/*
> + * Faketime's common definitions
> + *
> + * Copyright 2013 Balint Reczey <balint@balintreczey.hu>
> + *
> + * This file is part of the libfaketime.
> + *
> + * libfaketime is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License v2 as published by the Free
> + * Software Foundation.
> + *
> + * libfaketime is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License v2 along
> + * with libfaketime; if not, write to the Free Software Foundation, Inc.,
> + * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef FAKETIME_COMMON_H
> +#define FAKETIME_COMMON_H
> +
> +#include <stdint.h>
> +
> +struct system_time_s
> +{
> +  /* System time according to CLOCK_REALTIME */
> +  struct timespec real;
> +  /* System time according to CLOCK_MONOTONIC */
> +  struct timespec mon;
> +  /* System time according to CLOCK_MONOTONIC_RAW */
> +  struct timespec mon_raw;
> +#ifdef CLOCK_BOOTTIME
> +  /* System time according to CLOCK_BOOTTIME */
> +  struct timespec boot;
> +#endif
> +};
> +
> +/* Data shared among faketime-spawned processes */
> +struct ft_shared_s
> +{
> +  /*
> +   * When advancing time linearly with each time(), etc. call, the calls are
> +   * counted here */
> +  uint64_t ticks;
> +  /* Index of timstamp to be loaded from file */
> +  uint64_t file_idx;
> +  /* System time Faketime started at */
> +  struct system_time_s start_time;
> +};
> +
> +/* These are all needed in order to properly build on OSX */
> +#ifdef __APPLE__
> +#include <mach/clock.h>
> +#include <mach/mach_host.h>
> +#include <mach/mach_port.h>
> +#endif
> +
> +#endif
> diff --git a/scripts/libfaketime/libfaketime.c b/scripts/libfaketime/libfaketime.c
> new file mode 100644
> index 0000000..eb2d01b
> --- /dev/null
> +++ b/scripts/libfaketime/libfaketime.c
> @@ -0,0 +1,2410 @@
> +/*
> + *  This file is part of libfaketime, version 0.9.7
> + *
> + *  libfaketime is free software; you can redistribute it and/or modify it
> + *  under the terms of the GNU General Public License v2 as published by the
> + *  Free Software Foundation.
> + *
> + *  libfaketime is distributed in the hope that it will be useful, but WITHOUT
> + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + *  more details.
> + *
> + *  You should have received a copy of the GNU General Public License v2 along
> + *  with the libfaketime; if not, write to the Free Software Foundation,
> + *  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +/*
> + *      =======================================================================
> + *      Global settings, includes, and macros                          === HEAD
> + *      =======================================================================
> + */
> +
> +#define _GNU_SOURCE             /* required to get RTLD_NEXT defined */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <stdbool.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <poll.h>
> +#include <time.h>
> +#include <math.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <semaphore.h>
> +#include <sys/mman.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <netinet/in.h>
> +#include <limits.h>
> +
> +#include "time_ops.h"
> +#include "faketime_common.h"
> +
> +/* pthread-handling contributed by David North, TDI in version 0.7 */
> +#ifdef PTHREAD
> +#include <pthread.h>
> +#endif
> +
> +#include <sys/timeb.h>
> +#include <dlfcn.h>
> +
> +#define BUFFERLEN   256
> +
> +#ifndef __APPLE__
> +extern char *__progname;
> +#ifdef __sun
> +#include "sunos_endian.h"
> +#else
> +#include <endian.h>
> +#endif
> +#else
> +/* endianness related macros */
> +#ifndef OSSwapHostToBigInt64
> +#define OSSwapHostToBigInt64(x) ((uint64_t)(x))
> +#endif
> +#define htobe64(x) OSSwapHostToBigInt64(x)
> +#ifndef OSSwapHostToLittleInt64
> +#define OSSwapHostToLittleInt64(x) OSSwapInt64(x)
> +#endif
> +#define htole64(x) OSSwapHostToLittleInt64(x)
> +#ifndef OSSwapBigToHostInt64
> +#define OSSwapBigToHostInt64(x) ((uint64_t)(x))
> +#endif
> +#define be64toh(x) OSSwapBigToHostInt64(x)
> +#ifndef OSSwapLittleToHostInt64
> +#define OSSwapLittleToHostInt64(x) OSSwapInt64(x)
> +#endif
> +#define le64toh(x) OSSwapLittleToHostInt64(x)
> +
> +/* clock_gettime() and related clock definitions are missing on __APPLE__ */
> +#ifndef CLOCK_REALTIME
> +/* from GNU C Library time.h */
> +/* Identifier for system-wide realtime clock. ( == 1) */
> +#define CLOCK_REALTIME               CALENDAR_CLOCK
> +/* Monotonic system-wide clock. (== 0) */
> +#define CLOCK_MONOTONIC              SYSTEM_CLOCK
> +/* High-resolution timer from the CPU.  */
> +#define CLOCK_PROCESS_CPUTIME_ID     2
> +/* Thread-specific CPU-time clock.  */
> +#define CLOCK_THREAD_CPUTIME_ID      3
> +/* Monotonic system-wide clock, not adjusted for frequency scaling.  */
> +#define CLOCK_MONOTONIC_RAW          4
> +typedef int clockid_t;
> +#include <mach/clock.h>
> +#include <mach/mach.h>
> +#endif
> +#endif
> +
> +/* some systems lack raw clock */
> +#ifndef CLOCK_MONOTONIC_RAW
> +#define CLOCK_MONOTONIC_RAW (CLOCK_MONOTONIC + 1)
> +#endif
> +
> +/*
> + * Per thread variable, which we turn on inside real_* calls to avoid modifying
> + * time multiple times of for the whole process to prevent faking time
> + */
> +static __thread bool dont_fake = false;
> +
> +/* Wrapper for function calls, which we want to return system time */
> +#define DONT_FAKE_TIME(call)          \
> +  {                                   \
> +    bool dont_fake_orig = dont_fake;  \
> +    if (!dont_fake)                   \
> +    {                                 \
> +      dont_fake = true;               \
> +    }                                 \
> +    call;                             \
> +    dont_fake = dont_fake_orig;       \
> +  } while (0)
> +
> +/* pointers to real (not faked) functions */
> +static int          (*real_stat)            (int, const char *, struct stat *);
> +static int          (*real_fstat)           (int, int, struct stat *);
> +static int          (*real_fstatat)         (int, int, const char *, struct stat *, int);
> +static int          (*real_lstat)           (int, const char *, struct stat *);
> +static int          (*real_stat64)          (int, const char *, struct stat64 *);
> +static int          (*real_fstat64)         (int, int , struct stat64 *);
> +static int          (*real_fstatat64)       (int, int , const char *, struct stat64 *, int);
> +static int          (*real_lstat64)         (int, const char *, struct stat64 *);
> +static time_t       (*real_time)            (time_t *);
> +static int          (*real_ftime)           (struct timeb *);
> +static int          (*real_gettimeofday)    (struct timeval *, void *);
> +static int          (*real_clock_gettime)   (clockid_t clk_id, struct timespec *tp);
> +#ifdef FAKE_INTERNAL_CALLS
> +static int          (*real___ftime)           (struct timeb *);
> +static int          (*real___gettimeofday)    (struct timeval *, void *);
> +static int          (*real___clock_gettime)   (clockid_t clk_id, struct timespec *tp);
> +#endif
> +#ifndef __APPLEOSX__
> +#ifdef FAKE_TIMERS
> +static int          (*real_timer_settime_22)   (int timerid, int flags, const struct itimerspec *new_value,
> +                                                struct itimerspec * old_value);
> +static int          (*real_timer_settime_233)  (timer_t timerid, int flags,
> +                                                const struct itimerspec *new_value,
> +                                                struct itimerspec * old_value);
> +static int          (*real_timer_gettime_22)   (int timerid,
> +                                                struct itimerspec *curr_value);
> +static int          (*real_timer_gettime_233)  (timer_t timerid,
> +                                                struct itimerspec *curr_value);
> +#endif
> +#endif
> +#ifdef FAKE_SLEEP
> +static int          (*real_nanosleep)       (const struct timespec *req, struct timespec *rem);
> +static int          (*real_usleep)          (useconds_t usec);
> +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_select)          (int nfds, fd_set *restrict readfds,
> +                                             fd_set *restrict writefds,
> +                                             fd_set *restrict errorfds,
> +                                             struct timeval *restrict timeout);
> +static int          (*real_sem_timedwait)   (sem_t*, const struct timespec*);
> +#endif
> +#ifdef __APPLEOSX__
> +static int          (*real_clock_get_time)  (clock_serv_t clock_serv, mach_timespec_t *cur_timeclockid_t);
> +static int          apple_clock_gettime     (clockid_t clk_id, struct timespec *tp);
> +static clock_serv_t clock_serv_real;
> +#endif
> +
> +static int initialized = 0;
> +
> +/* prototypes */
> +static int    fake_gettimeofday(struct timeval *tv);
> +static int    fake_clock_gettime(clockid_t clk_id, struct timespec *tp);
> +
> +/** Semaphore protecting shared data */
> +static sem_t *shared_sem = NULL;
> +
> +/** Data shared among faketime-spawned processes */
> +static struct ft_shared_s *ft_shared = NULL;
> +
> +/** Storage format for timestamps written to file. Big endian.*/
> +struct saved_timestamp
> +{
> +  int64_t sec;
> +  uint64_t nsec;
> +};
> +
> +static inline void timespec_from_saved (struct timespec *tp,
> +  struct saved_timestamp *saved)
> +{
> +  /* read as big endian */
> +  tp->tv_sec = be64toh(saved->sec);
> +  tp->tv_nsec = be64toh(saved->nsec);
> +}
> +
> +/** Saved timestamps */
> +static struct saved_timestamp *stss = NULL;
> +static size_t infile_size;
> +static bool infile_set = false;
> +
> +/** File fd to save timestamps to */
> +static int outfile = -1;
> +
> +static bool limited_faking = false;
> +static long callcounter = 0;
> +static long ft_start_after_secs = -1;
> +static long ft_stop_after_secs = -1;
> +static long ft_start_after_ncalls = -1;
> +static long ft_stop_after_ncalls = -1;
> +
> +static bool spawnsupport = false;
> +static int spawned = 0;
> +static char ft_spawn_target[1024];
> +static long ft_spawn_secs = -1;
> +static long ft_spawn_ncalls = -1;
> +
> +static int fake_monotonic_clock = 1;
> +static int cache_enabled = 1;
> +static int cache_duration = 10;     /* cache fake time input for 10 seconds */
> +
> +/*
> + * Static timespec to store our startup time, followed by a load-time library
> + * initialization declaration.
> + */
> +#ifndef CLOCK_BOOTTIME
> +static struct system_time_s ftpl_starttime = {{0, -1}, {0, -1}, {0, -1}};
> +#else
> +static struct system_time_s ftpl_starttime = {{0, -1}, {0, -1}, {0, -1}, {0, -1}};
> +#endif
> +
> +static char user_faked_time_fmt[BUFSIZ] = {0};
> +
> +/* User supplied base time to fake */
> +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 */
> +static double user_rate = 1.0;
> +static bool user_rate_set = false;
> +static struct timespec user_per_tick_inc = {0, -1};
> +static bool user_per_tick_inc_set = false;
> +
> +enum ft_mode_t {FT_FREEZE, FT_START_AT, FT_NOOP} ft_mode = FT_FREEZE;
> +
> +/* Time to fake is not provided through FAKETIME env. var. */
> +static bool parse_config_file = true;
> +
> +void ft_cleanup (void) __attribute__ ((destructor));
> +void ftpl_init (void) __attribute__ ((constructor));
> +
> +
> +/*
> + *      =======================================================================
> + *      Shared memory related functions                                 === SHM
> + *      =======================================================================
> + */
> +
> +static void ft_shm_init (void)
> +{
> +  int ticks_shm_fd;
> +  char sem_name[256], shm_name[256], *ft_shared_env = getenv("FAKETIME_SHARED");
> +
> +  if (ft_shared_env != NULL)
> +  {
> +    if (sscanf(ft_shared_env, "%255s %255s", sem_name, shm_name) < 2)
> +    {
> +      printf("Error parsing semaphore name and shared memory id from string: %s", ft_shared_env);
> +      exit(1);
> +    }
> +
> +    if (SEM_FAILED == (shared_sem = sem_open(sem_name, 0)))
> +    {
> +      perror("sem_open");
> +      exit(1);
> +    }
> +
> +    if (-1 == (ticks_shm_fd = shm_open(shm_name, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)))
> +    {
> +      perror("shm_open");
> +      exit(1);
> +    }
> +
> +    if (MAP_FAILED == (ft_shared = mmap(NULL, sizeof(struct ft_shared_s), PROT_READ|PROT_WRITE,
> +            MAP_SHARED, ticks_shm_fd, 0)))
> +    {
> +      perror("mmap");
> +      exit(1);
> +    }
> +  }
> +}
> +
> +void ft_cleanup (void)
> +{
> +  /* detach from shared memory */
> +  if (ft_shared != NULL)
> +  {
> +    munmap(ft_shared, sizeof(uint64_t));
> +  }
> +  if (stss != NULL)
> +  {
> +    munmap(stss, infile_size);
> +  }
> +  if (shared_sem != NULL)
> +  {
> +    sem_close(shared_sem);
> +  }
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Internal time retrieval                                     === INTTIME
> + *      =======================================================================
> + */
> +
> +/* Get system time from system for all clocks */
> +static void system_time_from_system (struct system_time_s * systime)
> +{
> +#ifdef __APPLEOSX__
> +  /* from http://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x */
> +  clock_serv_t cclock;
> +  mach_timespec_t mts;
> +  host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clock_serv_real);
> +  (*real_clock_get_time)(clock_serv_real, &mts);
> +  systime->real.tv_sec = mts.tv_sec;
> +  systime->real.tv_nsec = mts.tv_nsec;
> +  host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
> +  (*real_clock_get_time)(cclock, &mts);
> +  mach_port_deallocate(mach_task_self(), cclock);
> +  systime->mon.tv_sec = mts.tv_sec;
> +  systime->mon.tv_nsec = mts.tv_nsec;
> +  systime->mon_raw.tv_sec = mts.tv_sec;
> +  systime->mon_raw.tv_nsec = mts.tv_nsec;
> +#else
> +  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_REALTIME, &systime->real))
> +   ;
> +  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_MONOTONIC, &systime->mon))
> +   ;
> +  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_MONOTONIC_RAW, &systime->mon_raw))
> +   ;
> +#ifdef CLOCK_BOOTTIME
> +  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_BOOTTIME, &systime->boot))
> +   ;
> +#endif
> +#endif
> +}
> +
> +static void next_time(struct timespec *tp, struct timespec *ticklen)
> +{
> +  if (shared_sem != NULL)
> +  {
> +    struct timespec inc;
> +    /* lock */
> +    if (sem_wait(shared_sem) == -1)
> +    {
> +      perror("sem_wait");
> +      exit(1);
> +    }
> +    /* calculate and update elapsed time */
> +    timespecmul(ticklen, ft_shared->ticks, &inc);
> +    timespecadd(&user_faked_time_timespec, &inc, tp);
> +    (ft_shared->ticks)++;
> +    /* unlock */
> +    if (sem_post(shared_sem) == -1)
> +    {
> +      perror("sem_post");
> +      exit(1);
> +    }
> +  }
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Saving & loading time                                          === SAVE
> + *      =======================================================================
> + */
> +
> +static void save_time(struct timespec *tp)
> +{
> +  if ((shared_sem != NULL) && (outfile != -1))
> +  {
> +    struct saved_timestamp time_write;
> +    ssize_t written;
> +    size_t n = 0;
> +
> +    time_write.sec = htobe64(tp->tv_sec);
> +    time_write.nsec = htobe64(tp->tv_nsec);
> +
> +    /* lock */
> +    if (sem_wait(shared_sem) == -1)
> +    {
> +      perror("sem_wait");
> +      exit(1);
> +    }
> +
> +    lseek(outfile, 0, SEEK_END);
> +    do
> +    {
> +      written = write(outfile, &(((char*)&time_write)[n]), sizeof(time_write) - n);
> +    }
> +    while (((written == -1) && (errno == EINTR)) ||
> +            (sizeof(time_write) < (n += written)));
> +
> +    if ((written == -1) || (n < sizeof(time_write)))
> +    {
> +      perror("Saving timestamp to file failed");
> +    }
> +
> +    /* unlock */
> +    if (sem_post(shared_sem) == -1)
> +    {
> +      perror("sem_post");
> +      exit(1);
> +    }
> +  }
> +}
> +
> +/*
> + * Provide faked time from file.
> + * @return time is set from filen
> + */
> +static bool load_time(struct timespec *tp)
> +{
> +  bool ret = false;
> +  if ((shared_sem != NULL) && (infile_set))
> +  {
> +    /* lock */
> +    if (sem_wait(shared_sem) == -1)
> +    {
> +      perror("sem_wait");
> +      exit(1);
> +    }
> +
> +    if ((sizeof(stss[0]) * (ft_shared->file_idx + 1)) > infile_size)
> +    {
> +      /* we are out of timstamps to replay, return to faking time by rules
> +       * using last timestamp from file as the user provided timestamp */
> +      timespec_from_saved(&user_faked_time_timespec, &stss[(infile_size / sizeof(stss[0])) - 1 ]);
> +
> +      if (ft_shared->ticks == 0)
> +      {
> +        /* we set shared memory to stop using infile */
> +        ft_shared->ticks = 1;
> +        system_time_from_system(&ftpl_starttime);
> +        ft_shared->start_time = ftpl_starttime;
> +      }
> +      else
> +      {
> +        ftpl_starttime = ft_shared->start_time;
> +      }
> +
> +      munmap(stss, infile_size);
> +      infile_set = false;
> +    }
> +    else
> +    {
> +      timespec_from_saved(tp, &stss[ft_shared->file_idx]);
> +      ft_shared->file_idx++;
> +      ret = true;
> +    }
> +
> +    /* unlock */
> +    if (sem_post(shared_sem) == -1)
> +    {
> +      perror("sem_post");
> +      exit(1);
> +    }
> +  }
> +  return ret;
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Faked system functions: file related                     === FAKE(FILE)
> + *      =======================================================================
> + */
> +
> +#ifdef FAKE_STAT
> +
> +#ifndef NO_ATFILE
> +#ifndef _ATFILE_SOURCE
> +#define _ATFILE_SOURCE
> +#endif
> +#include <fcntl.h> /* Definition of AT_* constants */
> +#endif
> +
> +#include <sys/stat.h>
> +
> +static int fake_stat_disabled = 0;
> +
> +#define FAKE_STRUCT_STAT_TIME(which) {                \
> +    struct timespec t = {buf->st_##which##time,       \
> +                         buf->st_##which##timensec};  \
> +    fake_clock_gettime(CLOCK_REALTIME, &t);           \
> +    buf->st_##which##time = t.tv_sec;                 \
> +    buf->st_##which##timensec = t.tv_nsec;            \
> +  } while (0)
> +
> +static inline void fake_statbuf (struct stat *buf) {
> +#ifndef st_atime
> +  FAKE_STRUCT_STAT_TIME(c);
> +  FAKE_STRUCT_STAT_TIME(a);
> +  FAKE_STRUCT_STAT_TIME(m);
> +#else
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_ctim);
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_atim);
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_mtim);
> +#endif
> +}
> +
> +static inline void fake_stat64buf (struct stat64 *buf) {
> +#ifndef st_atime
> +  FAKE_STRUCT_STAT_TIME(c);
> +  FAKE_STRUCT_STAT_TIME(a);
> +  FAKE_STRUCT_STAT_TIME(m);
> +#else
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_ctim);
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_atim);
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_mtim);
> +#endif
> +}
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __xstat (int ver, const char *path, struct stat *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_stat)
> +  { /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original stat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_stat(ver, path, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +   if (buf != NULL)
> +   {
> +     if (!fake_stat_disabled)
> +     {
> +       fake_statbuf(buf);
> +     }
> +   }
> +
> +  return result;
> +}
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __fxstat (int ver, int fildes, struct stat *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_fstat)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original fstat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_fstat(ver, fildes, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_statbuf(buf);
> +    }
> +  }
> +  return result;
> +}
> +
> +/* Added in v0.8 as suggested by Daniel Kahn Gillmor */
> +#ifndef NO_ATFILE
> +int __fxstatat(int ver, int fildes, const char *filename, struct stat *buf, int flag)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_fstatat)
> +  { /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original fstatat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_fstatat(ver, fildes, filename, buf, flag));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_statbuf(buf);
> +    }
> +  }
> +  return result;
> +}
> +#endif
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __lxstat (int ver, const char *path, struct stat *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_lstat)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original lstat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_lstat(ver, path, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_statbuf(buf);
> +    }
> +  }
> +  return result;
> +}
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __xstat64 (int ver, const char *path, struct stat64 *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_stat64)
> +  { /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original stat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_stat64(ver, path, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_stat64buf(buf);
> +    }
> +  }
> +  return result;
> +}
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __fxstat64 (int ver, int fildes, struct stat64 *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_fstat64)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original fstat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_fstat64(ver, fildes, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_stat64buf(buf);
> +    }
> +  }
> +  return result;
> +}
> +
> +/* Added in v0.8 as suggested by Daniel Kahn Gillmor */
> +#ifndef NO_ATFILE
> +int __fxstatat64 (int ver, int fildes, const char *filename, struct stat64 *buf, int flag)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_fstatat64)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original fstatat64() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_fstatat64(ver, fildes, filename, buf, flag));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_stat64buf(buf);
> +    }
> +  }
> +  return result;
> +}
> +#endif
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __lxstat64 (int ver, const char *path, struct stat64 *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_lstat64)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original lstat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_lstat64(ver, path, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_stat64buf(buf);
> +    }
> +  }
> +  return result;
> +}
> +#endif
> +
> +/*
> + *      =======================================================================
> + *      Faked system functions: sleep/alarm/poll/timer related  === FAKE(SLEEP)
> + *      =======================================================================
> + *      Contributed by Balint Reczey in v0.9.5
> + */
> +
> +#ifdef FAKE_SLEEP
> +/*
> + * Faked nanosleep()
> + */
> +int nanosleep(const struct timespec *req, struct timespec *rem)
> +{
> +  int result;
> +  struct timespec real_req;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_nanosleep == NULL)
> +  {
> +    return -1;
> +  }
> +  if (req != NULL)
> +  {
> +    if (user_rate_set && !dont_fake)
> +    {
> +      timespecmul(req, 1.0 / user_rate, &real_req);
> +    }
> +    else
> +    {
> +      real_req = *req;
> +    }
> +  }
> +  else
> +  {
> +    return -1;
> +  }
> +
> +  DONT_FAKE_TIME(result = (*real_nanosleep)(&real_req, rem));
> +  if (result == -1)
> +  {
> +    return result;
> +  }
> +
> +  /* fake returned parts */
> +  if ((rem != NULL) && ((rem->tv_sec != 0) || (rem->tv_nsec != 0)))
> +  {
> +    if (user_rate_set && !dont_fake)
> +    {
> +      timespecmul(rem, user_rate, rem);
> +    }
> +  }
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +/*
> + * Faked usleep()
> + */
> +int usleep(useconds_t usec)
> +{
> +  int result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (user_rate_set && !dont_fake)
> +  {
> +    struct timespec real_req;
> +
> +    if (real_nanosleep == NULL)
> +    {
> +      /* fall back to usleep() */
> +      if (real_usleep == NULL)
> +      {
> +        return -1;
> +      }
> +      DONT_FAKE_TIME(result = (*real_usleep)((1.0 / user_rate) * usec));
> +      return result;
> +    }
> +
> +    real_req.tv_sec = usec / 1000000;
> +    real_req.tv_nsec = (usec % 1000000) * 1000;
> +    timespecmul(&real_req, 1.0 / user_rate, &real_req);
> +    DONT_FAKE_TIME(result = (*real_nanosleep)(&real_req, NULL));
> +  }
> +  else
> +  {
> +    DONT_FAKE_TIME(result = (*real_usleep)(usec));
> +  }
> +  return result;
> +}
> +
> +/*
> + * Faked sleep()
> + */
> +unsigned int sleep(unsigned int seconds)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (user_rate_set && !dont_fake)
> +  {
> +    if (real_nanosleep == NULL)
> +    {
> +      /* fall back to sleep */
> +      unsigned int ret;
> +      if (real_sleep == NULL)
> +      {
> +        return 0;
> +      }
> +      DONT_FAKE_TIME(ret = (*real_sleep)((1.0 / user_rate) * seconds));
> +      return (user_rate_set && !dont_fake)?(user_rate * ret):ret;
> +    }
> +    else
> +    {
> +      int result;
> +      struct timespec real_req = {seconds, 0}, rem;
> +      timespecmul(&real_req, 1.0 / user_rate, &real_req);
> +      DONT_FAKE_TIME(result = (*real_nanosleep)(&real_req, &rem));
> +      if (result == -1)
> +      {
> +        return 0;
> +      }
> +
> +      /* fake returned parts */
> +      if ((rem.tv_sec != 0) || (rem.tv_nsec != 0))
> +      {
> +        timespecmul(&rem, user_rate, &rem);
> +      }
> +      /* return the result to the caller */
> +      return rem.tv_sec;
> +    }
> +  }
> +  else
> +  {
> +    /* no need to fake anything */
> +    unsigned int ret;
> +    DONT_FAKE_TIME(ret = (*real_sleep)(seconds));
> +    return ret;
> +  }
> +}
> +
> +/*
> + * Faked alarm()
> + * @note due to rounding alarm(2) with faketime -f '+0 x7' won't wait 2/7
> + * wall clock seconds but 0 seconds
> + */
> +unsigned int alarm(unsigned int seconds)
> +{
> +  unsigned int ret;
> +  unsigned int seconds_real = (user_rate_set && !dont_fake)?((1.0 / user_rate) * seconds):seconds;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_alarm == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  DONT_FAKE_TIME(ret = (*real_alarm)(seconds_real));
> +  return (user_rate_set && !dont_fake)?(user_rate * ret):ret;
> +}
> +
> +/*
> + * Faked ppoll()
> + */
> +int ppoll(struct pollfd *fds, nfds_t nfds,
> +    const struct timespec *timeout_ts, const sigset_t *sigmask)
> +{
> +  struct timespec real_timeout, *real_timeout_pt;
> +  int ret;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_ppoll == NULL)
> +  {
> +    return -1;
> +  }
> +  if (timeout_ts != NULL)
> +  {
> +    if (user_rate_set && !dont_fake && (timeout_ts->tv_sec > 0))
> +    {
> +      timespecmul(timeout_ts, 1.0 / user_rate, &real_timeout);
> +      real_timeout_pt = &real_timeout;
> +    }
> +    else
> +    {
> +      /* cast away constness */
> +      real_timeout_pt = (struct timespec *)timeout_ts;
> +    }
> +  }
> +  else
> +  {
> +    real_timeout_pt = NULL;
> +  }
> +
> +  DONT_FAKE_TIME(ret = (*real_ppoll)(fds, nfds, real_timeout_pt, sigmask));
> +  return ret;
> +}
> +
> +/*
> + * Faked poll()
> + */
> +int poll(struct pollfd *fds, nfds_t nfds, int timeout)
> +{
> +  int ret, timeout_real = (user_rate_set && !dont_fake && (timeout > 0))?(timeout / user_rate):timeout;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_poll == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  DONT_FAKE_TIME(ret = (*real_poll)(fds, nfds, timeout_real));
> +  return ret;
> +}
> +
> +/*
> + * Faked select()
> + */
> +int select(int nfds, fd_set *readfds,
> +           fd_set *writefds,
> +           fd_set *errorfds,
> +           struct timeval *timeout)
> +{
> +  int ret;
> +  struct timeval timeout_real;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +
> +  if (real_select == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  if (timeout != NULL)
> +  {
> +    if (user_rate_set && !dont_fake && (timeout->tv_sec > 0 || timeout->tv_usec > 0))
> +    {
> +      struct timespec ts;
> +
> +      ts.tv_sec = timeout->tv_sec;
> +      ts.tv_nsec = timeout->tv_usec * 1000;
> +
> +      timespecmul(&ts, 1.0 / user_rate, &ts);
> +
> +      timeout_real.tv_sec = ts.tv_sec;
> +      timeout_real.tv_usec = ts.tv_nsec / 1000;
> +    }
> +    else
> +    {
> +      timeout_real.tv_sec = timeout->tv_sec;
> +      timeout_real.tv_usec = timeout->tv_usec;
> +    }
> +  }
> +
> +  DONT_FAKE_TIME(ret = (*real_select)(nfds, readfds, writefds, errorfds, timeout == NULL ? timeout : &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__
> +#ifdef FAKE_TIMERS
> +
> +/* timer related functions and structures */
> +typedef union {
> +  int int_member;
> +  timer_t timer_t_member;
> +} timer_t_or_int;
> +
> +/*
> + * Faketime's function implementation's compatibility mode
> + */
> +typedef enum {FT_COMPAT_GLIBC_2_2, FT_COMPAT_GLIBC_2_3_3} ft_lib_compat;
> +
> +
> +/*
> + * Faked timer_settime()
> + * Does not affect timer speed when stepping clock with each time() call.
> + */
> +static int
> +timer_settime_common(timer_t_or_int timerid, int flags,
> +         const struct itimerspec *new_value,
> +         struct itimerspec *old_value, ft_lib_compat compat)
> +{
> +  int result;
> +  struct itimerspec new_real;
> +  struct itimerspec *new_real_pt = &new_real;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (new_value == NULL)
> +  {
> +    new_real_pt = NULL;
> +  }
> +  else if (dont_fake)
> +  {
> +    /* cast away constness*/
> +    new_real_pt = (struct itimerspec *)new_value;
> +  }
> +  else
> +  {
> +    /* set it_value */
> +    if ((new_value->it_value.tv_sec != 0) ||
> +        (new_value->it_value.tv_nsec != 0))
> +    {
> +      if (flags & TIMER_ABSTIME)
> +      {
> +        struct timespec tdiff, timeadj;
> +        timespecsub(&new_value->it_value, &user_faked_time_timespec, &timeadj);
> +        if (user_rate_set)
> +        {
> +          timespecmul(&timeadj, 1.0/user_rate, &tdiff);
> +        }
> +        else
> +        {
> +          tdiff = timeadj;
> +        }
> +        /* only CLOCK_REALTIME is handled */
> +        timespecadd(&ftpl_starttime.real, &tdiff, &new_real.it_value);
> +      }
> +      else
> +      {
> +        if (user_rate_set)
> +        {
> +          timespecmul(&new_value->it_value, 1.0/user_rate, &new_real.it_value);
> +        }
> +        else
> +        {
> +          new_real.it_value = new_value->it_value;
> +        }
> +      }
> +    }
> +    else
> +    {
> +      new_real.it_value = new_value->it_value;
> +    }
> +    /* set it_interval */
> +    if (user_rate_set && ((new_value->it_interval.tv_sec != 0) ||
> +       (new_value->it_interval.tv_nsec != 0)))
> +    {
> +      timespecmul(&new_value->it_interval, 1.0/user_rate, &new_real.it_interval);
> +    }
> +    else
> +    {
> +      new_real.it_interval = new_value->it_interval;
> +    }
> +  }
> +
> +  switch (compat)
> +  {
> +    case FT_COMPAT_GLIBC_2_2:
> +      DONT_FAKE_TIME(result = (*real_timer_settime_22)(timerid.int_member, flags,
> +                    new_real_pt, old_value));
> +      break;
> +    case FT_COMPAT_GLIBC_2_3_3:
> +       DONT_FAKE_TIME(result = (*real_timer_settime_233)(timerid.timer_t_member,
> +                    flags, new_real_pt, old_value));
> +       break;
> +    default:
> +      result = -1;
> +      break;
> +  }
> +
> +  if (result == -1)
> +  {
> +    return result;
> +  }
> +
> +  /* fake returned parts */
> +  if ((old_value != NULL) && !dont_fake)
> +  {
> +    if ((old_value->it_value.tv_sec != 0) ||
> +        (old_value->it_value.tv_nsec != 0))
> +    {
> +      result = fake_clock_gettime(CLOCK_REALTIME, &old_value->it_value);
> +    }
> +    if (user_rate_set && ((old_value->it_interval.tv_sec != 0) ||
> +       (old_value->it_interval.tv_nsec != 0)))
> +    {
> +      timespecmul(&old_value->it_interval, user_rate, &old_value->it_interval);
> +    }
> +  }
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +/*
> + * Faked timer_settime() compatible with implementation in GLIBC 2.2
> + */
> +int timer_settime_22(int timerid, int flags,
> +         const struct itimerspec *new_value,
> +         struct itimerspec *old_value)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_timer_settime_22 == NULL)
> +  {
> +    return -1;
> +  }
> +  else
> +  {
> +    return (timer_settime_common((timer_t_or_int)timerid, flags, new_value, old_value,
> +            FT_COMPAT_GLIBC_2_2));
> +  }
> +}
> +
> +/*
> + * Faked timer_settime() compatible with implementation in GLIBC 2.3.3
> + */
> +int timer_settime_233(timer_t timerid, int flags,
> +      const struct itimerspec *new_value,
> +      struct itimerspec *old_value)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_timer_settime_233 == NULL)
> +  {
> +    return -1;
> +  }
> +  else
> +  {
> +    return (timer_settime_common((timer_t_or_int)timerid, flags, new_value, old_value,
> +            FT_COMPAT_GLIBC_2_3_3));
> +  }
> +}
> +
> +/*
> + * Faked timer_gettime()
> + * Does not affect timer speed when stepping clock with each time() call.
> + */
> +int timer_gettime_common(timer_t_or_int timerid, struct itimerspec *curr_value, ft_lib_compat compat)
> +{
> +  int result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_timer_gettime_233 == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  switch (compat)
> +  {
> +    case FT_COMPAT_GLIBC_2_2:
> +      DONT_FAKE_TIME(result = (*real_timer_gettime_22)(timerid.int_member, curr_value));
> +      break;
> +    case FT_COMPAT_GLIBC_2_3_3:
> +      DONT_FAKE_TIME(result = (*real_timer_gettime_233)(timerid.timer_t_member, curr_value));
> +      break;
> +    default:
> +      result = -1;
> +      break;
> +  }
> +
> +  if (result == -1)
> +  {
> +    return result;
> +  }
> +
> +  /* fake returned parts */
> +  if (curr_value != NULL)
> +  {
> +    if (user_rate_set && !dont_fake)
> +    {
> +      timespecmul(&curr_value->it_interval, user_rate, &curr_value->it_interval);
> +      timespecmul(&curr_value->it_value, user_rate, &curr_value->it_value);
> +    }
> +  }
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +/*
> + * Faked timer_gettime() compatible with implementation in GLIBC 2.2
> + */
> +int timer_gettime_22(timer_t timerid, struct itimerspec *curr_value)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_timer_gettime_22 == NULL)
> +  {
> +    return -1;
> +  }
> +  else
> +  {
> +    return (timer_gettime_common((timer_t_or_int)timerid, curr_value,
> +         FT_COMPAT_GLIBC_2_2));
> +  }
> +}
> +
> +/*
> + * Faked timer_gettime() compatible with implementation in GLIBC 2.3.3
> + */
> +int timer_gettime_233(timer_t timerid, struct itimerspec *curr_value)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_timer_gettime_233 == NULL)
> +  {
> +    return -1;
> +  }
> +  else
> +  {
> +    return (timer_gettime_common((timer_t_or_int)timerid, curr_value,
> +            FT_COMPAT_GLIBC_2_3_3));
> +  }
> +}
> +
> +__asm__(".symver timer_gettime_22, timer_gettime@GLIBC_2.2");
> +__asm__(".symver timer_gettime_233, timer_gettime@@GLIBC_2.3.3");
> +__asm__(".symver timer_settime_22, timer_settime@GLIBC_2.2");
> +__asm__(".symver timer_settime_233, timer_settime@@GLIBC_2.3.3");
> +
> +#endif
> +#endif
> +
> +
> +/*
> + *      =======================================================================
> + *      Faked system functions: basic time functions             === FAKE(TIME)
> + *      =======================================================================
> + */
> +
> +/*
> + * time() implementation using clock_gettime()
> + * @note Does not check for EFAULT, see man 2 time
> + */
> +time_t time(time_t *time_tptr)
> +{
> +  struct timespec tp;
> +  time_t result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
> +  if (result == -1) return -1;
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
> +
> +  if (time_tptr != NULL)
> +  {
> +    *time_tptr = tp.tv_sec;
> +  }
> +  return tp.tv_sec;
> +}
> +
> +int ftime(struct timeb *tb)
> +{
> +  struct timespec tp;
> +  int result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  /* sanity check */
> +  if (tb == NULL)
> +    return 0;               /* ftime() always returns 0, see manpage */
> +
> +  /* Check whether we've got a pointer to the real ftime() function yet */
> +  if (NULL == real_ftime)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original ftime() not found.\n");
> +#endif
> +    return 0; /* propagate error to caller */
> +  }
> +
> +  /* initialize our TZ result with the real current time */
> +  DONT_FAKE_TIME(result = (*real_ftime)(tb));
> +  if (result == -1)
> +  {
> +    return result;
> +  }
> +
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
> +  if (result == -1) return -1;
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
> +
> +  tb->time = tp.tv_sec;
> +  tb->millitm = tp.tv_nsec / 1000000;
> +
> +  /* return the result to the caller */
> +  return result; /* will always be 0 (see manpage) */
> +}
> +
> +int gettimeofday(struct timeval *tv, void *tz)
> +{
> +  int result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  /* sanity check */
> +  if (tv == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  /* Check whether we've got a pointer to the real ftime() function yet */
> +  if (NULL == real_gettimeofday)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original gettimeofday() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  /* initialize our result with the real current time */
> +  DONT_FAKE_TIME(result = (*real_gettimeofday)(tv, tz));
> +  if (result == -1) return result; /* original function failed */
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  result = fake_gettimeofday(tv);
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +int clock_gettime(clockid_t clk_id, struct timespec *tp)
> +{
> +  int result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  /* sanity check */
> +  if (tp == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  if (NULL == real_clock_gettime)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original clock_gettime() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  /* initialize our result with the real current time */
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(clk_id, tp));
> +  if (result == -1) return result; /* original function failed */
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  if (fake_monotonic_clock || clk_id != CLOCK_MONOTONIC)
> +  {
> +    result = fake_clock_gettime(clk_id, tp);
> +  }
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Parsing the user's faketime requests                          === PARSE
> + *      =======================================================================
> + */
> +
> +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])
> +  {
> +
> +    default:  /* Try and interpret this as a specified time */
> +      if (ft_mode != FT_NOOP) ft_mode = FT_FREEZE;
> +      user_faked_time_tm.tm_isdst = -1;
> +      if (NULL != strptime(user_faked_time, user_faked_time_fmt, &user_faked_time_tm))
> +      {
> +        user_faked_time_timespec.tv_sec = mktime(&user_faked_time_tm);
> +        user_faked_time_timespec.tv_nsec = 0;
> +        user_faked_time_set = true;
> +      }
> +      else
> +      {
> +        perror("Failed to parse FAKETIME timestamp");
> +        exit(EXIT_FAILURE);
> +      }
> +      break;
> +
> +    case '+':
> +    case '-': /* User-specified offset */
> +      if (ft_mode != FT_NOOP) ft_mode = FT_START_AT;
> +      /* fractional time offsets contributed by Karl Chen in v0.8 */
> +      double frac_offset = atof(user_faked_time);
> +
> +      /* offset is in seconds by default, but the string may contain
> +       * multipliers...
> +       */
> +      if (strchr(user_faked_time, 'm') != NULL) frac_offset *= 60;
> +      else if (strchr(user_faked_time, 'h') != NULL) frac_offset *= 60 * 60;
> +      else if (strchr(user_faked_time, 'd') != NULL) frac_offset *= 60 * 60 * 24;
> +      else if (strchr(user_faked_time, 'y') != NULL) frac_offset *= 60 * 60 * 24 * 365;
> +
> +      user_offset.tv_sec = floor(frac_offset);
> +      user_offset.tv_nsec = (frac_offset - user_offset.tv_sec) * SEC_TO_nSEC;
> +      timespecadd(&ftpl_starttime.real, &user_offset, &user_faked_time_timespec);
> +      goto parse_modifiers;
> +      break;
> +
> +      /* Contributed by David North, TDI in version 0.7 */
> +    case '@': /* Specific time, but clock along relative to that starttime */
> +      ft_mode = FT_START_AT;
> +      user_faked_time_tm.tm_isdst = -1;
> +      (void) strptime(&user_faked_time[1], user_faked_time_fmt, &user_faked_time_tm);
> +
> +      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;
> +
> +    case 'i':
> +    case 'x': /* Only modifiers are passed, don't fall back to strptime */
> +parse_modifiers:
> +      /* Speed-up / slow-down contributed by Karl Chen in v0.8 */
> +      if (strchr(user_faked_time, 'x') != NULL)
> +      {
> +        user_rate = atof(strchr(user_faked_time, 'x')+1);
> +        user_rate_set = true;
> +      }
> +      else if (NULL != (tmp_time_fmt = strchr(user_faked_time, 'i')))
> +      {
> +        double tick_inc = atof(tmp_time_fmt + 1);
> +        /* increment time with every time() call*/
> +        user_per_tick_inc.tv_sec = floor(tick_inc);
> +        user_per_tick_inc.tv_nsec = (tick_inc - user_per_tick_inc.tv_sec) * SEC_TO_nSEC ;
> +        user_per_tick_inc_set = true;
> +      }
> +      break;
> +  } // end of switch
> +
> +  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
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Initialization                                                 === INIT
> + *      =======================================================================
> + */
> +
> +void ftpl_init(void)
> +{
> +  char *tmp_env;
> +  bool dont_fake_final;
> +
> +#ifdef __APPLE__
> +  const char *progname = getprogname();
> +#else
> +  const char *progname = __progname;
> +#endif
> +
> +  /* Look up all real_* functions. NULL will mark missing ones. */
> +  real_stat =               dlsym(RTLD_NEXT, "__xstat");
> +  real_fstat =              dlsym(RTLD_NEXT, "__fxstat");
> +  real_fstatat =            dlsym(RTLD_NEXT, "__fxstatat");
> +  real_lstat =              dlsym(RTLD_NEXT, "__lxstat");
> +  real_stat64 =             dlsym(RTLD_NEXT,"__xstat64");
> +  real_fstat64 =            dlsym(RTLD_NEXT, "__fxstat64");
> +  real_fstatat64 =          dlsym(RTLD_NEXT, "__fxstatat64");
> +  real_lstat64 =            dlsym(RTLD_NEXT, "__lxstat64");
> +  real_time =               dlsym(RTLD_NEXT, "time");
> +  real_ftime =              dlsym(RTLD_NEXT, "ftime");
> +  real_gettimeofday =       dlsym(RTLD_NEXT, "gettimeofday");
> +#ifdef FAKE_SLEEP
> +  real_nanosleep =          dlsym(RTLD_NEXT, "nanosleep");
> +  real_usleep =             dlsym(RTLD_NEXT, "usleep");
> +  real_sleep =              dlsym(RTLD_NEXT, "sleep");
> +  real_alarm =              dlsym(RTLD_NEXT, "alarm");
> +  real_poll =               dlsym(RTLD_NEXT, "poll");
> +  real_ppoll =              dlsym(RTLD_NEXT, "ppoll");
> +  real_select =             dlsym(RTLD_NEXT, "select");
> +  real_sem_timedwait =      dlsym(RTLD_NEXT, "sem_timedwait");
> +#endif
> +#ifdef FAKE_INTERNAL_CALLS
> +  real___ftime =              dlsym(RTLD_NEXT, "__ftime");
> +  real___gettimeofday =       dlsym(RTLD_NEXT, "__gettimeofday");
> +  real___clock_gettime  =     dlsym(RTLD_NEXT, "__clock_gettime");
> +#endif
> +#ifdef __APPLEOSX__
> +  real_clock_get_time =     dlsym(RTLD_NEXT, "clock_get_time");
> +  real_clock_gettime  =     apple_clock_gettime;
> +#else
> +  real_clock_gettime  =     dlsym(RTLD_NEXT, "__clock_gettime");
> +  if (NULL == real_clock_gettime)
> +  {
> +    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)
> +  {
> +    real_timer_settime_233 =  dlsym(RTLD_NEXT, "timer_settime");
> +  }
> +  real_timer_gettime_22 =   dlvsym(RTLD_NEXT, "timer_gettime","GLIBC_2.2");
> +  real_timer_gettime_233 =  dlvsym(RTLD_NEXT, "timer_gettime","GLIBC_2.3.3");
> +  if (NULL == real_timer_gettime_233)
> +  {
> +    real_timer_gettime_233 =  dlsym(RTLD_NEXT, "timer_gettime");
> +  }
> +#endif
> +#endif
> +#endif
> +
> +  dont_fake = true; // Do not fake times during initialization
> +  dont_fake_final = false;
> +  initialized = 1;
> +
> +  ft_shm_init();
> +#ifdef FAKE_STAT
> +  if (getenv("NO_FAKE_STAT")!=NULL)
> +  {
> +    fake_stat_disabled = 1;  //Note that this is NOT re-checked
> +  }
> +#endif
> +
> +  if ((tmp_env = getenv("FAKETIME_CACHE_DURATION")) != NULL)
> +  {
> +    cache_duration = atoi(tmp_env);
> +  }
> +  if ((tmp_env = getenv("FAKETIME_NO_CACHE")) != NULL)
> +  {
> +    if (0 == strcmp(tmp_env, "1"))
> +    {
> +      cache_enabled = 0;
> +    }
> +  }
> +  if ((tmp_env = getenv("DONT_FAKE_MONOTONIC")) != NULL)
> +  {
> +    if (0 == strcmp(tmp_env, "1"))
> +    {
> +      fake_monotonic_clock = 0;
> +    }
> +  }
> +  /* Check whether we actually should be faking the returned timestamp. */
> +
> +  /* We can prevent faking time for specified commands */
> +  if ((tmp_env = getenv("FAKETIME_SKIP_CMDS")) != NULL)
> +  {
> +    char *skip_cmd, *saveptr, *tmpvar;
> +    /* Don't mess with the env variable directly. */
> +    tmpvar = strdup(tmp_env);
> +    if (tmpvar != NULL)
> +    {
> +      skip_cmd = strtok_r(tmpvar, ",", &saveptr);
> +      while (skip_cmd != NULL)
> +      {
> +        if (0 == strcmp(progname, skip_cmd))
> +        {
> +          ft_mode = FT_NOOP;
> +          dont_fake_final = true;
> +          break;
> +        }
> +        skip_cmd = strtok_r(NULL, ",", &saveptr);
> +      }
> +      free(tmpvar);
> +      tmpvar = NULL;
> +    }
> +    else
> +    {
> +      fprintf(stderr, "Error: Could not copy the environment variable value.\n");
> +      exit(EXIT_FAILURE);
> +    }
> +  }
> +
> +  /* We can limit faking time to specified commands */
> +  if ((tmp_env = getenv("FAKETIME_ONLY_CMDS")) != NULL)
> +  {
> +    char *only_cmd, *saveptr, *tmpvar;
> +    bool cmd_matched = false;
> +
> +    if (getenv("FAKETIME_SKIP_CMDS") != NULL)
> +    {
> +      fprintf(stderr, "Error: Both FAKETIME_SKIP_CMDS and FAKETIME_ONLY_CMDS can't be set.\n");
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    /* Don't mess with the env variable directly. */
> +    tmpvar = strdup(tmp_env);
> +    if (tmpvar != NULL) {
> +      only_cmd = strtok_r(tmpvar, ",", &saveptr);
> +      while (only_cmd != NULL)
> +      {
> +        if (0 == strcmp(progname, only_cmd))
> +        {
> +          cmd_matched = true;
> +          break;
> +        }
> +        only_cmd = strtok_r(NULL, ",", &saveptr);
> +      }
> +
> +      if (!cmd_matched)
> +      {
> +        ft_mode = FT_NOOP;
> +        dont_fake_final = true;
> +      }
> +      free(tmpvar);
> +    } else {
> +      fprintf(stderr, "Error: Could not copy the environment variable value.\n");
> +      exit(EXIT_FAILURE);
> +    }
> +  }
> +
> +  if ((tmp_env = getenv("FAKETIME_START_AFTER_SECONDS")) != NULL)
> +  {
> +    ft_start_after_secs = atol(tmp_env);
> +    limited_faking = true;
> +  }
> +  if ((tmp_env = getenv("FAKETIME_STOP_AFTER_SECONDS")) != NULL)
> +  {
> +    ft_stop_after_secs = atol(tmp_env);
> +    limited_faking = true;
> +  }
> +  if ((tmp_env = getenv("FAKETIME_START_AFTER_NUMCALLS")) != NULL)
> +  {
> +    ft_start_after_ncalls = atol(tmp_env);
> +    limited_faking = true;
> +  }
> +  if ((tmp_env = getenv("FAKETIME_STOP_AFTER_NUMCALLS")) != NULL)
> +  {
> +    ft_stop_after_ncalls = atol(tmp_env);
> +    limited_faking = true;
> +  }
> +
> +  /* check whether we should spawn an external command */
> +  if ((tmp_env = getenv("FAKETIME_SPAWN_TARGET")) != NULL)
> +  {
> +    spawnsupport = true;
> +    (void) strncpy(ft_spawn_target, getenv("FAKETIME_SPAWN_TARGET"), 1024);
> +    if ((tmp_env = getenv("FAKETIME_SPAWN_SECONDS")) != NULL)
> +    {
> +      ft_spawn_secs = atol(tmp_env);
> +    }
> +    if ((tmp_env = getenv("FAKETIME_SPAWN_NUMCALLS")) != NULL)
> +    {
> +      ft_spawn_ncalls = atol(tmp_env);
> +    }
> +  }
> +
> +  if ((tmp_env = getenv("FAKETIME_SAVE_FILE")) != NULL)
> +  {
> +    if (-1 == (outfile = open(tmp_env, O_RDWR | O_APPEND | O_CLOEXEC | O_CREAT,
> +                              S_IWUSR | S_IRUSR)))
> +    {
> +      perror("Opening file for saving timestamps failed");
> +      exit(EXIT_FAILURE);
> +    }
> +  }
> +
> +  /* load file only if reading timstamps from it is not finished yet */
> +  if ((tmp_env = getenv("FAKETIME_LOAD_FILE")) != NULL)
> +  {
> +    int infile = -1;
> +    struct stat sb;
> +    if (-1 == (infile = open(tmp_env, O_RDONLY|O_CLOEXEC)))
> +    {
> +      perror("Opening file for loading timestamps failed");
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    fstat(infile, &sb);
> +    if (sizeof(stss[0]) > (infile_size = sb.st_size))
> +    {
> +      printf("There are no timestamps in the provided file to load timestamps from");
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    if ((infile_size % sizeof(stss[0])) != 0)
> +    {
> +      printf("File size is not multiple of timestamp size. It is probably damaged.");
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    stss = mmap(NULL, infile_size, PROT_READ, MAP_SHARED, infile, 0);
> +    if (stss == MAP_FAILED)
> +    {
> +      perror("Mapping file for loading timestamps failed");
> +      exit(EXIT_FAILURE);
> +    }
> +    infile_set = true;
> +  }
> +
> +  tmp_env = getenv("FAKETIME_FMT");
> +  if (tmp_env == NULL)
> +  {
> +    strcpy(user_faked_time_fmt, "%Y-%m-%d %T");
> +  }
> +  else
> +  {
> +    strncpy(user_faked_time_fmt, tmp_env, BUFSIZ);
> +  }
> +
> +  if (shared_sem != 0)
> +  {
> +    if (sem_wait(shared_sem) == -1)
> +    {
> +      perror("sem_wait");
> +      exit(1);
> +    }
> +    if (ft_shared->start_time.real.tv_nsec == -1)
> +    {
> +      /* set up global start time */
> +      system_time_from_system(&ftpl_starttime);
> +      ft_shared->start_time = ftpl_starttime;
> +    }
> +    else
> +    {
> +      /** get preset start time */
> +      ftpl_starttime = ft_shared->start_time;
> +    }
> +    if (sem_post(shared_sem) == -1)
> +    {
> +      perror("sem_post");
> +      exit(1);
> +    }
> +  }
> +  else
> +  {
> +    system_time_from_system(&ftpl_starttime);
> +  }
> +  /* fake time supplied as environment variable? */
> +  if (NULL != (tmp_env = getenv("FAKETIME")))
> +  {
> +    parse_config_file = false;
> +    parse_ft_string(tmp_env);
> +  }
> +
> +  dont_fake = dont_fake_final;
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Helper functions                                             === HELPER
> + *      =======================================================================
> + */
> +
> +static void remove_trailing_eols(char *line)
> +{
> +  char *endp = line + strlen(line);
> +  /*
> +   * erase the last char if it's a newline
> +   * or carriage return, and back up.
> +   * keep doing this, but don't back up
> +   * past the beginning of the string.
> +   */
> +# define is_eolchar(c) ((c) == '\n' || (c) == '\r')
> +  while (endp > line && is_eolchar(endp[-1]))
> +  {
> +    *--endp = '\0';
> +  }
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Implementation of faked functions                        === FAKE(FAKE)
> + *      =======================================================================
> + */
> +
> +int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
> +{
> +  /* variables used for caching, introduced in version 0.6 */
> +  static time_t last_data_fetch = 0;  /* not fetched previously at first call */
> +  static int cache_expired = 1;       /* considered expired at first call */
> +
> +  if (dont_fake) return 0;
> +  /* Per process timers are only sped up or slowed down */
> +  if ((clk_id == CLOCK_PROCESS_CPUTIME_ID ) || (clk_id == CLOCK_THREAD_CPUTIME_ID))
> +  {
> +    if (user_rate_set)
> +    {
> +      timespecmul(tp, user_rate, tp);
> +    }
> +    return 0;
> +  }
> +
> +  /* Sanity check by Karl Chan since v0.8 */
> +  if (tp == NULL) return -1;
> +
> +#ifdef PTHREAD_SINGLETHREADED_TIME
> +  static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
> +  pthread_mutex_lock(&time_mutex);
> +  pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, (void *)&time_mutex);
> +#endif
> +
> +  if ((limited_faking &&
> +     ((ft_start_after_ncalls != -1) || (ft_stop_after_ncalls != -1))) ||
> +     (spawnsupport && ft_spawn_ncalls))
> +  {
> +    if (callcounter < LONG_MAX) callcounter++;
> +  }
> +
> +  if (limited_faking || spawnsupport)
> +  {
> +    struct timespec tmp_ts;
> +    /* For debugging, output #seconds and #calls */
> +    switch (clk_id)
> +    {
> +      case CLOCK_REALTIME:
> +#ifdef CLOCK_REALTIME_COARSE
> +      case CLOCK_REALTIME_COARSE:
> +#endif
> +        timespecsub(tp, &ftpl_starttime.real, &tmp_ts);
> +        break;
> +      case CLOCK_MONOTONIC:
> +#ifdef CLOCK_MONOTONIC_COARSE
> +      case CLOCK_MONOTONIC_COARSE:
> +#endif
> +        timespecsub(tp, &ftpl_starttime.mon, &tmp_ts);
> +        break;
> +      case CLOCK_MONOTONIC_RAW:
> +        timespecsub(tp, &ftpl_starttime.mon_raw, &tmp_ts);
> +        break;
> +#ifdef CLOCK_BOOTTIME
> +      case CLOCK_BOOTTIME:
> +        timespecsub(tp, &ftpl_starttime.boot, &tmp_ts);
> +        break;
> +#endif
> +      default:
> +        printf("Invalid clock_id for clock_gettime: %d", clk_id);
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    if (limited_faking)
> +    {
> +      /* Check whether we actually should be faking the returned timestamp. */
> +      /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
> +      if ((ft_start_after_secs != -1)   && (tmp_ts.tv_sec < ft_start_after_secs)) return 0;
> +      if ((ft_stop_after_secs != -1)    && (tmp_ts.tv_sec >= ft_stop_after_secs)) return 0;
> +      if ((ft_start_after_ncalls != -1) && (callcounter < ft_start_after_ncalls)) return 0;
> +      if ((ft_stop_after_ncalls != -1)  && (callcounter >= ft_stop_after_ncalls)) return 0;
> +      /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu continues\n", (*time_tptr - ftpl_starttime), callcounter); */
> +    }
> +
> +    if (spawnsupport)
> +    {
> +      /* check whether we should spawn an external command */
> +      if (spawned == 0)
> +      { /* exec external command once only */
> +        if (((tmp_ts.tv_sec == ft_spawn_secs) || (callcounter == ft_spawn_ncalls)) && (spawned == 0))
> +        {
> +          spawned = 1;
> +          (void) (system(ft_spawn_target) + 1);
> +        }
> +      }
> +    }
> +  }
> +
> +  if (last_data_fetch > 0)
> +  {
> +    if ((tp->tv_sec - last_data_fetch) > cache_duration)
> +    {
> +      cache_expired = 1;
> +    }
> +    else
> +    {
> +      cache_expired = 0;
> +    }
> +  }
> +
> +  if (cache_enabled == 0)
> +  {
> +    cache_expired = 1;
> +  }
> +
> +  if (cache_expired == 1)
> +  {
> +    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)
> +    {
> +      char custom_filename[BUFSIZ];
> +      char filename[BUFSIZ];
> +      FILE *faketimerc;
> +      /* 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,
> +       * Jacob Moorman, and Wayne Davison of SourceForge, Inc. in version 0.6 */
> +      (void) snprintf(custom_filename, BUFSIZ, "%s", getenv("FAKETIME_TIMESTAMP_FILE"));
> +      (void) snprintf(filename, BUFSIZ, "%s/.faketimerc", getenv("HOME"));
> +      if ((faketimerc = fopen(custom_filename, "rt")) != NULL ||
> +          (faketimerc = fopen(filename, "rt")) != NULL ||
> +          (faketimerc = fopen("/etc/faketimerc", "rt")) != NULL)
> +      {
> +        char line[BUFFERLEN];
> +        while(fgets(line, BUFFERLEN, faketimerc) != NULL)
> +        {
> +          if ((strlen(line) > 1) && (line[0] != ' ') &&
> +              (line[0] != '#') && (line[0] != ';'))
> +          {
> +            remove_trailing_eols(line);
> +            strncpy(user_faked_time, line, BUFFERLEN-1);
> +            user_faked_time[BUFFERLEN-1] = 0;
> +            break;
> +          }
> +        }
> +        fclose(faketimerc);
> +      }
> +    } /* read fake time from file */
> +    parse_ft_string(user_faked_time);
> +  } /* cache had expired */
> +
> +  if (infile_set)
> +  {
> +    if (load_time(tp))
> +    {
> +      return 0;
> +    }
> +  }
> +
> +  /* check whether the user gave us an absolute time to fake */
> +  switch (ft_mode)
> +  {
> +    case FT_FREEZE:  /* a specified time */
> +      if (user_faked_time_set)
> +      {
> +        *tp = user_faked_time_timespec;
> +      }
> +      break;
> +
> +    case FT_START_AT: /* User-specified offset */
> +      if (user_per_tick_inc_set)
> +      {
> +        /* increment time with every time() call*/
> +        next_time(tp, &user_per_tick_inc);
> +      }
> +      else
> +      {
> +        /* Speed-up / slow-down contributed by Karl Chen in v0.8 */
> +        struct timespec tdiff, timeadj;
> +        switch (clk_id)
> +        {
> +          case CLOCK_REALTIME:
> +#ifdef CLOCK_REALTIME_COARSE
> +          case CLOCK_REALTIME_COARSE:
> +#endif
> +            timespecsub(tp, &ftpl_starttime.real, &tdiff);
> +            break;
> +          case CLOCK_MONOTONIC:
> +#ifdef CLOCK_MONOTONIC_COARSE
> +          case CLOCK_MONOTONIC_COARSE:
> +#endif
> +            timespecsub(tp, &ftpl_starttime.mon, &tdiff);
> +            break;
> +          case CLOCK_MONOTONIC_RAW:
> +            timespecsub(tp, &ftpl_starttime.mon_raw, &tdiff);
> +            break;
> +#ifdef CLOCK_BOOTTIME
> +          case CLOCK_BOOTTIME:
> +            timespecsub(tp, &ftpl_starttime.boot, &tdiff);
> +            break;
> +#endif
> +          default:
> +            printf("Invalid clock_id for clock_gettime: %d", clk_id);
> +            exit(EXIT_FAILURE);
> +        } // end of switch (clk_id)
> +        if (user_rate_set)
> +        {
> +          timespecmul(&tdiff, user_rate, &timeadj);
> +        }
> +        else
> +        {
> +          timeadj = tdiff;
> +        }
> +        timespecadd(&user_faked_time_timespec, &timeadj, tp);
> +      }
> +      break;
> +
> +    default:
> +      return -1;
> +  } // end of switch(ft_mode)
> +
> +#ifdef PTHREAD_SINGLETHREADED_TIME
> +  pthread_cleanup_pop(1);
> +#endif
> +  save_time(tp);
> +  return 0;
> +}
> +
> +int fake_gettimeofday(struct timeval *tv)
> +{
> +  struct timespec ts;
> +  int ret;
> +  ts.tv_sec = tv->tv_sec;
> +  ts.tv_nsec = tv->tv_usec * 1000  + ftpl_starttime.real.tv_nsec % 1000;
> +
> +  ret = fake_clock_gettime(CLOCK_REALTIME, &ts);
> +  tv->tv_sec = ts.tv_sec;
> +  tv->tv_usec =ts.tv_nsec / 1000;
> +
> +  return ret;
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Faked system functions: Apple Mac OS X specific           === FAKE(OSX)
> + *      =======================================================================
> + */
> +
> +#ifdef __APPLEOSX__
> +/*
> + * clock_gettime implementation for __APPLE__
> + * @note It always behave like being called with CLOCK_REALTIME.
> + */
> +static int apple_clock_gettime(clockid_t clk_id, struct timespec *tp)
> +{
> +  int result;
> +  mach_timespec_t cur_timeclockid_t;
> +  (void) clk_id; /* unused */
> +
> +  if (NULL == real_clock_get_time)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original clock_get_time() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  DONT_FAKE_TIME(result = (*real_clock_get_time)(clock_serv_real, &cur_timeclockid_t));
> +  tp->tv_sec =  cur_timeclockid_t.tv_sec;
> +  tp->tv_nsec = cur_timeclockid_t.tv_nsec;
> +  return result;
> +}
> +
> +int clock_get_time(clock_serv_t clock_serv, mach_timespec_t *cur_timeclockid_t)
> +{
> +  int result;
> +  struct timespec ts;
> +
> +  /*
> +   * Initialize our result with the real current time from CALENDAR_CLOCK.
> +   * This is a bit of cheating, but we don't keep track of obtained clock
> +   * services.
> +   */
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &ts));
> +  if (result == -1) return result; /* original function failed */
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  result = fake_clock_gettime(CLOCK_REALTIME, &ts);
> +  cur_timeclockid_t->tv_sec = ts.tv_sec;
> +  cur_timeclockid_t->tv_nsec = ts.tv_nsec;
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +#endif
> +
> +
> +/*
> + *      =======================================================================
> + *      Faked system-internal functions                           === FAKE(INT)
> + *      =======================================================================
> + */
> +
> +#ifdef FAKE_INTERNAL_CALLS
> +int __gettimeofday(struct timeval *tv, void *tz)
> +{
> +  int result;
> +
> +  /* sanity check */
> +  if (tv == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  /* Check whether we've got a pointer to the real ftime() function yet */
> +  if (NULL == real___gettimeofday)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original __gettimeofday() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  /* initialize our result with the real current time */
> +  DONT_FAKE_TIME(result = (*real___gettimeofday)(tv, tz));
> +  if (result == -1) return result; /* original function failed */
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  result = fake_gettimeofday(tv);
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +int __clock_gettime(clockid_t clk_id, struct timespec *tp)
> +{
> +  int result;
> +
> +  /* sanity check */
> +  if (tp == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  if (NULL == real___clock_gettime)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original __clock_gettime() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  /* initialize our result with the real current time */
> +  DONT_FAKE_TIME(result = (*real___clock_gettime)(clk_id, tp));
> +  if (result == -1) return result; /* original function failed */
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  if (fake_monotonic_clock || clk_id != CLOCK_MONOTONIC)
> +  {
> +    result = fake_clock_gettime(clk_id, tp);
> +  }
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +time_t __time(time_t *time_tptr)
> +{
> +  struct timespec tp;
> +  time_t result;
> +
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
> +  if (result == -1) return -1;
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
> +
> +  if (time_tptr != NULL)
> +  {
> +    *time_tptr = tp.tv_sec;
> +  }
> +  return tp.tv_sec;
> +}
> +
> +int __ftime(struct timeb *tb)
> +{
> +  struct timespec tp;
> +  int result;
> +
> +  /* sanity check */
> +  if (tb == NULL)
> +    return 0;               /* ftime() always returns 0, see manpage */
> +
> +  /* Check whether we've got a pointer to the real ftime() function yet */
> +  if (NULL == real___ftime)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original ftime() not found.\n");
> +#endif
> +    return 0; /* propagate error to caller */
> +  }
> +
> +  /* initialize our TZ result with the real current time */
> +  DONT_FAKE_TIME(result = (*real___ftime)(tb));
> +  if (result == -1)
> +  {
> +    return result;
> +  }
> +
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
> +  if (result == -1) return -1;
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
> +
> +  tb->time = tp.tv_sec;
> +  tb->millitm = tp.tv_nsec / 1000000;
> +
> +  /* return the result to the caller */
> +  return result; /* will always be 0 (see manpage) */
> +}
> +
> +#endif
> +
> +/*
> + * Editor modelines
> + *
> + * Local variables:
> + * c-basic-offset: 2
> + * tab-width: 2
> + * indent-tabs-mode: nil
> + * End:
> + *
> + * vi: set shiftwidth=2 tabstop=2 expandtab:
> + * :indentSize=2:tabSize=2:noTabs=true:
> + */
> +
> +/* eof */
> diff --git a/scripts/libfaketime/libfaketime.map b/scripts/libfaketime/libfaketime.map
> new file mode 100644
> index 0000000..6e008cf
> --- /dev/null
> +++ b/scripts/libfaketime/libfaketime.map
> @@ -0,0 +1,10 @@
> +GLIBC_2.2 {
> +  global:
> +
> +  timer_gettime; timer_settime;
> +  local: timer_settime_*; timer_gettime_*;
> +};
> +GLIBC_2.3.3 {
> +  # Changed timer_t.
> +  timer_gettime; timer_settime;
> +} GLIBC_2.2;
> diff --git a/scripts/libfaketime/time_ops.h b/scripts/libfaketime/time_ops.h
> new file mode 100644
> index 0000000..59ab1ee
> --- /dev/null
> +++ b/scripts/libfaketime/time_ops.h
> @@ -0,0 +1,104 @@
> +/*
> + * Time operation macros based on sys/time.h
> + * Copyright 2013 Balint Reczey <balint@balintreczey.hu>
> + *
> + * This file is part of libfaketime.
> + *
> + * libfaketime is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License v2 as published by the Free
> + * Software Foundation.
> + *
> + * libfaketime is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License v2 along
> + * with libfaketime; if not, write to the Free Software Foundation, Inc.,
> + * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef TIME_OPS_H
> +#define TIME_OPS_H
> +#include <time.h>
> +
> +#define SEC_TO_uSEC 1000000
> +#define SEC_TO_nSEC 1000000000
> +
> +/* Convenience macros for operations on timevals.
> +   NOTE: `timercmp' does not work for >= or <=.  */
> +#define timerisset2(tvp, prefix) ((tvp)->tv_sec || (tvp)->tv_##prefix##sec)
> +#define timerclear2(tvp, prefix) ((tvp)->tv_sec = (tvp)->tv_##prefix##sec = 0)
> +#define timercmp2(a, b, CMP, prefix)                                \
> +  (((a)->tv_sec == (b)->tv_sec) ?                                   \
> +   ((a)->tv_##prefix##sec CMP (b)->tv_##prefix##sec) :              \
> +   ((a)->tv_sec CMP (b)->tv_sec))
> +#define timeradd2(a, b, result, prefix)                             \
> +  do                                                                \
> +  {                                                                 \
> +    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                   \
> +    (result)->tv_##prefix##sec = (a)->tv_##prefix##sec +            \
> +      (b)->tv_##prefix##sec;                                        \
> +    if ((result)->tv_##prefix##sec >= SEC_TO_##prefix##SEC)         \
> +      {                                                             \
> +        ++(result)->tv_sec;                                         \
> +        (result)->tv_##prefix##sec -= SEC_TO_##prefix##SEC;         \
> +      }                                                             \
> +  } while (0)
> +#define timersub2(a, b, result, prefix)                             \
> +  do                                                                \
> +  {                                                                 \
> +    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                   \
> +    (result)->tv_##prefix##sec = (a)->tv_##prefix##sec -            \
> +      (b)->tv_##prefix##sec;                                        \
> +    if ((result)->tv_##prefix##sec < 0)                             \
> +    {                                                               \
> +      --(result)->tv_sec;                                           \
> +      (result)->tv_##prefix##sec += SEC_TO_##prefix##SEC;           \
> +    }                                                               \
> +  } while (0)
> +#define timermul2(tvp, c, result, prefix)                           \
> +  do                                                                \
> +  {                                                                 \
> +    long long tmp_time;                                             \
> +    tmp_time = (c) * ((tvp)->tv_sec * SEC_TO_##prefix##SEC +        \
> +               (tvp)->tv_##prefix##sec);                            \
> +    (result)->tv_##prefix##sec = tmp_time % SEC_TO_##prefix##SEC;   \
> +    (result)->tv_sec = (tmp_time - (result)->tv_##prefix##sec) /    \
> +      SEC_TO_##prefix##SEC;                                         \
> +    if ((result)->tv_##prefix##sec < 0)                             \
> +    {                                                               \
> +      (result)->tv_##prefix##sec +=  SEC_TO_##prefix##SEC;          \
> +      (result)->tv_sec -= 1;                                        \
> +    }                                                               \
> +  } while (0)
> +
> +/* ops for microsecs */
> +#ifndef timerisset
> +#define timerisset(tvp) timerisset2(tvp,u)
> +#endif
> +#ifndef timerclear
> +#define timerclear(tvp) timerclear2(tvp, u)
> +#endif
> +#ifndef timercmp
> +#define timercmp(a, b, CMP) timercmp2(a, b, CMP, u)
> +#endif
> +#ifndef timeradd
> +#define timeradd(a, b, result) timeradd2(a, b, result, u)
> +#endif
> +#ifndef timersub
> +#define timersub(a, b, result) timersub2(a, b, result, u)
> +#endif
> +#ifndef timersub
> +#define timermul(a, c, result) timermul2(a, c, result, u)
> +#endif
> +
> +/* ops for nanosecs */
> +#define timespecisset(tvp) timerisset2(tvp,n)
> +#define timespecclear(tvp) timerclear2(tvp, n)
> +#define timespeccmp(a, b, CMP) timercmp2(a, b, CMP, n)
> +#define timespecadd(a, b, result) timeradd2(a, b, result, n)
> +#define timespecsub(a, b, result) timersub2(a, b, result, n)
> +#define timespecmul(a, c, result) timermul2(a, c, result, n)
> +
> +#endif
> -- 
> 1.9.1
> 
> 
> _______________________________________________
> ptxdist mailing list
> ptxdist@pengutronix.de

-- 
Roland Hieber                     | r.hieber@pengutronix.de     |
Pengutronix e.K.                  | https://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim | Phone: +49-5121-206917-5086 |
Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |

_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support
  2018-08-08  9:50 ` [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support Roland Hieber
@ 2018-08-08 10:58   ` Jon Ringle
  2018-08-08 19:27     ` Jon Ringle
  0 siblings, 1 reply; 6+ messages in thread
From: Jon Ringle @ 2018-08-08 10:58 UTC (permalink / raw)
  To: ptxdist; +Cc: ptxdist, Jon Ringle


[-- Attachment #1.1: Type: text/plain, Size: 1980 bytes --]

On Wed, Aug 8, 2018 at 5:50 AM Roland Hieber <r.hieber@pengutronix.de>
wrote:

> On Fri, Aug 03, 2018 at 11:44:55AM -0400, jon@ringle.org wrote:
> > From: Jon Ringle <jringle@gridpoint.com>
> >
> > libfaketime will be used during patchin so that committer timestamps
> always
> > have a fixed value and therefore making the ${PKG}_SERIES_SHA256 value
> > repeatable
> >
> > The minimal set of source files was picked out of libfaketime-0.9.7
> >
> > Signed-off-by: Jon Ringle <jringle@gridpoint.com>
> > ---
> >  Makefile.in                           |   14 +-
> >  scripts/libfaketime/Makefile          |  118 ++
> >  scripts/libfaketime/faketime.c        |  385 ++++++
> >  scripts/libfaketime/faketime_common.h |   61 +
> >  scripts/libfaketime/libfaketime.c     | 2410
> +++++++++++++++++++++++++++++++++
> >  scripts/libfaketime/libfaketime.map   |   10 +
> >  scripts/libfaketime/time_ops.h        |  104 ++
>
> Uh. Does it really make more sense to vendor libfaketime instead of
> using the package from the host system, like we do it with python, bash,
> etc.?
>

The reason that this is needed as a core component of ptxdist rather than
just being built as a host package is that patchin step uses libfaketime
and therefore is potentially needed before even a single package is ever
built. What would happen if we just used a host-libfaketime package and
someone adds a patch series for libfaketime? (In fact, I actually do have
such a patch series locally that I will be sending to the ptxdist ml
later). This is a chicken vs egg problem that is resolved by making
libfaketime an integral part of ptxdist. The ptxdist usage of libfaketime
in the patchin step does not need a patched version of libfaketime (it just
needs to set an absolute date time and the libfaketime code I have here
does that). It doesn’t need new configuration features or bug fixes for
fixing the time manipulation via some specific system call.

-Jon

[-- Attachment #1.2: Type: text/html, Size: 2626 bytes --]

[-- Attachment #2: Type: text/plain, Size: 91 bytes --]

_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support
  2018-08-08 10:58   ` Jon Ringle
@ 2018-08-08 19:27     ` Jon Ringle
  0 siblings, 0 replies; 6+ messages in thread
From: Jon Ringle @ 2018-08-08 19:27 UTC (permalink / raw)
  To: ptxdist; +Cc: ptxdist, Jon Ringle

On Wed, Aug 8, 2018 at 6:58 AM Jon Ringle <jon@ringle.org> wrote:
> On Wed, Aug 8, 2018 at 5:50 AM Roland Hieber <r.hieber@pengutronix.de> wrote:
>> On Fri, Aug 03, 2018 at 11:44:55AM -0400, jon@ringle.org wrote:
>> > From: Jon Ringle <jringle@gridpoint.com>
>> >
>> > libfaketime will be used during patchin so that committer timestamps always
>> > have a fixed value and therefore making the ${PKG}_SERIES_SHA256 value
>> > repeatable
>> >
>> > The minimal set of source files was picked out of libfaketime-0.9.7
>> >
>> > Signed-off-by: Jon Ringle <jringle@gridpoint.com>
>> > ---
>> >  Makefile.in                           |   14 +-
>> >  scripts/libfaketime/Makefile          |  118 ++
>> >  scripts/libfaketime/faketime.c        |  385 ++++++
>> >  scripts/libfaketime/faketime_common.h |   61 +
>> >  scripts/libfaketime/libfaketime.c     | 2410 +++++++++++++++++++++++++++++++++
>> >  scripts/libfaketime/libfaketime.map   |   10 +
>> >  scripts/libfaketime/time_ops.h        |  104 ++
>>
>> Uh. Does it really make more sense to vendor libfaketime instead of
>> using the package from the host system, like we do it with python, bash,
>> etc.?
>
>
> The reason that this is needed as a core component of ptxdist rather than just being built as a host package is that patchin step uses libfaketime and therefore is potentially needed before even a single package is ever built. What would happen if we just used a host-libfaketime package and someone adds a patch series for libfaketime? (In fact, I actually do have such a patch series locally that I will be sending to the ptxdist ml later). This is a chicken vs egg problem that is resolved by making libfaketime an integral part of ptxdist. The ptxdist usage of libfaketime in the patchin step does not need a patched version of libfaketime (it just needs to set an absolute date time and the libfaketime code I have here does that). It doesn’t need new configuration features or bug fixes for fixing the time manipulation via some specific system call.

Roland, I think I see now what you are getting at. However, do you
think it is ok to ask everyone to install libfaketime on their system
(`sudo apt-get install libfaketime`) before they are able to configure
the next version of ptxdist? On ubuntu 14.04 this package installs the
following files for me:

/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1
/usr/lib/x86_64-linux-gnu/faketime/libfaketimeMT.so.1
/usr/share/doc/libfaketime/README.gz
/usr/share/doc/libfaketime/changelog.Debian.gz
/usr/share/doc/libfaketime/copyright

There is nothing here that I see that can be used to properly set the
correct location of the libfaketime.so.1 when setting LD_PRELOAD
environment. It could be in a different location on some other
distribution.
The libfaketime code is fairly small and making it a part of ptxdist
like kconfig is just makes sense to me given the use case where it is
needed

-Jon

_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support
  2018-08-03 15:44 [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support jon
  2018-08-03 15:44 ` [ptxdist] [PATCH v4 2/2] Detect changes in package patch series jon
  2018-08-08  9:50 ` [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support Roland Hieber
@ 2018-08-27 16:27 ` Michael Olbrich
  2 siblings, 0 replies; 6+ messages in thread
From: Michael Olbrich @ 2018-08-27 16:27 UTC (permalink / raw)
  To: ptxdist

On Fri, Aug 03, 2018 at 11:44:55AM -0400, jon@ringle.org wrote:
> From: Jon Ringle <jringle@gridpoint.com>
> 
> libfaketime will be used during patchin so that committer timestamps always
> have a fixed value and therefore making the ${PKG}_SERIES_SHA256 value
> repeatable
> 
> The minimal set of source files was picked out of libfaketime-0.9.7

I think it should be possible to provide the correct timestamps with
GIT_AUTHOR_DATE and/or GIT_COMMITTER_DATE or something like that.

Michael

> 
> Signed-off-by: Jon Ringle <jringle@gridpoint.com>
> ---
>  Makefile.in                           |   14 +-
>  scripts/libfaketime/Makefile          |  118 ++
>  scripts/libfaketime/faketime.c        |  385 ++++++
>  scripts/libfaketime/faketime_common.h |   61 +
>  scripts/libfaketime/libfaketime.c     | 2410 +++++++++++++++++++++++++++++++++
>  scripts/libfaketime/libfaketime.map   |   10 +
>  scripts/libfaketime/time_ops.h        |  104 ++
>  7 files changed, 3101 insertions(+), 1 deletion(-)
>  create mode 100644 scripts/libfaketime/Makefile
>  create mode 100644 scripts/libfaketime/faketime.c
>  create mode 100644 scripts/libfaketime/faketime_common.h
>  create mode 100644 scripts/libfaketime/libfaketime.c
>  create mode 100644 scripts/libfaketime/libfaketime.map
>  create mode 100644 scripts/libfaketime/time_ops.h
> 
> diff --git a/Makefile.in b/Makefile.in
> index 40c676c..6e08377 100644
> --- a/Makefile.in
> +++ b/Makefile.in
> @@ -22,7 +22,7 @@ export SHELL
>  
>  @BUILD_NCONF_TRUE@NCONF = nconf
>  
> -all: kconfig environment
> +all: kconfig libfaketime environment
>  	@touch .done
>  
>  kconfig:
> @@ -41,6 +41,17 @@ kconfig:
>  		conf mconf $(NCONF)
>  	@echo "done."
>  
> +libfaketime:
> +	@echo "building libfaketime ..."
> +	@CC="$(CC)" \
> +	CXX="$(CXX)" \
> +	CFLAGS="$(CFLAGS)" \
> +	CXXFLAGS="$(CXXFLAGS)" \
> +	CPPFLAGS="$(CPPFLAGS)" \
> +	LDFLAGS="$(LDFLAGS)" \
> +	$(MAKE) -C "$(abs_srcdir)/scripts/libfaketime" all
> +	@echo "done."
> +
>  environment:
>  	@echo -n "preparing PTXdist environment ..."
>  	@ln -sf @AWK@ "$(abs_srcdir)/bin/awk"
> @@ -89,6 +100,7 @@ clean:
>  	@rm -f .done
>  	@find "$(abs_srcdir)/bin" -type l -print0 | xargs -0 rm -f
>  	@$(MAKE) -C "$(abs_srcdir)/scripts/kconfig" clean
> +	@$(MAKE) -C "$(abs_srcdir)/scripts/libfaketime" clean
>  
>  dirty-check:
>  	@case "$(version)" in \
> diff --git a/scripts/libfaketime/Makefile b/scripts/libfaketime/Makefile
> new file mode 100644
> index 0000000..a557c38
> --- /dev/null
> +++ b/scripts/libfaketime/Makefile
> @@ -0,0 +1,118 @@
> +#
> +# Notes:
> +#
> +#   * Compilation Defines:
> +#
> +#     FAKE_STAT
> +#         - Enables time faking also for files' timestamps.
> +#
> +#     NO_ATFILE
> +#         - Disables support for the fstatat() group of functions
> +#
> +#     PTHREAD
> +#         - Define this to enable multithreading support.
> +#
> +#     PTHREAD_SINGLETHREADED_TIME
> +#         - Define this if you want to single-thread time() ... there ARE
> +#           possibile caching side-effects in a multithreaded environment
> +#           without this, but the performance impact may require you to
> +#           try it unsynchronized.
> +#
> +#     FAKE_INTERNAL_CALLS
> +#         - Also intercept libc internal __functions, e.g. not just time(),
> +#           but also __time(). Enhances compatibility with applications
> +#           that make use of low-level system calls, such as Java Virtual
> +#           Machines.
> +#
> +# 	  FAKE_SLEEP
> +# 	      - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
> +#
> +#	  FAKE_TIMERS
> +#	      - Also intercept timer_settime() and timer_gettime()
> +#
> +#	  MULTI_ARCH
> +#	  	  - If MULTI_ARCH is set, the faketime wrapper program will put a literal
> +#	  	    $LIB into the LD_PRELOAD environment variable it creates, which makes
> +#	  	    ld automatically choose the correct library version to use for the
> +#	  	    target binary. Use for Linux platforms with Multi-Arch support only!
> +#
> +#   * Compilation addition: second libMT target added for building the pthread-
> +#     enabled library as a separate library
> +#
> +#   * Compilation switch change: previous versions compiled using '-nostartfiles'
> +#     This is no longer the case since there is a 'startup' constructor for the library
> +#     which is used to activate the start-at times when specified. This also initializes
> +#     the dynamic disabling of the FAKE_STAT calls.
> +#
> +# By default, libfaketime will be compiled for your system's default architecture.
> +# To build 32-bit libraries and binaries, add -m32 to CFLAGS and LDFLAGS.
> +#
> +# Change PREFIX to where you want libfaketime (libraries and wrapper binary) installed.
> +# LIBDIRNAME is relative to PREFIX. The default is to install into $PREFIX/lib/faketime,
> +# but you can set LIBDIRNAME to, e.g., /lib64 if you want to install it elsewhere.
> +# LIBDIRNAME has been introduced to support MultiLib systems. Please do not change the 
> +# default value on MultiArch systems. 
> +#
> +# For testing in the current directory without installation, try make PREFIX= LIBDIRNAME='.'
> +
> +CC ?= gcc
> +INSTALL ?= install
> +
> +PREFIX ?= /usr/local
> +LIBDIRNAME ?= /lib/faketime
> +PLATFORM ?=$(shell uname)
> +
> +CFLAGS += -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -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 += -lpthread
> +ifneq ($(PLATFORM),SunOS)
> +LDFLAGS += -Wl,--version-script=libfaketime.map
> +endif
> +
> +LDADD += -ldl -lm -lrt
> +BIN_LDFLAGS += -lrt
> +
> +SRC = libfaketime.c
> +LIBS_OBJ = libfaketime.o libfaketimeMT.o
> +BINS = faketime
> +
> +SONAME = 1
> +LIBS = libfaketime.so.${SONAME} libfaketimeMT.so.${SONAME}
> +
> +all: ${LIBS} ${BINS}
> +
> +libfaketimeMT.o: EXTRA_FLAGS := -DPTHREAD -DPTHREAD_SINGLETHREADED_TIME
> +
> +${LIBS_OBJ}: libfaketime.c
> +	${CC} -o $@ -c ${CFLAGS} ${EXTRA_FLAGS} $<
> +
> +%.so.${SONAME}: %.o libfaketime.map
> +	${CC} -o $@ -Wl,-soname,$@ ${LDFLAGS} ${LIB_LDFLAGS} $< ${LDADD}
> +
> +${BINS}: faketime.c
> +	${CC} -o $@ ${CFLAGS} ${EXTRA_FLAGS} $< ${LDFLAGS} ${BIN_LDFLAGS}
> +
> +clean:
> +	@rm -f ${LIBS_OBJ} ${LIBS} ${BINS}
> +
> +distclean: clean
> +	@echo
> +
> +install: ${LIBS} ${BINS}
> +	@echo
> +	@echo "Copying the faketime libraries to ${DESTDIR}${PREFIX}${LIBDIRNAME} and the faketime wrapper script to ${DESTDIR}${PREFIX}/bin ..."
> +	$(INSTALL) -dm0755 "${DESTDIR}${PREFIX}${LIBDIRNAME}/"
> +	$(INSTALL) -m0644 ${LIBS} "${DESTDIR}${PREFIX}${LIBDIRNAME}/"
> +	$(INSTALL) -Dm0755 faketime "${DESTDIR}${PREFIX}/bin/faketime"
> +
> +uninstall:
> +	for f in ${LIBS}; do rm -f "${DESTDIR}${PREFIX}${LIBDIRNAME}/$$f"; done
> +	rmdir "${DESTDIR}${PREFIX}${LIBDIRNAME}"
> +	rm -f "${DESTDIR}${PREFIX}/bin/faketime"
> +
> +.PHONY: all clean distclean install uninstall
> diff --git a/scripts/libfaketime/faketime.c b/scripts/libfaketime/faketime.c
> new file mode 100644
> index 0000000..138ebbd
> --- /dev/null
> +++ b/scripts/libfaketime/faketime.c
> @@ -0,0 +1,385 @@
> +/*
> + *  libfaketime wrapper command
> + *
> + *  This file is part of libfaketime, version 0.9.7
> + *
> + *  libfaketime is free software; you can redistribute it and/or modify it
> + *  under the terms of the GNU General Public License v2 as published by the
> + *  Free Software Foundation.
> + *
> + *  libfaketime is distributed in the hope that it will be useful, but WITHOUT
> + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + *  more details.
> + *
> + *  You should have received a copy of the GNU General Public License v2 along
> + *  with the libfaketime; if not, write to the Free Software Foundation,
> + *  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + *
> + * Converted from shell script by Balint Reczey with the following credits
> + * and comments:
> + *
> + * Thanks to Daniel Kahn Gillmor for improvement suggestions.
> +
> + * This wrapper exposes only a small subset of the libfaketime functionality.
> + * Please see libfaketime's README file and man page for more details.
> +
> + * Acknowledgment: Parts of the functionality of this wrapper have been
> + * inspired by Matthias Urlichs' datefudge 1.14.
> +
> + * Compile time configuration: Path where the libfaketime libraries can be found
> + * on Linux/UNIX
> + *
> + */
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <time.h>
> +#include <fcntl.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include <sys/mman.h>
> +#include <semaphore.h>
> +
> +#include "faketime_common.h"
> +
> +const char version[] = "0.9.7";
> +
> +#ifdef __APPLE__
> +static const char *date_cmd = "gdate";
> +#else
> +static const char *date_cmd = "date";
> +#endif
> +
> +#define PATH_BUFSIZE 4096
> +
> +/* semaphore and shared memory names */
> +char sem_name[PATH_BUFSIZE] = {0}, shm_name[PATH_BUFSIZE] = {0};
> +
> +void usage(const char *name)
> +{
> +  printf("\n"
> +  "Usage: %s [switches] <timestamp> <program with arguments>\n"
> +  "\n"
> +  "This will run the specified 'program' with the given 'arguments'.\n"
> +  "The program will be tricked into seeing the given 'timestamp' as its starting date and time.\n"
> +  "The clock will continue to run from this timestamp. Please see the manpage (man faketime)\n"
> +  "for advanced options, such as stopping the wall clock and make it run faster or slower.\n"
> +  "\n"
> +  "The optional switches are:\n"
> +  "  -m                  : Use the multi-threaded version of libfaketime\n"
> +  "  -f                  : Use the advanced timestamp specification format (see manpage)\n"
> +  "  --exclude-monotonic : Prevent monotonic clock from drifting (not the raw monotonic one)\n"
> +  "\n"
> +  "Examples:\n"
> +  "%s 'last friday 5 pm' /bin/date\n"
> +  "%s '2008-12-24 08:15:42' /bin/date\n"
> +  "%s -f '+2,5y x10,0' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n"
> +  "%s -f '+2,5y x0,50' /bin/bash -c 'date; while true; do echo $SECONDS ; sleep 1 ; done'\n"
> +  "%s -f '+2,5y i2,0' /bin/bash -c 'date; while true; do date; sleep 1 ; done'\n"
> +  "In this single case all spawned processes will use the same global clock\n"
> +  "without restarting it at the start of each process.\n\n"
> +  "(Please note that it depends on your locale settings whether . or , has to be used for fractions)\n"
> +  "\n", name, name, name, name, name, name);
> +}
> +
> +/** Clean up shared objects */
> +static void cleanup_shobjs()
> +{
> +  if (-1 == sem_unlink(sem_name))
> +  {
> +    perror("sem_unlink");
> +  }
> +  if (-1 == shm_unlink(shm_name))
> +  {
> +    perror("shm_unlink");
> +  }
> +}
> +
> +int main (int argc, char **argv)
> +{
> +  pid_t child_pid;
> +  int curr_opt = 1;
> +  bool use_mt = false, use_direct = false;
> +  long offset;
> +
> +  while(curr_opt < argc)
> +  {
> +    if (0 == strcmp(argv[curr_opt], "-m"))
> +    {
> +      use_mt = true;
> +      curr_opt++;
> +      continue;
> +    }
> +    else if (0 == strcmp(argv[curr_opt], "-f"))
> +    {
> +      use_direct = true;
> +      curr_opt++;
> +      continue;
> +    }
> +    else if (0 == strcmp(argv[curr_opt], "--exclude-monotonic"))
> +    {
> +      setenv("DONT_FAKE_MONOTONIC", "1", true);
> +      curr_opt++;
> +      continue;
> +    }
> +    else if ((0 == strcmp(argv[curr_opt], "-v")) ||
> +             (0 == strcmp(argv[curr_opt], "--version")))
> +    {
> +      printf("\n%s: Version %s\n"
> +         "For usage information please use '%s --help'.\n",
> +         argv[0], version, argv[0]);
> +      exit(EXIT_SUCCESS);
> +    }
> +    else if ((0 == strcmp(argv[curr_opt], "-h")) ||
> +             (0 == strcmp(argv[curr_opt], "-?")) ||
> +             (0 == strcmp(argv[curr_opt], "--help")))
> +    {
> +      usage(argv[0]);
> +      exit(EXIT_SUCCESS);
> +    }
> +    else
> +    {
> +      /* we parsed all options */
> +      break;
> +    }
> +  }
> +
> +  /* we need at least a timestamp string and a command to run */
> +  if (argc - curr_opt < 2)
> +  {
> +    usage(argv[0]);
> +    exit(EXIT_FAILURE);
> +  }
> +
> +  if (!use_direct)
> +  {
> +    // TODO get seconds
> +    int pfds[2];
> +    (void) (pipe(pfds) + 1);
> +    int ret = EXIT_SUCCESS;
> +
> +    if (0 == (child_pid = fork()))
> +    {
> +      close(1);       /* close normal stdout */
> +      (void) (dup(pfds[1]) + 1);   /* make stdout same as pfds[1] */
> +      close(pfds[0]); /* we don't need this */
> +      if (EXIT_SUCCESS != execlp(date_cmd, date_cmd, "-d", argv[curr_opt], "+%s",(char *) NULL))
> +      {
> +        perror("Running (g)date failed");
> +        exit(EXIT_FAILURE);
> +      }
> +    }
> +    else
> +    {
> +      char buf[256] = {0}; /* e will have way less than 256 digits */
> +      close(pfds[1]);   /* we won't write to this */
> +      (void) (read(pfds[0], buf, 256) + 1);
> +      waitpid(child_pid, &ret, 0);
> +      if (ret != EXIT_SUCCESS)
> +      {
> +        printf("Error: Timestamp to fake not recognized, please re-try with a "
> +               "different timestamp.\n");
> +        exit(EXIT_FAILURE);
> +      }
> +      offset = atol(buf) - time(NULL);
> +      ret = snprintf(buf, sizeof(buf), "%s%ld", (offset >= 0)?"+":"", offset);
> +      setenv("FAKETIME", buf, true);
> +      close(pfds[0]); /* finished reading */
> +    }
> +  }
> +  else
> +  {
> +    /* simply pass format string along */
> +    setenv("FAKETIME", argv[curr_opt], true);
> +  }
> +  int keepalive_fds[2];
> +  (void) (pipe(keepalive_fds) + 1);
> +
> +  /* we just consumed the timestamp option */
> +  curr_opt++;
> +
> +  {
> +    /* create semaphores and shared memory */
> +    int shm_fd;
> +    sem_t *sem;
> +    struct ft_shared_s *ft_shared;
> +    char shared_objs[PATH_BUFSIZE];
> +
> +    /*
> +     * 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)))
> +    {
> +      perror("sem_open");
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    /* create shm */
> +    if (-1 == (shm_fd = shm_open(shm_name, O_CREAT|O_EXCL|O_RDWR, S_IWUSR|S_IRUSR)))
> +    {
> +      perror("shm_open");
> +      if (-1 == sem_unlink(argv[2]))
> +      {
> +        perror("sem_unlink");
> +      }
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    /* set shm size */
> +    if (-1 == ftruncate(shm_fd, sizeof(uint64_t)))
> +    {
> +      perror("ftruncate");
> +      cleanup_shobjs();
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    /* map shm */
> +    if (MAP_FAILED == (ft_shared = mmap(NULL, sizeof(struct ft_shared_s), PROT_READ|PROT_WRITE,
> +                        MAP_SHARED, shm_fd, 0)))
> +    {
> +      perror("mmap");
> +      cleanup_shobjs();
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    if (sem_wait(sem) == -1)
> +    {
> +      perror("sem_wait");
> +      cleanup_shobjs();
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    /* init elapsed time ticks to zero */
> +    ft_shared->ticks = 0;
> +    ft_shared->file_idx = 0;
> +    ft_shared->start_time.real.tv_sec = 0;
> +    ft_shared->start_time.real.tv_nsec = -1;
> +    ft_shared->start_time.mon.tv_sec = 0;
> +    ft_shared->start_time.mon.tv_nsec = -1;
> +    ft_shared->start_time.mon_raw.tv_sec = 0;
> +    ft_shared->start_time.mon_raw.tv_nsec = -1;
> +
> +    if (-1 == munmap(ft_shared, (sizeof(struct ft_shared_s))))
> +    {
> +      perror("munmap");
> +      cleanup_shobjs();
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    if (sem_post(sem) == -1)
> +    {
> +      perror("semop");
> +      cleanup_shobjs();
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    snprintf(shared_objs, PATH_BUFSIZE, "%s %s", sem_name, shm_name);
> +    setenv("FAKETIME_SHARED", shared_objs, true);
> +    sem_close(sem);
> +  }
> +
> +  {
> +    char *ftpl_path;
> +#ifdef __APPLE__
> +    ftpl_path = PREFIX "/libfaketime.1.dylib";
> +    FILE *check;
> +    check = fopen(ftpl_path, "ro");
> +    if (check == NULL)
> +    {
> +      ftpl_path = PREFIX "/lib/faketime/libfaketime.1.dylib";
> +    }
> +    else
> +    {
> +      fclose(check);
> +    }
> +    setenv("DYLD_INSERT_LIBRARIES", ftpl_path, true);
> +    setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", true);
> +#else
> +    {
> +      char *ld_preload_new, *ld_preload = getenv("LD_PRELOAD");
> +      size_t len;
> +      if (use_mt)
> +      {
> +        /*
> +         * on MultiArch platforms, such as Debian, we put a literal $LIB into LD_PRELOAD.
> +         */
> +#ifndef MULTI_ARCH
> +        ftpl_path = PREFIX LIBDIRNAME "/libfaketimeMT.so.1";
> +#else
> +        ftpl_path = PREFIX "/$LIB/faketime/libfaketimeMT.so.1";
> +#endif
> +      }
> +      else
> +      {
> +#ifndef MULTI_ARCH
> +        ftpl_path = PREFIX LIBDIRNAME "/libfaketime.so.1";
> +#else
> +        ftpl_path = PREFIX "/$LIB/faketime/libfaketime.so.1";
> +#endif
> +      }
> +      len = ((ld_preload)?strlen(ld_preload) + 1: 0) + 1 + strlen(ftpl_path);
> +      ld_preload_new = malloc(len);
> +      snprintf(ld_preload_new, len ,"%s%s%s", (ld_preload)?ld_preload:"",
> +              (ld_preload)?":":"", ftpl_path);
> +      setenv("LD_PRELOAD", ld_preload_new, true);
> +      free(ld_preload_new);
> +    }
> +#endif
> +  }
> +
> +  /* run command and clean up shared objects */
> +  if (0 == (child_pid = fork()))
> +  {
> +    close(keepalive_fds[0]); /* only parent needs to read this */
> +    if (EXIT_SUCCESS != execvp(argv[curr_opt], &argv[curr_opt]))
> +    {
> +      perror("Running specified command failed");
> +      exit(EXIT_FAILURE);
> +    }
> +  }
> +  else
> +  {
> +    int ret;
> +    char buf;
> +    close(keepalive_fds[1]); /* only children need keep this open */
> +    waitpid(child_pid, &ret, 0);
> +    (void) (read(keepalive_fds[0], &buf, 1) + 1); /* reads 0B when all children exit */
> +    cleanup_shobjs();
> +    if (WIFSIGNALED(ret))
> +    {
> +      fprintf(stderr, "Caught %s\n", strsignal(WTERMSIG(ret)));
> +      exit(EXIT_FAILURE);
> +    }
> +    exit(WEXITSTATUS(ret));
> +  }
> +
> +  return EXIT_SUCCESS;
> +}
> +
> +/*
> + * Editor modelines
> + *
> + * Local variables:
> + * c-basic-offset: 2
> + * tab-width: 2
> + * indent-tabs-mode: nil
> + * End:
> + *
> + * vi: set shiftwidth=2 tabstop=2 expandtab:
> + * :indentSize=2:tabSize=2:noTabs=true:
> + */
> +
> +/* eof */
> diff --git a/scripts/libfaketime/faketime_common.h b/scripts/libfaketime/faketime_common.h
> new file mode 100644
> index 0000000..9fda6a7
> --- /dev/null
> +++ b/scripts/libfaketime/faketime_common.h
> @@ -0,0 +1,61 @@
> +/*
> + * Faketime's common definitions
> + *
> + * Copyright 2013 Balint Reczey <balint@balintreczey.hu>
> + *
> + * This file is part of the libfaketime.
> + *
> + * libfaketime is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License v2 as published by the Free
> + * Software Foundation.
> + *
> + * libfaketime is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License v2 along
> + * with libfaketime; if not, write to the Free Software Foundation, Inc.,
> + * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef FAKETIME_COMMON_H
> +#define FAKETIME_COMMON_H
> +
> +#include <stdint.h>
> +
> +struct system_time_s
> +{
> +  /* System time according to CLOCK_REALTIME */
> +  struct timespec real;
> +  /* System time according to CLOCK_MONOTONIC */
> +  struct timespec mon;
> +  /* System time according to CLOCK_MONOTONIC_RAW */
> +  struct timespec mon_raw;
> +#ifdef CLOCK_BOOTTIME
> +  /* System time according to CLOCK_BOOTTIME */
> +  struct timespec boot;
> +#endif
> +};
> +
> +/* Data shared among faketime-spawned processes */
> +struct ft_shared_s
> +{
> +  /*
> +   * When advancing time linearly with each time(), etc. call, the calls are
> +   * counted here */
> +  uint64_t ticks;
> +  /* Index of timstamp to be loaded from file */
> +  uint64_t file_idx;
> +  /* System time Faketime started at */
> +  struct system_time_s start_time;
> +};
> +
> +/* These are all needed in order to properly build on OSX */
> +#ifdef __APPLE__
> +#include <mach/clock.h>
> +#include <mach/mach_host.h>
> +#include <mach/mach_port.h>
> +#endif
> +
> +#endif
> diff --git a/scripts/libfaketime/libfaketime.c b/scripts/libfaketime/libfaketime.c
> new file mode 100644
> index 0000000..eb2d01b
> --- /dev/null
> +++ b/scripts/libfaketime/libfaketime.c
> @@ -0,0 +1,2410 @@
> +/*
> + *  This file is part of libfaketime, version 0.9.7
> + *
> + *  libfaketime is free software; you can redistribute it and/or modify it
> + *  under the terms of the GNU General Public License v2 as published by the
> + *  Free Software Foundation.
> + *
> + *  libfaketime is distributed in the hope that it will be useful, but WITHOUT
> + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + *  more details.
> + *
> + *  You should have received a copy of the GNU General Public License v2 along
> + *  with the libfaketime; if not, write to the Free Software Foundation,
> + *  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +/*
> + *      =======================================================================
> + *      Global settings, includes, and macros                          === HEAD
> + *      =======================================================================
> + */
> +
> +#define _GNU_SOURCE             /* required to get RTLD_NEXT defined */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <stdbool.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <poll.h>
> +#include <time.h>
> +#include <math.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <semaphore.h>
> +#include <sys/mman.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <netinet/in.h>
> +#include <limits.h>
> +
> +#include "time_ops.h"
> +#include "faketime_common.h"
> +
> +/* pthread-handling contributed by David North, TDI in version 0.7 */
> +#ifdef PTHREAD
> +#include <pthread.h>
> +#endif
> +
> +#include <sys/timeb.h>
> +#include <dlfcn.h>
> +
> +#define BUFFERLEN   256
> +
> +#ifndef __APPLE__
> +extern char *__progname;
> +#ifdef __sun
> +#include "sunos_endian.h"
> +#else
> +#include <endian.h>
> +#endif
> +#else
> +/* endianness related macros */
> +#ifndef OSSwapHostToBigInt64
> +#define OSSwapHostToBigInt64(x) ((uint64_t)(x))
> +#endif
> +#define htobe64(x) OSSwapHostToBigInt64(x)
> +#ifndef OSSwapHostToLittleInt64
> +#define OSSwapHostToLittleInt64(x) OSSwapInt64(x)
> +#endif
> +#define htole64(x) OSSwapHostToLittleInt64(x)
> +#ifndef OSSwapBigToHostInt64
> +#define OSSwapBigToHostInt64(x) ((uint64_t)(x))
> +#endif
> +#define be64toh(x) OSSwapBigToHostInt64(x)
> +#ifndef OSSwapLittleToHostInt64
> +#define OSSwapLittleToHostInt64(x) OSSwapInt64(x)
> +#endif
> +#define le64toh(x) OSSwapLittleToHostInt64(x)
> +
> +/* clock_gettime() and related clock definitions are missing on __APPLE__ */
> +#ifndef CLOCK_REALTIME
> +/* from GNU C Library time.h */
> +/* Identifier for system-wide realtime clock. ( == 1) */
> +#define CLOCK_REALTIME               CALENDAR_CLOCK
> +/* Monotonic system-wide clock. (== 0) */
> +#define CLOCK_MONOTONIC              SYSTEM_CLOCK
> +/* High-resolution timer from the CPU.  */
> +#define CLOCK_PROCESS_CPUTIME_ID     2
> +/* Thread-specific CPU-time clock.  */
> +#define CLOCK_THREAD_CPUTIME_ID      3
> +/* Monotonic system-wide clock, not adjusted for frequency scaling.  */
> +#define CLOCK_MONOTONIC_RAW          4
> +typedef int clockid_t;
> +#include <mach/clock.h>
> +#include <mach/mach.h>
> +#endif
> +#endif
> +
> +/* some systems lack raw clock */
> +#ifndef CLOCK_MONOTONIC_RAW
> +#define CLOCK_MONOTONIC_RAW (CLOCK_MONOTONIC + 1)
> +#endif
> +
> +/*
> + * Per thread variable, which we turn on inside real_* calls to avoid modifying
> + * time multiple times of for the whole process to prevent faking time
> + */
> +static __thread bool dont_fake = false;
> +
> +/* Wrapper for function calls, which we want to return system time */
> +#define DONT_FAKE_TIME(call)          \
> +  {                                   \
> +    bool dont_fake_orig = dont_fake;  \
> +    if (!dont_fake)                   \
> +    {                                 \
> +      dont_fake = true;               \
> +    }                                 \
> +    call;                             \
> +    dont_fake = dont_fake_orig;       \
> +  } while (0)
> +
> +/* pointers to real (not faked) functions */
> +static int          (*real_stat)            (int, const char *, struct stat *);
> +static int          (*real_fstat)           (int, int, struct stat *);
> +static int          (*real_fstatat)         (int, int, const char *, struct stat *, int);
> +static int          (*real_lstat)           (int, const char *, struct stat *);
> +static int          (*real_stat64)          (int, const char *, struct stat64 *);
> +static int          (*real_fstat64)         (int, int , struct stat64 *);
> +static int          (*real_fstatat64)       (int, int , const char *, struct stat64 *, int);
> +static int          (*real_lstat64)         (int, const char *, struct stat64 *);
> +static time_t       (*real_time)            (time_t *);
> +static int          (*real_ftime)           (struct timeb *);
> +static int          (*real_gettimeofday)    (struct timeval *, void *);
> +static int          (*real_clock_gettime)   (clockid_t clk_id, struct timespec *tp);
> +#ifdef FAKE_INTERNAL_CALLS
> +static int          (*real___ftime)           (struct timeb *);
> +static int          (*real___gettimeofday)    (struct timeval *, void *);
> +static int          (*real___clock_gettime)   (clockid_t clk_id, struct timespec *tp);
> +#endif
> +#ifndef __APPLEOSX__
> +#ifdef FAKE_TIMERS
> +static int          (*real_timer_settime_22)   (int timerid, int flags, const struct itimerspec *new_value,
> +                                                struct itimerspec * old_value);
> +static int          (*real_timer_settime_233)  (timer_t timerid, int flags,
> +                                                const struct itimerspec *new_value,
> +                                                struct itimerspec * old_value);
> +static int          (*real_timer_gettime_22)   (int timerid,
> +                                                struct itimerspec *curr_value);
> +static int          (*real_timer_gettime_233)  (timer_t timerid,
> +                                                struct itimerspec *curr_value);
> +#endif
> +#endif
> +#ifdef FAKE_SLEEP
> +static int          (*real_nanosleep)       (const struct timespec *req, struct timespec *rem);
> +static int          (*real_usleep)          (useconds_t usec);
> +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_select)          (int nfds, fd_set *restrict readfds,
> +                                             fd_set *restrict writefds,
> +                                             fd_set *restrict errorfds,
> +                                             struct timeval *restrict timeout);
> +static int          (*real_sem_timedwait)   (sem_t*, const struct timespec*);
> +#endif
> +#ifdef __APPLEOSX__
> +static int          (*real_clock_get_time)  (clock_serv_t clock_serv, mach_timespec_t *cur_timeclockid_t);
> +static int          apple_clock_gettime     (clockid_t clk_id, struct timespec *tp);
> +static clock_serv_t clock_serv_real;
> +#endif
> +
> +static int initialized = 0;
> +
> +/* prototypes */
> +static int    fake_gettimeofday(struct timeval *tv);
> +static int    fake_clock_gettime(clockid_t clk_id, struct timespec *tp);
> +
> +/** Semaphore protecting shared data */
> +static sem_t *shared_sem = NULL;
> +
> +/** Data shared among faketime-spawned processes */
> +static struct ft_shared_s *ft_shared = NULL;
> +
> +/** Storage format for timestamps written to file. Big endian.*/
> +struct saved_timestamp
> +{
> +  int64_t sec;
> +  uint64_t nsec;
> +};
> +
> +static inline void timespec_from_saved (struct timespec *tp,
> +  struct saved_timestamp *saved)
> +{
> +  /* read as big endian */
> +  tp->tv_sec = be64toh(saved->sec);
> +  tp->tv_nsec = be64toh(saved->nsec);
> +}
> +
> +/** Saved timestamps */
> +static struct saved_timestamp *stss = NULL;
> +static size_t infile_size;
> +static bool infile_set = false;
> +
> +/** File fd to save timestamps to */
> +static int outfile = -1;
> +
> +static bool limited_faking = false;
> +static long callcounter = 0;
> +static long ft_start_after_secs = -1;
> +static long ft_stop_after_secs = -1;
> +static long ft_start_after_ncalls = -1;
> +static long ft_stop_after_ncalls = -1;
> +
> +static bool spawnsupport = false;
> +static int spawned = 0;
> +static char ft_spawn_target[1024];
> +static long ft_spawn_secs = -1;
> +static long ft_spawn_ncalls = -1;
> +
> +static int fake_monotonic_clock = 1;
> +static int cache_enabled = 1;
> +static int cache_duration = 10;     /* cache fake time input for 10 seconds */
> +
> +/*
> + * Static timespec to store our startup time, followed by a load-time library
> + * initialization declaration.
> + */
> +#ifndef CLOCK_BOOTTIME
> +static struct system_time_s ftpl_starttime = {{0, -1}, {0, -1}, {0, -1}};
> +#else
> +static struct system_time_s ftpl_starttime = {{0, -1}, {0, -1}, {0, -1}, {0, -1}};
> +#endif
> +
> +static char user_faked_time_fmt[BUFSIZ] = {0};
> +
> +/* User supplied base time to fake */
> +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 */
> +static double user_rate = 1.0;
> +static bool user_rate_set = false;
> +static struct timespec user_per_tick_inc = {0, -1};
> +static bool user_per_tick_inc_set = false;
> +
> +enum ft_mode_t {FT_FREEZE, FT_START_AT, FT_NOOP} ft_mode = FT_FREEZE;
> +
> +/* Time to fake is not provided through FAKETIME env. var. */
> +static bool parse_config_file = true;
> +
> +void ft_cleanup (void) __attribute__ ((destructor));
> +void ftpl_init (void) __attribute__ ((constructor));
> +
> +
> +/*
> + *      =======================================================================
> + *      Shared memory related functions                                 === SHM
> + *      =======================================================================
> + */
> +
> +static void ft_shm_init (void)
> +{
> +  int ticks_shm_fd;
> +  char sem_name[256], shm_name[256], *ft_shared_env = getenv("FAKETIME_SHARED");
> +
> +  if (ft_shared_env != NULL)
> +  {
> +    if (sscanf(ft_shared_env, "%255s %255s", sem_name, shm_name) < 2)
> +    {
> +      printf("Error parsing semaphore name and shared memory id from string: %s", ft_shared_env);
> +      exit(1);
> +    }
> +
> +    if (SEM_FAILED == (shared_sem = sem_open(sem_name, 0)))
> +    {
> +      perror("sem_open");
> +      exit(1);
> +    }
> +
> +    if (-1 == (ticks_shm_fd = shm_open(shm_name, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)))
> +    {
> +      perror("shm_open");
> +      exit(1);
> +    }
> +
> +    if (MAP_FAILED == (ft_shared = mmap(NULL, sizeof(struct ft_shared_s), PROT_READ|PROT_WRITE,
> +            MAP_SHARED, ticks_shm_fd, 0)))
> +    {
> +      perror("mmap");
> +      exit(1);
> +    }
> +  }
> +}
> +
> +void ft_cleanup (void)
> +{
> +  /* detach from shared memory */
> +  if (ft_shared != NULL)
> +  {
> +    munmap(ft_shared, sizeof(uint64_t));
> +  }
> +  if (stss != NULL)
> +  {
> +    munmap(stss, infile_size);
> +  }
> +  if (shared_sem != NULL)
> +  {
> +    sem_close(shared_sem);
> +  }
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Internal time retrieval                                     === INTTIME
> + *      =======================================================================
> + */
> +
> +/* Get system time from system for all clocks */
> +static void system_time_from_system (struct system_time_s * systime)
> +{
> +#ifdef __APPLEOSX__
> +  /* from http://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x */
> +  clock_serv_t cclock;
> +  mach_timespec_t mts;
> +  host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clock_serv_real);
> +  (*real_clock_get_time)(clock_serv_real, &mts);
> +  systime->real.tv_sec = mts.tv_sec;
> +  systime->real.tv_nsec = mts.tv_nsec;
> +  host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
> +  (*real_clock_get_time)(cclock, &mts);
> +  mach_port_deallocate(mach_task_self(), cclock);
> +  systime->mon.tv_sec = mts.tv_sec;
> +  systime->mon.tv_nsec = mts.tv_nsec;
> +  systime->mon_raw.tv_sec = mts.tv_sec;
> +  systime->mon_raw.tv_nsec = mts.tv_nsec;
> +#else
> +  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_REALTIME, &systime->real))
> +   ;
> +  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_MONOTONIC, &systime->mon))
> +   ;
> +  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_MONOTONIC_RAW, &systime->mon_raw))
> +   ;
> +#ifdef CLOCK_BOOTTIME
> +  DONT_FAKE_TIME((*real_clock_gettime)(CLOCK_BOOTTIME, &systime->boot))
> +   ;
> +#endif
> +#endif
> +}
> +
> +static void next_time(struct timespec *tp, struct timespec *ticklen)
> +{
> +  if (shared_sem != NULL)
> +  {
> +    struct timespec inc;
> +    /* lock */
> +    if (sem_wait(shared_sem) == -1)
> +    {
> +      perror("sem_wait");
> +      exit(1);
> +    }
> +    /* calculate and update elapsed time */
> +    timespecmul(ticklen, ft_shared->ticks, &inc);
> +    timespecadd(&user_faked_time_timespec, &inc, tp);
> +    (ft_shared->ticks)++;
> +    /* unlock */
> +    if (sem_post(shared_sem) == -1)
> +    {
> +      perror("sem_post");
> +      exit(1);
> +    }
> +  }
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Saving & loading time                                          === SAVE
> + *      =======================================================================
> + */
> +
> +static void save_time(struct timespec *tp)
> +{
> +  if ((shared_sem != NULL) && (outfile != -1))
> +  {
> +    struct saved_timestamp time_write;
> +    ssize_t written;
> +    size_t n = 0;
> +
> +    time_write.sec = htobe64(tp->tv_sec);
> +    time_write.nsec = htobe64(tp->tv_nsec);
> +
> +    /* lock */
> +    if (sem_wait(shared_sem) == -1)
> +    {
> +      perror("sem_wait");
> +      exit(1);
> +    }
> +
> +    lseek(outfile, 0, SEEK_END);
> +    do
> +    {
> +      written = write(outfile, &(((char*)&time_write)[n]), sizeof(time_write) - n);
> +    }
> +    while (((written == -1) && (errno == EINTR)) ||
> +            (sizeof(time_write) < (n += written)));
> +
> +    if ((written == -1) || (n < sizeof(time_write)))
> +    {
> +      perror("Saving timestamp to file failed");
> +    }
> +
> +    /* unlock */
> +    if (sem_post(shared_sem) == -1)
> +    {
> +      perror("sem_post");
> +      exit(1);
> +    }
> +  }
> +}
> +
> +/*
> + * Provide faked time from file.
> + * @return time is set from filen
> + */
> +static bool load_time(struct timespec *tp)
> +{
> +  bool ret = false;
> +  if ((shared_sem != NULL) && (infile_set))
> +  {
> +    /* lock */
> +    if (sem_wait(shared_sem) == -1)
> +    {
> +      perror("sem_wait");
> +      exit(1);
> +    }
> +
> +    if ((sizeof(stss[0]) * (ft_shared->file_idx + 1)) > infile_size)
> +    {
> +      /* we are out of timstamps to replay, return to faking time by rules
> +       * using last timestamp from file as the user provided timestamp */
> +      timespec_from_saved(&user_faked_time_timespec, &stss[(infile_size / sizeof(stss[0])) - 1 ]);
> +
> +      if (ft_shared->ticks == 0)
> +      {
> +        /* we set shared memory to stop using infile */
> +        ft_shared->ticks = 1;
> +        system_time_from_system(&ftpl_starttime);
> +        ft_shared->start_time = ftpl_starttime;
> +      }
> +      else
> +      {
> +        ftpl_starttime = ft_shared->start_time;
> +      }
> +
> +      munmap(stss, infile_size);
> +      infile_set = false;
> +    }
> +    else
> +    {
> +      timespec_from_saved(tp, &stss[ft_shared->file_idx]);
> +      ft_shared->file_idx++;
> +      ret = true;
> +    }
> +
> +    /* unlock */
> +    if (sem_post(shared_sem) == -1)
> +    {
> +      perror("sem_post");
> +      exit(1);
> +    }
> +  }
> +  return ret;
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Faked system functions: file related                     === FAKE(FILE)
> + *      =======================================================================
> + */
> +
> +#ifdef FAKE_STAT
> +
> +#ifndef NO_ATFILE
> +#ifndef _ATFILE_SOURCE
> +#define _ATFILE_SOURCE
> +#endif
> +#include <fcntl.h> /* Definition of AT_* constants */
> +#endif
> +
> +#include <sys/stat.h>
> +
> +static int fake_stat_disabled = 0;
> +
> +#define FAKE_STRUCT_STAT_TIME(which) {                \
> +    struct timespec t = {buf->st_##which##time,       \
> +                         buf->st_##which##timensec};  \
> +    fake_clock_gettime(CLOCK_REALTIME, &t);           \
> +    buf->st_##which##time = t.tv_sec;                 \
> +    buf->st_##which##timensec = t.tv_nsec;            \
> +  } while (0)
> +
> +static inline void fake_statbuf (struct stat *buf) {
> +#ifndef st_atime
> +  FAKE_STRUCT_STAT_TIME(c);
> +  FAKE_STRUCT_STAT_TIME(a);
> +  FAKE_STRUCT_STAT_TIME(m);
> +#else
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_ctim);
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_atim);
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_mtim);
> +#endif
> +}
> +
> +static inline void fake_stat64buf (struct stat64 *buf) {
> +#ifndef st_atime
> +  FAKE_STRUCT_STAT_TIME(c);
> +  FAKE_STRUCT_STAT_TIME(a);
> +  FAKE_STRUCT_STAT_TIME(m);
> +#else
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_ctim);
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_atim);
> +  fake_clock_gettime(CLOCK_REALTIME, &buf->st_mtim);
> +#endif
> +}
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __xstat (int ver, const char *path, struct stat *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_stat)
> +  { /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original stat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_stat(ver, path, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +   if (buf != NULL)
> +   {
> +     if (!fake_stat_disabled)
> +     {
> +       fake_statbuf(buf);
> +     }
> +   }
> +
> +  return result;
> +}
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __fxstat (int ver, int fildes, struct stat *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_fstat)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original fstat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_fstat(ver, fildes, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_statbuf(buf);
> +    }
> +  }
> +  return result;
> +}
> +
> +/* Added in v0.8 as suggested by Daniel Kahn Gillmor */
> +#ifndef NO_ATFILE
> +int __fxstatat(int ver, int fildes, const char *filename, struct stat *buf, int flag)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_fstatat)
> +  { /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original fstatat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_fstatat(ver, fildes, filename, buf, flag));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_statbuf(buf);
> +    }
> +  }
> +  return result;
> +}
> +#endif
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __lxstat (int ver, const char *path, struct stat *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_lstat)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original lstat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_lstat(ver, path, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_statbuf(buf);
> +    }
> +  }
> +  return result;
> +}
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __xstat64 (int ver, const char *path, struct stat64 *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_stat64)
> +  { /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original stat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_stat64(ver, path, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_stat64buf(buf);
> +    }
> +  }
> +  return result;
> +}
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __fxstat64 (int ver, int fildes, struct stat64 *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_fstat64)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original fstat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_fstat64(ver, fildes, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_stat64buf(buf);
> +    }
> +  }
> +  return result;
> +}
> +
> +/* Added in v0.8 as suggested by Daniel Kahn Gillmor */
> +#ifndef NO_ATFILE
> +int __fxstatat64 (int ver, int fildes, const char *filename, struct stat64 *buf, int flag)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_fstatat64)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original fstatat64() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_fstatat64(ver, fildes, filename, buf, flag));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_stat64buf(buf);
> +    }
> +  }
> +  return result;
> +}
> +#endif
> +
> +/* Contributed by Philipp Hachtmann in version 0.6 */
> +int __lxstat64 (int ver, const char *path, struct stat64 *buf)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (NULL == real_lstat64)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original lstat() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  int result;
> +  DONT_FAKE_TIME(result = real_lstat64(ver, path, buf));
> +  if (result == -1)
> +  {
> +    return -1;
> +  }
> +
> +  if (buf != NULL)
> +  {
> +    if (!fake_stat_disabled)
> +    {
> +      fake_stat64buf(buf);
> +    }
> +  }
> +  return result;
> +}
> +#endif
> +
> +/*
> + *      =======================================================================
> + *      Faked system functions: sleep/alarm/poll/timer related  === FAKE(SLEEP)
> + *      =======================================================================
> + *      Contributed by Balint Reczey in v0.9.5
> + */
> +
> +#ifdef FAKE_SLEEP
> +/*
> + * Faked nanosleep()
> + */
> +int nanosleep(const struct timespec *req, struct timespec *rem)
> +{
> +  int result;
> +  struct timespec real_req;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_nanosleep == NULL)
> +  {
> +    return -1;
> +  }
> +  if (req != NULL)
> +  {
> +    if (user_rate_set && !dont_fake)
> +    {
> +      timespecmul(req, 1.0 / user_rate, &real_req);
> +    }
> +    else
> +    {
> +      real_req = *req;
> +    }
> +  }
> +  else
> +  {
> +    return -1;
> +  }
> +
> +  DONT_FAKE_TIME(result = (*real_nanosleep)(&real_req, rem));
> +  if (result == -1)
> +  {
> +    return result;
> +  }
> +
> +  /* fake returned parts */
> +  if ((rem != NULL) && ((rem->tv_sec != 0) || (rem->tv_nsec != 0)))
> +  {
> +    if (user_rate_set && !dont_fake)
> +    {
> +      timespecmul(rem, user_rate, rem);
> +    }
> +  }
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +/*
> + * Faked usleep()
> + */
> +int usleep(useconds_t usec)
> +{
> +  int result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (user_rate_set && !dont_fake)
> +  {
> +    struct timespec real_req;
> +
> +    if (real_nanosleep == NULL)
> +    {
> +      /* fall back to usleep() */
> +      if (real_usleep == NULL)
> +      {
> +        return -1;
> +      }
> +      DONT_FAKE_TIME(result = (*real_usleep)((1.0 / user_rate) * usec));
> +      return result;
> +    }
> +
> +    real_req.tv_sec = usec / 1000000;
> +    real_req.tv_nsec = (usec % 1000000) * 1000;
> +    timespecmul(&real_req, 1.0 / user_rate, &real_req);
> +    DONT_FAKE_TIME(result = (*real_nanosleep)(&real_req, NULL));
> +  }
> +  else
> +  {
> +    DONT_FAKE_TIME(result = (*real_usleep)(usec));
> +  }
> +  return result;
> +}
> +
> +/*
> + * Faked sleep()
> + */
> +unsigned int sleep(unsigned int seconds)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (user_rate_set && !dont_fake)
> +  {
> +    if (real_nanosleep == NULL)
> +    {
> +      /* fall back to sleep */
> +      unsigned int ret;
> +      if (real_sleep == NULL)
> +      {
> +        return 0;
> +      }
> +      DONT_FAKE_TIME(ret = (*real_sleep)((1.0 / user_rate) * seconds));
> +      return (user_rate_set && !dont_fake)?(user_rate * ret):ret;
> +    }
> +    else
> +    {
> +      int result;
> +      struct timespec real_req = {seconds, 0}, rem;
> +      timespecmul(&real_req, 1.0 / user_rate, &real_req);
> +      DONT_FAKE_TIME(result = (*real_nanosleep)(&real_req, &rem));
> +      if (result == -1)
> +      {
> +        return 0;
> +      }
> +
> +      /* fake returned parts */
> +      if ((rem.tv_sec != 0) || (rem.tv_nsec != 0))
> +      {
> +        timespecmul(&rem, user_rate, &rem);
> +      }
> +      /* return the result to the caller */
> +      return rem.tv_sec;
> +    }
> +  }
> +  else
> +  {
> +    /* no need to fake anything */
> +    unsigned int ret;
> +    DONT_FAKE_TIME(ret = (*real_sleep)(seconds));
> +    return ret;
> +  }
> +}
> +
> +/*
> + * Faked alarm()
> + * @note due to rounding alarm(2) with faketime -f '+0 x7' won't wait 2/7
> + * wall clock seconds but 0 seconds
> + */
> +unsigned int alarm(unsigned int seconds)
> +{
> +  unsigned int ret;
> +  unsigned int seconds_real = (user_rate_set && !dont_fake)?((1.0 / user_rate) * seconds):seconds;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_alarm == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  DONT_FAKE_TIME(ret = (*real_alarm)(seconds_real));
> +  return (user_rate_set && !dont_fake)?(user_rate * ret):ret;
> +}
> +
> +/*
> + * Faked ppoll()
> + */
> +int ppoll(struct pollfd *fds, nfds_t nfds,
> +    const struct timespec *timeout_ts, const sigset_t *sigmask)
> +{
> +  struct timespec real_timeout, *real_timeout_pt;
> +  int ret;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_ppoll == NULL)
> +  {
> +    return -1;
> +  }
> +  if (timeout_ts != NULL)
> +  {
> +    if (user_rate_set && !dont_fake && (timeout_ts->tv_sec > 0))
> +    {
> +      timespecmul(timeout_ts, 1.0 / user_rate, &real_timeout);
> +      real_timeout_pt = &real_timeout;
> +    }
> +    else
> +    {
> +      /* cast away constness */
> +      real_timeout_pt = (struct timespec *)timeout_ts;
> +    }
> +  }
> +  else
> +  {
> +    real_timeout_pt = NULL;
> +  }
> +
> +  DONT_FAKE_TIME(ret = (*real_ppoll)(fds, nfds, real_timeout_pt, sigmask));
> +  return ret;
> +}
> +
> +/*
> + * Faked poll()
> + */
> +int poll(struct pollfd *fds, nfds_t nfds, int timeout)
> +{
> +  int ret, timeout_real = (user_rate_set && !dont_fake && (timeout > 0))?(timeout / user_rate):timeout;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_poll == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  DONT_FAKE_TIME(ret = (*real_poll)(fds, nfds, timeout_real));
> +  return ret;
> +}
> +
> +/*
> + * Faked select()
> + */
> +int select(int nfds, fd_set *readfds,
> +           fd_set *writefds,
> +           fd_set *errorfds,
> +           struct timeval *timeout)
> +{
> +  int ret;
> +  struct timeval timeout_real;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +
> +  if (real_select == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  if (timeout != NULL)
> +  {
> +    if (user_rate_set && !dont_fake && (timeout->tv_sec > 0 || timeout->tv_usec > 0))
> +    {
> +      struct timespec ts;
> +
> +      ts.tv_sec = timeout->tv_sec;
> +      ts.tv_nsec = timeout->tv_usec * 1000;
> +
> +      timespecmul(&ts, 1.0 / user_rate, &ts);
> +
> +      timeout_real.tv_sec = ts.tv_sec;
> +      timeout_real.tv_usec = ts.tv_nsec / 1000;
> +    }
> +    else
> +    {
> +      timeout_real.tv_sec = timeout->tv_sec;
> +      timeout_real.tv_usec = timeout->tv_usec;
> +    }
> +  }
> +
> +  DONT_FAKE_TIME(ret = (*real_select)(nfds, readfds, writefds, errorfds, timeout == NULL ? timeout : &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__
> +#ifdef FAKE_TIMERS
> +
> +/* timer related functions and structures */
> +typedef union {
> +  int int_member;
> +  timer_t timer_t_member;
> +} timer_t_or_int;
> +
> +/*
> + * Faketime's function implementation's compatibility mode
> + */
> +typedef enum {FT_COMPAT_GLIBC_2_2, FT_COMPAT_GLIBC_2_3_3} ft_lib_compat;
> +
> +
> +/*
> + * Faked timer_settime()
> + * Does not affect timer speed when stepping clock with each time() call.
> + */
> +static int
> +timer_settime_common(timer_t_or_int timerid, int flags,
> +         const struct itimerspec *new_value,
> +         struct itimerspec *old_value, ft_lib_compat compat)
> +{
> +  int result;
> +  struct itimerspec new_real;
> +  struct itimerspec *new_real_pt = &new_real;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (new_value == NULL)
> +  {
> +    new_real_pt = NULL;
> +  }
> +  else if (dont_fake)
> +  {
> +    /* cast away constness*/
> +    new_real_pt = (struct itimerspec *)new_value;
> +  }
> +  else
> +  {
> +    /* set it_value */
> +    if ((new_value->it_value.tv_sec != 0) ||
> +        (new_value->it_value.tv_nsec != 0))
> +    {
> +      if (flags & TIMER_ABSTIME)
> +      {
> +        struct timespec tdiff, timeadj;
> +        timespecsub(&new_value->it_value, &user_faked_time_timespec, &timeadj);
> +        if (user_rate_set)
> +        {
> +          timespecmul(&timeadj, 1.0/user_rate, &tdiff);
> +        }
> +        else
> +        {
> +          tdiff = timeadj;
> +        }
> +        /* only CLOCK_REALTIME is handled */
> +        timespecadd(&ftpl_starttime.real, &tdiff, &new_real.it_value);
> +      }
> +      else
> +      {
> +        if (user_rate_set)
> +        {
> +          timespecmul(&new_value->it_value, 1.0/user_rate, &new_real.it_value);
> +        }
> +        else
> +        {
> +          new_real.it_value = new_value->it_value;
> +        }
> +      }
> +    }
> +    else
> +    {
> +      new_real.it_value = new_value->it_value;
> +    }
> +    /* set it_interval */
> +    if (user_rate_set && ((new_value->it_interval.tv_sec != 0) ||
> +       (new_value->it_interval.tv_nsec != 0)))
> +    {
> +      timespecmul(&new_value->it_interval, 1.0/user_rate, &new_real.it_interval);
> +    }
> +    else
> +    {
> +      new_real.it_interval = new_value->it_interval;
> +    }
> +  }
> +
> +  switch (compat)
> +  {
> +    case FT_COMPAT_GLIBC_2_2:
> +      DONT_FAKE_TIME(result = (*real_timer_settime_22)(timerid.int_member, flags,
> +                    new_real_pt, old_value));
> +      break;
> +    case FT_COMPAT_GLIBC_2_3_3:
> +       DONT_FAKE_TIME(result = (*real_timer_settime_233)(timerid.timer_t_member,
> +                    flags, new_real_pt, old_value));
> +       break;
> +    default:
> +      result = -1;
> +      break;
> +  }
> +
> +  if (result == -1)
> +  {
> +    return result;
> +  }
> +
> +  /* fake returned parts */
> +  if ((old_value != NULL) && !dont_fake)
> +  {
> +    if ((old_value->it_value.tv_sec != 0) ||
> +        (old_value->it_value.tv_nsec != 0))
> +    {
> +      result = fake_clock_gettime(CLOCK_REALTIME, &old_value->it_value);
> +    }
> +    if (user_rate_set && ((old_value->it_interval.tv_sec != 0) ||
> +       (old_value->it_interval.tv_nsec != 0)))
> +    {
> +      timespecmul(&old_value->it_interval, user_rate, &old_value->it_interval);
> +    }
> +  }
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +/*
> + * Faked timer_settime() compatible with implementation in GLIBC 2.2
> + */
> +int timer_settime_22(int timerid, int flags,
> +         const struct itimerspec *new_value,
> +         struct itimerspec *old_value)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_timer_settime_22 == NULL)
> +  {
> +    return -1;
> +  }
> +  else
> +  {
> +    return (timer_settime_common((timer_t_or_int)timerid, flags, new_value, old_value,
> +            FT_COMPAT_GLIBC_2_2));
> +  }
> +}
> +
> +/*
> + * Faked timer_settime() compatible with implementation in GLIBC 2.3.3
> + */
> +int timer_settime_233(timer_t timerid, int flags,
> +      const struct itimerspec *new_value,
> +      struct itimerspec *old_value)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_timer_settime_233 == NULL)
> +  {
> +    return -1;
> +  }
> +  else
> +  {
> +    return (timer_settime_common((timer_t_or_int)timerid, flags, new_value, old_value,
> +            FT_COMPAT_GLIBC_2_3_3));
> +  }
> +}
> +
> +/*
> + * Faked timer_gettime()
> + * Does not affect timer speed when stepping clock with each time() call.
> + */
> +int timer_gettime_common(timer_t_or_int timerid, struct itimerspec *curr_value, ft_lib_compat compat)
> +{
> +  int result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_timer_gettime_233 == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  switch (compat)
> +  {
> +    case FT_COMPAT_GLIBC_2_2:
> +      DONT_FAKE_TIME(result = (*real_timer_gettime_22)(timerid.int_member, curr_value));
> +      break;
> +    case FT_COMPAT_GLIBC_2_3_3:
> +      DONT_FAKE_TIME(result = (*real_timer_gettime_233)(timerid.timer_t_member, curr_value));
> +      break;
> +    default:
> +      result = -1;
> +      break;
> +  }
> +
> +  if (result == -1)
> +  {
> +    return result;
> +  }
> +
> +  /* fake returned parts */
> +  if (curr_value != NULL)
> +  {
> +    if (user_rate_set && !dont_fake)
> +    {
> +      timespecmul(&curr_value->it_interval, user_rate, &curr_value->it_interval);
> +      timespecmul(&curr_value->it_value, user_rate, &curr_value->it_value);
> +    }
> +  }
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +/*
> + * Faked timer_gettime() compatible with implementation in GLIBC 2.2
> + */
> +int timer_gettime_22(timer_t timerid, struct itimerspec *curr_value)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_timer_gettime_22 == NULL)
> +  {
> +    return -1;
> +  }
> +  else
> +  {
> +    return (timer_gettime_common((timer_t_or_int)timerid, curr_value,
> +         FT_COMPAT_GLIBC_2_2));
> +  }
> +}
> +
> +/*
> + * Faked timer_gettime() compatible with implementation in GLIBC 2.3.3
> + */
> +int timer_gettime_233(timer_t timerid, struct itimerspec *curr_value)
> +{
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  if (real_timer_gettime_233 == NULL)
> +  {
> +    return -1;
> +  }
> +  else
> +  {
> +    return (timer_gettime_common((timer_t_or_int)timerid, curr_value,
> +            FT_COMPAT_GLIBC_2_3_3));
> +  }
> +}
> +
> +__asm__(".symver timer_gettime_22, timer_gettime@GLIBC_2.2");
> +__asm__(".symver timer_gettime_233, timer_gettime@@GLIBC_2.3.3");
> +__asm__(".symver timer_settime_22, timer_settime@GLIBC_2.2");
> +__asm__(".symver timer_settime_233, timer_settime@@GLIBC_2.3.3");
> +
> +#endif
> +#endif
> +
> +
> +/*
> + *      =======================================================================
> + *      Faked system functions: basic time functions             === FAKE(TIME)
> + *      =======================================================================
> + */
> +
> +/*
> + * time() implementation using clock_gettime()
> + * @note Does not check for EFAULT, see man 2 time
> + */
> +time_t time(time_t *time_tptr)
> +{
> +  struct timespec tp;
> +  time_t result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
> +  if (result == -1) return -1;
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
> +
> +  if (time_tptr != NULL)
> +  {
> +    *time_tptr = tp.tv_sec;
> +  }
> +  return tp.tv_sec;
> +}
> +
> +int ftime(struct timeb *tb)
> +{
> +  struct timespec tp;
> +  int result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  /* sanity check */
> +  if (tb == NULL)
> +    return 0;               /* ftime() always returns 0, see manpage */
> +
> +  /* Check whether we've got a pointer to the real ftime() function yet */
> +  if (NULL == real_ftime)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original ftime() not found.\n");
> +#endif
> +    return 0; /* propagate error to caller */
> +  }
> +
> +  /* initialize our TZ result with the real current time */
> +  DONT_FAKE_TIME(result = (*real_ftime)(tb));
> +  if (result == -1)
> +  {
> +    return result;
> +  }
> +
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
> +  if (result == -1) return -1;
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
> +
> +  tb->time = tp.tv_sec;
> +  tb->millitm = tp.tv_nsec / 1000000;
> +
> +  /* return the result to the caller */
> +  return result; /* will always be 0 (see manpage) */
> +}
> +
> +int gettimeofday(struct timeval *tv, void *tz)
> +{
> +  int result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  /* sanity check */
> +  if (tv == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  /* Check whether we've got a pointer to the real ftime() function yet */
> +  if (NULL == real_gettimeofday)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original gettimeofday() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  /* initialize our result with the real current time */
> +  DONT_FAKE_TIME(result = (*real_gettimeofday)(tv, tz));
> +  if (result == -1) return result; /* original function failed */
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  result = fake_gettimeofday(tv);
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +int clock_gettime(clockid_t clk_id, struct timespec *tp)
> +{
> +  int result;
> +
> +  if (!initialized)
> +  {
> +    ftpl_init();
> +  }
> +  /* sanity check */
> +  if (tp == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  if (NULL == real_clock_gettime)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original clock_gettime() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  /* initialize our result with the real current time */
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(clk_id, tp));
> +  if (result == -1) return result; /* original function failed */
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  if (fake_monotonic_clock || clk_id != CLOCK_MONOTONIC)
> +  {
> +    result = fake_clock_gettime(clk_id, tp);
> +  }
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Parsing the user's faketime requests                          === PARSE
> + *      =======================================================================
> + */
> +
> +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])
> +  {
> +
> +    default:  /* Try and interpret this as a specified time */
> +      if (ft_mode != FT_NOOP) ft_mode = FT_FREEZE;
> +      user_faked_time_tm.tm_isdst = -1;
> +      if (NULL != strptime(user_faked_time, user_faked_time_fmt, &user_faked_time_tm))
> +      {
> +        user_faked_time_timespec.tv_sec = mktime(&user_faked_time_tm);
> +        user_faked_time_timespec.tv_nsec = 0;
> +        user_faked_time_set = true;
> +      }
> +      else
> +      {
> +        perror("Failed to parse FAKETIME timestamp");
> +        exit(EXIT_FAILURE);
> +      }
> +      break;
> +
> +    case '+':
> +    case '-': /* User-specified offset */
> +      if (ft_mode != FT_NOOP) ft_mode = FT_START_AT;
> +      /* fractional time offsets contributed by Karl Chen in v0.8 */
> +      double frac_offset = atof(user_faked_time);
> +
> +      /* offset is in seconds by default, but the string may contain
> +       * multipliers...
> +       */
> +      if (strchr(user_faked_time, 'm') != NULL) frac_offset *= 60;
> +      else if (strchr(user_faked_time, 'h') != NULL) frac_offset *= 60 * 60;
> +      else if (strchr(user_faked_time, 'd') != NULL) frac_offset *= 60 * 60 * 24;
> +      else if (strchr(user_faked_time, 'y') != NULL) frac_offset *= 60 * 60 * 24 * 365;
> +
> +      user_offset.tv_sec = floor(frac_offset);
> +      user_offset.tv_nsec = (frac_offset - user_offset.tv_sec) * SEC_TO_nSEC;
> +      timespecadd(&ftpl_starttime.real, &user_offset, &user_faked_time_timespec);
> +      goto parse_modifiers;
> +      break;
> +
> +      /* Contributed by David North, TDI in version 0.7 */
> +    case '@': /* Specific time, but clock along relative to that starttime */
> +      ft_mode = FT_START_AT;
> +      user_faked_time_tm.tm_isdst = -1;
> +      (void) strptime(&user_faked_time[1], user_faked_time_fmt, &user_faked_time_tm);
> +
> +      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;
> +
> +    case 'i':
> +    case 'x': /* Only modifiers are passed, don't fall back to strptime */
> +parse_modifiers:
> +      /* Speed-up / slow-down contributed by Karl Chen in v0.8 */
> +      if (strchr(user_faked_time, 'x') != NULL)
> +      {
> +        user_rate = atof(strchr(user_faked_time, 'x')+1);
> +        user_rate_set = true;
> +      }
> +      else if (NULL != (tmp_time_fmt = strchr(user_faked_time, 'i')))
> +      {
> +        double tick_inc = atof(tmp_time_fmt + 1);
> +        /* increment time with every time() call*/
> +        user_per_tick_inc.tv_sec = floor(tick_inc);
> +        user_per_tick_inc.tv_nsec = (tick_inc - user_per_tick_inc.tv_sec) * SEC_TO_nSEC ;
> +        user_per_tick_inc_set = true;
> +      }
> +      break;
> +  } // end of switch
> +
> +  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
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Initialization                                                 === INIT
> + *      =======================================================================
> + */
> +
> +void ftpl_init(void)
> +{
> +  char *tmp_env;
> +  bool dont_fake_final;
> +
> +#ifdef __APPLE__
> +  const char *progname = getprogname();
> +#else
> +  const char *progname = __progname;
> +#endif
> +
> +  /* Look up all real_* functions. NULL will mark missing ones. */
> +  real_stat =               dlsym(RTLD_NEXT, "__xstat");
> +  real_fstat =              dlsym(RTLD_NEXT, "__fxstat");
> +  real_fstatat =            dlsym(RTLD_NEXT, "__fxstatat");
> +  real_lstat =              dlsym(RTLD_NEXT, "__lxstat");
> +  real_stat64 =             dlsym(RTLD_NEXT,"__xstat64");
> +  real_fstat64 =            dlsym(RTLD_NEXT, "__fxstat64");
> +  real_fstatat64 =          dlsym(RTLD_NEXT, "__fxstatat64");
> +  real_lstat64 =            dlsym(RTLD_NEXT, "__lxstat64");
> +  real_time =               dlsym(RTLD_NEXT, "time");
> +  real_ftime =              dlsym(RTLD_NEXT, "ftime");
> +  real_gettimeofday =       dlsym(RTLD_NEXT, "gettimeofday");
> +#ifdef FAKE_SLEEP
> +  real_nanosleep =          dlsym(RTLD_NEXT, "nanosleep");
> +  real_usleep =             dlsym(RTLD_NEXT, "usleep");
> +  real_sleep =              dlsym(RTLD_NEXT, "sleep");
> +  real_alarm =              dlsym(RTLD_NEXT, "alarm");
> +  real_poll =               dlsym(RTLD_NEXT, "poll");
> +  real_ppoll =              dlsym(RTLD_NEXT, "ppoll");
> +  real_select =             dlsym(RTLD_NEXT, "select");
> +  real_sem_timedwait =      dlsym(RTLD_NEXT, "sem_timedwait");
> +#endif
> +#ifdef FAKE_INTERNAL_CALLS
> +  real___ftime =              dlsym(RTLD_NEXT, "__ftime");
> +  real___gettimeofday =       dlsym(RTLD_NEXT, "__gettimeofday");
> +  real___clock_gettime  =     dlsym(RTLD_NEXT, "__clock_gettime");
> +#endif
> +#ifdef __APPLEOSX__
> +  real_clock_get_time =     dlsym(RTLD_NEXT, "clock_get_time");
> +  real_clock_gettime  =     apple_clock_gettime;
> +#else
> +  real_clock_gettime  =     dlsym(RTLD_NEXT, "__clock_gettime");
> +  if (NULL == real_clock_gettime)
> +  {
> +    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)
> +  {
> +    real_timer_settime_233 =  dlsym(RTLD_NEXT, "timer_settime");
> +  }
> +  real_timer_gettime_22 =   dlvsym(RTLD_NEXT, "timer_gettime","GLIBC_2.2");
> +  real_timer_gettime_233 =  dlvsym(RTLD_NEXT, "timer_gettime","GLIBC_2.3.3");
> +  if (NULL == real_timer_gettime_233)
> +  {
> +    real_timer_gettime_233 =  dlsym(RTLD_NEXT, "timer_gettime");
> +  }
> +#endif
> +#endif
> +#endif
> +
> +  dont_fake = true; // Do not fake times during initialization
> +  dont_fake_final = false;
> +  initialized = 1;
> +
> +  ft_shm_init();
> +#ifdef FAKE_STAT
> +  if (getenv("NO_FAKE_STAT")!=NULL)
> +  {
> +    fake_stat_disabled = 1;  //Note that this is NOT re-checked
> +  }
> +#endif
> +
> +  if ((tmp_env = getenv("FAKETIME_CACHE_DURATION")) != NULL)
> +  {
> +    cache_duration = atoi(tmp_env);
> +  }
> +  if ((tmp_env = getenv("FAKETIME_NO_CACHE")) != NULL)
> +  {
> +    if (0 == strcmp(tmp_env, "1"))
> +    {
> +      cache_enabled = 0;
> +    }
> +  }
> +  if ((tmp_env = getenv("DONT_FAKE_MONOTONIC")) != NULL)
> +  {
> +    if (0 == strcmp(tmp_env, "1"))
> +    {
> +      fake_monotonic_clock = 0;
> +    }
> +  }
> +  /* Check whether we actually should be faking the returned timestamp. */
> +
> +  /* We can prevent faking time for specified commands */
> +  if ((tmp_env = getenv("FAKETIME_SKIP_CMDS")) != NULL)
> +  {
> +    char *skip_cmd, *saveptr, *tmpvar;
> +    /* Don't mess with the env variable directly. */
> +    tmpvar = strdup(tmp_env);
> +    if (tmpvar != NULL)
> +    {
> +      skip_cmd = strtok_r(tmpvar, ",", &saveptr);
> +      while (skip_cmd != NULL)
> +      {
> +        if (0 == strcmp(progname, skip_cmd))
> +        {
> +          ft_mode = FT_NOOP;
> +          dont_fake_final = true;
> +          break;
> +        }
> +        skip_cmd = strtok_r(NULL, ",", &saveptr);
> +      }
> +      free(tmpvar);
> +      tmpvar = NULL;
> +    }
> +    else
> +    {
> +      fprintf(stderr, "Error: Could not copy the environment variable value.\n");
> +      exit(EXIT_FAILURE);
> +    }
> +  }
> +
> +  /* We can limit faking time to specified commands */
> +  if ((tmp_env = getenv("FAKETIME_ONLY_CMDS")) != NULL)
> +  {
> +    char *only_cmd, *saveptr, *tmpvar;
> +    bool cmd_matched = false;
> +
> +    if (getenv("FAKETIME_SKIP_CMDS") != NULL)
> +    {
> +      fprintf(stderr, "Error: Both FAKETIME_SKIP_CMDS and FAKETIME_ONLY_CMDS can't be set.\n");
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    /* Don't mess with the env variable directly. */
> +    tmpvar = strdup(tmp_env);
> +    if (tmpvar != NULL) {
> +      only_cmd = strtok_r(tmpvar, ",", &saveptr);
> +      while (only_cmd != NULL)
> +      {
> +        if (0 == strcmp(progname, only_cmd))
> +        {
> +          cmd_matched = true;
> +          break;
> +        }
> +        only_cmd = strtok_r(NULL, ",", &saveptr);
> +      }
> +
> +      if (!cmd_matched)
> +      {
> +        ft_mode = FT_NOOP;
> +        dont_fake_final = true;
> +      }
> +      free(tmpvar);
> +    } else {
> +      fprintf(stderr, "Error: Could not copy the environment variable value.\n");
> +      exit(EXIT_FAILURE);
> +    }
> +  }
> +
> +  if ((tmp_env = getenv("FAKETIME_START_AFTER_SECONDS")) != NULL)
> +  {
> +    ft_start_after_secs = atol(tmp_env);
> +    limited_faking = true;
> +  }
> +  if ((tmp_env = getenv("FAKETIME_STOP_AFTER_SECONDS")) != NULL)
> +  {
> +    ft_stop_after_secs = atol(tmp_env);
> +    limited_faking = true;
> +  }
> +  if ((tmp_env = getenv("FAKETIME_START_AFTER_NUMCALLS")) != NULL)
> +  {
> +    ft_start_after_ncalls = atol(tmp_env);
> +    limited_faking = true;
> +  }
> +  if ((tmp_env = getenv("FAKETIME_STOP_AFTER_NUMCALLS")) != NULL)
> +  {
> +    ft_stop_after_ncalls = atol(tmp_env);
> +    limited_faking = true;
> +  }
> +
> +  /* check whether we should spawn an external command */
> +  if ((tmp_env = getenv("FAKETIME_SPAWN_TARGET")) != NULL)
> +  {
> +    spawnsupport = true;
> +    (void) strncpy(ft_spawn_target, getenv("FAKETIME_SPAWN_TARGET"), 1024);
> +    if ((tmp_env = getenv("FAKETIME_SPAWN_SECONDS")) != NULL)
> +    {
> +      ft_spawn_secs = atol(tmp_env);
> +    }
> +    if ((tmp_env = getenv("FAKETIME_SPAWN_NUMCALLS")) != NULL)
> +    {
> +      ft_spawn_ncalls = atol(tmp_env);
> +    }
> +  }
> +
> +  if ((tmp_env = getenv("FAKETIME_SAVE_FILE")) != NULL)
> +  {
> +    if (-1 == (outfile = open(tmp_env, O_RDWR | O_APPEND | O_CLOEXEC | O_CREAT,
> +                              S_IWUSR | S_IRUSR)))
> +    {
> +      perror("Opening file for saving timestamps failed");
> +      exit(EXIT_FAILURE);
> +    }
> +  }
> +
> +  /* load file only if reading timstamps from it is not finished yet */
> +  if ((tmp_env = getenv("FAKETIME_LOAD_FILE")) != NULL)
> +  {
> +    int infile = -1;
> +    struct stat sb;
> +    if (-1 == (infile = open(tmp_env, O_RDONLY|O_CLOEXEC)))
> +    {
> +      perror("Opening file for loading timestamps failed");
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    fstat(infile, &sb);
> +    if (sizeof(stss[0]) > (infile_size = sb.st_size))
> +    {
> +      printf("There are no timestamps in the provided file to load timestamps from");
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    if ((infile_size % sizeof(stss[0])) != 0)
> +    {
> +      printf("File size is not multiple of timestamp size. It is probably damaged.");
> +      exit(EXIT_FAILURE);
> +    }
> +
> +    stss = mmap(NULL, infile_size, PROT_READ, MAP_SHARED, infile, 0);
> +    if (stss == MAP_FAILED)
> +    {
> +      perror("Mapping file for loading timestamps failed");
> +      exit(EXIT_FAILURE);
> +    }
> +    infile_set = true;
> +  }
> +
> +  tmp_env = getenv("FAKETIME_FMT");
> +  if (tmp_env == NULL)
> +  {
> +    strcpy(user_faked_time_fmt, "%Y-%m-%d %T");
> +  }
> +  else
> +  {
> +    strncpy(user_faked_time_fmt, tmp_env, BUFSIZ);
> +  }
> +
> +  if (shared_sem != 0)
> +  {
> +    if (sem_wait(shared_sem) == -1)
> +    {
> +      perror("sem_wait");
> +      exit(1);
> +    }
> +    if (ft_shared->start_time.real.tv_nsec == -1)
> +    {
> +      /* set up global start time */
> +      system_time_from_system(&ftpl_starttime);
> +      ft_shared->start_time = ftpl_starttime;
> +    }
> +    else
> +    {
> +      /** get preset start time */
> +      ftpl_starttime = ft_shared->start_time;
> +    }
> +    if (sem_post(shared_sem) == -1)
> +    {
> +      perror("sem_post");
> +      exit(1);
> +    }
> +  }
> +  else
> +  {
> +    system_time_from_system(&ftpl_starttime);
> +  }
> +  /* fake time supplied as environment variable? */
> +  if (NULL != (tmp_env = getenv("FAKETIME")))
> +  {
> +    parse_config_file = false;
> +    parse_ft_string(tmp_env);
> +  }
> +
> +  dont_fake = dont_fake_final;
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Helper functions                                             === HELPER
> + *      =======================================================================
> + */
> +
> +static void remove_trailing_eols(char *line)
> +{
> +  char *endp = line + strlen(line);
> +  /*
> +   * erase the last char if it's a newline
> +   * or carriage return, and back up.
> +   * keep doing this, but don't back up
> +   * past the beginning of the string.
> +   */
> +# define is_eolchar(c) ((c) == '\n' || (c) == '\r')
> +  while (endp > line && is_eolchar(endp[-1]))
> +  {
> +    *--endp = '\0';
> +  }
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Implementation of faked functions                        === FAKE(FAKE)
> + *      =======================================================================
> + */
> +
> +int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
> +{
> +  /* variables used for caching, introduced in version 0.6 */
> +  static time_t last_data_fetch = 0;  /* not fetched previously at first call */
> +  static int cache_expired = 1;       /* considered expired at first call */
> +
> +  if (dont_fake) return 0;
> +  /* Per process timers are only sped up or slowed down */
> +  if ((clk_id == CLOCK_PROCESS_CPUTIME_ID ) || (clk_id == CLOCK_THREAD_CPUTIME_ID))
> +  {
> +    if (user_rate_set)
> +    {
> +      timespecmul(tp, user_rate, tp);
> +    }
> +    return 0;
> +  }
> +
> +  /* Sanity check by Karl Chan since v0.8 */
> +  if (tp == NULL) return -1;
> +
> +#ifdef PTHREAD_SINGLETHREADED_TIME
> +  static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
> +  pthread_mutex_lock(&time_mutex);
> +  pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, (void *)&time_mutex);
> +#endif
> +
> +  if ((limited_faking &&
> +     ((ft_start_after_ncalls != -1) || (ft_stop_after_ncalls != -1))) ||
> +     (spawnsupport && ft_spawn_ncalls))
> +  {
> +    if (callcounter < LONG_MAX) callcounter++;
> +  }
> +
> +  if (limited_faking || spawnsupport)
> +  {
> +    struct timespec tmp_ts;
> +    /* For debugging, output #seconds and #calls */
> +    switch (clk_id)
> +    {
> +      case CLOCK_REALTIME:
> +#ifdef CLOCK_REALTIME_COARSE
> +      case CLOCK_REALTIME_COARSE:
> +#endif
> +        timespecsub(tp, &ftpl_starttime.real, &tmp_ts);
> +        break;
> +      case CLOCK_MONOTONIC:
> +#ifdef CLOCK_MONOTONIC_COARSE
> +      case CLOCK_MONOTONIC_COARSE:
> +#endif
> +        timespecsub(tp, &ftpl_starttime.mon, &tmp_ts);
> +        break;
> +      case CLOCK_MONOTONIC_RAW:
> +        timespecsub(tp, &ftpl_starttime.mon_raw, &tmp_ts);
> +        break;
> +#ifdef CLOCK_BOOTTIME
> +      case CLOCK_BOOTTIME:
> +        timespecsub(tp, &ftpl_starttime.boot, &tmp_ts);
> +        break;
> +#endif
> +      default:
> +        printf("Invalid clock_id for clock_gettime: %d", clk_id);
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    if (limited_faking)
> +    {
> +      /* Check whether we actually should be faking the returned timestamp. */
> +      /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
> +      if ((ft_start_after_secs != -1)   && (tmp_ts.tv_sec < ft_start_after_secs)) return 0;
> +      if ((ft_stop_after_secs != -1)    && (tmp_ts.tv_sec >= ft_stop_after_secs)) return 0;
> +      if ((ft_start_after_ncalls != -1) && (callcounter < ft_start_after_ncalls)) return 0;
> +      if ((ft_stop_after_ncalls != -1)  && (callcounter >= ft_stop_after_ncalls)) return 0;
> +      /* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu continues\n", (*time_tptr - ftpl_starttime), callcounter); */
> +    }
> +
> +    if (spawnsupport)
> +    {
> +      /* check whether we should spawn an external command */
> +      if (spawned == 0)
> +      { /* exec external command once only */
> +        if (((tmp_ts.tv_sec == ft_spawn_secs) || (callcounter == ft_spawn_ncalls)) && (spawned == 0))
> +        {
> +          spawned = 1;
> +          (void) (system(ft_spawn_target) + 1);
> +        }
> +      }
> +    }
> +  }
> +
> +  if (last_data_fetch > 0)
> +  {
> +    if ((tp->tv_sec - last_data_fetch) > cache_duration)
> +    {
> +      cache_expired = 1;
> +    }
> +    else
> +    {
> +      cache_expired = 0;
> +    }
> +  }
> +
> +  if (cache_enabled == 0)
> +  {
> +    cache_expired = 1;
> +  }
> +
> +  if (cache_expired == 1)
> +  {
> +    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)
> +    {
> +      char custom_filename[BUFSIZ];
> +      char filename[BUFSIZ];
> +      FILE *faketimerc;
> +      /* 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,
> +       * Jacob Moorman, and Wayne Davison of SourceForge, Inc. in version 0.6 */
> +      (void) snprintf(custom_filename, BUFSIZ, "%s", getenv("FAKETIME_TIMESTAMP_FILE"));
> +      (void) snprintf(filename, BUFSIZ, "%s/.faketimerc", getenv("HOME"));
> +      if ((faketimerc = fopen(custom_filename, "rt")) != NULL ||
> +          (faketimerc = fopen(filename, "rt")) != NULL ||
> +          (faketimerc = fopen("/etc/faketimerc", "rt")) != NULL)
> +      {
> +        char line[BUFFERLEN];
> +        while(fgets(line, BUFFERLEN, faketimerc) != NULL)
> +        {
> +          if ((strlen(line) > 1) && (line[0] != ' ') &&
> +              (line[0] != '#') && (line[0] != ';'))
> +          {
> +            remove_trailing_eols(line);
> +            strncpy(user_faked_time, line, BUFFERLEN-1);
> +            user_faked_time[BUFFERLEN-1] = 0;
> +            break;
> +          }
> +        }
> +        fclose(faketimerc);
> +      }
> +    } /* read fake time from file */
> +    parse_ft_string(user_faked_time);
> +  } /* cache had expired */
> +
> +  if (infile_set)
> +  {
> +    if (load_time(tp))
> +    {
> +      return 0;
> +    }
> +  }
> +
> +  /* check whether the user gave us an absolute time to fake */
> +  switch (ft_mode)
> +  {
> +    case FT_FREEZE:  /* a specified time */
> +      if (user_faked_time_set)
> +      {
> +        *tp = user_faked_time_timespec;
> +      }
> +      break;
> +
> +    case FT_START_AT: /* User-specified offset */
> +      if (user_per_tick_inc_set)
> +      {
> +        /* increment time with every time() call*/
> +        next_time(tp, &user_per_tick_inc);
> +      }
> +      else
> +      {
> +        /* Speed-up / slow-down contributed by Karl Chen in v0.8 */
> +        struct timespec tdiff, timeadj;
> +        switch (clk_id)
> +        {
> +          case CLOCK_REALTIME:
> +#ifdef CLOCK_REALTIME_COARSE
> +          case CLOCK_REALTIME_COARSE:
> +#endif
> +            timespecsub(tp, &ftpl_starttime.real, &tdiff);
> +            break;
> +          case CLOCK_MONOTONIC:
> +#ifdef CLOCK_MONOTONIC_COARSE
> +          case CLOCK_MONOTONIC_COARSE:
> +#endif
> +            timespecsub(tp, &ftpl_starttime.mon, &tdiff);
> +            break;
> +          case CLOCK_MONOTONIC_RAW:
> +            timespecsub(tp, &ftpl_starttime.mon_raw, &tdiff);
> +            break;
> +#ifdef CLOCK_BOOTTIME
> +          case CLOCK_BOOTTIME:
> +            timespecsub(tp, &ftpl_starttime.boot, &tdiff);
> +            break;
> +#endif
> +          default:
> +            printf("Invalid clock_id for clock_gettime: %d", clk_id);
> +            exit(EXIT_FAILURE);
> +        } // end of switch (clk_id)
> +        if (user_rate_set)
> +        {
> +          timespecmul(&tdiff, user_rate, &timeadj);
> +        }
> +        else
> +        {
> +          timeadj = tdiff;
> +        }
> +        timespecadd(&user_faked_time_timespec, &timeadj, tp);
> +      }
> +      break;
> +
> +    default:
> +      return -1;
> +  } // end of switch(ft_mode)
> +
> +#ifdef PTHREAD_SINGLETHREADED_TIME
> +  pthread_cleanup_pop(1);
> +#endif
> +  save_time(tp);
> +  return 0;
> +}
> +
> +int fake_gettimeofday(struct timeval *tv)
> +{
> +  struct timespec ts;
> +  int ret;
> +  ts.tv_sec = tv->tv_sec;
> +  ts.tv_nsec = tv->tv_usec * 1000  + ftpl_starttime.real.tv_nsec % 1000;
> +
> +  ret = fake_clock_gettime(CLOCK_REALTIME, &ts);
> +  tv->tv_sec = ts.tv_sec;
> +  tv->tv_usec =ts.tv_nsec / 1000;
> +
> +  return ret;
> +}
> +
> +
> +/*
> + *      =======================================================================
> + *      Faked system functions: Apple Mac OS X specific           === FAKE(OSX)
> + *      =======================================================================
> + */
> +
> +#ifdef __APPLEOSX__
> +/*
> + * clock_gettime implementation for __APPLE__
> + * @note It always behave like being called with CLOCK_REALTIME.
> + */
> +static int apple_clock_gettime(clockid_t clk_id, struct timespec *tp)
> +{
> +  int result;
> +  mach_timespec_t cur_timeclockid_t;
> +  (void) clk_id; /* unused */
> +
> +  if (NULL == real_clock_get_time)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original clock_get_time() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  DONT_FAKE_TIME(result = (*real_clock_get_time)(clock_serv_real, &cur_timeclockid_t));
> +  tp->tv_sec =  cur_timeclockid_t.tv_sec;
> +  tp->tv_nsec = cur_timeclockid_t.tv_nsec;
> +  return result;
> +}
> +
> +int clock_get_time(clock_serv_t clock_serv, mach_timespec_t *cur_timeclockid_t)
> +{
> +  int result;
> +  struct timespec ts;
> +
> +  /*
> +   * Initialize our result with the real current time from CALENDAR_CLOCK.
> +   * This is a bit of cheating, but we don't keep track of obtained clock
> +   * services.
> +   */
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &ts));
> +  if (result == -1) return result; /* original function failed */
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  result = fake_clock_gettime(CLOCK_REALTIME, &ts);
> +  cur_timeclockid_t->tv_sec = ts.tv_sec;
> +  cur_timeclockid_t->tv_nsec = ts.tv_nsec;
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +#endif
> +
> +
> +/*
> + *      =======================================================================
> + *      Faked system-internal functions                           === FAKE(INT)
> + *      =======================================================================
> + */
> +
> +#ifdef FAKE_INTERNAL_CALLS
> +int __gettimeofday(struct timeval *tv, void *tz)
> +{
> +  int result;
> +
> +  /* sanity check */
> +  if (tv == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  /* Check whether we've got a pointer to the real ftime() function yet */
> +  if (NULL == real___gettimeofday)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original __gettimeofday() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  /* initialize our result with the real current time */
> +  DONT_FAKE_TIME(result = (*real___gettimeofday)(tv, tz));
> +  if (result == -1) return result; /* original function failed */
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  result = fake_gettimeofday(tv);
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +int __clock_gettime(clockid_t clk_id, struct timespec *tp)
> +{
> +  int result;
> +
> +  /* sanity check */
> +  if (tp == NULL)
> +  {
> +    return -1;
> +  }
> +
> +  if (NULL == real___clock_gettime)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original __clock_gettime() not found.\n");
> +#endif
> +    return -1; /* propagate error to caller */
> +  }
> +
> +  /* initialize our result with the real current time */
> +  DONT_FAKE_TIME(result = (*real___clock_gettime)(clk_id, tp));
> +  if (result == -1) return result; /* original function failed */
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  if (fake_monotonic_clock || clk_id != CLOCK_MONOTONIC)
> +  {
> +    result = fake_clock_gettime(clk_id, tp);
> +  }
> +
> +  /* return the result to the caller */
> +  return result;
> +}
> +
> +time_t __time(time_t *time_tptr)
> +{
> +  struct timespec tp;
> +  time_t result;
> +
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
> +  if (result == -1) return -1;
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
> +
> +  if (time_tptr != NULL)
> +  {
> +    *time_tptr = tp.tv_sec;
> +  }
> +  return tp.tv_sec;
> +}
> +
> +int __ftime(struct timeb *tb)
> +{
> +  struct timespec tp;
> +  int result;
> +
> +  /* sanity check */
> +  if (tb == NULL)
> +    return 0;               /* ftime() always returns 0, see manpage */
> +
> +  /* Check whether we've got a pointer to the real ftime() function yet */
> +  if (NULL == real___ftime)
> +  {  /* dlsym() failed */
> +#ifdef DEBUG
> +    (void) fprintf(stderr, "faketime problem: original ftime() not found.\n");
> +#endif
> +    return 0; /* propagate error to caller */
> +  }
> +
> +  /* initialize our TZ result with the real current time */
> +  DONT_FAKE_TIME(result = (*real___ftime)(tb));
> +  if (result == -1)
> +  {
> +    return result;
> +  }
> +
> +  DONT_FAKE_TIME(result = (*real_clock_gettime)(CLOCK_REALTIME, &tp));
> +  if (result == -1) return -1;
> +
> +  /* pass the real current time to our faking version, overwriting it */
> +  (void)fake_clock_gettime(CLOCK_REALTIME, &tp);
> +
> +  tb->time = tp.tv_sec;
> +  tb->millitm = tp.tv_nsec / 1000000;
> +
> +  /* return the result to the caller */
> +  return result; /* will always be 0 (see manpage) */
> +}
> +
> +#endif
> +
> +/*
> + * Editor modelines
> + *
> + * Local variables:
> + * c-basic-offset: 2
> + * tab-width: 2
> + * indent-tabs-mode: nil
> + * End:
> + *
> + * vi: set shiftwidth=2 tabstop=2 expandtab:
> + * :indentSize=2:tabSize=2:noTabs=true:
> + */
> +
> +/* eof */
> diff --git a/scripts/libfaketime/libfaketime.map b/scripts/libfaketime/libfaketime.map
> new file mode 100644
> index 0000000..6e008cf
> --- /dev/null
> +++ b/scripts/libfaketime/libfaketime.map
> @@ -0,0 +1,10 @@
> +GLIBC_2.2 {
> +  global:
> +
> +  timer_gettime; timer_settime;
> +  local: timer_settime_*; timer_gettime_*;
> +};
> +GLIBC_2.3.3 {
> +  # Changed timer_t.
> +  timer_gettime; timer_settime;
> +} GLIBC_2.2;
> diff --git a/scripts/libfaketime/time_ops.h b/scripts/libfaketime/time_ops.h
> new file mode 100644
> index 0000000..59ab1ee
> --- /dev/null
> +++ b/scripts/libfaketime/time_ops.h
> @@ -0,0 +1,104 @@
> +/*
> + * Time operation macros based on sys/time.h
> + * Copyright 2013 Balint Reczey <balint@balintreczey.hu>
> + *
> + * This file is part of libfaketime.
> + *
> + * libfaketime is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License v2 as published by the Free
> + * Software Foundation.
> + *
> + * libfaketime is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License v2 along
> + * with libfaketime; if not, write to the Free Software Foundation, Inc.,
> + * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef TIME_OPS_H
> +#define TIME_OPS_H
> +#include <time.h>
> +
> +#define SEC_TO_uSEC 1000000
> +#define SEC_TO_nSEC 1000000000
> +
> +/* Convenience macros for operations on timevals.
> +   NOTE: `timercmp' does not work for >= or <=.  */
> +#define timerisset2(tvp, prefix) ((tvp)->tv_sec || (tvp)->tv_##prefix##sec)
> +#define timerclear2(tvp, prefix) ((tvp)->tv_sec = (tvp)->tv_##prefix##sec = 0)
> +#define timercmp2(a, b, CMP, prefix)                                \
> +  (((a)->tv_sec == (b)->tv_sec) ?                                   \
> +   ((a)->tv_##prefix##sec CMP (b)->tv_##prefix##sec) :              \
> +   ((a)->tv_sec CMP (b)->tv_sec))
> +#define timeradd2(a, b, result, prefix)                             \
> +  do                                                                \
> +  {                                                                 \
> +    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                   \
> +    (result)->tv_##prefix##sec = (a)->tv_##prefix##sec +            \
> +      (b)->tv_##prefix##sec;                                        \
> +    if ((result)->tv_##prefix##sec >= SEC_TO_##prefix##SEC)         \
> +      {                                                             \
> +        ++(result)->tv_sec;                                         \
> +        (result)->tv_##prefix##sec -= SEC_TO_##prefix##SEC;         \
> +      }                                                             \
> +  } while (0)
> +#define timersub2(a, b, result, prefix)                             \
> +  do                                                                \
> +  {                                                                 \
> +    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                   \
> +    (result)->tv_##prefix##sec = (a)->tv_##prefix##sec -            \
> +      (b)->tv_##prefix##sec;                                        \
> +    if ((result)->tv_##prefix##sec < 0)                             \
> +    {                                                               \
> +      --(result)->tv_sec;                                           \
> +      (result)->tv_##prefix##sec += SEC_TO_##prefix##SEC;           \
> +    }                                                               \
> +  } while (0)
> +#define timermul2(tvp, c, result, prefix)                           \
> +  do                                                                \
> +  {                                                                 \
> +    long long tmp_time;                                             \
> +    tmp_time = (c) * ((tvp)->tv_sec * SEC_TO_##prefix##SEC +        \
> +               (tvp)->tv_##prefix##sec);                            \
> +    (result)->tv_##prefix##sec = tmp_time % SEC_TO_##prefix##SEC;   \
> +    (result)->tv_sec = (tmp_time - (result)->tv_##prefix##sec) /    \
> +      SEC_TO_##prefix##SEC;                                         \
> +    if ((result)->tv_##prefix##sec < 0)                             \
> +    {                                                               \
> +      (result)->tv_##prefix##sec +=  SEC_TO_##prefix##SEC;          \
> +      (result)->tv_sec -= 1;                                        \
> +    }                                                               \
> +  } while (0)
> +
> +/* ops for microsecs */
> +#ifndef timerisset
> +#define timerisset(tvp) timerisset2(tvp,u)
> +#endif
> +#ifndef timerclear
> +#define timerclear(tvp) timerclear2(tvp, u)
> +#endif
> +#ifndef timercmp
> +#define timercmp(a, b, CMP) timercmp2(a, b, CMP, u)
> +#endif
> +#ifndef timeradd
> +#define timeradd(a, b, result) timeradd2(a, b, result, u)
> +#endif
> +#ifndef timersub
> +#define timersub(a, b, result) timersub2(a, b, result, u)
> +#endif
> +#ifndef timersub
> +#define timermul(a, c, result) timermul2(a, c, result, u)
> +#endif
> +
> +/* ops for nanosecs */
> +#define timespecisset(tvp) timerisset2(tvp,n)
> +#define timespecclear(tvp) timerclear2(tvp, n)
> +#define timespeccmp(a, b, CMP) timercmp2(a, b, CMP, n)
> +#define timespecadd(a, b, result) timeradd2(a, b, result, n)
> +#define timespecsub(a, b, result) timersub2(a, b, result, n)
> +#define timespecmul(a, c, result) timermul2(a, c, result, n)
> +
> +#endif
> -- 
> 1.9.1
> 
> 
> _______________________________________________
> ptxdist mailing list
> ptxdist@pengutronix.de

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-08-27 16:27 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-03 15:44 [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support jon
2018-08-03 15:44 ` [ptxdist] [PATCH v4 2/2] Detect changes in package patch series jon
2018-08-08  9:50 ` [ptxdist] [PATCH v4 1/2] Add libfaketime as a core component of ptxdist for patchin support Roland Hieber
2018-08-08 10:58   ` Jon Ringle
2018-08-08 19:27     ` Jon Ringle
2018-08-27 16:27 ` Michael Olbrich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox