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