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>