From: Juergen Perlinger Date: Wed, 7 Sep 2011 17:25:23 +0000 (+0200) Subject: [Bug 1995] added support for getting build time stamp X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ab196742dc412cb86cf4bd6d162d58f45932c796;p=thirdparty%2Fntp.git [Bug 1995] added support for getting build time stamp bk: 4e67a903NrKh0FVxJHxbmViWXxDfNQ --- diff --git a/ChangeLog b/ChangeLog index dbb4c17823..9ac0e04918 100644 --- 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 * [Bug 2003] from 4.2.6p4-RC3: ntpq_read_assoc_peervars() broken. (4.2.7p211) 2011/09/01 Released by Harlan Stenn diff --git a/include/ntp_calendar.h b/include/ntp_calendar.h index d978921162..2b1b4ab5c8 100644 --- a/include/ntp_calendar.h +++ b/include/ntp_calendar.h @@ -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 */ diff --git a/libntp/ntp_calendar.c b/libntp/ntp_calendar.c index 8e9b1f99b1..9e8b0a3764 100644 --- a/libntp/ntp_calendar.c +++ b/libntp/ntp_calendar.c @@ -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); +} + + /* * ================================================================== * diff --git a/libntp/systime.c b/libntp/systime.c index a862e69b27..1a7afd46e8 100644 --- a/libntp/systime.c +++ b/libntp/systime.c @@ -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 @@ -26,6 +29,19 @@ #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);