1/*++ 2/* NAME 3/* sane_time 3 4/* SUMMARY 5/* time(2) with backward time jump protection. 6/* SYNOPSIS 7/* #include <sane_time.h> 8/* 9/* time_t sane_time(void) 10/* 11/* DESCRIPTION 12/* This module provides time(2) like call for applications 13/* which need monotonically increasing time function rather 14/* than the real exact time. It eliminates the need for various 15/* workarounds all over the application which would handle 16/* potential problems if time suddenly jumps backward. 17/* Instead we choose to deal with this problem inside this 18/* module and let the application focus on its own tasks. 19/* 20/* sane_time() returns the current timestamp as obtained from 21/* time(2) call, at least most of the time. In case this routine 22/* detects that time has jumped backward, it keeps returning 23/* whatever timestamp it returned before, until this timestamp 24/* and the time(2) timestamp become synchronized again. 25/* Additionally, the returned timestamp is slowly increased to 26/* prevent the faked clock from freezing for too long. 27/* SEE ALSO 28/* time(2) get current time 29/* DIAGNOSTICS 30/* Warning message is logged if backward time jump is detected. 31/* LICENSE 32/* .ad 33/* .fi 34/* The Secure Mailer license must be distributed with this software. 35/* AUTHOR(S) 36/* Patrik Rak 37/* Modra 6 38/* 155 00, Prague, Czech Republic 39/*--*/ 40 41/* System library. */ 42 43#include <sys_defs.h> 44 45/* Utility library. */ 46 47#include <msg.h> 48 49/* Application-specific. */ 50 51#include "sane_time.h" 52 53/* 54 * How many times shall we slow down the real clock when recovering from 55 * time jump. 56 */ 57#define SLEW_FACTOR 2 58 59/* sane_time - get current time, protected against time warping */ 60 61time_t sane_time(void) 62{ 63 time_t now; 64 static time_t last_time, 65 last_real; 66 int delta; 67 static int fraction; 68 static int warned; 69 70 now = time((time_t *) 0); 71 72 if ((delta = now - last_time) < 0 && last_time != 0) { 73 if ((delta = now - last_real) < 0) { 74 msg_warn("%sbackward time jump detected -- slewing clock", 75 warned++ ? "another " : ""); 76 } else { 77 delta += fraction; 78 last_time += delta / SLEW_FACTOR; 79 fraction = delta % SLEW_FACTOR; 80 } 81 } else { 82 if (warned) { 83 warned = 0; 84 msg_warn("backward time jump recovered -- back to normality"); 85 fraction = 0; 86 } 87 last_time = now; 88 } 89 last_real = now; 90 91 return (last_time); 92} 93 94#ifdef TEST 95 96 /* 97 * Proof-of-concept test program. Repeatedly print current system time and 98 * time returned by sane_time(). Meanwhile, try stepping your system clock 99 * back and forth to see what happens. 100 */ 101 102#include <stdlib.h> 103#include <msg_vstream.h> 104#include <iostuff.h> /* doze() */ 105 106int main(int argc, char **argv) 107{ 108 int delay = 1000000; 109 time_t now; 110 111 msg_vstream_init(argv[0], VSTREAM_ERR); 112 113 if (argc == 2 && (delay = atol(argv[1]) * 1000) > 0) 114 /* void */ ; 115 else if (argc != 1) 116 msg_fatal("usage: %s [delay in ms (default 1 second)]", argv[0]); 117 118 for (;;) { 119 now = time((time_t *) 0); 120 vstream_printf("real: %s", ctime(&now)); 121 now = sane_time(); 122 vstream_printf("fake: %s\n", ctime(&now)); 123 vstream_fflush(VSTREAM_OUT); 124 doze(delay); 125 } 126} 127 128#endif 129