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