38 Commits
v0.8 ... v0.9

Author SHA1 Message Date
Wolfgang Hommel
dac5d28af2 Updated documentation for the upcoming 0.9 release 2012-01-11 22:37:21 +01:00
Wolfgang Hommel
84f61b75b3 Updated todo list to reflect OSX improvements
The Mac OS X 10.7 Lion issues have been fixed. Updated
the todo list accordingly and outlined the next steps.
2012-01-11 22:35:14 +01:00
Wolfgang Hommel
ec89c44011 Added feature to exec external command after x sec
This feature makes libfaketime execute an arbitrary system
command, such as a shell script, after a program has been
running for X seconds or has made Y time-related function
calls.
It is controlled by three environment variables.
FAKETIME_SPAWN_TARGET is the full path + file name +
command line arguments to the user-specified system
command.
FAKETIME_SPAWN_SECONDS is the number of seconds (after
program start / program's first time function call) after
which FAKETIME_SPAWN_TARGET will be executed.
FAKETIME_SPAWN_NUMCALLS can be used as an alternative
to ..._SECONDS.
2012-01-11 22:23:09 +01:00
Wolfgang Hommel
837e2c7e62 Added new feature to limit libfaketime activity
These changes add a new feature that can be used to limit
libfaketime's activity period, and prepares for the upcoming
0.9 release.
Four new environment variables can optionally be set:
FAKETIME_START_AFTER_SECONDS, FAKETIME_STOP_AFTER_SECONDS,
FAKETIME_START_AFTER_NUMCALLS, and FAKETIME_START_AFTER_NUMCALLS.
libfaketime will only return faked timestamps if the program's
runtime is between FAKETIME_START_AFTER_SECONDS and
FAKETIME_STOP_AFTER_SECONDS seconds. For example, a program
may be started with the real current time, and after 60
seconds, it will start to receive faked timestamps, e.g.,
one year in the future. The other pair of environment
variables limits libfaketime's activity based on the number
of time-related system calls of the started program,
instead of its run-time in seconds.
Using this new feature will break applications that cannot
handle larger sudden changes in timestamps, so use it with
care.
2012-01-08 22:41:54 +01:00
Wolfgang Hommel
e72d8e0419 Fixed build issues as suggested by Paul Wouters
- Updates COPYING file (fixed wrong FSE address)
- Avoid overwriting CFLAGS and LDFLAGS in src/Makefile
2011-11-28 19:40:00 +01:00
Wolfgang Hommel
4acfdddc89 Minor changes
Minor changes to README.OSX
2011-10-19 23:03:53 +02:00
Wolfgang Hommel
0a1c887a8a Fixed issues on Mac OS X 10.7 Lion
- Changed interception of internal syscalls on OSX
  and malloc arena treatment
- Adapted the faketime wrapper shell script to set
  the appropriate environment variables on OSX and
  use gdate instead of date
- Added README.OSX to explain the OSX-specific
  aspects of compiling and using libfaketime
2011-10-19 21:03:41 +02:00
Wolfgang Hommel
18adec4fae Added TODO item about libfaketime on OS X 10.7 (Lion)
libfaketime appears not to work on OS X 10.7 (Lion). It does not fake th
e time and sporadically causes a segfault.
2011-07-30 11:19:16 +02:00
Wolfgang Hommel
f07939d948 Minor adaptions for Mac OS X 2011-07-30 10:58:12 +02:00
Wolfgang Hommel
68ccdb74b5 Described recent changes and next steps 2011-07-30 10:50:19 +02:00
wolfcw
a5896e3dcb Merge pull request #3 from dfong/master
eliminate use of dc
2011-07-26 14:33:53 -07:00
don fong
54bc41ffaf compute pow() with shell only, in case we don't have bc, dc, perl 2011-07-26 12:54:42 -07:00
wolfcw
9099c4ab85 Merge pull request #2 from dfong/master
new framework for functional tests
2011-07-25 22:15:25 -07:00
don fong
ea15324e30 add support for new framework for functional tests 2011-07-25 17:04:09 -07:00
Lukas Fleischer
e4cfb671dd NEWS: Add note on MacOS port
Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-07-15 15:50:03 +02:00
Lukas Fleischer
ab66fd5237 NEWS: Fix trailing whitespace
Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-07-15 15:50:03 +02:00
Lukas Fleischer
86f738b25e Restructure meta files
* Move "COPYING" and "Changelog" from "meta/" to the top-level source
  directory. No need to have a separate directory for two small text
  files. Also, it's common practice to put these there.

* Makefile: Merge "meta/Makefile".

* Rename "Changelog" to "NEWS". The file containing a summary of changes
  between two releases in generally called "NEWS". The name "ChangeLog"
  should only be used for a detailed log of every commit.

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-07-15 15:49:58 +02:00
wolfcw
f2ba5c7750 Merge pull request #1 from dbrashear/master
I ported libfaketime to MacOS.
2011-07-09 09:47:29 -07:00
Derrick Brashear
74852f1682 add multi-architecture support
extra -arch flags should do it.
2011-07-08 08:19:29 -04:00
Derrick Brashear
3c24c524b3 macos: pass one gettimeofday unmodified
needed to avoid a malloc recursion; dyld calls the libSystem
initializer, which calls malloc as the first caller; that uses
the arc4 randomizer, which calls gettimeofday... the call to fake_time
calls strptime_l, _strptime0, gmtsub, and boom, back at malloc.

pass one gettimeofday call to let the malloc succeed.
2011-07-05 10:46:34 -04:00
Derrick Brashear
eb59447a6d libfaketime macos port
port libfaketime to macos and dyld.
1) _ftpl_time calls gettimeofday since real time() does so. needed
   to avoid double adjustment.
2) reduce call stack: use time tptr and call fake_time instead of
   calling time for faking other time calls.
3) provide MacOS makefile and README notes.
4) make posix realtime calls under ifdef; define for base port but not
MacOS.
2011-07-05 09:05:38 -04:00
Wolfgang Hommel
ed25084970 Modified documentation and changelog based on the recent changes 2011-05-22 00:21:04 +02:00
Wolfgang Hommel
2a384f70ba fixed one more hard-coded path
changed the Makefile echo output so it also uses the prefix
environment variables just like the install calls.
2011-05-22 00:05:24 +02:00
Lukas Fleischer
4991c61b77 Overwrite existing man pages when running make install.
Add "-f" option to gzip(1) invocation to avoid user prompts if
compressed man pages already exist in the target directory.

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-05-10 22:07:49 +02:00
Lukas Fleischer
b6ca32ed23 Use install(1) instead of mkdir(1) and cp(1) in Makefiles.
Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-05-10 22:07:10 +02:00
Lukas Fleischer
bb9b292a41 Use a separate Makefile for meta files.
* Create separate "install" and "uninstall" targets for meta files.

* Add meta file targets to the shortcut Makefile.

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-05-10 22:02:14 +02:00
Lukas Fleischer
9763cdebd2 Use a separate Makefile for man pages.
* Create separate "install" and "uninstall" targets for man pages.

* Add man page targets to the shortcut Makefile.

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-05-10 21:43:24 +02:00
Lukas Fleischer
8c6c487b24 Tell the compiler to be C99 compliant, enable all warnings.
Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-05-10 21:43:23 +02:00
Lukas Fleischer
5fa942b4cf Cast time_t to unsigned integer when using printf().
Suppress compiler warnings when using "-Wformat".

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-05-10 21:43:23 +02:00
Lukas Fleischer
d2108361c0 timetest.c: Add "sys/time.h" include (required for gettimeofday()).
Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-05-10 21:43:23 +02:00
Lukas Fleischer
403d240444 Add shortcut Makefile.
Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-05-10 21:43:23 +02:00
Lukas Fleischer
9b62bb4f38 Test suite Makefile overhaul.
* Use variables for compiler and linker flags.

* Use variables for source/object files and binaries.

* Use proper targets instead of phony targets to build the timetest
  program.

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-05-10 21:43:23 +02:00
Lukas Fleischer
52c30f866d Source Makefile overhaul.
* Use variables for compiler and linker flags.

* Use variables for source/object files, library names and sonames.

* Use proper targets instead of phony targets to build the shared
  libraries.

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-05-10 21:43:21 +02:00
Lukas Fleischer
cf0ccef687 Move test suite to a separate subdirectory.
* Move test suite related stuff from "src/" to "test/".

* Fix "test.sh" to search for libfaketime libraries in the right place.

* Split up Makefile into two separate Makefiles (one for the main
  program and one for the test suite).

Test cases should go in another directory for the sake of clean code
separation. This will also facilitate the creation of proper Makefiles.

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-04-27 18:50:40 +02:00
Lukas Fleischer
9234f5df86 Add ".PHONY" target to the Makefile.
This is required for targets that do not directly refer to files.

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-04-26 17:29:22 +02:00
Lukas Fleischer
cd0667a7a6 Add an uninstall target to the Makefile.
This is especially advantageous if libfaketime is built from source as
there isn't another convenient way to do a clean uninstall.

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-04-26 17:25:55 +02:00
Lukas Fleischer
46f6bd5b9b Use "$DESTDIR" and "$PREFIX" in the Makefile.
This is a standard used by almost all open source projects and allows
installing to different locations than the default location (which is
especially useful for packagers, e.g.) Switch to installing to
"/usr/local" by default, also. "/usr" should never be used as default
prefix.

Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-04-26 17:22:12 +02:00
Lukas Fleischer
5bbb393e07 Add ".gitignore".
Signed-off-by: Lukas Fleischer <info@cryptocrack.de>
2011-04-26 17:17:16 +02:00
25 changed files with 1096 additions and 120 deletions

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
*.o
*.so.1
timetest
src/libfaketime.dylib.1
src/core

View File

@@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@@ -55,7 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@@ -109,6 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@@ -166,6 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
@@ -222,6 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
@@ -251,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@@ -273,8 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@@ -298,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
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
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@@ -331,5 +335,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

30
Makefile Normal file
View File

@@ -0,0 +1,30 @@
all:
$(MAKE) -C src all
$(MAKE) -C test all
test:
$(MAKE) -C test all
install:
$(MAKE) -C src install
$(MAKE) -C man install
$(INSTALL) -dm0755 "${DESTDIR}${PREFIX}/share/doc/faketime/"
$(INSTALL) -m0644 README "${DESTDIR}${PREFIX}/share/doc/faketime/README"
$(INSTALL) -m0644 NEWS "${DESTDIR}${PREFIX}/share/doc/faketime/NEWS"
uninstall:
$(MAKE) -C src uninstall
$(MAKE) -C man uninstall
rm -f "${DESTDIR}${PREFIX}/share/doc/faketime/README"
rm -f "${DESTDIR}${PREFIX}/share/doc/faketime/NEWS"
rmdir "${DESTDIR}${PREFIX}/share/doc/faketime"
clean:
$(MAKE) -C src clean
$(MAKE) -C test clean
distclean:
$(MAKE) -C src distclean
$(MAKE) -C test distclean
.PHONY: all test install uninstall clean distclean

View File

@@ -1,6 +1,30 @@
Since 0.8.2:
- Added support for "limited faking".
You can optionally specify when libfaketime starts to fake the
returned timestamps and when it shall stop doing so. For example,
a program can be started regularly, and after 5 minutes run-time
it will be sent two years into the future. Those limiting
start and stop times can be specified in seconds or as the
number of any time-related function calls within the program.
- Added a feature to spawn an external process after x seconds
or y time-related system calls. This can, for example, be used
to execute an arbitrary shell script x seconds after a program
has been started.
Since 0.8.1:
- Added a MacOS port.
Thanks to Derrick Brashear!
- Added a functional test framework that aids in automatically
determining whether libfaketime works properly on the current
machine. Thanks to Don Fong!
Since 0.8:
- Changed directory layout and Makefile structure.
Thanks to Lukas Fleischer!
Since 0.7:
- Added support for fstatat() and fstatat64() which were introduced in
Linux kernel 2.6.16 and used in recent coreutils.
Linux kernel 2.6.16 and used in recent coreutils.
Thanks to Daniel Kahn Gillmor for the report!
This can be disabled by passing -DNO_ATFILE in the Makefile.
- Added a simple wrapper shell script and a man page for it. Makes it
@@ -9,7 +33,7 @@ Since 0.7:
please adjust this path if necessary. The "install" target in the
Makefile has been adapted accordingly.
- Added support for fractional time offsets, such as FAKETIME="+1,5h".
Please note that either , or . has to be used as a delimiter
Please note that either , or . has to be used as a delimiter
depending on your locale. Thanks to Karl Chen!
- Added support for speeding the clock up or slowing it down. For
example, FAKETIME="+5d x2,0" will set the faked time 5 days into
@@ -18,7 +42,7 @@ Since 0.7:
Again, the delimiter to use for the fraction depends on your locale.
Thanks to Karl Chen!
Since 0.6:
Since 0.6:
Main version 0.7 contributions by David North, TDI:
- Added ability to 'start clock at' a specific time.
- Added pthread synchronization support
@@ -31,22 +55,22 @@ Since 0.6:
- Repaired a bug w.r.t. strptime/mktime wherein 'isdst' was uninitialized
which led to pseudorandom +/- 1 hour results being returned in 'start at'
or absolute time modes
Other enhancements:
Other enhancements:
- Fixed missing interceptions to libc-internal functions and added notes
about a workaround for running Java programs with faked times in the
future (they worked properly, but often locked up at exiting). Thanks to
Jamie Cameron of Google for in-depth analysis and prototype solution!
Since 0.5:
- Performance enhancements by means of caching the data read
- Performance enhancements by means of caching the data read
e.g. from $HOME/.faketimerc for 10 seconds.
- Several file timestamp related system calls such as fstat() will be
intercepted now. See the README file on how to turn this off if you
do not need it. Thanks to Philipp Hachtmann!
- A system-wide /etc/faketimerc file will now be used if no FAKETIME
environment variable has been set and no $HOME/.faketimerc is present.
Thanks to David Burley, Jacob Moorman, and Wayne Davison of
Thanks to David Burley, Jacob Moorman, and Wayne Davison of
SourceForge, Inc.!
- Added trivial Makefile targets clean/distclean/install
- Changed Makefile target test to run new test.sh script
@@ -64,4 +88,4 @@ Since 0.2:
Since 0.1:
- Fixed segfault when calling time(NULL). Thanks to Andres Ojamaa!
- Added additional sanity checks.

121
README
View File

@@ -1,6 +1,6 @@
===================================================
FakeTime Preload Library, version 0.8 (August 2008)
===================================================
=====================================================
FakeTime Preload Library, version 0.9 (February 2011)
=====================================================
Content of this file:
@@ -17,6 +17,8 @@ Content of this file:
e) Advanced features and caveats
f) Faking the date and time system-wide
g) Using the "faketime" wrapper script
h) "Limiting" libfaketime
i) Spawning an external process
5. License
6. Contact
@@ -81,11 +83,12 @@ it then also executes.
If the test works fine, you should copy the FTPL libraries (libfaketime.so.1,
and libfaketimeMT.so.1) to the place you want them in. Running "make install"
will attempt to place them in /usr/lib/faketime and will install the wrapper
shell script "faketime" in /usr/bin, both of which most likely will require
will attempt to place them in /usr/local/lib/faketime and will install the wrapper
shell script "faketime" in /usr/local/bin, both of which most likely will require
root privileges; however, from a technical point of view, there is no
necessity for a system-wide installation, so you can use FTPL also on machines
where you do not have root privileges.
where you do not have root privileges. You may want to adjust the PREFIX
variable in the Makefiles accordingly.
Since version 0.6, system calls to file timestamps are also intercepted now,
thanks to a contribution by Philipp Hachtmann. This is especially useful in
@@ -95,6 +98,12 @@ not need this feature or if it confuses the application you want to use FTPL
with, define the environment variable NO_FAKE_STAT, and the intercepted stat
calls will be passed through unaltered.
On MacOS, it is necessary to compile differently, due to the different
behavior dyld has. Use the Makefile.MacOS provided to compile
libfaketime.dylib.1. Additionally, instead of using LD_PRELOAD,
the variable DYLD_INSERT_LIBRARIES should be set to the path to
libfaketime.dylib.1, and the variable DYLD_FORCE_FLAT_NAMESPACE should be
set (to anything).
4. Usage
--------
@@ -311,6 +320,104 @@ faketime '2008-12-24 08:15:42' /bin/date
Thanks to Daniel Kahn Gillmor for providing these suggestions!
4h) "Limiting" libfaketime
--------------------------
Starting with version 0.9, libfaketime can be configured to not be continuously
active, but only during a certain time interval.
For example, you might want to start a program with the real current time, but
after 5 minutes of usage, you might want it to see a faked time, e.g., a year
in the future.
Dynamic changes to the faked time are alternatively possible by
- changing the FAKETIME environment variable at run-time; this is the preferred
way if you use libfaketime for debugging and testing as a programmer, as it
gives you the most direct control of libfaketime without any performance
penalities.
- not using the FAKETIME environment variable, but specifying the fake time in a
file (such as ~/.faketimerc). You can change the content of this file at
run-time. This works best with caching disabled (see Makefile), but comes at a
performance cost because this file has to be read and evaluated each time.
The feature described here works based on two pairs of environment variables,
FAKETIME_START_AFTER_SECONDS and FAKETIME_STOP_AFTER_SECONDS, and
FAKETIME_START_AFTER_NUMCALLS and FAKETIME_STOP_AFTER_NUMCALLS
The default value for each of these environment variables is -1, which means
"ignore this value".
If you want libfaketime to be only active during the run-time minutes 2 to 5
of your application, you would set
FAKETIME_START_AFTER_SECONDS=60
FAKETIME_STOP_AFTER_SECONDS=300
This means that your application will work with the real time from start (second
0) up to second 60. It will then see a faked time from run-time seconds 60 to
300 (minutes 2, 3, 4, and 5). After run-time second 600, it will again see the
real (not-faked) time.
This approach is not as flexible as changing the FAKETIME environment variable
during runtime, but may be easier to use, works on a per-program (and not a
per-user or system-wide) scope, and has only a minor performance overhead.
Using the other pair of environment variables, you can limit the activity time
of libfaketime not based on wall-clock seconds, but on the number of
time-related function calls the started program performs. This alternative is
probably only suitable for programmers who either know the code of the program
in order to determine useful start/stop values or want to perform fuzzing
tests.
Both pairs of environment variables can be combined to further restrict
libfaketime activity, although this is only useful in very few scenarios.
Limiting libfaketime activity in this way is not recommended in general. Many
programs will break when they are subject to sudden changes in time, especially
if they are started using the current (real) time and are then sent back into
the past after, e.g., 5 minutes. For example, they may appear to be frozen or
stuck because they are waiting until a certain point in time that, however, is
never reached due to the delayed libfaketime activity. Avoid using this
functionality unless you are sure you really need it and know what you are
doing.
4i) Spawning an external process
--------------------------------
From version 0.9 on, libfaketime can execute a shell command once after an
arbitrary number of seconds or number of time-related system calls of the
program started. This has two limitations one needs to be aware of:
* Spawning the external process happens during a time-related system call
of the original program. If you want the external process to be started
5 seconds after program start, but this program does not make any time-
related system calls before run-time second 8, the start of your external
process will be delayed until run-time second 8.
* The original program is blocked until the external process is finished,
because the intercepting time-related system call will not return earlier. If
you need to start a long-running external process, make sure it forks into the
background.
Spawning the external process is controlled using three environment variables:
FAKETIME_SPAWN_TARGET, FAKETIME_SPAWN_SECONDS, FAKETIME_SPAWN_NUMCALLS.
Example (using bash on Linux):
(... usual libfaketime setup here, setting LD_PRELOAD and FAKETIME ...)
export FAKETIME_SPAWN_TARGET="/bin/echo 'Hello world'"
export FAKETIME_SPAWN_SECONDS=5
/opt/local/bin/myprogram
This will run the "echo" command with the given parameter during the first
time-related system function call that "myprogram" performs after running for 5
seconds.
5. License
----------
@@ -327,3 +434,5 @@ appreciated.
Please send an email to: wolf /at/ code-wizards.com
git pull requests are welcome, see https://github.com/wolfcw/libfaketime

98
README.OSX Normal file
View File

@@ -0,0 +1,98 @@
README file for libfaketime on Mac OS X
=======================================
Support for Mac OS X is still preliminary. Development and tests are
done under 10.7 Lion only currently.
Compiling and using libfaketime on OS X is slightly different than
on Linux. Please make sure to read the README file for general
setup and usage, and refer to this file only about OS X specifics.
1) Compiling libfaketime on OS X
--------------------------------
Use the OSX-specific Makefiles that are provided, e.g.:
cd src/
make -f Makefile.MacOS
The resulting library will be named libfaketime.dylib.1
2) Using libfaketime from the command line on OS X
--------------------------------------------------
You will need to set three environment variables. In a Terminal.app
or iTerm session, the following commands can be used:
export DYLD_FORCE_FLAT_NAMESPACE=1
export DYLD_INSERT_LIBRARIES=/path/to/libfaketime.dylib.1
export FAKETIME="your favorite faketime-spec here"
Please refer to the general README file concerning the format
of the FAKETIME environment variable value and other environment
variables that are related to it.
The "faketime" wrapper shell script has been adapted to OS X;
it offers the same limited libfaketime functionality as on Linux
in a simple-to-use manner without the need to manually set
those environment variables.
3) Integrating libfaketime with applications
--------------------------------------------
Given the limited number of system calls libfaketime intercepts,
it does not work too well with GUI applications on OS X. Crashes
after a random time are common issues, some applications will
not or at least not always see the faked time, and so on.
A safe way to try out whether a specific application works fine
with libfaketime is to start it from the command line. Perform
the steps outlined above and run the application by issuing the
following command:
/Applications/ApplicationName.app/Contents/MacOS/ApplicationName
(Make sure to replace "ApplicationName" twice in that command with
the name of your actual application.)
If it works fine, you can configure the application to permanently
run with libfaketime by editing its Info.plist file. Add the
LSEnvironment key unless it is already there and add a dictionary
with the three keys like this:
<key>LSEnvironment</key>
<dict>
<key>DYLD_FORCE_FLAT_NAMESPACE</key>
<string>1</string>
<key>DYLD_INSERT_LIBRARIES</key>
<string>/path/to/libfaketime.dylib.1</string>
<key>FAKETIME</key>
<string>value of FAKETIME here</string>
</dict>
(If the application is installed in /Applications instead of in
$HOME/Applications, you eventually will need root privileges. If
the application's Info.plist is not in XML, but in binary format,
use appropriate editing or conversion tools.)
Afterwards, you will probably need to run
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -v -f /Applications/ApplicationName.app
to make sure the change to Info.plist does not go unnoticed.
Please note that modifications to Info.plist will be lost when the
application is updated, so this process needs to be repeated after
such updates, including own new builds when using Xcode.
4) Notes for developers of OS X applications
--------------------------------------------
The environment variable FAKETIME can be changed at application run-time
and always takes precedence over other user-controlled settings. It can
be re-set to 0 (zero) to work around potential incompatibilities.

7
TODO Normal file
View File

@@ -0,0 +1,7 @@
Open issues / next steps for libfaketime development
- add more functional tests that check more than the basic functionality
- use the new testing framework to also implement unit tests
- make the new "limiting" and "spawning" features more flexible to use
and available through the wrapper shell script

14
man/Makefile Normal file
View File

@@ -0,0 +1,14 @@
INSTALL = install
PREFIX = /usr/local
all:
install:
$(INSTALL) -Dm0644 faketime.1 "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
gzip -f "${DESTDIR}${PREFIX}/share/man/man1/faketime.1"
uninstall:
rm -f "${DESTDIR}${PREFIX}/share/man/man1/faketime.1.gz"
.PHONY: all install uninstall

View File

@@ -30,6 +30,13 @@
# frequently. Disabling the cache may negatively influence the
# performance.
#
# LIMITEDFAKING
# - Support environment variables that limit time faking to certain
# time intervals or number of function calls.
#
# SPAWNSUPPORT
# - Enable support for spawning an external process at a given
# timestamp.
#
# * Compilation addition: second libMT target added for building the pthread-
# enabled library as a separate library
@@ -41,42 +48,45 @@
#
CC = gcc
INSTALL = install
all: lib libMT testprog test
PREFIX = /usr/local
libs: lib libMT
CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -DFAKE_INTERNAL_CALLS -fPIC -DPOSIX_REALTIME -DLIMITEDFAKING -DSPAWNSUPPORT
LDFLAGS += -shared -ldl -lm -lpthread
lib: faketime.c
${CC} -DFAKE_STAT -DFAKE_INTERNAL_CALLS -shared -fPIC -Wl,-soname,libfaketime.so.1 -o libfaketime.so.1 faketime.c -ldl -lm -lpthread
SRC = faketime.c
OBJ = faketime.o faketimeMT.o
libMT: faketime.c
${CC} -DFAKE_STAT -DFAKE_INTERNAL_CALLS -DPTHREAD -DPTHREAD_SINGLETHREADED_TIME -shared -fPIC -Wl,-soname,libfaketimeMT.so.1 -o libfaketimeMT.so.1 faketime.c -ldl -lm -lpthread
SONAME = 1
LIBS = libfaketime.so.${SONAME} libfaketimeMT.so.${SONAME}
testprog: timetest.c
${CC} -DFAKE_STAT -o timetest timetest.c -lrt
all: ${LIBS}
test: lib testprog
@echo
@./test.sh
faketimeMT.o: EXTRA_FLAGS := -DPTHREAD -DPTHREAD_SINGLETHREADED_TIME
notest: lib libMT testprog
@echo
${OBJ}: faketime.c
${CC} -o $@ -c ${CFLAGS} ${EXTRA_FLAGS} $<
lib%.so.${SONAME}: %.o
${CC} -o $@ -Wl,-soname,$@ ${LDFLAGS} $<
clean:
@rm -f libfaketime.so.1 libfaketimeMT.so.1 timetest
@rm -f ${OBJ} ${LIBS}
distclean: clean
@echo
install: libs
install: ${LIBS}
@echo
@echo "Copying the libraries to /usr/lib/faketime and the wrapper script to /usr/bin ..."
-mkdir -p /usr/lib/faketime
cp libfaketime.so.1 libfaketimeMT.so.1 /usr/lib/faketime
cp faketime /usr/bin
cp faketime.1 /usr/share/man/man1/faketime.1
gzip /usr/share/man/man1/faketime.1
-mkdir -p /usr/share/doc/faketime
cp README /usr/share/doc/faketime/README
cp Changelog /usr/share/doc/faketime/Changelog
@echo "Copying the faketime libraries to ${DESTDIR}${PREFIX}/lib/faketime and the faketime wrapper script to ${DESTDIR}${PREFIX}/bin ..."
$(INSTALL) -dm0755 "${DESTDIR}${PREFIX}/lib/faketime/"
$(INSTALL) -m0644 ${LIBS} "${DESTDIR}${PREFIX}/lib/faketime/"
$(INSTALL) -Dm0755 faketime "${DESTDIR}${PREFIX}/bin/faketime"
uninstall:
for f in ${LIBS}; do rm -f "${DESTDIR}${PREFIX}/lib/faketime/$$f"; done
rmdir "${DESTDIR}${PREFIX}/lib/faketime"
rm -f "${DESTDIR}${PREFIX}/bin/faketime"
.PHONY: all clean distclean install uninstall

91
src/Makefile.MacOS Normal file
View File

@@ -0,0 +1,91 @@
#
# 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.
#
# NO_CACHING
# - Disables the caching of the fake time offset. Only disable caching
# if you change the fake time offset during program runtime very
# frequently. Disabling the cache may negatively influence the
# performance.
#
# LIMITEDFAKING
# - Support environment variables that limit time faking to certain
# time intervals or number of function calls.
#
# SPAWNSUPPORT
# - Enable support for spawning an external process at a given
# timestamp.
#
#
# * 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.
#
CC = gcc
INSTALL = install
PREFIX = /usr/local
# If you get an error about an unsupported architecture, remove it. Some
# versions of XCode support different subsets of architectures, depending on
# age.
# 10.5
#CFLAGS = -dynamiclib -DFAKE_INTERNAL_CALLS -arch i386 -arch ppc
# 10.6
CFLAGS = -dynamiclib -DFAKE_INTERNAL_CALLS -arch i386 -arch x86_64 -DLIMITEDFAKING -DSPAWNSUPPORT
SRC = faketime.c
SONAME = 1
LIBS = libfaketime.dylib.${SONAME}
all: ${LIBS}
libfaketime.dylib.${SONAME}: ${SRC}
${CC} -o $@ ${CFLAGS} $<
clean:
@rm -f ${OBJ} ${LIBS}
distclean: clean
@echo
install: ${LIBS}
@echo
@echo "Copying the faketime libraries to ${DESTDIR}${PREFIX}/lib/faketime and the faketime wrapper script to ${DESTDIR}${PREFIX}/bin ..."
$(INSTALL) -dm0755 "${DESTDIR}${PREFIX}/lib/faketime/"
$(INSTALL) -m0644 ${LIBS} "${DESTDIR}${PREFIX}/lib/faketime/"
$(INSTALL) -Dm0755 faketime "${DESTDIR}${PREFIX}/bin/faketime"
uninstall:
for f in ${LIBS}; do rm -f "${DESTDIR}${PREFIX}/lib/faketime/$$f"; done
rmdir "${DESTDIR}${PREFIX}/lib/faketime"
rm -f "${DESTDIR}${PREFIX}/bin/faketime"
.PHONY: all clean distclean install uninstall

View File

@@ -12,11 +12,16 @@
# Acknowledgment: Parts of the functionality of this wrapper have been
# inspired by Matthias Urlichs' datefudge 1.14.
# Configuration: Path where the libfaketime libraries can be found.
# Configuration: Path where the libfaketime libraries can be found on Linux/UNIX.
FTPL_PATH=/usr/lib/faketime
# For Mac OS X users: Full path and name to libfaketime.dylib.1
MAC_FTPL_PATH=./libfaketime.dylib.1
offset="$1"
DATE_CMD=date
USEMT=0
USEDIRECT=0
@@ -60,8 +65,15 @@ fi
shift
# Setting LD_PRELOAD ...
# Check whether we are on Mac OS X (Darwin)
UNAME=$(uname)
if [ "$UNAME" = "Darwin" ] ; then
export DYLD_FORCE_FLAT_NAMESPACE=1
export DYLD_INSERT_LIBRARIES=$MAC_FTPL_PATH
DATE_CMD=gdate
fi
# Setting LD_PRELOAD ...
if [ "$USEMT" -eq 0 ] ; then
export LD_PRELOAD="${LD_PRELOAD}${LD_PRELOAD:+:}$FTPL_PATH/libfaketime.so.1"
fi
@@ -74,13 +86,13 @@ fi
# Setting FAKETIME ...
if [ "$USEDIRECT" -eq 0 ] ; then
seconds=$(date -d "$offset" '+%s')
seconds=$($DATE_CMD -d "$offset" '+%s')
if [ $? -ne 0 ] ; then
echo "Error: Timestamp to fake not recognized, please re-try with a different timestamp."
exit 1
fi
offset=$(expr $seconds - $(date '+%s'))
offset=$(expr $seconds - $($DATE_CMD '+%s'))
if [ $? -ne 0 ] ; then
echo "Error: Cannot calculate the faketime offset in seconds, please re-try with a different timestamp."
exit 1

View File

@@ -1,6 +1,4 @@
/*
* Copyright (C) 2003,2004,2005,2006,2007,2008 Wolfgang Hommel
*
* This file is part of the FakeTime Preload Library, version 0.8.
*
* The FakeTime Preload Library is free software; you can redistribute it
@@ -60,7 +58,9 @@ static pthread_mutex_t once_mutex=PTHREAD_MUTEX_INITIALIZER;
time_t fake_time(time_t *time_tptr);
int fake_ftime(struct timeb *tp);
int fake_gettimeofday(struct timeval *tv, void *tz);
#ifdef POSIX_REALTIME
int fake_clock_gettime(clockid_t clk_id, struct timespec *tp);
#endif
/*
* Intercepted system calls:
@@ -375,6 +375,16 @@ int __lxstat64 (int ver, const char *path, struct stat64 *buf){
}
#endif
/*
* On MacOS, time() internally uses gettimeofday. If we don't
* break the cycle by just calling it directly, we double-apply
* relative changes.
*/
#ifdef __APPLE__
static int (*real_gettimeofday)(struct timeval *, void *);
static int has_real_gettimeofday = 0;
#endif
/*
* Our version of time() allows us to return fake values, so the calling
* program thinks it's retrieving the current date and time, while it is
@@ -382,26 +392,54 @@ int __lxstat64 (int ver, const char *path, struct stat64 *buf){
* Note that this routine is split into two parts so that the initialization
* piece can call the 'real' time function to establish a base time.
*/
static time_t _ftpl_time(time_t *time_tptr) {
#ifdef __APPLE__
struct timeval tvm, *tv = &tvm;
#else
static time_t (*real_time)(time_t *);
static int has_real_time = 0;
#endif
time_t result;
time_t null_dummy;
/* Handle null pointers correctly, fix as suggested by Andres Ojamaa */
if (time_tptr == NULL) {
time_tptr = &null_dummy;
/* (void) fprintf(stderr, "NULL pointer caught in time().\n"); */
}
#ifdef __APPLE__
/* Check whether we've got a pointer to the real ftime() function yet */
SINGLE_IF(has_real_gettimeofday==0)
real_gettimeofday = NULL;
real_gettimeofday = dlsym(RTLD_NEXT, "gettimeofday");
/* check whether dlsym() worked */
if (dlerror() == NULL) {
has_real_gettimeofday = 1;
}
END_SINGLE_IF
if (!has_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 */
result = (*real_gettimeofday)(tv, NULL);
if (result == -1) return result; /* original function failed */
if (time_tptr != NULL)
*time_tptr = tv->tv_sec;
result = tv->tv_sec;
#else
/* Check whether we've got a pointer to the real time function yet */
SINGLE_IF(has_real_time==0)
real_time = NULL;
real_time = dlsym(RTLD_NEXT, "time");
/* check whether dlsym() worked */
if (dlerror() == NULL) {
has_real_time = 1;
@@ -415,9 +453,11 @@ static time_t _ftpl_time(time_t *time_tptr) {
*time_tptr = -1;
return -1; /* propagate error to caller */
}
/* initialize our result with the real current time */
result = (*real_time)(time_tptr);
#endif
return result;
}
@@ -477,10 +517,12 @@ int ftime(struct timeb *tp) {
}
int gettimeofday(struct timeval *tv, void *tz) {
#ifndef __APPLE__
static int (*real_gettimeofday)(struct timeval *, void *);
static int has_real_gettimeofday = 0;
#endif
int result;
/* sanity check */
if (tv == NULL) {
return -1;
@@ -509,11 +551,12 @@ int gettimeofday(struct timeval *tv, void *tz) {
/* pass the real current time to our faking version, overwriting it */
result = fake_gettimeofday(tv, tz);
/* return the result to the caller */
return result;
}
#ifdef POSIX_REALTIME
int clock_gettime(clockid_t clk_id, struct timespec *tp) {
static int (*real_clock_gettime)(clockid_t clk_id, struct timespec *tp);
static int has_real_clock_gettime = 0;
@@ -551,6 +594,7 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp) {
/* return the result to the caller */
return result;
}
#endif
/*
* Static time_t to store our startup time, followed by a load-time library
@@ -586,6 +630,33 @@ time_t fake_time(time_t *time_tptr) {
static int cache_expired = 1; /* considered expired at first call */
static int cache_duration = 10; /* cache fake time input for 10 seconds */
#ifdef LIMITEDFAKING
static long callcounter = 0;
static int limited_initialized = 0;
char envvarbuf[32];
static long FAKETIME_START_AFTER_SECONDS = -1;
static long FAKETIME_STOP_AFTER_SECONDS = -1;
static long FAKETIME_START_AFTER_NUMCALLS = -1;
static long FAKETIME_STOP_AFTER_NUMCALLS = -1;
#endif
#ifdef SPAWNSUPPORT
static int spawned = 0;
static long spawn_callcounter = 0;
static int spawn_initialized = 0;
char spawn_envvarbuf[32];
static char FAKETIME_SPAWN_TARGET[1024];
static long FAKETIME_SPAWN_SECONDS = -1;
static long FAKETIME_SPAWN_NUMCALLS = -1;
#endif
/*
* This no longer appears to be necessary in Mac OS X 10.7 Lion
*/
//#ifdef __APPLE__
// static int malloc_arena = 0;
//#endif
#ifdef PTHREAD_SINGLETHREADED_TIME
static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&time_mutex);
@@ -595,13 +666,84 @@ static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
/* Sanity check by Karl Chan since v0.8 */
if (time_tptr == NULL) return -1;
#ifdef LIMITEDFAKING
/* Check whether we actually should be faking the returned timestamp. */
if (ftpl_starttime > 0) {
if (limited_initialized == 0) {
if (getenv("FAKETIME_START_AFTER_SECONDS") != NULL) {
(void) strncpy(envvarbuf, getenv("FAKETIME_START_AFTER_SECONDS"), 30);
FAKETIME_START_AFTER_SECONDS = atol(envvarbuf);
}
if (getenv("FAKETIME_STOP_AFTER_SECONDS") != NULL) {
(void) strncpy(envvarbuf, getenv("FAKETIME_STOP_AFTER_SECONDS"), 30);
FAKETIME_STOP_AFTER_SECONDS = atol(envvarbuf);
}
if (getenv("FAKETIME_START_AFTER_NUMCALLS") != NULL) {
(void) strncpy(envvarbuf, getenv("FAKETIME_START_AFTER_NUMCALLS"), 30);
FAKETIME_START_AFTER_NUMCALLS = atol(envvarbuf);
}
if (getenv("FAKETIME_STOP_AFTER_NUMCALLS") != NULL) {
(void) strncpy(envvarbuf, getenv("FAKETIME_STOP_AFTER_NUMCALLS"), 30);
FAKETIME_STOP_AFTER_NUMCALLS = atol(envvarbuf);
}
limited_initialized = 1;
}
if ((callcounter + 1) >= callcounter) callcounter++;
/* For debugging, output #seconds and #calls */
/* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
if ((FAKETIME_START_AFTER_SECONDS != -1) && ((*time_tptr - ftpl_starttime) < FAKETIME_START_AFTER_SECONDS)) return *time_tptr;
if ((FAKETIME_STOP_AFTER_SECONDS != -1) && ((*time_tptr - ftpl_starttime) >= FAKETIME_STOP_AFTER_SECONDS)) return *time_tptr;
if ((FAKETIME_START_AFTER_NUMCALLS != -1) && (callcounter < FAKETIME_START_AFTER_NUMCALLS)) return *time_tptr;
if ((FAKETIME_STOP_AFTER_NUMCALLS != -1) && (callcounter >= FAKETIME_STOP_AFTER_NUMCALLS)) return *time_tptr;
/* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu continues\n", (*time_tptr - ftpl_starttime), callcounter); */
}
#endif
#ifdef SPAWNSUPPORT
/* check whether we should spawn an external command */
if (ftpl_starttime > 0) {
if(spawn_initialized == 0) {
if (getenv("FAKETIME_SPAWN_TARGET") != NULL) {
(void) strncpy(FAKETIME_SPAWN_TARGET, getenv("FAKETIME_SPAWN_TARGET"), 1024);
if (getenv("FAKETIME_SPAWN_SECONDS") != NULL) {
(void) strncpy(spawn_envvarbuf, getenv("FAKETIME_SPAWN_SECONDS"), 30);
FAKETIME_SPAWN_SECONDS = atol(spawn_envvarbuf);
}
if (getenv("FAKETIME_SPAWN_NUMCALLS") != NULL) {
(void) strncpy(spawn_envvarbuf, getenv("FAKETIME_SPAWN_NUMCALLS"), 30);
FAKETIME_SPAWN_NUMCALLS = atol(spawn_envvarbuf);
}
}
spawn_initialized = 1;
}
if (spawned == 0) { /* exec external command once only */
if ((spawn_callcounter + 1) >= spawn_callcounter) spawn_callcounter++;
if ((((*time_tptr - ftpl_starttime) == FAKETIME_SPAWN_SECONDS) || (spawn_callcounter == FAKETIME_SPAWN_NUMCALLS)) && (spawned == 0)) {
spawned = 1;
system(FAKETIME_SPAWN_TARGET);
}
}
}
#endif
if (last_data_fetch > 0) {
if ((*time_tptr - last_data_fetch) > cache_duration) {
cache_expired = 1;
}
if ((*time_tptr - last_data_fetch) > cache_duration) {
cache_expired = 1;
}
else {
cache_expired = 0;
}
cache_expired = 0;
}
}
#ifdef NO_CACHING
@@ -654,6 +796,16 @@ static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
} /* cache had expired */
/*
* This no longer appears to be necessary in Mac OS X 10.7 Lion
*/
//#ifdef __APPLE__
// SINGLE_IF(malloc_arena==0)
// malloc_arena = 1;
// return *time_tptr;
// END_SINGLE_IF
//#endif
/* check whether the user gave us an absolute time to fake */
switch (user_faked_time[0]) {
@@ -724,41 +876,49 @@ static pthread_mutex_t time_mutex=PTHREAD_MUTEX_INITIALIZER;
}
int fake_ftime(struct timeb *tp) {
time_t temp_tt;
time_t temp_tt = tp->time;
tp->time = time(&temp_tt);
tp->time = fake_time(&temp_tt);
return 0; /* always returns 0, see manpage */
}
int fake_gettimeofday(struct timeval *tv, void *tz) {
time_t temp_tt;
tv->tv_sec = time(&temp_tt);
time_t temp_tt = tv->tv_sec;
tv->tv_sec = fake_time(&temp_tt);
return 0;
}
#ifdef POSIX_REALTIME
int fake_clock_gettime(clockid_t clk_id, struct timespec *tp) {
time_t temp_tt;
time_t temp_tt = tp->tv_sec;
/* Fake only if the call is realtime clock related */
if (clk_id == CLOCK_REALTIME) {
tp->tv_sec = time(&temp_tt);
tp->tv_sec = fake_time(&temp_tt);
}
return 0;
}
#endif
/*
* This causes serious issues in Mac OS X 10.7 Lion and is disabled there
*/
#ifndef __APPLE__
/* Added in v0.7 as suggested by Jamie Cameron, Google */
#ifdef FAKE_INTERNAL_CALLS
int __gettimeofday(struct timeval *tv, void *tz) {
return gettimeofday(tv, tz);
}
#ifdef POSIX_REALTIME
int __clock_gettime(clockid_t clk_id, struct timespec *tp) {
return clock_gettime(clk_id, tp);
}
#endif
int __ftime(struct timeb *tp) {
return ftime(tp);
@@ -768,4 +928,7 @@ time_t __time(time_t *time_tptr) {
return time(time_tptr);
}
#endif
#endif
/* eof */

View File

@@ -1,40 +0,0 @@
#!/bin/sh
if [ -f /etc/faketimerc ] ; then
echo "Running the test program with your system-wide default in /etc/faketimerc"
echo "\$ LD_PRELOAD=./libfaketime.so.1 ./timetest"
LD_PRELOAD=./libfaketime.so.1 ./timetest
echo
else
echo "Running the test program with no faked time specified"
echo "\$ LD_PRELOAD=./libfaketime.so.1 ./timetest"
LD_PRELOAD=./libfaketime.so.1 ./timetest
echo
fi
echo "Running the test program with absolute date 2003-01-01 10:00:05 specified"
echo "\$ LD_PRELOAD=./libfaketime.so.1 FAKETIME=\"2003-01-01 10:00:05\" ./timetest"
LD_PRELOAD=./libfaketime.so.1 FAKETIME="2003-01-01 10:00:05" ./timetest
echo
echo "Running the test program with START date @2005-03-29 14:14:14 specified"
echo "\$ LD_PRELOAD=./libfaketime.so.1 FAKETIME=\"@2005-03-29 14:14:14\" ./timetest"
LD_PRELOAD=./libfaketime.so.1 FAKETIME="@2005-03-29 14:14:14" ./timetest
echo
echo "Running the test program with 10 days negative offset specified"
echo "LD_PRELOAD=./libfaketime.so.1 FAKETIME=\"-10d\" ./timetest"
LD_PRELOAD=./libfaketime.so.1 FAKETIME="-10d" ./timetest
echo
echo "Running the test program with 10 days negative offset specified, and FAKE_STAT disabled"
echo "\$ LD_PRELOAD=./libfaketime.so.1 FAKETIME=\"-10d\" NO_FAKE_STAT=1 ./timetest"
LD_PRELOAD=./libfaketime.so.1 FAKETIME="-10d" NO_FAKE_STAT=1 ./timetest
echo
echo "Running the 'date' command with 15 days negative offset specified"
echo "\$ LD_PRELOAD=./libfaketime.so.1 FAKETIME=\"-15d\" date"
LD_PRELOAD=./libfaketime.so.1 FAKETIME="-15d" date
echo
exit 0

31
test/Makefile Normal file
View File

@@ -0,0 +1,31 @@
CC = gcc
CFLAGS = -std=gnu99 -Wall -DFAKE_STAT
LDFLAGS = -lrt
SRC = timetest.c
OBJ = ${SRC:.c=.o}
all: timetest test
.c.o:
${CC} -c ${CFLAGS} $<
timetest: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
test: timetest functest
@echo
@./test.sh
# run functional tests
functest:
./testframe.sh functests
clean:
@rm -f ${OBJ} timetest
distclean: clean
@echo
.PHONY: all test clean distclean

31
test/Makefile.MacOS Normal file
View File

@@ -0,0 +1,31 @@
CC = gcc
CFLAGS = -std=gnu99 -Wall -DFAKE_STAT
LDFLAGS =
SRC = timetest.c
OBJ = ${SRC:.c=.o}
all: timetest test
.c.o:
${CC} -c ${CFLAGS} $<
timetest: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
test: timetest functest
@echo
@./test.sh
# run functional tests
functest:
./testframe.sh functests
clean:
@rm -f ${OBJ} timetest
distclean: clean
@echo
.PHONY: all test clean distclean

39
test/README-testframe.txt Normal file
View File

@@ -0,0 +1,39 @@
# here's how the testframe script works.
#
# Usage for testing:
# usage: testframe.sh DIR
# testframe.sh runs each testsuite script found within DIR.
# (in the context of libfaketime, the DIR is functest.)
# exits with status 0 if all tests succeed.
#
# Interface:
# by convention, each testsuite script (within DIR) must be
# a bash script named test_*.sh. the script must define a
# function named "run". run takes no arguments. run is
# expected to call the framework-provided function
# run_testcase once for each test function. run_testcase
# uses the global vars NFAIL and NSUCC to keep track of how
# many testcases failed/succeeded.
#
# the test function is expected to call something like
# asserteq or assertneq (again, framework-provided).
#
# fine print: for each testsuite, the framework creates a
# subshell and dots in the script. also dotted in are
# testframe.inc and DIR/common.inc (if it exists). the
# testsuite script can make use of any functions defined
# in these inc files. the environment variable
# TESTSUITE_NAME is set to the filename of the testsuite
# script, for possible use in warning or info messages.
#
# see functests/test_true.sh for a simple example of
# a test suite script.
#
# Simple steps to add a new testsuite:
# 1. decide its name - eg, XXX.
# 2. choose a DIR of similar testsuites to put it in, or create a new one.
# 3. create DIR/test_XXX.sh.
# 4. write a run function and testcase functions in DIR/test_XXX.sh.
# 5. within the run function, call run_testcase for each testcase function.
# 6. within each testcase funtion, call assertneq or asserteq, or do
# the equivalent.

52
test/functests/common.inc Normal file
View File

@@ -0,0 +1,52 @@
# libfaketime-specific common support routines for tests
# say which *_fakecmd wrapper to use
platform()
{
# may want to expand the pattern for linuxlike
typeset out=$(uname)
case "$out" in
*Darwin*) echo "mac" ;;
*Linux*) echo "linuxlike" ;;
*) echo 1>&2 unsupported platform, uname=\"$out\" ;;
esac
}
# run faked command on a mac
# UNTESTED
mac_fakecmd()
{
typeset timestring="$1"; shift
typeset fakelib=../src/libfaketime.dylib.1
export DYLD_INSERT_LIBRARIES=$fakelib
export DYLD_FORCE_FLAT_NAMESPACE=1
FAKETIME="$timestring" \
"$@"
}
# run faked command on linuxlike OS
linuxlike_fakecmd()
{
typeset timestring="$1"; shift
typeset fakelib=../src/libfaketime.so.1
export LD_PRELOAD=$fakelib
FAKETIME="$timestring" \
"$@"
}
# run a command with libfaketime using the given timestring
fakecmd()
{
${PLATFORM}_fakecmd "$@"
}
# generate a sequence of numbers from a to b
range()
{
typeset a=$1 b=$2
typeset i=$a
while ((i <= b)); do
echo $i
((i = i+1))
done
}

View File

@@ -0,0 +1,7 @@
# a testsuite that will force failure - for testing purposes
run()
{
run_testcase false
}

View File

@@ -0,0 +1,13 @@
# check that the date doesn't happen to be 0.
run()
{
run_testcase nulltest
}
nulltest()
{
typeset tdate=${I2DATES[0]}
assertneq 0 "$(date +%s)" "($tdate)"
}

View File

@@ -0,0 +1,8 @@
# test suite that always succeds - for testing framework
run()
{
run_testcase true
return 0
}

67
test/functests/test_walkone.sh Executable file
View File

@@ -0,0 +1,67 @@
# walking-1 test.
# sourced in from testframe.sh.
#
# this script defines a suite of functional tests
# that verifies the correct operation of libfaketime
# with the date command.
run()
{
init
for i in $(range 0 30); do
run_testcase test_with_i $i
done
}
# ----- support routines
init()
{
typeset testsuite="$1"
PLATFORM=$(platform)
if [ -z "$PLATFORM" ]; then
echo "$testsuite: unknown platform! quitting"
return 1
fi
echo "# PLATFORM=$PLATFORM"
return 0
}
# run date cmd under faketime, print time in secs
fakedate()
{
#
# let the time format be raw seconds since Epoch
# for both input to libfaketime, and output of the date cmd.
#
typeset fmt='%s'
export FAKETIME_FMT=$fmt
fakecmd "$1" date +$fmt
}
#
# compute x**n.
# use only the shell, in case we need to run on machines
# without bc, dc, perl, etc.
#
pow()
{
typeset x="$1" n="$2"
typeset r=1
typeset i=0
while ((i < n)); do
((r = r*x))
((i++))
done
echo $r
}
# run a fakedate test with a given time t
test_with_i()
{
typeset i="$1"
typeset t=$(pow 2 $i)
asserteq $(fakedate $t) $t "(secs since Epoch)"
}

40
test/test.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/sh
if [ -f /etc/faketimerc ] ; then
echo "Running the test program with your system-wide default in /etc/faketimerc"
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 ./timetest"
LD_PRELOAD=../src/libfaketime.so.1 ./timetest
echo
else
echo "Running the test program with no faked time specified"
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 ./timetest"
LD_PRELOAD=../src/libfaketime.so.1 ./timetest
echo
fi
echo "Running the test program with absolute date 2003-01-01 10:00:05 specified"
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"2003-01-01 10:00:05\" ./timetest"
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="2003-01-01 10:00:05" ./timetest
echo
echo "Running the test program with START date @2005-03-29 14:14:14 specified"
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"@2005-03-29 14:14:14\" ./timetest"
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="@2005-03-29 14:14:14" ./timetest
echo
echo "Running the test program with 10 days negative offset specified"
echo "LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"-10d\" ./timetest"
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="-10d" ./timetest
echo
echo "Running the test program with 10 days negative offset specified, and FAKE_STAT disabled"
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"-10d\" NO_FAKE_STAT=1 ./timetest"
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="-10d" NO_FAKE_STAT=1 ./timetest
echo
echo "Running the 'date' command with 15 days negative offset specified"
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"-15d\" date"
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="-15d" date
echo
exit 0

55
test/testframe.inc Normal file
View File

@@ -0,0 +1,55 @@
# framework common functions for use in test suites and test cases
#
# run a test and keep stats on success/failure.
# arguments: a command, possibly a shell function.
# return value: 0 on success, 1 on failure.
# side effects: increments global var NSUCC on success, NFAIL on failure.
#
run_testcase()
{
if "$@"; then
((NSUCC++))
return 0
else
((NFAIL++))
return 1
fi
}
#
# verbosely check that the test output matches the expected value.
# arguments: the test output, the expected value, and a description.
# return value: 0 on if test output equals expected value; 1 otherwise.
# side effects: prints a descriptive message.
#
asserteq()
{
typeset out="$1" expected="$2" desc="$3"
echo -n "out=$out $desc"
if [ "$out" = "$expected" ]; then
echo " - ok"
return 0
else
echo " expected=$expected - bad"
return 1
fi
}
#
# verbosely check that the test output doesn't match the reference value.
# return value: 1 on if test output equals expected value; 0 if not equal.
# side effects: prints descriptive message.
#
assertneq()
{
typeset out="$1" ref="$2" desc="$3"
echo -n "out=$out $desc"
if [ "$out" = "$ref" ]; then
echo " ref=$ref - bad"
return 1
else
echo " ref=$ref - ok"
return 0
fi
}

99
test/testframe.sh Executable file
View File

@@ -0,0 +1,99 @@
#! /bin/bash
# testframe.sh DIR
# bare-bones testing framework.
# run the test suites in the given DIR;
# exit with nonzero status if any of them failed.
# see README.testframe.txt for details.
#
# echo labelled error/warning message to stderr
report()
{
echo $PROG: $* 1>&2
}
# echo OK or BAD depending on argument (0 or not)
status_word()
{
if [ "$1" -eq 0 ]; then
echo OK
else
echo BAD
fi
}
# run the given testsuite, return nonzero if any testcase failed.
run_testsuite()
{
typeset testsuite="$1"
NFAIL=0
NSUCC=0
# add testsuite dir to PATH for convenience
typeset dir=$(dirname $testsuite)
PATH=$dir:$PATH
. testframe.inc
if [ -f $dir/common.inc ]; then
. $dir/common.inc
fi
. $testsuite
export TESTSUITE_NAME=$testsuite
echo ""
echo "# Begin $testsuite"
run
typeset runstat=$?
echo "# $testsuite summary: $NSUCC succeeded, $NFAIL failed"
if [ $runstat -ne 0 ]; then
((NFAIL++))
report "error: $testsuite run exit_status=$runstat!"
fi
echo "# End $testsuite -" $(status_word $NFAIL)
[ $NFAIL -eq 0 ]
}
#
# list all testsuite scripts in the given directories.
# a testsuite file must be a bash script whose name is of the form test_*.sh .
#
list_testsuites()
{
for dir in "$@"; do
ls $dir/test_*.sh 2>/dev/null
done
}
main()
{
TS_NFAIL=0
TS_NSUCC=0
echo "# Begin Test Suites in $*"
typeset testsuites=$(list_testsuites "$@")
if [ -z "$testsuites" ]; then
report "error: no testsuites found"
exit 1
fi
for testsuite in $testsuites; do
if run_testsuite $testsuite; then
((TS_NSUCC++))
else
((TS_NFAIL++))
fi
done
echo ""
echo "# Test Suites summary: $TS_NSUCC succeeded, $TS_NFAIL failed"
echo "# End Test Suites -" $(status_word $TS_NFAIL)
[ $TS_NFAIL -eq 0 ]
}
# ----- start of mainline code
PROG=${0##*/}
main "${@:-.}"

View File

@@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/timeb.h>
#ifdef FAKE_STAT
@@ -35,14 +36,16 @@ int main (int argc, char **argv) {
time_t now;
struct timeb tb;
struct timeval tv;
#ifndef __APPLE__
struct timespec ts;
#endif
#ifdef FAKE_STAT
struct stat buf;
#endif
time(&now);
printf("time() : Current date and time: %s", ctime(&now));
printf("time(NULL) : Seconds since Epoch : %u\n", time(NULL));
printf("time(NULL) : Seconds since Epoch : %u\n", (unsigned int)time(NULL));
ftime(&tb);
printf("ftime() : Current date and time: %s", ctime(&tb.time));
@@ -54,8 +57,10 @@ int main (int argc, char **argv) {
gettimeofday(&tv, NULL);
printf("gettimeofday() : Current date and time: %s", ctime(&tv.tv_sec));
#ifndef __APPLE__
clock_gettime(CLOCK_REALTIME, &ts);
printf("clock_gettime(): Current date and time: %s", ctime(&ts.tv_sec));
#endif
#ifdef FAKE_STAT
lstat(argv[0], &buf);