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