Annotation of embedaddon/ntp/libntp/systime.c, revision 1.1
1.1 ! misho 1: /*
! 2: * systime -- routines to fiddle a UNIX clock.
! 3: *
! 4: * ATTENTION: Get approval from Dave Mills on all changes to this file!
! 5: *
! 6: */
! 7: #include "ntp_machine.h"
! 8: #include "ntp_fp.h"
! 9: #include "ntp_syslog.h"
! 10: #include "ntp_unixtime.h"
! 11: #include "ntp_stdlib.h"
! 12: #include "ntp_random.h"
! 13: #include "ntpd.h" /* for sys_precision */
! 14:
! 15: #ifdef HAVE_SYS_PARAM_H
! 16: # include <sys/param.h>
! 17: #endif
! 18: #ifdef HAVE_UTMP_H
! 19: # include <utmp.h>
! 20: #endif /* HAVE_UTMP_H */
! 21: #ifdef HAVE_UTMPX_H
! 22: # include <utmpx.h>
! 23: #endif /* HAVE_UTMPX_H */
! 24:
! 25:
! 26: #define FUZZ 500e-6 /* fuzz pivot */
! 27:
! 28: /*
! 29: * These routines (get_systime, step_systime, adj_systime) implement an
! 30: * interface between the system independent NTP clock and the Unix
! 31: * system clock in various architectures and operating systems. Time is
! 32: * a precious quantity in these routines and every effort is made to
! 33: * minimize errors by unbiased rounding and amortizing adjustment
! 34: * residues.
! 35: *
! 36: * In order to improve the apparent resolution, provide unbiased
! 37: * rounding and insure that the readings cannot be predicted, the low-
! 38: * order unused portion of the time below the resolution limit is filled
! 39: * with an unbiased random fuzz.
! 40: *
! 41: * The sys_tick variable secifies the system clock tick interval in
! 42: * seconds. For systems that can interpolate between timer interrupts,
! 43: * the resolution is presumed much less than the time to read the system
! 44: * clock, which is the value of sys_tick after the precision has been
! 45: * determined. For those systems that cannot interpolate between timer
! 46: * interrupts, sys_tick will be much larger in the order of 10 ms, so the
! 47: * fuzz should be that value. For Sunses the tick is not interpolated, but
! 48: * the system clock is derived from a 2-MHz oscillator, so the resolution
! 49: * is 500 ns and sys_tick is 500 ns.
! 50: */
! 51: double sys_tick = 0; /* precision (time to read the clock) */
! 52: double sys_residual = 0; /* adjustment residue (s) */
! 53:
! 54: #ifndef SIM
! 55:
! 56: /*
! 57: * get_systime - return system time in NTP timestamp format.
! 58: */
! 59: void
! 60: get_systime(
! 61: l_fp *now /* system time */
! 62: )
! 63: {
! 64: double dtemp;
! 65:
! 66: #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
! 67: struct timespec ts; /* seconds and nanoseconds */
! 68:
! 69: /*
! 70: * Convert Unix timespec from seconds and nanoseconds to NTP
! 71: * seconds and fraction.
! 72: */
! 73: # ifdef HAVE_CLOCK_GETTIME
! 74: clock_gettime(CLOCK_REALTIME, &ts);
! 75: # else
! 76: getclock(TIMEOFDAY, &ts);
! 77: # endif
! 78: now->l_i = (int32)ts.tv_sec + JAN_1970;
! 79: dtemp = 0;
! 80: if (sys_tick > FUZZ)
! 81: dtemp = ntp_random() * 2. / FRAC * sys_tick * 1e9;
! 82: else if (sys_tick > 0)
! 83: dtemp = ntp_random() * 2. / FRAC;
! 84: dtemp = (ts.tv_nsec + dtemp) * 1e-9;
! 85: if (dtemp >= 1.) {
! 86: dtemp -= 1.;
! 87: now->l_i++;
! 88: } else if (dtemp < 0) {
! 89: dtemp += 1.;
! 90: now->l_i--;
! 91: }
! 92: now->l_uf = (u_int32)(dtemp * FRAC);
! 93:
! 94: #else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
! 95: struct timeval tv; /* seconds and microseconds */
! 96:
! 97: /*
! 98: * Convert Unix timeval from seconds and microseconds to NTP
! 99: * seconds and fraction.
! 100: */
! 101: GETTIMEOFDAY(&tv, NULL);
! 102: now->l_i = tv.tv_sec + JAN_1970;
! 103: dtemp = 0;
! 104: if (sys_tick > FUZZ)
! 105: dtemp = ntp_random() * 2. / FRAC * sys_tick * 1e6;
! 106: else if (sys_tick > 0)
! 107: dtemp = ntp_random() * 2. / FRAC;
! 108: dtemp = (tv.tv_usec + dtemp) * 1e-6;
! 109: if (dtemp >= 1.) {
! 110: dtemp -= 1.;
! 111: now->l_i++;
! 112: } else if (dtemp < 0) {
! 113: dtemp += 1.;
! 114: now->l_i--;
! 115: }
! 116: now->l_uf = (u_int32)(dtemp * FRAC);
! 117:
! 118: #endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
! 119: }
! 120:
! 121:
! 122: /*
! 123: * adj_systime - adjust system time by the argument.
! 124: */
! 125: #if !defined SYS_WINNT
! 126: int /* 0 okay, 1 error */
! 127: adj_systime(
! 128: double now /* adjustment (s) */
! 129: )
! 130: {
! 131: struct timeval adjtv; /* new adjustment */
! 132: struct timeval oadjtv; /* residual adjustment */
! 133: double dtemp;
! 134: long ticks;
! 135: int isneg = 0;
! 136:
! 137: /*
! 138: * Most Unix adjtime() implementations adjust the system clock
! 139: * in microsecond quanta, but some adjust in 10-ms quanta. We
! 140: * carefully round the adjustment to the nearest quantum, then
! 141: * adjust in quanta and keep the residue for later.
! 142: */
! 143: dtemp = now + sys_residual;
! 144: if (dtemp < 0) {
! 145: isneg = 1;
! 146: dtemp = -dtemp;
! 147: }
! 148: adjtv.tv_sec = (long)dtemp;
! 149: dtemp -= adjtv.tv_sec;
! 150: ticks = (long)(dtemp / sys_tick + .5);
! 151: adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
! 152: dtemp -= adjtv.tv_usec / 1e6;
! 153: sys_residual = dtemp;
! 154:
! 155: /*
! 156: * Convert to signed seconds and microseconds for the Unix
! 157: * adjtime() system call. Note we purposely lose the adjtime()
! 158: * leftover.
! 159: */
! 160: if (isneg) {
! 161: adjtv.tv_sec = -adjtv.tv_sec;
! 162: adjtv.tv_usec = -adjtv.tv_usec;
! 163: sys_residual = -sys_residual;
! 164: }
! 165: if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) {
! 166: if (adjtime(&adjtv, &oadjtv) < 0) {
! 167: msyslog(LOG_ERR, "adj_systime: %m");
! 168: return (0);
! 169: }
! 170: }
! 171: return (1);
! 172: }
! 173: #endif
! 174:
! 175:
! 176: /*
! 177: * step_systime - step the system clock.
! 178: */
! 179: int
! 180: step_systime(
! 181: double now
! 182: )
! 183: {
! 184: struct timeval timetv, adjtv, oldtimetv;
! 185: int isneg = 0;
! 186: double dtemp;
! 187: #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
! 188: struct timespec ts;
! 189: #endif
! 190:
! 191: dtemp = sys_residual + now;
! 192: if (dtemp < 0) {
! 193: isneg = 1;
! 194: dtemp = - dtemp;
! 195: adjtv.tv_sec = (int32)dtemp;
! 196: adjtv.tv_usec = (u_int32)((dtemp -
! 197: (double)adjtv.tv_sec) * 1e6 + .5);
! 198: } else {
! 199: adjtv.tv_sec = (int32)dtemp;
! 200: adjtv.tv_usec = (u_int32)((dtemp -
! 201: (double)adjtv.tv_sec) * 1e6 + .5);
! 202: }
! 203: #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
! 204: # ifdef HAVE_CLOCK_GETTIME
! 205: (void) clock_gettime(CLOCK_REALTIME, &ts);
! 206: # else
! 207: (void) getclock(TIMEOFDAY, &ts);
! 208: # endif
! 209: timetv.tv_sec = ts.tv_sec;
! 210: timetv.tv_usec = ts.tv_nsec / 1000;
! 211: #else /* not HAVE_GETCLOCK */
! 212: (void) GETTIMEOFDAY(&timetv, (struct timezone *)0);
! 213: #endif /* not HAVE_GETCLOCK */
! 214:
! 215: oldtimetv = timetv;
! 216:
! 217: #ifdef DEBUG
! 218: if (debug)
! 219: printf("step_systime: step %.6f residual %.6f\n", now, sys_residual);
! 220: #endif
! 221: if (isneg) {
! 222: timetv.tv_sec -= adjtv.tv_sec;
! 223: timetv.tv_usec -= adjtv.tv_usec;
! 224: if (timetv.tv_usec < 0) {
! 225: timetv.tv_sec--;
! 226: timetv.tv_usec += 1000000;
! 227: }
! 228: } else {
! 229: timetv.tv_sec += adjtv.tv_sec;
! 230: timetv.tv_usec += adjtv.tv_usec;
! 231: if (timetv.tv_usec >= 1000000) {
! 232: timetv.tv_sec++;
! 233: timetv.tv_usec -= 1000000;
! 234: }
! 235: }
! 236: if (ntp_set_tod(&timetv, NULL) != 0) {
! 237: msyslog(LOG_ERR, "step-systime: %m");
! 238: return (0);
! 239: }
! 240: sys_residual = 0;
! 241:
! 242: #ifdef NEED_HPUX_ADJTIME
! 243: /*
! 244: * CHECKME: is this correct when called by ntpdate?????
! 245: */
! 246: _clear_adjtime();
! 247: #endif
! 248:
! 249: /*
! 250: * FreeBSD, for example, has:
! 251: * struct utmp {
! 252: * char ut_line[UT_LINESIZE];
! 253: * char ut_name[UT_NAMESIZE];
! 254: * char ut_host[UT_HOSTSIZE];
! 255: * long ut_time;
! 256: * };
! 257: * and appends line="|", name="date", host="", time for the OLD
! 258: * and appends line="{", name="date", host="", time for the NEW
! 259: * to _PATH_WTMP .
! 260: *
! 261: * Some OSes have utmp, some have utmpx.
! 262: */
! 263:
! 264: /*
! 265: * Write old and new time entries in utmp and wtmp if step
! 266: * adjustment is greater than one second.
! 267: *
! 268: * This might become even Uglier...
! 269: */
! 270: if (oldtimetv.tv_sec != timetv.tv_sec)
! 271: {
! 272: #ifdef HAVE_UTMP_H
! 273: struct utmp ut;
! 274: #endif
! 275: #ifdef HAVE_UTMPX_H
! 276: struct utmpx utx;
! 277: #endif
! 278:
! 279: #ifdef HAVE_UTMP_H
! 280: memset((char *)&ut, 0, sizeof(ut));
! 281: #endif
! 282: #ifdef HAVE_UTMPX_H
! 283: memset((char *)&utx, 0, sizeof(utx));
! 284: #endif
! 285:
! 286: /* UTMP */
! 287:
! 288: #ifdef UPDATE_UTMP
! 289: # ifdef HAVE_PUTUTLINE
! 290: ut.ut_type = OLD_TIME;
! 291: (void)strcpy(ut.ut_line, OTIME_MSG);
! 292: ut.ut_time = oldtimetv.tv_sec;
! 293: pututline(&ut);
! 294: setutent();
! 295: ut.ut_type = NEW_TIME;
! 296: (void)strcpy(ut.ut_line, NTIME_MSG);
! 297: ut.ut_time = timetv.tv_sec;
! 298: pututline(&ut);
! 299: endutent();
! 300: # else /* not HAVE_PUTUTLINE */
! 301: # endif /* not HAVE_PUTUTLINE */
! 302: #endif /* UPDATE_UTMP */
! 303:
! 304: /* UTMPX */
! 305:
! 306: #ifdef UPDATE_UTMPX
! 307: # ifdef HAVE_PUTUTXLINE
! 308: utx.ut_type = OLD_TIME;
! 309: (void)strcpy(utx.ut_line, OTIME_MSG);
! 310: utx.ut_tv = oldtimetv;
! 311: pututxline(&utx);
! 312: setutxent();
! 313: utx.ut_type = NEW_TIME;
! 314: (void)strcpy(utx.ut_line, NTIME_MSG);
! 315: utx.ut_tv = timetv;
! 316: pututxline(&utx);
! 317: endutxent();
! 318: # else /* not HAVE_PUTUTXLINE */
! 319: # endif /* not HAVE_PUTUTXLINE */
! 320: #endif /* UPDATE_UTMPX */
! 321:
! 322: /* WTMP */
! 323:
! 324: #ifdef UPDATE_WTMP
! 325: # ifdef HAVE_PUTUTLINE
! 326: utmpname(WTMP_FILE);
! 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: ut.ut_type = NEW_TIME;
! 332: (void)strcpy(ut.ut_line, NTIME_MSG);
! 333: ut.ut_time = timetv.tv_sec;
! 334: pututline(&ut);
! 335: endutent();
! 336: # else /* not HAVE_PUTUTLINE */
! 337: # endif /* not HAVE_PUTUTLINE */
! 338: #endif /* UPDATE_WTMP */
! 339:
! 340: /* WTMPX */
! 341:
! 342: #ifdef UPDATE_WTMPX
! 343: # ifdef HAVE_PUTUTXLINE
! 344: utx.ut_type = OLD_TIME;
! 345: utx.ut_tv = oldtimetv;
! 346: (void)strcpy(utx.ut_line, OTIME_MSG);
! 347: # ifdef HAVE_UPDWTMPX
! 348: updwtmpx(WTMPX_FILE, &utx);
! 349: # else /* not HAVE_UPDWTMPX */
! 350: # endif /* not HAVE_UPDWTMPX */
! 351: # else /* not HAVE_PUTUTXLINE */
! 352: # endif /* not HAVE_PUTUTXLINE */
! 353: # ifdef HAVE_PUTUTXLINE
! 354: utx.ut_type = NEW_TIME;
! 355: utx.ut_tv = timetv;
! 356: (void)strcpy(utx.ut_line, NTIME_MSG);
! 357: # ifdef HAVE_UPDWTMPX
! 358: updwtmpx(WTMPX_FILE, &utx);
! 359: # else /* not HAVE_UPDWTMPX */
! 360: # endif /* not HAVE_UPDWTMPX */
! 361: # else /* not HAVE_PUTUTXLINE */
! 362: # endif /* not HAVE_PUTUTXLINE */
! 363: #endif /* UPDATE_WTMPX */
! 364:
! 365: }
! 366: return (1);
! 367: }
! 368:
! 369: #else /* SIM */
! 370: /*
! 371: * Clock routines for the simulator - Harish Nair, with help
! 372: */
! 373:
! 374:
! 375: /* SK:
! 376: * The code that used to be here has been moved to ntpsim.c,
! 377: * where, IMHO, it rightfully belonged.
! 378: */
! 379:
! 380: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>