1/* 2 * systime -- routines to fiddle a UNIX clock. 3 * 4 * ATTENTION: Get approval from Dave Mills on all changes to this file! 5 * 6 */ 7#include "ntp_machine.h" 8#include "ntp_fp.h" 9#include "ntp_syslog.h" 10#include "ntp_unixtime.h" 11#include "ntp_stdlib.h" 12#include "ntp_random.h" 13#include "ntpd.h" /* for sys_precision */ 14 15#include <os/trace.h> 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 */ 53double sys_tick = 0; /* precision (time to read the clock) */ 54double sys_residual = 0; /* adjustment residue (s) */ 55 56#ifndef SIM 57 58/* 59 * get_systime - return system time in NTP timestamp format. 60 */ 61void 62get_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 128int /* 0 okay, 1 error */ 129adj_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 os_trace("Adjust: %f", now); 140 /* 141 * Most Unix adjtime() implementations adjust the system clock 142 * in microsecond quanta, but some adjust in 10-ms quanta. We 143 * carefully round the adjustment to the nearest quantum, then 144 * adjust in quanta and keep the residue for later. 145 */ 146 dtemp = now + sys_residual; 147 if (dtemp < 0) { 148 isneg = 1; 149 dtemp = -dtemp; 150 } 151 adjtv.tv_sec = (long)dtemp; 152 dtemp -= adjtv.tv_sec; 153 ticks = (long)(dtemp / sys_tick + .5); 154 adjtv.tv_usec = (long)(ticks * sys_tick * 1e6); 155 dtemp -= adjtv.tv_usec / 1e6; 156 sys_residual = dtemp; 157 158 /* 159 * Convert to signed seconds and microseconds for the Unix 160 * adjtime() system call. Note we purposely lose the adjtime() 161 * leftover. 162 */ 163 if (isneg) { 164 adjtv.tv_sec = -adjtv.tv_sec; 165 adjtv.tv_usec = -adjtv.tv_usec; 166 sys_residual = -sys_residual; 167 } 168 if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) { 169 if (adjtime(&adjtv, &oadjtv) < 0) { 170 msyslog(LOG_ERR, "adj_systime: %m"); 171 return (0); 172 } 173 } 174 return (1); 175} 176#endif 177 178 179/* 180 * step_systime - step the system clock. 181 */ 182int 183step_systime( 184 double now 185 ) 186{ 187 struct timeval timetv, adjtv, oldtimetv; 188 int isneg = 0; 189 double dtemp; 190#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 191 struct timespec ts; 192#endif 193 194 os_trace("step: %f", now); 195 dtemp = sys_residual + now; 196 if (dtemp < 0) { 197 isneg = 1; 198 dtemp = - dtemp; 199 adjtv.tv_sec = (int32)dtemp; 200 adjtv.tv_usec = (u_int32)((dtemp - 201 (double)adjtv.tv_sec) * 1e6 + .5); 202 } else { 203 adjtv.tv_sec = (int32)dtemp; 204 adjtv.tv_usec = (u_int32)((dtemp - 205 (double)adjtv.tv_sec) * 1e6 + .5); 206 } 207#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 208# ifdef HAVE_CLOCK_GETTIME 209 (void) clock_gettime(CLOCK_REALTIME, &ts); 210# else 211 (void) getclock(TIMEOFDAY, &ts); 212# endif 213 timetv.tv_sec = ts.tv_sec; 214 timetv.tv_usec = ts.tv_nsec / 1000; 215#else /* not HAVE_GETCLOCK */ 216 (void) GETTIMEOFDAY(&timetv, (struct timezone *)0); 217#endif /* not HAVE_GETCLOCK */ 218 219 oldtimetv = timetv; 220 221#ifdef DEBUG 222 if (debug) 223 printf("step_systime: step %.6f residual %.6f\n", now, sys_residual); 224#endif 225 if (isneg) { 226 timetv.tv_sec -= adjtv.tv_sec; 227 timetv.tv_usec -= adjtv.tv_usec; 228 if (timetv.tv_usec < 0) { 229 timetv.tv_sec--; 230 timetv.tv_usec += 1000000; 231 } 232 } else { 233 timetv.tv_sec += adjtv.tv_sec; 234 timetv.tv_usec += adjtv.tv_usec; 235 if (timetv.tv_usec >= 1000000) { 236 timetv.tv_sec++; 237 timetv.tv_usec -= 1000000; 238 } 239 } 240 if (ntp_set_tod(&timetv, NULL) != 0) { 241 msyslog(LOG_ERR, "step-systime: %m"); 242 return (0); 243 } 244 sys_residual = 0; 245 246#ifdef NEED_HPUX_ADJTIME 247 /* 248 * CHECKME: is this correct when called by ntpdate????? 249 */ 250 _clear_adjtime(); 251#endif 252 253 /* 254 * FreeBSD, for example, has: 255 * struct utmp { 256 * char ut_line[UT_LINESIZE]; 257 * char ut_name[UT_NAMESIZE]; 258 * char ut_host[UT_HOSTSIZE]; 259 * long ut_time; 260 * }; 261 * and appends line="|", name="date", host="", time for the OLD 262 * and appends line="{", name="date", host="", time for the NEW 263 * to _PATH_WTMP . 264 * 265 * Some OSes have utmp, some have utmpx. 266 */ 267 268 /* 269 * Write old and new time entries in utmp and wtmp if step 270 * adjustment is greater than one second. 271 * 272 * This might become even Uglier... 273 */ 274 if (oldtimetv.tv_sec != timetv.tv_sec) 275 { 276#ifdef HAVE_UTMP_H 277 struct utmp ut; 278#endif 279#ifdef HAVE_UTMPX_H 280 struct utmpx utx; 281#endif 282 283#ifdef HAVE_UTMP_H 284 memset((char *)&ut, 0, sizeof(ut)); 285#endif 286#ifdef HAVE_UTMPX_H 287 memset((char *)&utx, 0, sizeof(utx)); 288#endif 289 290 /* UTMP */ 291 292#ifdef UPDATE_UTMP 293# ifdef HAVE_PUTUTLINE 294 ut.ut_type = OLD_TIME; 295 (void)strcpy(ut.ut_line, OTIME_MSG); 296 ut.ut_time = oldtimetv.tv_sec; 297 pututline(&ut); 298 setutent(); 299 ut.ut_type = NEW_TIME; 300 (void)strcpy(ut.ut_line, NTIME_MSG); 301 ut.ut_time = timetv.tv_sec; 302 pututline(&ut); 303 endutent(); 304# else /* not HAVE_PUTUTLINE */ 305# endif /* not HAVE_PUTUTLINE */ 306#endif /* UPDATE_UTMP */ 307 308 /* UTMPX */ 309 310#ifdef UPDATE_UTMPX 311# ifdef HAVE_PUTUTXLINE 312 utx.ut_type = OLD_TIME; 313 (void)strcpy(utx.ut_line, OTIME_MSG); 314 utx.ut_tv = oldtimetv; 315 pututxline(&utx); 316 setutxent(); 317 utx.ut_type = NEW_TIME; 318 (void)strcpy(utx.ut_line, NTIME_MSG); 319 utx.ut_tv = timetv; 320 pututxline(&utx); 321 endutxent(); 322# else /* not HAVE_PUTUTXLINE */ 323# endif /* not HAVE_PUTUTXLINE */ 324#endif /* UPDATE_UTMPX */ 325 326 /* WTMP */ 327 328#ifdef UPDATE_WTMP 329# ifdef HAVE_PUTUTLINE 330 utmpname(WTMP_FILE); 331 ut.ut_type = OLD_TIME; 332 (void)strcpy(ut.ut_line, OTIME_MSG); 333 ut.ut_time = oldtimetv.tv_sec; 334 pututline(&ut); 335 ut.ut_type = NEW_TIME; 336 (void)strcpy(ut.ut_line, NTIME_MSG); 337 ut.ut_time = timetv.tv_sec; 338 pututline(&ut); 339 endutent(); 340# else /* not HAVE_PUTUTLINE */ 341# endif /* not HAVE_PUTUTLINE */ 342#endif /* UPDATE_WTMP */ 343 344 /* WTMPX */ 345 346#ifdef UPDATE_WTMPX 347# ifdef HAVE_PUTUTXLINE 348 utx.ut_type = OLD_TIME; 349 utx.ut_tv = oldtimetv; 350 (void)strcpy(utx.ut_line, OTIME_MSG); 351# ifdef HAVE_UPDWTMPX 352 updwtmpx(WTMPX_FILE, &utx); 353# else /* not HAVE_UPDWTMPX */ 354# endif /* not HAVE_UPDWTMPX */ 355# else /* not HAVE_PUTUTXLINE */ 356# endif /* not HAVE_PUTUTXLINE */ 357# ifdef HAVE_PUTUTXLINE 358 utx.ut_type = NEW_TIME; 359 utx.ut_tv = timetv; 360 (void)strcpy(utx.ut_line, NTIME_MSG); 361# ifdef HAVE_UPDWTMPX 362 updwtmpx(WTMPX_FILE, &utx); 363# else /* not HAVE_UPDWTMPX */ 364# endif /* not HAVE_UPDWTMPX */ 365# else /* not HAVE_PUTUTXLINE */ 366# endif /* not HAVE_PUTUTXLINE */ 367#endif /* UPDATE_WTMPX */ 368 369 } 370 return (1); 371} 372 373#else /* SIM */ 374/* 375 * Clock routines for the simulator - Harish Nair, with help 376 */ 377 378 379/* SK: 380 * The code that used to be here has been moved to ntpsim.c, 381 * where, IMHO, it rightfully belonged. 382 */ 383 384#endif 385