Make time zone file parser more robust [BZ #17715]
[glibc.git] / time / tzset.c
blobd115bae0bef91c07f1f604d6920cc35ea49fd60c
1 /* Copyright (C) 1991-2015 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
18 #include <ctype.h>
19 #include <errno.h>
20 #include <bits/libc-lock.h>
21 #include <stdbool.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
29 #define NOID
30 #include <timezone/tzfile.h>
32 char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
33 int __daylight = 0;
34 long int __timezone = 0L;
36 weak_alias (__tzname, tzname)
37 weak_alias (__daylight, daylight)
38 weak_alias (__timezone, timezone)
40 /* This locks all the state variables in tzfile.c and this file. */
41 __libc_lock_define_initialized (static, tzset_lock)
44 #define min(a, b) ((a) < (b) ? (a) : (b))
45 #define max(a, b) ((a) > (b) ? (a) : (b))
46 #define sign(x) ((x) < 0 ? -1 : 1)
49 /* This structure contains all the information about a
50 timezone given in the POSIX standard TZ envariable. */
51 typedef struct
53 const char *name;
55 /* When to change. */
56 enum { J0, J1, M } type; /* Interpretation of: */
57 unsigned short int m, n, d; /* Month, week, day. */
58 int secs; /* Time of day. */
60 long int offset; /* Seconds east of GMT (west if < 0). */
62 /* We cache the computed time of change for a
63 given year so we don't have to recompute it. */
64 time_t change; /* When to change to this zone. */
65 int computed_for; /* Year above is computed for. */
66 } tz_rule;
68 /* tz_rules[0] is standard, tz_rules[1] is daylight. */
69 static tz_rule tz_rules[2];
72 static void compute_change (tz_rule *rule, int year) __THROW internal_function;
73 static void tzset_internal (int always, int explicit)
74 __THROW internal_function;
76 /* List of buffers containing time zone strings. */
77 struct tzstring_l
79 struct tzstring_l *next;
80 size_t len; /* strlen(data) - doesn't count terminating NUL! */
81 char data[0];
84 static struct tzstring_l *tzstring_list;
86 /* Allocate a permanent home for the first LEN characters of S. It
87 will never be moved or deallocated, but may share space with other
88 strings. Don't modify the returned string. */
89 static char *
90 __tzstring_len (const char *s, size_t len)
92 char *p;
93 struct tzstring_l *t, *u, *new;
95 /* Walk the list and look for a match. If this string is the same
96 as the end of an already-allocated string, it can share space. */
97 for (u = t = tzstring_list; t; u = t, t = t->next)
98 if (len <= t->len)
100 p = &t->data[t->len - len];
101 if (memcmp (s, p, len) == 0)
102 return p;
105 /* Not found; allocate a new buffer. */
106 new = malloc (sizeof (struct tzstring_l) + len + 1);
107 if (!new)
108 return NULL;
110 new->next = NULL;
111 new->len = len;
112 memcpy (new->data, s, len);
113 new->data[len] = '\0';
115 if (u)
116 u->next = new;
117 else
118 tzstring_list = new;
120 return new->data;
123 /* Allocate a permanent home for S. It will never be moved or
124 deallocated, but may share space with other strings. Don't modify
125 the returned string. */
126 char *
127 __tzstring (const char *s)
129 return __tzstring_len (s, strlen (s));
132 /* Maximum length of a timezone name. tzset_internal keeps this up to date
133 (never decreasing it) when ! __use_tzfile.
134 tzfile.c keeps it up to date when __use_tzfile. */
135 size_t __tzname_cur_max;
137 long int
138 __tzname_max (void)
140 __libc_lock_lock (tzset_lock);
142 tzset_internal (0, 0);
144 __libc_lock_unlock (tzset_lock);
146 return __tzname_cur_max;
149 static char *old_tz;
151 static void
152 internal_function
153 update_vars (void)
155 __daylight = tz_rules[0].offset != tz_rules[1].offset;
156 __timezone = -tz_rules[0].offset;
157 __tzname[0] = (char *) tz_rules[0].name;
158 __tzname[1] = (char *) tz_rules[1].name;
160 /* Keep __tzname_cur_max up to date. */
161 size_t len0 = strlen (__tzname[0]);
162 size_t len1 = strlen (__tzname[1]);
163 if (len0 > __tzname_cur_max)
164 __tzname_cur_max = len0;
165 if (len1 > __tzname_cur_max)
166 __tzname_cur_max = len1;
170 static unsigned int
171 __attribute_noinline__
172 compute_offset (unsigned int ss, unsigned int mm, unsigned int hh)
174 return min (ss, 59) + min (mm, 59) * 60 + min (hh, 24) * 60 * 60;
177 /* Parses the time zone name at *TZP, and writes a pointer to an
178 interned string to tz_rules[WHICHRULE].name. On success, advances
179 *TZP, and returns true. Returns false otherwise. */
180 static bool
181 parse_tzname (const char **tzp, int whichrule)
183 const char *start = *tzp;
184 const char *p = start;
185 while (('a' <= *p && *p <= 'z')
186 || ('A' <= *p && *p <= 'Z'))
187 ++p;
188 size_t len = p - start;
189 if (len < 3)
191 p = *tzp;
192 if (__glibc_unlikely (*p++ != '<'))
193 return false;
194 start = p;
195 while (('a' <= *p && *p <= 'z')
196 || ('A' <= *p && *p <= 'Z')
197 || ('0' <= *p && *p <= '9')
198 || *p == '+' || *p == '-')
199 ++p;
200 len = p - start;
201 if (*p++ != '>' || len < 3)
202 return false;
204 tz_rules[whichrule].name = __tzstring_len (start, len);
205 *tzp = p;
206 return true;
209 /* Parses the time zone offset at *TZP, and writes it to
210 tz_rules[WHICHRULE].offset. Returns true if the parse was
211 successful. */
212 static bool
213 parse_offset (const char **tzp, int whichrule)
215 const char *tz = *tzp;
216 if (whichrule == 0
217 && (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz))))
218 return false;
220 long sign;
221 if (*tz == '-' || *tz == '+')
222 sign = *tz++ == '-' ? 1L : -1L;
223 else
224 sign = -1L;
225 *tzp = tz;
227 unsigned short int hh;
228 unsigned short mm = 0;
229 unsigned short ss = 0;
230 int consumed = 0;
231 if (sscanf (tz, "%hu%n:%hu%n:%hu%n",
232 &hh, &consumed, &mm, &consumed, &ss, &consumed) > 0)
233 tz_rules[whichrule].offset = sign * compute_offset (ss, mm, hh);
234 else
235 /* Nothing could be parsed. */
236 if (whichrule == 0)
238 /* Standard time defaults to offset zero. */
239 tz_rules[0].offset = 0;
240 return false;
242 else
243 /* DST defaults to one hour later than standard time. */
244 tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
245 *tzp = tz + consumed;
246 return true;
249 /* Parses the standard <-> DST rules at *TZP. Updates
250 tz_rule[WHICHRULE]. On success, advances *TZP and returns true.
251 Otherwise, returns false. */
252 static bool
253 parse_rule (const char **tzp, int whichrule)
255 const char *tz = *tzp;
256 tz_rule *tzr = &tz_rules[whichrule];
258 /* Ignore comma to support string following the incorrect
259 specification in early POSIX.1 printings. */
260 tz += *tz == ',';
262 /* Get the date of the change. */
263 if (*tz == 'J' || isdigit (*tz))
265 char *end;
266 tzr->type = *tz == 'J' ? J1 : J0;
267 if (tzr->type == J1 && !isdigit (*++tz))
268 return false;
269 unsigned long int d = strtoul (tz, &end, 10);
270 if (end == tz || d > 365)
271 return false;
272 if (tzr->type == J1 && d == 0)
273 return false;
274 tzr->d = d;
275 tz = end;
277 else if (*tz == 'M')
279 tzr->type = M;
280 int consumed;
281 if (sscanf (tz, "M%hu.%hu.%hu%n",
282 &tzr->m, &tzr->n, &tzr->d, &consumed) != 3
283 || tzr->m < 1 || tzr->m > 12
284 || tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
285 return false;
286 tz += consumed;
288 else if (*tz == '\0')
290 /* Daylight time rules in the U.S. are defined in the U.S. Code,
291 Title 15, Chapter 6, Subchapter IX - Standard Time. These
292 dates were established by Congress in the Energy Policy Act
293 of 2005 [Pub. L. no. 109-58, 119 Stat 594 (2005)].
294 Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed
295 since 2:00AM is the default]. */
296 tzr->type = M;
297 if (tzr == &tz_rules[0])
299 tzr->m = 3;
300 tzr->n = 2;
301 tzr->d = 0;
303 else
305 tzr->m = 11;
306 tzr->n = 1;
307 tzr->d = 0;
310 else
311 return false;
313 if (*tz != '\0' && *tz != '/' && *tz != ',')
314 return false;
315 else if (*tz == '/')
317 /* Get the time of day of the change. */
318 int negative;
319 ++tz;
320 if (*tz == '\0')
321 return false;
322 negative = *tz == '-';
323 tz += negative;
324 /* Default to 2:00 AM. */
325 unsigned short hh = 2;
326 unsigned short mm = 0;
327 unsigned short ss = 0;
328 int consumed = 0;
329 sscanf (tz, "%hu%n:%hu%n:%hu%n",
330 &hh, &consumed, &mm, &consumed, &ss, &consumed);;
331 tz += consumed;
332 tzr->secs = (negative ? -1 : 1) * ((hh * 60 * 60) + (mm * 60) + ss);
334 else
335 /* Default to 2:00 AM. */
336 tzr->secs = 2 * 60 * 60;
338 tzr->computed_for = -1;
339 *tzp = tz;
340 return true;
343 /* Parse the POSIX TZ-style string. */
344 void
345 __tzset_parse_tz (const char *tz)
347 /* Clear out old state and reset to unnamed UTC. */
348 memset (tz_rules, '\0', sizeof tz_rules);
349 tz_rules[0].name = tz_rules[1].name = "";
351 /* Get the standard timezone name. */
352 if (parse_tzname (&tz, 0) && parse_offset (&tz, 0))
354 /* Get the DST timezone name (if any). */
355 if (*tz != '\0')
357 if (parse_tzname (&tz, 1))
359 parse_offset (&tz, 1);
360 if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
362 /* There is no rule. See if there is a default rule
363 file. */
364 __tzfile_default (tz_rules[0].name, tz_rules[1].name,
365 tz_rules[0].offset, tz_rules[1].offset);
366 if (__use_tzfile)
368 free (old_tz);
369 old_tz = NULL;
370 return;
374 /* Figure out the standard <-> DST rules. */
375 if (parse_rule (&tz, 0))
376 parse_rule (&tz, 1);
378 else
380 /* There is no DST. */
381 tz_rules[1].name = tz_rules[0].name;
382 tz_rules[1].offset = tz_rules[0].offset;
386 update_vars ();
389 /* Interpret the TZ envariable. */
390 static void
391 internal_function
392 tzset_internal (always, explicit)
393 int always;
394 int explicit;
396 static int is_initialized;
397 const char *tz;
399 if (is_initialized && !always)
400 return;
401 is_initialized = 1;
403 /* Examine the TZ environment variable. */
404 tz = getenv ("TZ");
405 if (tz == NULL && !explicit)
406 /* Use the site-wide default. This is a file name which means we
407 would not see changes to the file if we compare only the file
408 name for change. We want to notice file changes if tzset() has
409 been called explicitly. Leave TZ as NULL in this case. */
410 tz = TZDEFAULT;
411 if (tz && *tz == '\0')
412 /* User specified the empty string; use UTC explicitly. */
413 tz = "Universal";
415 /* A leading colon means "implementation defined syntax".
416 We ignore the colon and always use the same algorithm:
417 try a data file, and if none exists parse the 1003.1 syntax. */
418 if (tz && *tz == ':')
419 ++tz;
421 /* Check whether the value changed since the last run. */
422 if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
423 /* No change, simply return. */
424 return;
426 if (tz == NULL)
427 /* No user specification; use the site-wide default. */
428 tz = TZDEFAULT;
430 tz_rules[0].name = NULL;
431 tz_rules[1].name = NULL;
433 /* Save the value of `tz'. */
434 free (old_tz);
435 old_tz = tz ? __strdup (tz) : NULL;
437 /* Try to read a data file. */
438 __tzfile_read (tz, 0, NULL);
439 if (__use_tzfile)
440 return;
442 /* No data file found. Default to UTC if nothing specified. */
444 if (tz == NULL || *tz == '\0'
445 || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
447 memset (tz_rules, '\0', sizeof tz_rules);
448 tz_rules[0].name = tz_rules[1].name = "UTC";
449 if (J0 != 0)
450 tz_rules[0].type = tz_rules[1].type = J0;
451 tz_rules[0].change = tz_rules[1].change = (time_t) -1;
452 update_vars ();
453 return;
456 __tzset_parse_tz (tz);
459 /* Figure out the exact time (as a time_t) in YEAR
460 when the change described by RULE will occur and
461 put it in RULE->change, saving YEAR in RULE->computed_for. */
462 static void
463 internal_function
464 compute_change (rule, year)
465 tz_rule *rule;
466 int year;
468 time_t t;
470 if (year != -1 && rule->computed_for == year)
471 /* Operations on times in 2 BC will be slower. Oh well. */
472 return;
474 /* First set T to January 1st, 0:00:00 GMT in YEAR. */
475 if (year > 1970)
476 t = ((year - 1970) * 365
477 + /* Compute the number of leapdays between 1970 and YEAR
478 (exclusive). There is a leapday every 4th year ... */
479 + ((year - 1) / 4 - 1970 / 4)
480 /* ... except every 100th year ... */
481 - ((year - 1) / 100 - 1970 / 100)
482 /* ... but still every 400th year. */
483 + ((year - 1) / 400 - 1970 / 400)) * SECSPERDAY;
484 else
485 t = 0;
487 switch (rule->type)
489 case J1:
490 /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
491 In non-leap years, or if the day number is 59 or less, just
492 add SECSPERDAY times the day number-1 to the time of
493 January 1, midnight, to get the day. */
494 t += (rule->d - 1) * SECSPERDAY;
495 if (rule->d >= 60 && __isleap (year))
496 t += SECSPERDAY;
497 break;
499 case J0:
500 /* n - Day of year.
501 Just add SECSPERDAY times the day number to the time of Jan 1st. */
502 t += rule->d * SECSPERDAY;
503 break;
505 case M:
506 /* Mm.n.d - Nth "Dth day" of month M. */
508 unsigned int i;
509 int d, m1, yy0, yy1, yy2, dow;
510 const unsigned short int *myday =
511 &__mon_yday[__isleap (year)][rule->m];
513 /* First add SECSPERDAY for each day in months before M. */
514 t += myday[-1] * SECSPERDAY;
516 /* Use Zeller's Congruence to get day-of-week of first day of month. */
517 m1 = (rule->m + 9) % 12 + 1;
518 yy0 = (rule->m <= 2) ? (year - 1) : year;
519 yy1 = yy0 / 100;
520 yy2 = yy0 % 100;
521 dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
522 if (dow < 0)
523 dow += 7;
525 /* DOW is the day-of-week of the first day of the month. Get the
526 day-of-month (zero-origin) of the first DOW day of the month. */
527 d = rule->d - dow;
528 if (d < 0)
529 d += 7;
530 for (i = 1; i < rule->n; ++i)
532 if (d + 7 >= (int) myday[0] - myday[-1])
533 break;
534 d += 7;
537 /* D is the day-of-month (zero-origin) of the day we want. */
538 t += d * SECSPERDAY;
540 break;
543 /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
544 Just add the time of day and local offset from GMT, and we're done. */
546 rule->change = t - rule->offset + rule->secs;
547 rule->computed_for = year;
551 /* Figure out the correct timezone for TM and set `__tzname',
552 `__timezone', and `__daylight' accordingly. */
553 void
554 internal_function
555 __tz_compute (timer, tm, use_localtime)
556 time_t timer;
557 struct tm *tm;
558 int use_localtime;
560 compute_change (&tz_rules[0], 1900 + tm->tm_year);
561 compute_change (&tz_rules[1], 1900 + tm->tm_year);
563 if (use_localtime)
565 int isdst;
567 /* We have to distinguish between northern and southern
568 hemisphere. For the latter the daylight saving time
569 ends in the next year. */
570 if (__builtin_expect (tz_rules[0].change
571 > tz_rules[1].change, 0))
572 isdst = (timer < tz_rules[1].change
573 || timer >= tz_rules[0].change);
574 else
575 isdst = (timer >= tz_rules[0].change
576 && timer < tz_rules[1].change);
577 tm->tm_isdst = isdst;
578 tm->tm_zone = __tzname[isdst];
579 tm->tm_gmtoff = tz_rules[isdst].offset;
583 /* Reinterpret the TZ environment variable and set `tzname'. */
584 #undef tzset
586 void
587 __tzset (void)
589 __libc_lock_lock (tzset_lock);
591 tzset_internal (1, 1);
593 if (!__use_tzfile)
595 /* Set `tzname'. */
596 __tzname[0] = (char *) tz_rules[0].name;
597 __tzname[1] = (char *) tz_rules[1].name;
600 __libc_lock_unlock (tzset_lock);
602 weak_alias (__tzset, tzset)
604 /* Return the `struct tm' representation of *TIMER in the local timezone.
605 Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
606 struct tm *
607 __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
609 long int leap_correction;
610 int leap_extra_secs;
612 if (timer == NULL)
614 __set_errno (EINVAL);
615 return NULL;
618 __libc_lock_lock (tzset_lock);
620 /* Update internal database according to current TZ setting.
621 POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
622 This is a good idea since this allows at least a bit more parallelism. */
623 tzset_internal (tp == &_tmbuf && use_localtime, 1);
625 if (__use_tzfile)
626 __tzfile_compute (*timer, use_localtime, &leap_correction,
627 &leap_extra_secs, tp);
628 else
630 if (! __offtime (timer, 0, tp))
631 tp = NULL;
632 else
633 __tz_compute (*timer, tp, use_localtime);
634 leap_correction = 0L;
635 leap_extra_secs = 0;
638 __libc_lock_unlock (tzset_lock);
640 if (tp)
642 if (! use_localtime)
644 tp->tm_isdst = 0;
645 tp->tm_zone = "GMT";
646 tp->tm_gmtoff = 0L;
649 if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
650 tp->tm_sec += leap_extra_secs;
651 else
652 tp = NULL;
655 return tp;
659 libc_freeres_fn (free_mem)
661 while (tzstring_list != NULL)
663 struct tzstring_l *old = tzstring_list;
665 tzstring_list = tzstring_list->next;
666 free (old);
668 free (old_tz);
669 old_tz = NULL;