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