1 /* $NetBSD: systime.c,v 1.1.1.1 2009/12/13 16:55:01 kardel Exp $ */ 2 3 /* 4 * systime -- routines to fiddle a UNIX clock. 5 * 6 * ATTENTION: Get approval from Dave Mills on all changes to this file! 7 * 8 */ 9 #include "ntp_machine.h" 10 #include "ntp_fp.h" 11 #include "ntp_syslog.h" 12 #include "ntp_unixtime.h" 13 #include "ntp_stdlib.h" 14 #include "ntp_random.h" 15 #include "ntpd.h" /* for sys_precision */ 16 17 #ifdef HAVE_SYS_PARAM_H 18 # include <sys/param.h> 19 #endif 20 #ifdef HAVE_UTMP_H 21 # include <utmp.h> 22 #endif /* HAVE_UTMP_H */ 23 #ifdef HAVE_UTMPX_H 24 # include <utmpx.h> 25 #endif /* HAVE_UTMPX_H */ 26 27 28 #define FUZZ 500e-6 /* fuzz pivot */ 29 30 /* 31 * These routines (get_systime, step_systime, adj_systime) implement an 32 * interface between the system independent NTP clock and the Unix 33 * system clock in various architectures and operating systems. Time is 34 * a precious quantity in these routines and every effort is made to 35 * minimize errors by unbiased rounding and amortizing adjustment 36 * residues. 37 * 38 * In order to improve the apparent resolution, provide unbiased 39 * rounding and insure that the readings cannot be predicted, the low- 40 * order unused portion of the time below the resolution limit is filled 41 * with an unbiased random fuzz. 42 * 43 * The sys_tick variable secifies the system clock tick interval in 44 * seconds. For systems that can interpolate between timer interrupts, 45 * the resolution is presumed much less than the time to read the system 46 * clock, which is the value of sys_tick after the precision has been 47 * determined. For those systems that cannot interpolate between timer 48 * interrupts, sys_tick will be much larger in the order of 10 ms, so the 49 * fuzz should be that value. For Sunses the tick is not interpolated, but 50 * the system clock is derived from a 2-MHz oscillator, so the resolution 51 * is 500 ns and sys_tick is 500 ns. 52 */ 53 double sys_tick = 0; /* precision (time to read the clock) */ 54 double sys_residual = 0; /* adjustment residue (s) */ 55 56 #ifndef SIM 57 58 /* 59 * get_systime - return system time in NTP timestamp format. 60 */ 61 void 62 get_systime( 63 l_fp *now /* system time */ 64 ) 65 { 66 double dtemp; 67 68 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 69 struct timespec ts; /* seconds and nanoseconds */ 70 71 /* 72 * Convert Unix timespec from seconds and nanoseconds to NTP 73 * seconds and fraction. 74 */ 75 # ifdef HAVE_CLOCK_GETTIME 76 clock_gettime(CLOCK_REALTIME, &ts); 77 # else 78 getclock(TIMEOFDAY, &ts); 79 # endif 80 now->l_i = (int32)ts.tv_sec + JAN_1970; 81 dtemp = 0; 82 if (sys_tick > FUZZ) 83 dtemp = ntp_random() * 2. / FRAC * sys_tick * 1e9; 84 else if (sys_tick > 0) 85 dtemp = ntp_random() * 2. / FRAC; 86 dtemp = (ts.tv_nsec + dtemp) * 1e-9 + sys_residual; 87 if (dtemp >= 1.) { 88 dtemp -= 1.; 89 now->l_i++; 90 } else if (dtemp < 0) { 91 dtemp += 1.; 92 now->l_i--; 93 } 94 now->l_uf = (u_int32)(dtemp * FRAC); 95 96 #else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 97 struct timeval tv; /* seconds and microseconds */ 98 99 /* 100 * Convert Unix timeval from seconds and microseconds to NTP 101 * seconds and fraction. 102 */ 103 GETTIMEOFDAY(&tv, NULL); 104 now->l_i = tv.tv_sec + JAN_1970; 105 dtemp = 0; 106 if (sys_tick > FUZZ) 107 dtemp = ntp_random() * 2. / FRAC * sys_tick * 1e6; 108 else if (sys_tick > 0) 109 dtemp = ntp_random() * 2. / FRAC; 110 dtemp = (tv.tv_usec + dtemp) * 1e-6 + sys_residual; 111 if (dtemp >= 1.) { 112 dtemp -= 1.; 113 now->l_i++; 114 } else if (dtemp < 0) { 115 dtemp += 1.; 116 now->l_i--; 117 } 118 now->l_uf = (u_int32)(dtemp * FRAC); 119 120 #endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 121 } 122 123 124 /* 125 * adj_systime - adjust system time by the argument. 126 */ 127 #if !defined SYS_WINNT 128 int /* 0 okay, 1 error */ 129 adj_systime( 130 double now /* adjustment (s) */ 131 ) 132 { 133 struct timeval adjtv; /* new adjustment */ 134 struct timeval oadjtv; /* residual adjustment */ 135 double dtemp; 136 long ticks; 137 int isneg = 0; 138 139 /* 140 * Most Unix adjtime() implementations adjust the system clock 141 * in microsecond quanta, but some adjust in 10-ms quanta. We 142 * carefully round the adjustment to the nearest quantum, then 143 * adjust in quanta and keep the residue for later. 144 */ 145 dtemp = now + sys_residual; 146 if (dtemp < 0) { 147 isneg = 1; 148 dtemp = -dtemp; 149 } 150 adjtv.tv_sec = (long)dtemp; 151 dtemp -= adjtv.tv_sec; 152 ticks = (long)(dtemp / sys_tick + .5); 153 adjtv.tv_usec = (long)(ticks * sys_tick * 1e6); 154 dtemp -= adjtv.tv_usec / 1e6; 155 sys_residual = dtemp; 156 157 /* 158 * Convert to signed seconds and microseconds for the Unix 159 * adjtime() system call. Note we purposely lose the adjtime() 160 * leftover. 161 */ 162 if (isneg) { 163 adjtv.tv_sec = -adjtv.tv_sec; 164 adjtv.tv_usec = -adjtv.tv_usec; 165 sys_residual = -sys_residual; 166 } 167 if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) { 168 if (adjtime(&adjtv, &oadjtv) < 0) { 169 msyslog(LOG_ERR, "adj_systime: %m"); 170 return (0); 171 } 172 } 173 return (1); 174 } 175 #endif 176 177 178 /* 179 * step_systime - step the system clock. 180 */ 181 int 182 step_systime( 183 double now 184 ) 185 { 186 struct timeval timetv, adjtv, oldtimetv; 187 int isneg = 0; 188 double dtemp; 189 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 190 struct timespec ts; 191 #endif 192 193 dtemp = sys_residual + now; 194 if (dtemp < 0) { 195 isneg = 1; 196 dtemp = - dtemp; 197 adjtv.tv_sec = (int32)dtemp; 198 adjtv.tv_usec = (u_int32)((dtemp - 199 (double)adjtv.tv_sec) * 1e6 + .5); 200 } else { 201 adjtv.tv_sec = (int32)dtemp; 202 adjtv.tv_usec = (u_int32)((dtemp - 203 (double)adjtv.tv_sec) * 1e6 + .5); 204 } 205 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 206 # ifdef HAVE_CLOCK_GETTIME 207 (void) clock_gettime(CLOCK_REALTIME, &ts); 208 # else 209 (void) getclock(TIMEOFDAY, &ts); 210 # endif 211 timetv.tv_sec = ts.tv_sec; 212 timetv.tv_usec = ts.tv_nsec / 1000; 213 #else /* not HAVE_GETCLOCK */ 214 (void) GETTIMEOFDAY(&timetv, (struct timezone *)0); 215 #endif /* not HAVE_GETCLOCK */ 216 217 oldtimetv = timetv; 218 219 #ifdef DEBUG 220 if (debug) 221 printf("step_systime: step %.6f residual %.6f\n", now, sys_residual); 222 #endif 223 if (isneg) { 224 timetv.tv_sec -= adjtv.tv_sec; 225 timetv.tv_usec -= adjtv.tv_usec; 226 if (timetv.tv_usec < 0) { 227 timetv.tv_sec--; 228 timetv.tv_usec += 1000000; 229 } 230 } else { 231 timetv.tv_sec += adjtv.tv_sec; 232 timetv.tv_usec += adjtv.tv_usec; 233 if (timetv.tv_usec >= 1000000) { 234 timetv.tv_sec++; 235 timetv.tv_usec -= 1000000; 236 } 237 } 238 if (ntp_set_tod(&timetv, NULL) != 0) { 239 msyslog(LOG_ERR, "step-systime: %m"); 240 return (0); 241 } 242 sys_residual = 0; 243 244 #ifdef NEED_HPUX_ADJTIME 245 /* 246 * CHECKME: is this correct when called by ntpdate????? 247 */ 248 _clear_adjtime(); 249 #endif 250 251 /* 252 * FreeBSD, for example, has: 253 * struct utmp { 254 * char ut_line[UT_LINESIZE]; 255 * char ut_name[UT_NAMESIZE]; 256 * char ut_host[UT_HOSTSIZE]; 257 * long ut_time; 258 * }; 259 * and appends line="|", name="date", host="", time for the OLD 260 * and appends line="{", name="date", host="", time for the NEW 261 * to _PATH_WTMP . 262 * 263 * Some OSes have utmp, some have utmpx. 264 */ 265 266 /* 267 * Write old and new time entries in utmp and wtmp if step 268 * adjustment is greater than one second. 269 * 270 * This might become even Uglier... 271 */ 272 if (oldtimetv.tv_sec != timetv.tv_sec) 273 { 274 #ifdef HAVE_UTMP_H 275 struct utmp ut; 276 #endif 277 #ifdef HAVE_UTMPX_H 278 struct utmpx utx; 279 #endif 280 281 #ifdef HAVE_UTMP_H 282 memset((char *)&ut, 0, sizeof(ut)); 283 #endif 284 #ifdef HAVE_UTMPX_H 285 memset((char *)&utx, 0, sizeof(utx)); 286 #endif 287 288 /* UTMP */ 289 290 #ifdef UPDATE_UTMP 291 # ifdef HAVE_PUTUTLINE 292 ut.ut_type = OLD_TIME; 293 (void)strcpy(ut.ut_line, OTIME_MSG); 294 ut.ut_time = oldtimetv.tv_sec; 295 pututline(&ut); 296 setutent(); 297 ut.ut_type = NEW_TIME; 298 (void)strcpy(ut.ut_line, NTIME_MSG); 299 ut.ut_time = timetv.tv_sec; 300 pututline(&ut); 301 endutent(); 302 # else /* not HAVE_PUTUTLINE */ 303 # endif /* not HAVE_PUTUTLINE */ 304 #endif /* UPDATE_UTMP */ 305 306 /* UTMPX */ 307 308 #ifdef UPDATE_UTMPX 309 # ifdef HAVE_PUTUTXLINE 310 utx.ut_type = OLD_TIME; 311 (void)strcpy(utx.ut_line, OTIME_MSG); 312 utx.ut_tv = oldtimetv; 313 pututxline(&utx); 314 setutxent(); 315 utx.ut_type = NEW_TIME; 316 (void)strcpy(utx.ut_line, NTIME_MSG); 317 utx.ut_tv = timetv; 318 pututxline(&utx); 319 endutxent(); 320 # else /* not HAVE_PUTUTXLINE */ 321 # endif /* not HAVE_PUTUTXLINE */ 322 #endif /* UPDATE_UTMPX */ 323 324 /* WTMP */ 325 326 #ifdef UPDATE_WTMP 327 # ifdef HAVE_PUTUTLINE 328 utmpname(WTMP_FILE); 329 ut.ut_type = OLD_TIME; 330 (void)strcpy(ut.ut_line, OTIME_MSG); 331 ut.ut_time = oldtimetv.tv_sec; 332 pututline(&ut); 333 ut.ut_type = NEW_TIME; 334 (void)strcpy(ut.ut_line, NTIME_MSG); 335 ut.ut_time = timetv.tv_sec; 336 pututline(&ut); 337 endutent(); 338 # else /* not HAVE_PUTUTLINE */ 339 # endif /* not HAVE_PUTUTLINE */ 340 #endif /* UPDATE_WTMP */ 341 342 /* WTMPX */ 343 344 #ifdef UPDATE_WTMPX 345 # ifdef HAVE_PUTUTXLINE 346 utx.ut_type = OLD_TIME; 347 utx.ut_tv = oldtimetv; 348 (void)strcpy(utx.ut_line, OTIME_MSG); 349 # ifdef HAVE_UPDWTMPX 350 updwtmpx(WTMPX_FILE, &utx); 351 # else /* not HAVE_UPDWTMPX */ 352 # endif /* not HAVE_UPDWTMPX */ 353 # else /* not HAVE_PUTUTXLINE */ 354 # endif /* not HAVE_PUTUTXLINE */ 355 # ifdef HAVE_PUTUTXLINE 356 utx.ut_type = NEW_TIME; 357 utx.ut_tv = timetv; 358 (void)strcpy(utx.ut_line, NTIME_MSG); 359 # ifdef HAVE_UPDWTMPX 360 updwtmpx(WTMPX_FILE, &utx); 361 # else /* not HAVE_UPDWTMPX */ 362 # endif /* not HAVE_UPDWTMPX */ 363 # else /* not HAVE_PUTUTXLINE */ 364 # endif /* not HAVE_PUTUTXLINE */ 365 #endif /* UPDATE_WTMPX */ 366 367 } 368 return (1); 369 } 370 371 #else /* SIM */ 372 /* 373 * Clock routines for the simulator - Harish Nair, with help 374 */ 375 376 377 /* SK: 378 * The code that used to be here has been moved to ntpsim.c, 379 * where, IMHO, it rightfully belonged. 380 */ 381 382 #endif 383