1 /* 2 * systime -- routines to fiddle a UNIX clock. 3 */ 4 5 #ifdef HAVE_CONFIG_H 6 # include <config.h> 7 #endif 8 9 #include <stdio.h> 10 #include <sys/types.h> 11 #include <sys/time.h> 12 #ifdef HAVE_SYS_PARAM_H 13 # include <sys/param.h> 14 #endif 15 #ifdef HAVE_UTMP_H 16 # include <utmp.h> 17 #endif /* HAVE_UTMP_H */ 18 #ifdef HAVE_UTMPX_H 19 # include <utmpx.h> 20 #endif /* HAVE_UTMPX_H */ 21 22 #include "ntp_machine.h" 23 #include "ntp_fp.h" 24 #include "ntp_syslog.h" 25 #include "ntp_unixtime.h" 26 #include "ntp_stdlib.h" 27 28 #if defined SYS_WINNT 29 #include "ntp_timer.h" 30 extern DWORD units_per_tick; 31 static long last_Adj = 0; 32 #endif 33 34 int systime_10ms_ticks = 0; /* adj sysclock in 10ms increments */ 35 36 #define MAXFREQ 500e-6 37 38 /* 39 * These routines (init_systime, get_systime, step_systime, adj_systime) 40 * implement an interface between the (more or less) system independent 41 * bits of NTP and the peculiarities of dealing with the Unix system 42 * clock. 43 */ 44 double sys_residual = 0; /* residual from previous adjustment */ 45 double sys_maxfreq = MAXFREQ; /* max frequency correction */ 46 47 48 /* 49 * get_systime - return the system time in timestamp format biased by 50 * the current time offset. 51 */ 52 void 53 get_systime( 54 l_fp *now 55 ) 56 { 57 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 58 struct timespec ts; 59 #else 60 struct timeval tv; 61 #endif 62 double dtemp; 63 64 /* 65 * We use nanosecond time if we can get it. Watch out for 66 * rounding wiggles, which may overflow the fraction. 67 */ 68 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 69 # ifdef HAVE_CLOCK_GETTIME 70 (void) clock_gettime(CLOCK_REALTIME, &ts); 71 # else 72 (void) getclock(TIMEOFDAY, &ts); 73 # endif 74 now->l_i = ts.tv_sec + JAN_1970; 75 dtemp = ts.tv_nsec * FRAC / 1e9; 76 if (dtemp >= FRAC) 77 now->l_i++; 78 now->l_uf = (u_int32)dtemp; 79 #else /* HAVE_CLOCK_GETTIME */ 80 (void) GETTIMEOFDAY(&tv, (struct timezone *)0); 81 now->l_i = tv.tv_sec + JAN_1970; 82 83 if (systime_10ms_ticks) { 84 /* fake better than 10ms resolution by interpolating 85 accumulated residual (in adj_systime(), see below) */ 86 dtemp = tv.tv_usec / 1e6; 87 if (sys_residual < 5000e-6 && sys_residual > -5000e-6) { 88 dtemp += sys_residual; 89 if (dtemp < 0) { 90 now->l_i--; 91 dtemp++; 92 } 93 } 94 dtemp *= FRAC; 95 } else { 96 dtemp = tv.tv_usec * FRAC / 1e6; 97 } 98 99 if (dtemp >= FRAC) 100 now->l_i++; 101 now->l_uf = (u_int32)dtemp; 102 #endif /* HAVE_CLOCK_GETTIME */ 103 104 } 105 106 107 /* 108 * adj_systime - called once every second to make system time adjustments. 109 * Returns 1 if okay, 0 if trouble. 110 */ 111 int 112 adj_systime( 113 double now 114 ) 115 { 116 double dtemp; 117 struct timeval adjtv; 118 u_char isneg = 0; 119 #if !defined SYS_WINNT && !defined SYS_CYGWIN32 120 struct timeval oadjtv; 121 #else 122 int rc; 123 long dwTimeAdjustment; 124 #endif 125 126 /* 127 * Add the residual from the previous adjustment to the new 128 * adjustment, bound and round. 129 */ 130 dtemp = sys_residual + now; 131 sys_residual = 0; 132 if (dtemp < 0) { 133 isneg = 1; 134 dtemp = -dtemp; 135 } 136 137 if (systime_10ms_ticks) { 138 /* accumulate changes until we have enough to adjust a tick */ 139 if (dtemp < 5000e-6) { 140 if (isneg) sys_residual = -dtemp; 141 else sys_residual = dtemp; 142 dtemp = 0; 143 } else { 144 if (isneg) sys_residual = 10000e-6 - dtemp; 145 else sys_residual = dtemp - 10000e-6; 146 dtemp = 10000e-6; 147 } 148 } else { 149 if (dtemp > sys_maxfreq) 150 dtemp = sys_maxfreq; 151 } 152 153 #ifdef SYS_WINNT 154 dtemp = dtemp * 1000000.0; 155 #else 156 dtemp = dtemp * 1e6 + .5; 157 #endif 158 if (isneg) 159 dtemp = -dtemp; 160 adjtv.tv_sec = 0; 161 adjtv.tv_usec = (int32)dtemp; 162 163 #if defined SYS_WINNT || defined SYS_CYGWIN32 164 /* dtemp is in micro seconds. NT uses 100 ns units, 165 * so a unit change in dwTimeAdjustment corresponds 166 * to slewing 10 ppm. 167 * Calculate the number of 100ns units to add, 168 * and leave the remainder in dtemp */ 169 dwTimeAdjustment = dtemp / 10; 170 dtemp += (double) -dwTimeAdjustment * 10.0; 171 dwTimeAdjustment += units_per_tick; 172 173 /* only adjust the clock if adjustment changes */ 174 if (last_Adj != dwTimeAdjustment) { 175 last_Adj = dwTimeAdjustment; 176 # ifdef DEBUG 177 if (debug > 1) 178 printf("SetSystemTimeAdjustment( %ld)\n", dwTimeAdjustment); 179 # endif 180 rc = !SetSystemTimeAdjustment(dwTimeAdjustment, FALSE); 181 } 182 else rc = 0; 183 if (rc) 184 #else 185 /* 186 * Here we do the actual adjustment. If for some reason the adjtime() 187 * call fails, like it is not implemented or something like that, 188 * we honk to the log. If the previous adjustment did not complete, 189 * we correct the residual offset. 190 */ 191 /* casey - we need a posix type thang here */ 192 if (adjtime(&adjtv, &oadjtv) < 0) 193 #endif /* SYS_WINNT */ 194 { 195 msyslog(LOG_ERR, "Can't adjust time: %m"); 196 return 0; 197 } 198 else { 199 #if !defined (SYS_WINNT) && !defined (SYS_CYGWIN32) 200 sys_residual += oadjtv.tv_usec / 1e6; 201 #else 202 sys_residual = dtemp / 1000000.0; 203 #endif /* SYS_WINNT */ 204 } 205 #ifdef DEBUG 206 if (debug > 6) 207 printf("adj_systime: adj %.9f -> remaining residual %.9f\n", now, sys_residual); 208 #endif 209 return 1; 210 } 211 212 213 /* 214 * step_systime - step the system clock. 215 */ 216 int 217 step_systime( 218 double now 219 ) 220 { 221 struct timeval timetv, adjtv, oldtimetv; 222 int isneg = 0; 223 double dtemp; 224 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 225 struct timespec ts; 226 #endif 227 228 dtemp = sys_residual + now; 229 if (dtemp < 0) { 230 isneg = 1; 231 dtemp = - dtemp; 232 adjtv.tv_sec = (int32)dtemp; 233 adjtv.tv_usec = (u_int32)((dtemp - (double)adjtv.tv_sec) * 234 1e6 + .5); 235 } else { 236 adjtv.tv_sec = (int32)dtemp; 237 adjtv.tv_usec = (u_int32)((dtemp - (double)adjtv.tv_sec) * 238 1e6 + .5); 239 } 240 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 241 #ifdef HAVE_CLOCK_GETTIME 242 (void) clock_gettime(CLOCK_REALTIME, &ts); 243 #else 244 (void) getclock(TIMEOFDAY, &ts); 245 #endif 246 timetv.tv_sec = ts.tv_sec; 247 timetv.tv_usec = ts.tv_nsec / 1000; 248 #else /* not HAVE_GETCLOCK */ 249 (void) GETTIMEOFDAY(&timetv, (struct timezone *)0); 250 #endif /* not HAVE_GETCLOCK */ 251 252 oldtimetv = timetv; 253 254 #ifdef DEBUG 255 if (debug) 256 printf("step_systime: step %.6f residual %.6f\n", now, sys_residual); 257 #endif 258 if (isneg) { 259 timetv.tv_sec -= adjtv.tv_sec; 260 timetv.tv_usec -= adjtv.tv_usec; 261 if (timetv.tv_usec < 0) { 262 timetv.tv_sec--; 263 timetv.tv_usec += 1000000; 264 } 265 } else { 266 timetv.tv_sec += adjtv.tv_sec; 267 timetv.tv_usec += adjtv.tv_usec; 268 if (timetv.tv_usec >= 1000000) { 269 timetv.tv_sec++; 270 timetv.tv_usec -= 1000000; 271 } 272 } 273 if (ntp_set_tod(&timetv, (struct timezone *)0) != 0) { 274 msyslog(LOG_ERR, "Can't set time of day: %m"); 275 return (0); 276 } 277 sys_residual = 0; 278 279 #ifdef NEED_HPUX_ADJTIME 280 /* 281 * CHECKME: is this correct when called by ntpdate????? 282 */ 283 _clear_adjtime(); 284 #endif 285 286 /* 287 * FreeBSD, for example, has: 288 * struct utmp { 289 * char ut_line[UT_LINESIZE]; 290 * char ut_name[UT_NAMESIZE]; 291 * char ut_host[UT_HOSTSIZE]; 292 * long ut_time; 293 * }; 294 * and appends line="|", name="date", host="", time for the OLD 295 * and appends line="{", name="date", host="", time for the NEW 296 * to _PATH_WTMP . 297 * 298 * Some OSes have utmp, some have utmpx. 299 */ 300 301 /* 302 * Write old and new time entries in utmp and wtmp if step adjustment 303 * is greater than one second. 304 * 305 * This might become even Uglier... 306 */ 307 if (oldtimetv.tv_sec != timetv.tv_sec) 308 { 309 #ifdef HAVE_UTMP_H 310 struct utmp ut; 311 #endif 312 #ifdef HAVE_UTMPX_H 313 struct utmpx utx; 314 #endif 315 316 #ifdef HAVE_UTMP_H 317 memset((char *)&ut, 0, sizeof(ut)); 318 #endif 319 #ifdef HAVE_UTMPX_H 320 memset((char *)&utx, 0, sizeof(utx)); 321 #endif 322 323 /* UTMP */ 324 325 #ifdef UPDATE_UTMP 326 # ifdef HAVE_PUTUTLINE 327 ut.ut_type = OLD_TIME; 328 (void)strcpy(ut.ut_line, OTIME_MSG); 329 ut.ut_time = oldtimetv.tv_sec; 330 pututline(&ut); 331 setutent(); 332 ut.ut_type = NEW_TIME; 333 (void)strcpy(ut.ut_line, NTIME_MSG); 334 ut.ut_time = timetv.tv_sec; 335 pututline(&ut); 336 endutent(); 337 # else /* not HAVE_PUTUTLINE */ 338 # endif /* not HAVE_PUTUTLINE */ 339 #endif /* UPDATE_UTMP */ 340 341 /* UTMPX */ 342 343 #ifdef UPDATE_UTMPX 344 # ifdef HAVE_PUTUTXLINE 345 utx.ut_type = OLD_TIME; 346 (void)strcpy(utx.ut_line, OTIME_MSG); 347 utx.ut_tv = oldtimetv; 348 pututxline(&utx); 349 setutxent(); 350 utx.ut_type = NEW_TIME; 351 (void)strcpy(utx.ut_line, NTIME_MSG); 352 utx.ut_tv = timetv; 353 pututxline(&utx); 354 endutxent(); 355 # else /* not HAVE_PUTUTXLINE */ 356 # endif /* not HAVE_PUTUTXLINE */ 357 #endif /* UPDATE_UTMPX */ 358 359 /* WTMP */ 360 361 #ifdef UPDATE_WTMP 362 # ifdef HAVE_PUTUTLINE 363 utmpname(WTMP_FILE); 364 ut.ut_type = OLD_TIME; 365 (void)strcpy(ut.ut_line, OTIME_MSG); 366 ut.ut_time = oldtimetv.tv_sec; 367 pututline(&ut); 368 ut.ut_type = NEW_TIME; 369 (void)strcpy(ut.ut_line, NTIME_MSG); 370 ut.ut_time = timetv.tv_sec; 371 pututline(&ut); 372 endutent(); 373 # else /* not HAVE_PUTUTLINE */ 374 # endif /* not HAVE_PUTUTLINE */ 375 #endif /* UPDATE_WTMP */ 376 377 /* WTMPX */ 378 379 #ifdef UPDATE_WTMPX 380 # ifdef HAVE_PUTUTXLINE 381 utx.ut_type = OLD_TIME; 382 utx.ut_tv = oldtimetv; 383 (void)strcpy(utx.ut_line, OTIME_MSG); 384 # ifdef HAVE_UPDWTMPX 385 updwtmpx(WTMPX_FILE, &utx); 386 # else /* not HAVE_UPDWTMPX */ 387 # endif /* not HAVE_UPDWTMPX */ 388 # else /* not HAVE_PUTUTXLINE */ 389 # endif /* not HAVE_PUTUTXLINE */ 390 # ifdef HAVE_PUTUTXLINE 391 utx.ut_type = NEW_TIME; 392 utx.ut_tv = timetv; 393 (void)strcpy(utx.ut_line, NTIME_MSG); 394 # ifdef HAVE_UPDWTMPX 395 updwtmpx(WTMPX_FILE, &utx); 396 # else /* not HAVE_UPDWTMPX */ 397 # endif /* not HAVE_UPDWTMPX */ 398 # else /* not HAVE_PUTUTXLINE */ 399 # endif /* not HAVE_PUTUTXLINE */ 400 #endif /* UPDATE_WTMPX */ 401 402 } 403 return (1); 404 } 405