From 971216b69d390d92cca95c987600a23ef917d1ee Mon Sep 17 00:00:00 2001 From: phk Date: Mon, 11 Aug 2008 09:15:27 +0000 Subject: [PATCH] Be much more explicit about the string->time conversion disaster visited upon us by the brilliant minds behind POSIX. Parts from: Solaris patch from Theo Schlossnagle git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3077 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishd/varnishd.c | 8 +++- varnish-cache/configure.ac | 1 + varnish-cache/lib/libvarnish/time.c | 62 ++++++++++++++++++++++++--- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/varnish-cache/bin/varnishd/varnishd.c b/varnish-cache/bin/varnishd/varnishd.c index 10b742d9..9f57f813 100644 --- a/varnish-cache/bin/varnishd/varnishd.c +++ b/varnish-cache/bin/varnishd/varnishd.c @@ -429,7 +429,13 @@ main(int argc, char * const *argv) setbuf(stdout, NULL); setbuf(stderr, NULL); - AZ(setenv("TZ", "GMT", 1)); + /* + * Run in UTC timezone, on the off-chance that this operating + * system does not have a timegm() function, and translates + * timestamps on the local timescale. + * See lib/libvarnish/time.c + */ + AZ(setenv("TZ", "UTC", 1)); tzset(); memset(cli, 0, sizeof cli); diff --git a/varnish-cache/configure.ac b/varnish-cache/configure.ac index bf26019f..ee6ed332 100644 --- a/varnish-cache/configure.ac +++ b/varnish-cache/configure.ac @@ -101,6 +101,7 @@ AC_CHECK_FUNCS([strptime]) AC_CHECK_FUNCS([fmtcheck]) AC_CHECK_FUNCS([getdtablesize]) AC_CHECK_FUNCS([abort2]) +AC_CHECK_FUNCS([timegm]) save_LIBS="${LIBS}" LIBS="${PTHREAD_LIBS}" diff --git a/varnish-cache/lib/libvarnish/time.c b/varnish-cache/lib/libvarnish/time.c index 03caa16c..0f2cce7d 100644 --- a/varnish-cache/lib/libvarnish/time.c +++ b/varnish-cache/lib/libvarnish/time.c @@ -112,18 +112,70 @@ static const char *fmts[] = { time_t TIM_parse(const char *p) { + time_t t; struct tm tm; const char **r; for (r = fmts; *r != NULL; r++) { memset(&tm, 0, sizeof tm); - if (strptime(p, *r, &tm) != NULL) - return (mktime(&tm)); + if (strptime(p, *r, &tm) != NULL) { + /* + * Make sure this is initialized on the off-chance + * that some raving loonie would apply DST to UTC. + */ + tm.tm_isdst = -1; +#if defined(HAVE_TIMEGM) + t = timegm(&tm); +#else + /* + * Ahh, another POSIX_STUPIDITY, how unexpected. + * Instead of, as would have been logical, to have + * tm_timezone element, mktime() is standardized as + * always working in localtime. This brilliant idea + * came from the same people who said "leap-seconds ? + * Naah, screw it!". + * + * On broken systems without a working timegm(), + * it is the responsibility of the calling program + * to set the timezone to UTC. We check that. + */ + t = mktime(&tm); + assert(!strcmp(tzname[0], "UTC")); +#endif + return (t); + } } return (0); } #ifdef TEST_DRIVER + +#include + +/* + * Compile with: + * cc -o foo -DTEST_DRIVER -I../.. -I../../include time.c assert.c + * Test with: + * env TZ=UTC ./foo + * env TZ=CET ./foo + */ + +static void +tst(const char *s, time_t good) +{ + time_t t; + char buf[BUFSIZ]; + + t = TIM_parse(s); + TIM_format(t, buf); + printf("%-30s -> %12jd -> %s\n", s, (intmax_t)t, buf); + if (t != good) { + printf("Parse error! Got: %jd should have %jd diff %jd\n", + (intmax_t)t, (intmax_t)good, (intmax_t)(t - good)); + exit (2); + } +} + int main(int argc, char **argv) { @@ -136,9 +188,9 @@ main(int argc, char **argv) printf("scan = %d <%s>\n", TIM_parse(buf), buf); /* Examples from RFC2616 section 3.3.1 */ - printf("scan = %d\n", TIM_parse("Sun, 06 Nov 1994 08:49:37 GMT")); - printf("scan = %d\n", TIM_parse("Sunday, 06-Nov-94 08:49:37 GMT")); - printf("scan = %d\n", TIM_parse("Sun Nov 6 08:49:37 1994")); + tst("Sun, 06 Nov 1994 08:49:37 GMT", 784111777); + tst("Sunday, 06-Nov-94 08:49:37 GMT", 784111777); + tst("Sun Nov 6 08:49:37 1994", 784111777); return (0); } -- 2.39.5