|
|
commit 42261ad731991df345880b0b509d83b0b9a9b9d8 |
|
|
Author: Florian Weimer <fweimer@redhat.com> |
|
|
Date: Fri Apr 24 17:34:47 2015 +0200 |
|
|
|
|
|
Make time zone file parser more robust [BZ #17715] |
|
|
|
|
|
commit 6807b1db8233ed84671f061b5d825622233df303 |
|
|
Author: Kevin Easton <kevin@guarana.org> |
|
|
Date: Tue Feb 24 23:57:07 2015 -0500 |
|
|
|
|
|
Reduce lock contention in __tz_convert() [BZ #16145] (partial fix) |
|
|
|
|
|
commit 9d46370ca338054cb6ea7ebeddcf06c7ac7ad1a9 |
|
|
Author: Joseph Myers <joseph@codesourcery.com> |
|
|
Date: Fri Oct 16 20:21:49 2015 +0000 |
|
|
|
|
|
Convert 703 function definitions to prototype style. |
|
|
(A subset of these changes (tzset.c) were applied as part of this patch.) |
|
|
|
|
|
commit 0748546f660d27a2ad29fa6174d456e2f6490758 |
|
|
Author: Paul Eggert <eggert@cs.ucla.edu> |
|
|
Date: Wed Sep 18 13:15:12 2013 -0700 |
|
|
|
|
|
Support TZ transition times < 00:00:00. |
|
|
|
|
|
This is needed for version-3 tz-format files; it supports time |
|
|
stamps past 2037 for America/Godthab (the only entry in the tz |
|
|
database for which this change is relevant). |
|
|
* manual/time.texi (TZ Variable): Document transition times |
|
|
from -167:59:59 through -00:00:01. |
|
|
* time/tzset.c (tz_rule): Time of day is now signed. |
|
|
(__tzset_parse_tz): Parse negative time of day. |
|
|
(A subset of these changes were applied as part of this patch.) |
|
|
|
|
|
commit 3cc652e951c71785032019fec82e3b8543d85305 |
|
|
Author: Mike Frysinger <vapier@gentoo.org> |
|
|
Date: Fri Sep 18 13:49:08 2015 -0400 |
|
|
|
|
|
timezone: fix parallel check failures |
|
|
|
|
|
The XT testdata install rules expect the testdata dir to already exist in |
|
|
the build tree, but it doesn't actually create it. Instead, it relies on |
|
|
the build-testdata define happening to be executed before it (which runs |
|
|
zic which creates the dir). When we run in parallel though, it's easy to |
|
|
hit a failure: |
|
|
$ cd timezone |
|
|
$ rm -rf $objdir/timezone/testdata |
|
|
$ make check -j |
|
|
... |
|
|
cp testdata/XT1 .../timezone/testdata/XT1 |
|
|
cp: cannot create regular file '.../timezone/testdata/XT1': No such file or directory |
|
|
Makefile:116: recipe for target '.../timezone/testdata/XT1' failed |
|
|
make: *** [.../timezone/testdata/XT1] Error 1 |
|
|
make: *** Waiting for unfinished jobs.... |
|
|
|
|
|
diff --git a/time/tzfile.c b/time/tzfile.c |
|
|
--- a/time/tzfile.c |
|
|
+++ b/time/tzfile.c |
|
|
@@ -213,6 +213,9 @@ |
|
|
num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt); |
|
|
num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt); |
|
|
|
|
|
+ if (__glibc_unlikely (num_isstd > num_types || num_isgmt > num_types)) |
|
|
+ goto lose; |
|
|
+ |
|
|
/* For platforms with 64-bit time_t we use the new format if available. */ |
|
|
if (sizeof (time_t) == 8 && trans_width == 4 |
|
|
&& tzhead.tzh_version[0] != '\0') |
|
|
@@ -445,12 +448,20 @@ |
|
|
goto lose; |
|
|
|
|
|
tzspec_len = st.st_size - off - 1; |
|
|
- char *tzstr = alloca (tzspec_len); |
|
|
+ if (tzspec_len == 0) |
|
|
+ goto lose; |
|
|
+ char *tzstr = malloc (tzspec_len); |
|
|
+ if (tzstr == NULL) |
|
|
+ goto lose; |
|
|
if (getc_unlocked (f) != '\n' |
|
|
|| (fread_unlocked (tzstr, 1, tzspec_len - 1, f) != tzspec_len - 1)) |
|
|
- goto lose; |
|
|
+ { |
|
|
+ free (tzstr); |
|
|
+ goto lose; |
|
|
+ } |
|
|
tzstr[tzspec_len - 1] = '\0'; |
|
|
tzspec = __tzstring (tzstr); |
|
|
+ free (tzstr); |
|
|
} |
|
|
|
|
|
/* Don't use an empty TZ string. */ |
|
|
|
|
|
diff --git a/time/tzset.c b/time/tzset.c |
|
|
--- a/time/tzset.c |
|
|
+++ b/time/tzset.c |
|
|
@@ -1,4 +1,4 @@ |
|
|
-/* Copyright (C) 1991-2012 Free Software Foundation, Inc. |
|
|
+/* Copyright (C) 1991-2016 Free Software Foundation, Inc. |
|
|
This file is part of the GNU C Library. |
|
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or |
|
|
@@ -18,6 +18,7 @@ |
|
|
#include <ctype.h> |
|
|
#include <errno.h> |
|
|
#include <bits/libc-lock.h> |
|
|
+#include <stdbool.h> |
|
|
#include <stddef.h> |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
@@ -54,7 +55,7 @@ |
|
|
/* When to change. */ |
|
|
enum { J0, J1, M } type; /* Interpretation of: */ |
|
|
unsigned short int m, n, d; /* Month, week, day. */ |
|
|
- unsigned int secs; /* Time of day. */ |
|
|
+ int secs; /* Time of day. */ |
|
|
|
|
|
long int offset; /* Seconds east of GMT (west if < 0). */ |
|
|
|
|
|
@@ -82,15 +83,14 @@ |
|
|
|
|
|
static struct tzstring_l *tzstring_list; |
|
|
|
|
|
-/* Allocate a permanent home for S. It will never be moved or deallocated, |
|
|
- but may share space with other strings. |
|
|
- Don't modify the returned string. */ |
|
|
-char * |
|
|
-__tzstring (const char *s) |
|
|
+/* Allocate a permanent home for the first LEN characters of S. It |
|
|
+ will never be moved or deallocated, but may share space with other |
|
|
+ strings. Don't modify the returned string. */ |
|
|
+static char * |
|
|
+__tzstring_len (const char *s, size_t len) |
|
|
{ |
|
|
char *p; |
|
|
struct tzstring_l *t, *u, *new; |
|
|
- size_t len = strlen (s); |
|
|
|
|
|
/* Walk the list and look for a match. If this string is the same |
|
|
as the end of an already-allocated string, it can share space. */ |
|
|
@@ -98,7 +98,7 @@ |
|
|
if (len <= t->len) |
|
|
{ |
|
|
p = &t->data[t->len - len]; |
|
|
- if (strcmp (s, p) == 0) |
|
|
+ if (memcmp (s, p, len) == 0) |
|
|
return p; |
|
|
} |
|
|
|
|
|
@@ -109,7 +109,8 @@ |
|
|
|
|
|
new->next = NULL; |
|
|
new->len = len; |
|
|
- strcpy (new->data, s); |
|
|
+ memcpy (new->data, s, len); |
|
|
+ new->data[len] = '\0'; |
|
|
|
|
|
if (u) |
|
|
u->next = new; |
|
|
@@ -118,6 +119,15 @@ |
|
|
|
|
|
return new->data; |
|
|
} |
|
|
+ |
|
|
+/* Allocate a permanent home for S. It will never be moved or |
|
|
+ deallocated, but may share space with other strings. Don't modify |
|
|
+ the returned string. */ |
|
|
+char * |
|
|
+__tzstring (const char *s) |
|
|
+{ |
|
|
+ return __tzstring_len (s, strlen (s)); |
|
|
+} |
|
|
|
|
|
/* Maximum length of a timezone name. tzset_internal keeps this up to date |
|
|
(never decreasing it) when ! __use_tzfile. |
|
|
@@ -125,7 +135,7 @@ |
|
|
size_t __tzname_cur_max; |
|
|
|
|
|
long int |
|
|
-__tzname_max () |
|
|
+__tzname_max (void) |
|
|
{ |
|
|
__libc_lock_lock (tzset_lock); |
|
|
|
|
|
@@ -164,243 +174,227 @@ |
|
|
return min (ss, 59) + min (mm, 59) * 60 + min (hh, 24) * 60 * 60; |
|
|
} |
|
|
|
|
|
- |
|
|
-/* Parse the POSIX TZ-style string. */ |
|
|
-void |
|
|
-__tzset_parse_tz (tz) |
|
|
- const char *tz; |
|
|
-{ |
|
|
- unsigned short int hh, mm, ss; |
|
|
- |
|
|
- /* Clear out old state and reset to unnamed UTC. */ |
|
|
- memset (tz_rules, '\0', sizeof tz_rules); |
|
|
- tz_rules[0].name = tz_rules[1].name = ""; |
|
|
- |
|
|
- /* Get the standard timezone name. */ |
|
|
- char *tzbuf = strdupa (tz); |
|
|
- |
|
|
- int consumed; |
|
|
- if (sscanf (tz, "%[A-Za-z]%n", tzbuf, &consumed) != 1) |
|
|
- { |
|
|
- /* Check for the quoted version. */ |
|
|
- char *wp = tzbuf; |
|
|
- if (__builtin_expect (*tz++ != '<', 0)) |
|
|
- goto out; |
|
|
- |
|
|
- while (isalnum (*tz) || *tz == '+' || *tz == '-') |
|
|
- *wp++ = *tz++; |
|
|
- if (__builtin_expect (*tz++ != '>' || wp - tzbuf < 3, 0)) |
|
|
- goto out; |
|
|
- *wp = '\0'; |
|
|
+/* Parses the time zone name at *TZP, and writes a pointer to an |
|
|
+ interned string to tz_rules[WHICHRULE].name. On success, advances |
|
|
+ *TZP, and returns true. Returns false otherwise. */ |
|
|
+static bool |
|
|
+parse_tzname (const char **tzp, int whichrule) |
|
|
+{ |
|
|
+ const char *start = *tzp; |
|
|
+ const char *p = start; |
|
|
+ while (('a' <= *p && *p <= 'z') |
|
|
+ || ('A' <= *p && *p <= 'Z')) |
|
|
+ ++p; |
|
|
+ size_t len = p - start; |
|
|
+ if (len < 3) |
|
|
+ { |
|
|
+ p = *tzp; |
|
|
+ if (__glibc_unlikely (*p++ != '<')) |
|
|
+ return false; |
|
|
+ start = p; |
|
|
+ while (('a' <= *p && *p <= 'z') |
|
|
+ || ('A' <= *p && *p <= 'Z') |
|
|
+ || ('0' <= *p && *p <= '9') |
|
|
+ || *p == '+' || *p == '-') |
|
|
+ ++p; |
|
|
+ len = p - start; |
|
|
+ if (*p++ != '>' || len < 3) |
|
|
+ return false; |
|
|
} |
|
|
- else if (__builtin_expect (consumed < 3, 0)) |
|
|
- goto out; |
|
|
- else |
|
|
- tz += consumed; |
|
|
|
|
|
- tz_rules[0].name = __tzstring (tzbuf); |
|
|
+ tz_rules[whichrule].name = __tzstring_len (start, len); |
|
|
+ |
|
|
+ *tzp = p; |
|
|
+ return true; |
|
|
+} |
|
|
|
|
|
- /* Figure out the standard offset from UTC. */ |
|
|
- if (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz))) |
|
|
- goto out; |
|
|
+/* Parses the time zone offset at *TZP, and writes it to |
|
|
+ tz_rules[WHICHRULE].offset. Returns true if the parse was |
|
|
+ successful. */ |
|
|
+static bool |
|
|
+parse_offset (const char **tzp, int whichrule) |
|
|
+{ |
|
|
+ const char *tz = *tzp; |
|
|
+ if (whichrule == 0 |
|
|
+ && (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz)))) |
|
|
+ return false; |
|
|
|
|
|
+ long sign; |
|
|
if (*tz == '-' || *tz == '+') |
|
|
- tz_rules[0].offset = *tz++ == '-' ? 1L : -1L; |
|
|
+ sign = *tz++ == '-' ? 1L : -1L; |
|
|
else |
|
|
- tz_rules[0].offset = -1L; |
|
|
- switch (sscanf (tz, "%hu%n:%hu%n:%hu%n", |
|
|
- &hh, &consumed, &mm, &consumed, &ss, &consumed)) |
|
|
- { |
|
|
- default: |
|
|
- tz_rules[0].offset = 0; |
|
|
- goto out; |
|
|
- case 1: |
|
|
- mm = 0; |
|
|
- case 2: |
|
|
- ss = 0; |
|
|
- case 3: |
|
|
- break; |
|
|
- } |
|
|
- tz_rules[0].offset *= compute_offset (ss, mm, hh); |
|
|
- tz += consumed; |
|
|
- |
|
|
- /* Get the DST timezone name (if any). */ |
|
|
- if (*tz != '\0') |
|
|
- { |
|
|
- if (sscanf (tz, "%[A-Za-z]%n", tzbuf, &consumed) != 1) |
|
|
- { |
|
|
- /* Check for the quoted version. */ |
|
|
- char *wp = tzbuf; |
|
|
- const char *rp = tz; |
|
|
- if (__builtin_expect (*rp++ != '<', 0)) |
|
|
- /* Punt on name, set up the offsets. */ |
|
|
- goto done_names; |
|
|
- |
|
|
- while (isalnum (*rp) || *rp == '+' || *rp == '-') |
|
|
- *wp++ = *rp++; |
|
|
- if (__builtin_expect (*rp++ != '>' || wp - tzbuf < 3, 0)) |
|
|
- /* Punt on name, set up the offsets. */ |
|
|
- goto done_names; |
|
|
- *wp = '\0'; |
|
|
- tz = rp; |
|
|
- } |
|
|
- else if (__builtin_expect (consumed < 3, 0)) |
|
|
- /* Punt on name, set up the offsets. */ |
|
|
- goto done_names; |
|
|
- else |
|
|
- tz += consumed; |
|
|
+ sign = -1L; |
|
|
+ *tzp = tz; |
|
|
|
|
|
- tz_rules[1].name = __tzstring (tzbuf); |
|
|
- |
|
|
- /* Figure out the DST offset from GMT. */ |
|
|
- if (*tz == '-' || *tz == '+') |
|
|
- tz_rules[1].offset = *tz++ == '-' ? 1L : -1L; |
|
|
+ unsigned short int hh; |
|
|
+ unsigned short mm = 0; |
|
|
+ unsigned short ss = 0; |
|
|
+ int consumed = 0; |
|
|
+ if (sscanf (tz, "%hu%n:%hu%n:%hu%n", |
|
|
+ &hh, &consumed, &mm, &consumed, &ss, &consumed) > 0) |
|
|
+ tz_rules[whichrule].offset = sign * compute_offset (ss, mm, hh); |
|
|
+ else |
|
|
+ /* Nothing could be parsed. */ |
|
|
+ if (whichrule == 0) |
|
|
+ { |
|
|
+ /* Standard time defaults to offset zero. */ |
|
|
+ tz_rules[0].offset = 0; |
|
|
+ return false; |
|
|
+ } |
|
|
else |
|
|
- tz_rules[1].offset = -1L; |
|
|
+ /* DST defaults to one hour later than standard time. */ |
|
|
+ tz_rules[1].offset = tz_rules[0].offset + (60 * 60); |
|
|
+ *tzp = tz + consumed; |
|
|
+ return true; |
|
|
+} |
|
|
|
|
|
- switch (sscanf (tz, "%hu%n:%hu%n:%hu%n", |
|
|
- &hh, &consumed, &mm, &consumed, &ss, &consumed)) |
|
|
+/* Parses the standard <-> DST rules at *TZP. Updates |
|
|
+ tz_rule[WHICHRULE]. On success, advances *TZP and returns true. |
|
|
+ Otherwise, returns false. */ |
|
|
+static bool |
|
|
+parse_rule (const char **tzp, int whichrule) |
|
|
+{ |
|
|
+ const char *tz = *tzp; |
|
|
+ tz_rule *tzr = &tz_rules[whichrule]; |
|
|
+ |
|
|
+ /* Ignore comma to support string following the incorrect |
|
|
+ specification in early POSIX.1 printings. */ |
|
|
+ tz += *tz == ','; |
|
|
+ |
|
|
+ /* Get the date of the change. */ |
|
|
+ if (*tz == 'J' || isdigit (*tz)) |
|
|
+ { |
|
|
+ char *end; |
|
|
+ tzr->type = *tz == 'J' ? J1 : J0; |
|
|
+ if (tzr->type == J1 && !isdigit (*++tz)) |
|
|
+ return false; |
|
|
+ unsigned long int d = strtoul (tz, &end, 10); |
|
|
+ if (end == tz || d > 365) |
|
|
+ return false; |
|
|
+ if (tzr->type == J1 && d == 0) |
|
|
+ return false; |
|
|
+ tzr->d = d; |
|
|
+ tz = end; |
|
|
+ } |
|
|
+ else if (*tz == 'M') |
|
|
+ { |
|
|
+ tzr->type = M; |
|
|
+ int consumed; |
|
|
+ if (sscanf (tz, "M%hu.%hu.%hu%n", |
|
|
+ &tzr->m, &tzr->n, &tzr->d, &consumed) != 3 |
|
|
+ || tzr->m < 1 || tzr->m > 12 |
|
|
+ || tzr->n < 1 || tzr->n > 5 || tzr->d > 6) |
|
|
+ return false; |
|
|
+ tz += consumed; |
|
|
+ } |
|
|
+ else if (*tz == '\0') |
|
|
+ { |
|
|
+ /* Daylight time rules in the U.S. are defined in the U.S. Code, |
|
|
+ Title 15, Chapter 6, Subchapter IX - Standard Time. These |
|
|
+ dates were established by Congress in the Energy Policy Act |
|
|
+ of 2005 [Pub. L. no. 109-58, 119 Stat 594 (2005)]. |
|
|
+ Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed |
|
|
+ since 2:00AM is the default]. */ |
|
|
+ tzr->type = M; |
|
|
+ if (tzr == &tz_rules[0]) |
|
|
{ |
|
|
- default: |
|
|
- /* Default to one hour later than standard time. */ |
|
|
- tz_rules[1].offset = tz_rules[0].offset + (60 * 60); |
|
|
- break; |
|
|
- |
|
|
- case 1: |
|
|
- mm = 0; |
|
|
- case 2: |
|
|
- ss = 0; |
|
|
- case 3: |
|
|
- tz_rules[1].offset *= compute_offset (ss, mm, hh); |
|
|
- tz += consumed; |
|
|
- break; |
|
|
+ tzr->m = 3; |
|
|
+ tzr->n = 2; |
|
|
+ tzr->d = 0; |
|
|
} |
|
|
- if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0')) |
|
|
+ else |
|
|
{ |
|
|
- /* There is no rule. See if there is a default rule file. */ |
|
|
- __tzfile_default (tz_rules[0].name, tz_rules[1].name, |
|
|
- tz_rules[0].offset, tz_rules[1].offset); |
|
|
- if (__use_tzfile) |
|
|
- { |
|
|
- free (old_tz); |
|
|
- old_tz = NULL; |
|
|
- return; |
|
|
- } |
|
|
+ tzr->m = 11; |
|
|
+ tzr->n = 1; |
|
|
+ tzr->d = 0; |
|
|
} |
|
|
} |
|
|
else |
|
|
- { |
|
|
- /* There is no DST. */ |
|
|
- tz_rules[1].name = tz_rules[0].name; |
|
|
- tz_rules[1].offset = tz_rules[0].offset; |
|
|
- goto out; |
|
|
+ return false; |
|
|
+ |
|
|
+ if (*tz != '\0' && *tz != '/' && *tz != ',') |
|
|
+ return false; |
|
|
+ else if (*tz == '/') |
|
|
+ { |
|
|
+ /* Get the time of day of the change. */ |
|
|
+ int negative; |
|
|
+ ++tz; |
|
|
+ if (*tz == '\0') |
|
|
+ return false; |
|
|
+ negative = *tz == '-'; |
|
|
+ tz += negative; |
|
|
+ /* Default to 2:00 AM. */ |
|
|
+ unsigned short hh = 2; |
|
|
+ unsigned short mm = 0; |
|
|
+ unsigned short ss = 0; |
|
|
+ int consumed = 0; |
|
|
+ sscanf (tz, "%hu%n:%hu%n:%hu%n", |
|
|
+ &hh, &consumed, &mm, &consumed, &ss, &consumed);; |
|
|
+ tz += consumed; |
|
|
+ tzr->secs = (negative ? -1 : 1) * ((hh * 60 * 60) + (mm * 60) + ss); |
|
|
} |
|
|
+ else |
|
|
+ /* Default to 2:00 AM. */ |
|
|
+ tzr->secs = 2 * 60 * 60; |
|
|
|
|
|
- done_names: |
|
|
- /* Figure out the standard <-> DST rules. */ |
|
|
- for (unsigned int whichrule = 0; whichrule < 2; ++whichrule) |
|
|
- { |
|
|
- register tz_rule *tzr = &tz_rules[whichrule]; |
|
|
+ tzr->computed_for = -1; |
|
|
+ *tzp = tz; |
|
|
+ return true; |
|
|
+} |
|
|
|
|
|
- /* Ignore comma to support string following the incorrect |
|
|
- specification in early POSIX.1 printings. */ |
|
|
- tz += *tz == ','; |
|
|
+/* Parse the POSIX TZ-style string. */ |
|
|
+void |
|
|
+__tzset_parse_tz (const char *tz) |
|
|
+{ |
|
|
+ /* Clear out old state and reset to unnamed UTC. */ |
|
|
+ memset (tz_rules, '\0', sizeof tz_rules); |
|
|
+ tz_rules[0].name = tz_rules[1].name = ""; |
|
|
|
|
|
- /* Get the date of the change. */ |
|
|
- if (*tz == 'J' || isdigit (*tz)) |
|
|
- { |
|
|
- char *end; |
|
|
- tzr->type = *tz == 'J' ? J1 : J0; |
|
|
- if (tzr->type == J1 && !isdigit (*++tz)) |
|
|
- goto out; |
|
|
- unsigned long int d = strtoul (tz, &end, 10); |
|
|
- if (end == tz || d > 365) |
|
|
- goto out; |
|
|
- if (tzr->type == J1 && d == 0) |
|
|
- goto out; |
|
|
- tzr->d = d; |
|
|
- tz = end; |
|
|
- } |
|
|
- else if (*tz == 'M') |
|
|
- { |
|
|
- tzr->type = M; |
|
|
- if (sscanf (tz, "M%hu.%hu.%hu%n", |
|
|
- &tzr->m, &tzr->n, &tzr->d, &consumed) != 3 |
|
|
- || tzr->m < 1 || tzr->m > 12 |
|
|
- || tzr->n < 1 || tzr->n > 5 || tzr->d > 6) |
|
|
- goto out; |
|
|
- tz += consumed; |
|
|
- } |
|
|
- else if (*tz == '\0') |
|
|
+ /* Get the standard timezone name. */ |
|
|
+ if (parse_tzname (&tz, 0) && parse_offset (&tz, 0)) |
|
|
+ { |
|
|
+ /* Get the DST timezone name (if any). */ |
|
|
+ if (*tz != '\0') |
|
|
{ |
|
|
- /* Daylight time rules in the U.S. are defined in the |
|
|
- U.S. Code, Title 15, Chapter 6, Subchapter IX - Standard |
|
|
- Time. These dates were established by Congress in the |
|
|
- Energy Policy Act of 2005 [Pub. L. no. 109-58, 119 Stat 594 |
|
|
- (2005)]. |
|
|
- Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed |
|
|
- since 2:00AM is the default]. */ |
|
|
- tzr->type = M; |
|
|
- if (tzr == &tz_rules[0]) |
|
|
+ if (parse_tzname (&tz, 1)) |
|
|
{ |
|
|
- tzr->m = 3; |
|
|
- tzr->n = 2; |
|
|
- tzr->d = 0; |
|
|
- } |
|
|
- else |
|
|
- { |
|
|
- tzr->m = 11; |
|
|
- tzr->n = 1; |
|
|
- tzr->d = 0; |
|
|
+ parse_offset (&tz, 1); |
|
|
+ if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0')) |
|
|
+ { |
|
|
+ /* There is no rule. See if there is a default rule |
|
|
+ file. */ |
|
|
+ __tzfile_default (tz_rules[0].name, tz_rules[1].name, |
|
|
+ tz_rules[0].offset, tz_rules[1].offset); |
|
|
+ if (__use_tzfile) |
|
|
+ { |
|
|
+ free (old_tz); |
|
|
+ old_tz = NULL; |
|
|
+ return; |
|
|
+ } |
|
|
+ } |
|
|
} |
|
|
+ /* Figure out the standard <-> DST rules. */ |
|
|
+ if (parse_rule (&tz, 0)) |
|
|
+ parse_rule (&tz, 1); |
|
|
} |
|
|
else |
|
|
- goto out; |
|
|
- |
|
|
- if (*tz != '\0' && *tz != '/' && *tz != ',') |
|
|
- goto out; |
|
|
- else if (*tz == '/') |
|
|
{ |
|
|
- /* Get the time of day of the change. */ |
|
|
- ++tz; |
|
|
- if (*tz == '\0') |
|
|
- goto out; |
|
|
- consumed = 0; |
|
|
- switch (sscanf (tz, "%hu%n:%hu%n:%hu%n", |
|
|
- &hh, &consumed, &mm, &consumed, &ss, &consumed)) |
|
|
- { |
|
|
- default: |
|
|
- hh = 2; /* Default to 2:00 AM. */ |
|
|
- case 1: |
|
|
- mm = 0; |
|
|
- case 2: |
|
|
- ss = 0; |
|
|
- case 3: |
|
|
- break; |
|
|
- } |
|
|
- tz += consumed; |
|
|
- tzr->secs = (hh * 60 * 60) + (mm * 60) + ss; |
|
|
+ /* There is no DST. */ |
|
|
+ tz_rules[1].name = tz_rules[0].name; |
|
|
+ tz_rules[1].offset = tz_rules[0].offset; |
|
|
} |
|
|
- else |
|
|
- /* Default to 2:00 AM. */ |
|
|
- tzr->secs = 2 * 60 * 60; |
|
|
- |
|
|
- tzr->computed_for = -1; |
|
|
} |
|
|
|
|
|
- out: |
|
|
update_vars (); |
|
|
} |
|
|
|
|
|
/* Interpret the TZ envariable. */ |
|
|
static void |
|
|
internal_function |
|
|
-tzset_internal (always, explicit) |
|
|
- int always; |
|
|
- int explicit; |
|
|
+tzset_internal (int always, int explicit) |
|
|
{ |
|
|
static int is_initialized; |
|
|
- register const char *tz; |
|
|
+ const char *tz; |
|
|
|
|
|
if (is_initialized && !always) |
|
|
return; |
|
|
@@ -467,11 +461,9 @@ |
|
|
put it in RULE->change, saving YEAR in RULE->computed_for. */ |
|
|
static void |
|
|
internal_function |
|
|
-compute_change (rule, year) |
|
|
- tz_rule *rule; |
|
|
- int year; |
|
|
+compute_change (tz_rule *rule, int year) |
|
|
{ |
|
|
- register time_t t; |
|
|
+ time_t t; |
|
|
|
|
|
if (year != -1 && rule->computed_for == year) |
|
|
/* Operations on times in 2 BC will be slower. Oh well. */ |
|
|
@@ -558,10 +550,7 @@ |
|
|
`__timezone', and `__daylight' accordingly. */ |
|
|
void |
|
|
internal_function |
|
|
-__tz_compute (timer, tm, use_localtime) |
|
|
- time_t timer; |
|
|
- struct tm *tm; |
|
|
- int use_localtime; |
|
|
+__tz_compute (time_t timer, struct tm *tm, int use_localtime) |
|
|
{ |
|
|
compute_change (&tz_rules[0], 1900 + tm->tm_year); |
|
|
compute_change (&tz_rules[1], 1900 + tm->tm_year); |
|
|
@@ -641,6 +630,8 @@ |
|
|
leap_extra_secs = 0; |
|
|
} |
|
|
|
|
|
+ __libc_lock_unlock (tzset_lock); |
|
|
+ |
|
|
if (tp) |
|
|
{ |
|
|
if (! use_localtime) |
|
|
@@ -656,8 +647,6 @@ |
|
|
tp = NULL; |
|
|
} |
|
|
|
|
|
- __libc_lock_unlock (tzset_lock); |
|
|
- |
|
|
return tp; |
|
|
} |
|
|
|
|
|
diff --git a/timezone/Makefile b/timezone/Makefile |
|
|
index 17424b8..5f18545 100644 |
|
|
--- a/timezone/Makefile |
|
|
+++ b/timezone/Makefile |
|
|
@@ -23,7 +23,7 @@ |
|
|
extra-objs := scheck.o ialloc.o |
|
|
|
|
|
others := zdump zic |
|
|
-tests := test-tz tst-timezone |
|
|
+tests := test-tz tst-timezone tst-tzset |
|
|
|
|
|
# pacificnew doesn't compile; if it is to be used, it should be included in |
|
|
# northamerica. |
|
|
@@ -87,9 +87,11 @@ |
|
|
Australia/Melbourne \ |
|
|
America/Sao_Paulo Asia/Tokyo \ |
|
|
Europe/London) |
|
|
+$(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4) |
|
|
|
|
|
test-tz-ENV = TZDIR=$(testdata) |
|
|
tst-timezone-ENV = TZDIR=$(testdata) |
|
|
+tst-tzset-ENV = TZDIR=$(testdata) |
|
|
|
|
|
# Note this must come second in the deps list for $(built-program-cmd) to work. |
|
|
zic-deps = $(objpfx)zic $(leapseconds) yearistype |
|
|
@@ -111,6 +113,8 @@ |
|
|
$(testdata)/Asia/Tokyo: asia $(zic-deps) |
|
|
$(build-testdata) |
|
|
|
|
|
+$(testdata)/XT%: testdata/XT% |
|
|
+ cp $< $@ |
|
|
|
|
|
$(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make |
|
|
sed -e 's|/bin/bash|$(KSH)|g' \ |
|
|
diff --git a/timezone/README b/timezone/README |
|
|
index 7a5e31c..2268f8e 100644 |
|
|
--- a/timezone/README |
|
|
+++ b/timezone/README |
|
|
@@ -15,3 +15,6 @@ version of the tzcode and tzdata packages. |
|
|
|
|
|
These packages may be found at ftp://ftp.iana.org/tz/releases/. Commentary |
|
|
should be addressed to tz@iana.org. |
|
|
+ |
|
|
+The subdirectory testdata contains manually edited data files for |
|
|
+regression testing purposes. |
|
|
--- /dev/null |
|
|
+++ b/timezone/tst-tzset.c |
|
|
@@ -0,0 +1,200 @@ |
|
|
+/* tzset tests with crafted time zone data. |
|
|
+ Copyright (C) 2015 Free Software Foundation, Inc. |
|
|
+ |
|
|
+ The GNU C Library is free software; you can redistribute it and/or |
|
|
+ modify it under the terms of the GNU Lesser General Public |
|
|
+ License as published by the Free Software Foundation; either |
|
|
+ version 2.1 of the License, or (at your option) any later version. |
|
|
+ |
|
|
+ The GNU C Library is distributed in the hope that it will be useful, |
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
|
+ Lesser General Public License for more details. |
|
|
+ |
|
|
+ You should have received a copy of the GNU Lesser General Public |
|
|
+ License along with the GNU C Library; if not, see |
|
|
+ <http://www.gnu.org/licenses/>. */ |
|
|
+ |
|
|
+#define _GNU_SOURCE 1 |
|
|
+ |
|
|
+#include <errno.h> |
|
|
+#include <stdio.h> |
|
|
+#include <stdlib.h> |
|
|
+#include <string.h> |
|
|
+#include <sys/resource.h> |
|
|
+#include <time.h> |
|
|
+#include <unistd.h> |
|
|
+ |
|
|
+static int do_test (void); |
|
|
+#define TEST_FUNCTION do_test () |
|
|
+#include "../test-skeleton.c" |
|
|
+ |
|
|
+/* Returns the name of a large TZ file. */ |
|
|
+static char * |
|
|
+create_tz_file (off64_t size) |
|
|
+{ |
|
|
+ char *path; |
|
|
+ int fd = create_temp_file ("tst-tzset-", &path); |
|
|
+ if (fd < 0) |
|
|
+ exit (1); |
|
|
+ |
|
|
+ // Reopen for large-file support. |
|
|
+ close (fd); |
|
|
+ fd = open64 (path, O_WRONLY); |
|
|
+ if (fd < 0) |
|
|
+ { |
|
|
+ printf ("open64 (%s) failed: %m\n", path); |
|
|
+ exit (1); |
|
|
+ } |
|
|
+ |
|
|
+ static const char data[] = { |
|
|
+ 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, |
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, |
|
|
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, |
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, |
|
|
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, |
|
|
+ 0x00, 0x00, 0x58, 0x54, 0x47, 0x00, 0x00, 0x00, |
|
|
+ 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, |
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, |
|
|
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, |
|
|
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, |
|
|
+ 0x00, 0x00, 0x00, 0x04, 0xf8, 0x00, 0x00, 0x00, |
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
+ 0x00, 0x00, 0x00, 0x58, 0x54, 0x47, 0x00, 0x00, |
|
|
+ 0x00, 0x0a, 0x58, 0x54, 0x47, 0x30, 0x0a |
|
|
+ }; |
|
|
+ ssize_t ret = write (fd, data, sizeof (data)); |
|
|
+ if (ret < 0) |
|
|
+ { |
|
|
+ printf ("write failed: %m\n"); |
|
|
+ exit (1); |
|
|
+ } |
|
|
+ if ((size_t) ret != sizeof (data)) |
|
|
+ { |
|
|
+ printf ("Short write\n"); |
|
|
+ exit (1); |
|
|
+ } |
|
|
+ if (lseek64 (fd, size, SEEK_CUR) < 0) |
|
|
+ { |
|
|
+ printf ("lseek failed: %m\n"); |
|
|
+ close (fd); |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ if (write (fd, "", 1) != 1) |
|
|
+ { |
|
|
+ printf ("Single-byte write failed\n"); |
|
|
+ close (fd); |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ if (close (fd) != 0) |
|
|
+ { |
|
|
+ printf ("close failed: %m\n"); |
|
|
+ exit (1); |
|
|
+ } |
|
|
+ return path; |
|
|
+} |
|
|
+ |
|
|
+static void |
|
|
+test_tz_file (off64_t size) |
|
|
+{ |
|
|
+ char *path = create_tz_file (size); |
|
|
+ if (setenv ("TZ", path, 1) < 0) |
|
|
+ { |
|
|
+ printf ("setenv failed: %m\n"); |
|
|
+ exit (1); |
|
|
+ } |
|
|
+ tzset (); |
|
|
+ free (path); |
|
|
+} |
|
|
+ |
|
|
+static int |
|
|
+do_test (void) |
|
|
+{ |
|
|
+ /* Limit the size of the process. Otherwise, some of the tests will |
|
|
+ consume a lot of resources. */ |
|
|
+ { |
|
|
+ struct rlimit limit; |
|
|
+ if (getrlimit (RLIMIT_AS, &limit) != 0) |
|
|
+ { |
|
|
+ printf ("getrlimit (RLIMIT_AS) failed: %m\n"); |
|
|
+ return 1; |
|
|
+ } |
|
|
+ long target = 512 * 1024 * 1024; |
|
|
+ if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target) |
|
|
+ { |
|
|
+ limit.rlim_cur = 512 * 1024 * 1024; |
|
|
+ if (setrlimit (RLIMIT_AS, &limit) != 0) |
|
|
+ { |
|
|
+ printf ("setrlimit (RLIMIT_AS) failed: %m\n"); |
|
|
+ return 1; |
|
|
+ } |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ int errors = 0; |
|
|
+ for (int i = 1; i <= 4; ++i) |
|
|
+ { |
|
|
+ char tz[16]; |
|
|
+ snprintf (tz, sizeof (tz), "XT%d", i); |
|
|
+ if (setenv ("TZ", tz, 1) < 0) |
|
|
+ { |
|
|
+ printf ("setenv failed: %m\n"); |
|
|
+ return 1; |
|
|
+ } |
|
|
+ tzset (); |
|
|
+ if (strcmp (tzname[0], tz) == 0) |
|
|
+ { |
|
|
+ printf ("Unexpected success for %s\n", tz); |
|
|
+ ++errors; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ /* Large TZ files. */ |
|
|
+ |
|
|
+ /* This will succeed on 64-bit architectures, and fail on 32-bit |
|
|
+ architectures. It used to crash on 32-bit. */ |
|
|
+ test_tz_file (64 * 1024 * 1024); |
|
|
+ |
|
|
+ /* This will fail on 64-bit and 32-bit architectures. It used to |
|
|
+ cause a test timeout on 64-bit and crash on 32-bit if the TZ file |
|
|
+ open succeeded for some reason (it does not use O_LARGEFILE in |
|
|
+ regular builds). */ |
|
|
+ test_tz_file (4LL * 1024 * 1024 * 1024 - 6); |
|
|
+ |
|
|
+ /* Large TZ variables. */ |
|
|
+ { |
|
|
+ size_t length = 64 * 1024 * 1024; |
|
|
+ char *value = malloc (length + 1); |
|
|
+ if (value == NULL) |
|
|
+ { |
|
|
+ puts ("malloc failed: %m"); |
|
|
+ return 1; |
|
|
+ } |
|
|
+ value[length] = '\0'; |
|
|
+ |
|
|
+ memset (value, ' ', length); |
|
|
+ value[0] = 'U'; |
|
|
+ value[1] = 'T'; |
|
|
+ value[2] = 'C'; |
|
|
+ if (setenv ("TZ", value, 1) < 0) |
|
|
+ { |
|
|
+ printf ("setenv failed: %m\n"); |
|
|
+ return 1; |
|
|
+ } |
|
|
+ tzset (); |
|
|
+ |
|
|
+ memset (value, '0', length); |
|
|
+ value[0] = '<'; |
|
|
+ value[length - 1] = '>'; |
|
|
+ if (setenv ("TZ", value, 1) < 0) |
|
|
+ { |
|
|
+ printf ("setenv failed: %m\n"); |
|
|
+ return 1; |
|
|
+ } |
|
|
+ tzset (); |
|
|
+ } |
|
|
+ |
|
|
+ return errors > 0; |
|
|
+} |
|
|
diff --git a/timezone/Makefile b/timezone/Makefile |
|
|
index 81d4a3e..bfb3463 100644 |
|
|
--- a/timezone/Makefile |
|
|
+++ b/timezone/Makefile |
|
|
@@ -113,6 +113,7 @@ $(testdata)/Asia/Tokyo: asia $(zic-deps) |
|
|
$(build-testdata) |
|
|
|
|
|
$(testdata)/XT%: testdata/XT% |
|
|
+ $(make-target-directory) |
|
|
cp $< $@ |
|
|
|
|
|
$(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make |
|
|
diff -Nrup -a a/timezone/testdata/XT1 b/timezone/testdata/XT1 |
|
|
--- a/timezone/testdata/XT1 1969-12-31 19:00:00.000000000 -0500 |
|
|
+++ b/timezone/testdata/XT1 2017-09-14 10:19:11.382923956 -0400 |
|
|
@@ -0,0 +1,2 @@ |
|
|
+TZif2 |