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