Skip to content

Commit 75d91ea

Browse files
authored
Merge pull request #533 from GeneralDisarray/implement-faketime-follow-absolute
Implement FAKETIME_FOLLOW_ABSOLUTE feature
2 parents 3062fb2 + 6c7aa39 commit 75d91ea

3 files changed

Lines changed: 111 additions & 2 deletions

File tree

README

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,15 @@ LD_PRELOAD=/path/to/libfaketime.so.1 \
420420
# (in a different terminal window or whatever)
421421
touch -t 2002290123.45 /tmp/my-demo-file.tmp
422422

423+
Setting the environment variable FAKETIME_FOLLOW_ABSOLUTE=1 enables a submode
424+
of FAKETIME_FOLLOW_FILE behavior where fake time ONLY advances when the follow
425+
file's timestamp advances. In this mode an application that is not subject to
426+
libfaketime LD_PRELOAD intercept can absolutely control time for applications
427+
that are hooked by libfaketime. For example, a host application can control the
428+
timestamp of a follow file mapped into a container to implement (relatively)
429+
clean pause/resume behavior for fake time applications running within the
430+
container.
431+
423432

424433
Changing the 'x' modifier during run-time
425434
-----------------------------------------

src/libfaketime.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2701,12 +2701,33 @@ static void parse_ft_string(const char *user_faked_time)
27012701
else
27022702
{
27032703
user_faked_time_timespec.tv_sec = master_file_stats.st_mtime;
2704-
user_faked_time_timespec.tv_nsec = 0;
2704+
if (NULL == getenv("FAKETIME_FOLLOW_ABSOLUTE"))
2705+
{
2706+
/* Normal FAKETIME_FOLLOW_FILE behavior; fake time coasts between mtime updates */
2707+
user_faked_time_timespec.tv_nsec = 0;
2708+
}
2709+
else
2710+
{
2711+
/* Set fake time to nanosecond-precision mtime */
2712+
user_faked_time_timespec.tv_nsec = master_file_stats.st_mtim.tv_nsec;
2713+
2714+
/* Freeze fake time (mtime is absolute truth in this mode) */
2715+
if (ft_mode != FT_NOOP)
2716+
{
2717+
ft_mode = FT_FREEZE;
2718+
}
2719+
2720+
/* Bypass parse_modifiers since we have absolute time */
2721+
user_faked_time_set = true;
2722+
}
27052723
}
27062724
}
27072725
if (NULL == getenv("FAKETIME_DONT_RESET"))
27082726
reset_time();
2709-
goto parse_modifiers;
2727+
if (!user_faked_time_set)
2728+
{
2729+
goto parse_modifiers;
2730+
}
27102731
break;
27112732

27122733
case 'i':
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Tests for FAKETIME_FOLLOW_ABSOLUTE feature.
2+
#
3+
# When FAKETIME_FOLLOW_ABSOLUTE=1 is set alongside FAKETIME="%" and
4+
# FAKETIME_FOLLOW_FILE, time freezes at the follow file's mtime
5+
# and only advances when the file's mtime changes.
6+
7+
FOLLOW_FILE=".follow_absolute_test_file"
8+
9+
init()
10+
{
11+
typeset testsuite="$1"
12+
PLATFORM=$(platform)
13+
if [ -z "$PLATFORM" ]; then
14+
echo "$testsuite: unknown platform! quitting"
15+
return 1
16+
fi
17+
echo "# PLATFORM=$PLATFORM"
18+
return 0
19+
}
20+
21+
run()
22+
{
23+
init
24+
25+
run_testcase follow_absolute_basic
26+
run_testcase follow_absolute_freeze
27+
run_testcase follow_absolute_tracks_mtime
28+
29+
rm -f "$FOLLOW_FILE"
30+
}
31+
32+
# Helper to run a command with follow-absolute configuration
33+
follow_absolute_cmd()
34+
{
35+
FAKETIME_FOLLOW_FILE="$FOLLOW_FILE" \
36+
FAKETIME_FOLLOW_ABSOLUTE=1 \
37+
fakecmd "%" "$@"
38+
}
39+
40+
# Test that time matches the follow file's mtime
41+
follow_absolute_basic()
42+
{
43+
touch -d "2020-03-15 10:30:00 UTC" "$FOLLOW_FILE"
44+
typeset actual
45+
actual=$(follow_absolute_cmd date -u +"%Y-%m-%d %H:%M:%S")
46+
asserteq "$actual" "2020-03-15 10:30:00" \
47+
"time should match follow file mtime"
48+
}
49+
50+
# Test that time stays frozen (does not advance with real time)
51+
follow_absolute_freeze()
52+
{
53+
touch -d "2020-03-15 10:30:00 UTC" "$FOLLOW_FILE"
54+
typeset timestamps
55+
timestamps=$(follow_absolute_cmd \
56+
perl -e 'print time(), "\n"; sleep(2); print time(), "\n"')
57+
typeset first second
58+
first=$(echo "$timestamps" | head -1)
59+
second=$(echo "$timestamps" | tail -1)
60+
asserteq "$first" "$second" \
61+
"time should stay frozen within a single process"
62+
}
63+
64+
# Test that time tracks file mtime changes at millisecond precision
65+
follow_absolute_tracks_mtime()
66+
{
67+
touch -d "2020-03-15 10:30:00.000 UTC" "$FOLLOW_FILE"
68+
typeset first
69+
first=$(follow_absolute_cmd \
70+
perl -MTime::HiRes=time -e 'printf "%.3f\n", time()')
71+
72+
touch -d "2020-03-15 10:30:00.005 UTC" "$FOLLOW_FILE"
73+
typeset second
74+
second=$(follow_absolute_cmd \
75+
perl -MTime::HiRes=time -e 'printf "%.3f\n", time()')
76+
77+
assertneq "$first" "$second" \
78+
"time should advance with file mtime (ms precision)"
79+
}

0 commit comments

Comments
 (0)