]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 1995] added support for getting build time stamp
authorJuergen Perlinger <perlinger@ntp.org>
Wed, 7 Sep 2011 17:25:23 +0000 (19:25 +0200)
committerJuergen Perlinger <perlinger@ntp.org>
Wed, 7 Sep 2011 17:25:23 +0000 (19:25 +0200)
bk: 4e67a903NrKh0FVxJHxbmViWXxDfNQ

ChangeLog
include/ntp_calendar.h
libntp/ntp_calendar.c
libntp/systime.c

index dbb4c17823256fa237108156c280674e02f2a9a7..9ac0e0491833ec9352fb19a01306d68aabb9e7af 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,5 @@
+* [Bug 1995] add compile time stamp based era unfolding for
+  'step_systime()' and needed support to 'ntp-calendar.c'.
 (4.2.7p212) 2011/09/07 Released by Harlan Stenn <stenn@ntp.org>
 * [Bug 2003] from 4.2.6p4-RC3: ntpq_read_assoc_peervars() broken.
 (4.2.7p211) 2011/09/01 Released by Harlan Stenn <stenn@ntp.org>
index d978921162441d2715e1fa6da1f4fdb61f8bfcc9..2b1b4ab5c89ecc0df0825c54660fd9807d143e4a 100644 (file)
@@ -109,6 +109,21 @@ extern     const char * const daynames[7];
 extern void    caljulian       (u_int32, struct calendar *);
 extern u_int32 caltontp        (const struct calendar *);
 
+/*
+ * Convert between 'time_t' and 'vint64'
+ */
+extern vint64 time_to_vint64(const time_t *);
+extern time_t vint64_to_time(const vint64 *); 
+
+/*
+ * Get the build date & time. ATTENTION: The time zone is not specified!
+ * This depends entirely on the C compilers' capabilities to properly
+ * expand the '__TIME__' and '__DATE__' macros, as required by the C
+ * standard.
+ */
+extern int
+ntpcal_get_build_date(struct calendar * jd);
+
 /*
  * Convert a timestamp in NTP scale to a time_t value in the UN*X
  * scale with proper epoch unfolding around a given pivot or the
@@ -296,6 +311,9 @@ ntpcal_ntp_to_date(struct calendar *jd,     u_int32 ntp, const time_t *pivot);
 extern u_int32
 ntpcal_date_to_ntp(const struct calendar *jd);
 
+extern time_t
+ntpcal_date_to_time(const struct calendar *jd);
+
 /*
  * ISO week-calendar conversions
  */
index 8e9b1f99b1bcf73fd89e19d4ceaf60f63c0e785e..9e8b0a376422ee2bc6d530fa1cf693c88fb10549 100644 (file)
@@ -45,6 +45,145 @@ now(void)
        return (*systime_func)(NULL);
 }
 
+/*
+ *---------------------------------------------------------------------
+ * Convert between 'time_t' and 'vint64'
+ *---------------------------------------------------------------------
+ */
+vint64
+time_to_vint64(
+       const time_t * tv
+       )
+{
+       vint64 res;
+       time_t tmp;
+
+       /*
+        * shifting negative signed quantities is compiler-dependent, so
+        * we better avoid it and do it all manually. And shifting more
+        * than the width of a quantity is undefined. Also a don't do!
+        */
+
+#if SIZEOF_TIME_T <= 4
+
+       res.D_s.hi = 0;
+       if ((tmp = *tv) < 0) {
+               res.D_s.lo = (u_int32) -tmp;
+               M_NEG(res.D_s.hi, res.D_s.lo);
+       } else {
+               res.D_s.lo = (u_int32) tmp;
+       }
+
+#elif defined (HAVE_INT64)
+
+       (void)tmp;      /* touch it to avoid warnings... */
+       res.q_s = *tv;
+
+#else
+       time_t tmp = *tv;
+       if ((tmp = *tv) < 0) {
+               tmp = -tmp;
+               res.D_s.lo = (u_int32)tmp;
+               res.D_s.hi = (u_int32)(tmp >> 32);
+               M_NEG(res.D_s.hi, res.D_s.lo);
+       } else {
+               res.D_s.lo = (u_int32)tmp;
+               res.D_s.hi = (u_int32)(tmp >> 32);
+       }
+    
+#endif
+
+    return res;
+}
+
+
+time_t
+vint64_to_time(
+       const vint64 *tv
+       )
+{
+       time_t res;
+
+#if SIZEOF_TIME_T <= 4
+
+       res = (time_t)tv->D_s.lo;
+
+#elif defined (HAVE_INT64)
+
+       res = (time_t)tv->q_s;
+
+#else
+
+       res = ((time_t)tv->d_s.hi << 32) | tv->D_s.lo;
+    
+#endif
+
+       return res;
+} 
+
+/*
+ *---------------------------------------------------------------------
+ * Get the build date & time
+ *---------------------------------------------------------------------
+ */
+int
+ntpcal_get_build_date(
+       struct calendar * jd
+       )
+{
+       /* The C standard tells us the format of '__DATE__':
+        *
+        * __DATE__ The date of translation of the preprocessing
+        * translation unit: a character string literal of the form "Mmm
+        * dd yyyy", where the names of the months are the same as those
+        * generated by the asctime function, and the first character of
+        * dd is a space character if the value is less than 10. If the
+        * date of translation is not available, an
+        * implementation-defined valid date shall be supplied.
+        *
+        * __TIME__ The time of translation of the preprocessing
+        * translation unit: a character string literal of the form
+        * "hh:mm:ss" as in the time generated by the asctime
+        * function. If the time of translation is not available, an
+        * implementation-defined valid time shall be supplied.
+        *
+        * Note that MSVC declares DATE and TIME to be in the local time
+        * zone, while neither the C standard nor the GCC docs make any
+        * statement about this. As a result, we may be +/-12hrs off
+        * UTC.  But for practical purposes, this should not be a
+        * problem.
+        *
+        */
+       static const char build[] = __TIME__ "/" __DATE__;
+       static const char mlist[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+       char        month[4];
+       const char *cp;
+       u_short     hour, minute, second, year, day;
+               
+       memset(jd, 0, sizeof(struct calendar));
+       jd->year     = 1970;
+       jd->month    = 1;
+       jd->monthday = 1;
+
+       if (6 == sscanf(build, "%hu:%hu:%hu/%3s %hu %hu",
+                       &hour, &minute, &second, month, &day, &year)) {
+               cp = strstr(mlist, month);
+               if (NULL != cp) {
+                       jd->year     = year;
+                       jd->month    = (cp - mlist) / 3 + 1;
+                       jd->monthday = day;
+                       jd->hour     = hour;
+                       jd->minute   = minute;
+                       jd->second   = second;
+                       return 1;
+               }
+       }               
+
+       return 0;
+}
+
+
 /*
  *---------------------------------------------------------------------
  * basic calendar stuff
@@ -249,35 +388,18 @@ ntpcal_ntp_to_time(
        res.Q_s -= 0x80000000u;         /* unshift of half range */
        ntp     -= (u_int32)JAN_1970;   /* warp into UN*X domain */
        ntp     -= res.D_s.lo;          /* cycle difference      */
-       res.Q_s += (u_int64)ntp;                /* get expanded time     */
+       res.Q_s += (u_int64)ntp;        /* get expanded time     */
 
 #else /* no 64bit scalars */
        
        time_t tmp = pivot ? *pivot : now();
 
-       /*
-        * shifting negative signed quantities is compiler-dependent, so
-        * we better avoid it and do it all manually. And shifting more
-        * than the rgisterwidth is undefined. Also a don't do!
-        */
-#   if SIZEOF_TIME_T > 4
-       if (tmp < 0) {
-               tmp = -tmp;
-               res.D_s.lo = (u_int32)tmp;
-               res.D_s.hi = (u_int32)(tmp >> 32);
-               M_NEG(res.D_s.hi, res.D_s.lo);
-       } else {
-               res.D_s.lo = (u_int32)tmp;
-               res.D_s.hi = (u_int32)(tmp >> 32);
-       }
-#   else
-       res.D_s.lo = (u_int32)(int32)tmp;
-       res.D_s.hi = (tmp < 0) ? ~(u_int32)0 : 0;
-#   endif /* sizeof time_t <= 4 */
+       res = time_to_vint64(&tmp);
        M_SUB(res.D_s.hi, res.D_s.lo, 0, 0x80000000u);
        ntp -= (u_int32)JAN_1970;       /* warp into UN*X domain */
        ntp -= res.D_s.lo;              /* cycle difference      */
        M_ADD(res.D_s.hi, res.D_s.lo, 0, ntp);
+
 #endif /* no 64bit scalars */
 
        return res;
@@ -316,25 +438,7 @@ ntpcal_ntp_to_ntp(
        
        time_t tmp = pivot ? *pivot : now();
 
-       /*
-        * shifting negative signed quantities is compiler-dependent, so
-        * we better avoid it and do it all manually. And shifting more
-        * than the rgisterwidth is undefined. Also a don't do!
-        */
-#   if SIZEOF_TIME_T > 4
-       if (tmp < 0) {
-               tmp = -tmp;
-               res.D_s.lo = (u_int32)tmp;
-               res.D_s.hi = (u_int32)(tmp >> 32);
-               M_NEG(res.D_s.hi, res.D_s.lo);
-       } else {
-               res.D_s.lo = (u_int32)tmp;
-               res.D_s.hi = (u_int32)(tmp >> 32);
-       }
-#   else
-       res.D_s.lo = (u_int32)(int32)tmp;
-       res.D_s.hi = (tmp < 0) ? ~(u_int32)0 : 0;
-#   endif
+       res = time_to_vint64(&tmp);
        M_SUB(res.D_s.hi, res.D_s.lo, 0, 0x80000000u);
        M_ADD(res.D_s.hi, res.D_s.lo, 0, (u_int32)JAN_1970);/*into NTP */
        ntp -= res.D_s.lo;              /* cycle difference      */
@@ -789,8 +893,13 @@ ntpcal_dayjoin(
                M_NEG(res.D_s.hi, res.D_s.lo);
        
        /* properly add seconds */
-       p1 = secs;
-       p2 = (secs < 0) ? ~(u_int32)0 : 0;
+       p2 = 0;
+       if (secs < 0) {
+               p1 = (u_int32) -secs;
+               M_NEG(p2, p1);
+       } else {
+               p1 = (u_int32)  secs;
+       }
        M_ADD(res.D_s.hi, res.D_s.lo, p2, p1);
 
 #endif 
@@ -1064,6 +1173,25 @@ ntpcal_tm_to_daysec(
        return ntpcal_etime_to_seconds(utm->tm_hour, utm->tm_min, utm->tm_sec);
 }
 
+/*
+ *---------------------------------------------------------------------
+ * take a 'struct calendar' and convert it to a 'time_t'
+ *---------------------------------------------------------------------
+ */
+time_t
+ntpcal_date_to_time(
+       const struct calendar *jd)
+{
+       vint64 join;
+       int32  days, secs;
+
+       days = ntpcal_date_to_rd(jd) - DAY_UNIX_STARTS;
+       secs = ntpcal_date_to_daysec(jd);
+       join = ntpcal_dayjoin(days, secs);
+       return vint64_to_time(&join);
+}
+
+
 /*
  * ==================================================================
  *
index a862e69b27a34ac5a346087eb12de26709c9ea93..1a7afd46e888f4b9babd965c5ab3334602786458 100644 (file)
@@ -12,6 +12,9 @@
 #include "ntp_stdlib.h"
 #include "ntp_random.h"
 #include "ntpd.h"              /* for sys_precision */
+#include "timevalops.h"
+#include "timespecops.h"
+#include "ntp_calendar.h"
 
 #ifdef HAVE_SYS_PARAM_H
 # include <sys/param.h>
 
 #define        FUZZ    500e-6          /* fuzz pivot */
 
+#ifndef USE_COMPILETIME_PIVOT
+# define USE_COMPILETIME_PIVOT 1
+#endif
+
+#if defined(HAVE_CLOCK_GETTIME)
+# define GET_SYSTIME_AS_TIMESPEC(tsp) clock_gettime(CLOCK_REALTIME, tsp)
+#elif defined(HAVE_GETCLOCK)
+# define GET_SYSTIME_AS_TIMESPEC(tsp) getclock(TIMEOFDAY, tsp)
+#elif !defined(GETTIMEOFDAY)
+# include "bletch: cannot get system time?"
+#endif
+
+
 /*
  * These routines (get_systime, step_systime, adj_systime) implement an
  * interface between the system independent NTP clock and the Unix
@@ -65,18 +81,15 @@ get_systime(
 {
        double  dtemp;
 
-#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
+#if defined(GET_SYSTIME_AS_TIMESPEC)
+
        struct timespec ts;     /* seconds and nanoseconds */
 
        /*
         * Convert Unix timespec from seconds and nanoseconds to NTP
         * seconds and fraction.
         */
-# ifdef HAVE_CLOCK_GETTIME
-       clock_gettime(CLOCK_REALTIME, &ts);
-# else
-       getclock(TIMEOFDAY, &ts);
-# endif
+       GET_SYSTIME_AS_TIMESPEC(&ts);
        now->l_i = (int32)ts.tv_sec + JAN_1970;
        dtemp = 0;
        if (sys_tick > FUZZ)
@@ -93,7 +106,8 @@ get_systime(
        }
        now->l_uf = (u_int32)(dtemp * FRAC);
 
-#else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
+#else /* have GETTIMEOFDAY */
+
        struct timeval tv;      /* seconds and microseconds */
 
        /*
@@ -117,7 +131,7 @@ get_systime(
        }
        now->l_uf = (u_int32)(dtemp * FRAC);
 
-#endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
+#endif /* have GETTIMEOFDAY */
 }
 
 
@@ -178,67 +192,94 @@ adj_systime(
 /*
  * step_systime - step the system clock.
  */
+
 int
 step_systime(
-       double now
+       double step
        )
 {
-       struct timeval timetv, adjtv, oldtimetv;
-       int isneg = 0;
-       double dtemp;
-#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
-       struct timespec ts;
-#endif
+       time_t pivot; /* for ntp era unfolding */
+       struct timeval timetv, tvlast, tvdiff;
+       l_fp fp_ofs, fp_sys; /* offset and target system time in FP */
 
-       dtemp = sys_residual + now;
-       if (dtemp < 0) {
-               isneg = 1;
-               dtemp = - dtemp;
-               adjtv.tv_sec = (int32)dtemp;
-               adjtv.tv_usec = (u_int32)((dtemp -
-                   (double)adjtv.tv_sec) * 1e6 + .5);
-       } else {
-               adjtv.tv_sec = (int32)dtemp;
-               adjtv.tv_usec = (u_int32)((dtemp -
-                   (double)adjtv.tv_sec) * 1e6 + .5);
+       /* Get pivot time for NTP era unfolding. Since we don't step
+        * very often, we can afford to do the whole calculation from
+        * scratch. And we're not in the time-critical path yet.
+        */
+#if SIZEOF_TIME_T > 4
+       /*
+        * This code makes sure the resulting time stamp for the new
+        * system time is in the 2^32 seconds starting at 1970-01-01,
+        * 00:00:00 UTC.
+        */
+       pivot = 0x80000000U;
+#if USE_COMPILETIME_PIVOT
+       /*
+        * Add the compile time minus 10 years to get a possible target
+        * area of (compile time - 10 years) to (compile time + 126
+        * years).  This should be sufficient for a given binary of
+        * NTPD.
+        */
+       {
+               struct calendar jd;
+
+               if (ntpcal_get_build_date(&jd)) {
+                       jd.year -= 10;
+                       pivot += ntpcal_date_to_time(&jd);
+               } else {
+                       msyslog(LOG_ERR,
+                               "step-systime: assume 1970-01-01 as build date");
+               }
        }
-#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
-# ifdef HAVE_CLOCK_GETTIME
-       (void) clock_gettime(CLOCK_REALTIME, &ts);
-# else
-       (void) getclock(TIMEOFDAY, &ts);
-# endif
-       timetv.tv_sec = ts.tv_sec;
-       timetv.tv_usec = ts.tv_nsec / 1000;
-#else /*  not HAVE_GETCLOCK */
-       (void) GETTIMEOFDAY(&timetv, (struct timezone *)0);
-#endif /* not HAVE_GETCLOCK */
-
-       oldtimetv = timetv;
-
-#ifdef DEBUG
-       if (debug)
-               printf("step_systime: step %.6f residual %.6f\n", now, sys_residual);
+#endif /* USE_COMPILETIME_PIVOT */
+#else
+       /* This makes sure the resulting time stamp is on or after
+        * 1969-12-31/23:59:59 UTC and gives us additional two years,
+        * from the change of NTP era in 2036 to the UNIX rollover in
+        * 2038. (Minus one second, but that won't hurt.) We *really*
+        * need a longer 'time_t' after that!  Or a different baseline,
+        * but that would cause other serious trouble, too.
+        */
+       pivot = 0x7FFFFFFFU;
 #endif
-       if (isneg) {
-               timetv.tv_sec -= adjtv.tv_sec;
-               timetv.tv_usec -= adjtv.tv_usec;
-               if (timetv.tv_usec < 0) {
-                       timetv.tv_sec--;
-                       timetv.tv_usec += 1000000;
-               }
-       } else {
-               timetv.tv_sec += adjtv.tv_sec;
-               timetv.tv_usec += adjtv.tv_usec;
-               if (timetv.tv_usec >= 1000000) {
-                       timetv.tv_sec++;
-                       timetv.tv_usec -= 1000000;
-               }
+
+       /* get the complete jump distance as l_fp */
+       DTOLFP(sys_residual, &fp_sys);
+       DTOLFP(step,         &fp_ofs);
+       L_ADD(&fp_ofs, &fp_sys);
+
+       /* ---> time-critical path starts ---> */
+
+       /* get the current time as l_fp (without fuzz) and as struct timeval */
+#if defined(GET_SYSTIME_AS_TIMESPEC)
+       {
+               struct timespec timets;
+               (void) GET_SYSTIME_AS_TIMESPEC(&timets);
+               timespec_abstolfp(&fp_sys, &timets);
+               tvlast.tv_sec = timets.tv_sec;
+               tvlast.tv_usec = (timets.tv_nsec + 500) / 1000;
        }
+#else /* have GETTIMEOFDAY */
+       {
+           (void) GETTIMEOFDAY(&tvlast, NULL);
+           timeval_abstolfp(&fp_sys, &tvlast);
+       }
+#endif
+
+       /* get the target time as l_fp */
+       L_ADD(&fp_sys, &fp_ofs);
+
+       /* unfold the new system time */
+       timeval_absfromlfp(&timetv, &fp_sys, &pivot);
+
+       /* now set new system time */
        if (ntp_set_tod(&timetv, NULL) != 0) {
                msyslog(LOG_ERR, "step-systime: %m");
                return (0);
        }
+
+       /* <--- time-critical path ended with 'ntp_set_tod()' <--- */
+
        sys_residual = 0;
        if (step_callback)
                (*step_callback)();
@@ -271,7 +312,9 @@ step_systime(
         *
         * This might become even Uglier...
         */
-       if (oldtimetv.tv_sec != timetv.tv_sec)
+       timeval_sub(&tvdiff, &timetv, &tvlast);
+       timeval_abs(&tvdiff, &tvdiff);
+       if (tvdiff.tv_sec > 0)
        {
 #ifdef HAVE_UTMP_H
                struct utmp ut;
@@ -297,7 +340,7 @@ step_systime(
                utmpname(_PATH_UTMP);
                ut.ut_type = OLD_TIME;
                strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line));
-               ut.ut_time = oldtimetv.tv_sec;
+               ut.ut_time = tvlast.tv_sec;
                setutent();
                pututline(&ut);
                ut.ut_type = NEW_TIME;
@@ -316,7 +359,7 @@ step_systime(
 # ifdef HAVE_PUTUTXLINE
                utx.ut_type = OLD_TIME;
                strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line));
-               utx.ut_tv = oldtimetv;
+               utx.ut_tv = tvlast;
                setutxent();
                pututxline(&utx);
                utx.ut_type = NEW_TIME;
@@ -339,7 +382,7 @@ step_systime(
                utmpname(_PATH_WTMP);
                ut.ut_type = OLD_TIME;
                strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line));
-               ut.ut_time = oldtimetv.tv_sec;
+               ut.ut_time = tvlast.tv_sec;
                setutent();
                pututline(&ut);
                ut.ut_type = NEW_TIME;
@@ -357,7 +400,7 @@ step_systime(
 #ifdef UPDATE_WTMPX
 # ifdef HAVE_PUTUTXLINE
                utx.ut_type = OLD_TIME;
-               utx.ut_tv = oldtimetv;
+               utx.ut_tv = tvlast;
                strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line));
 #  ifdef HAVE_UPDWTMPX
                updwtmpx(WTMPX_FILE, &utx);