(__tzfile_read): Disable implicit locking for the stream.
[kopensolaris-gnu/glibc.git] / time / tzfile.c
1 /* Copyright (C) 1991-1993, 1995-2000, 2001 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
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.
8
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.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <assert.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdio_ext.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <unistd.h>
27
28 #define NOID
29 #include <timezone/tzfile.h>
30
31 int __use_tzfile;
32
33 struct ttinfo
34   {
35     long int offset;            /* Seconds east of GMT.  */
36     unsigned char isdst;        /* Used to set tm_isdst.  */
37     unsigned char idx;          /* Index into `zone_names'.  */
38     unsigned char isstd;        /* Transition times are in standard time.  */
39     unsigned char isgmt;        /* Transition times are in GMT.  */
40   };
41
42 struct leap
43   {
44     time_t transition;          /* Time the transition takes effect.  */
45     long int change;            /* Seconds of correction to apply.  */
46   };
47
48 static struct ttinfo *find_transition (time_t timer) internal_function;
49 static void compute_tzname_max (size_t) internal_function;
50
51 static size_t num_transitions;
52 static time_t *transitions;
53 static unsigned char *type_idxs;
54 static size_t num_types;
55 static struct ttinfo *types;
56 static char *zone_names;
57 static long int rule_stdoff;
58 static long int rule_dstoff;
59 static size_t num_leaps;
60 static struct leap *leaps;
61
62 #include <endian.h>
63 #include <byteswap.h>
64
65 /* Decode the four bytes at PTR as a signed integer in network byte order.  */
66 static inline int
67 decode (const void *ptr)
68 {
69   if ((BYTE_ORDER == BIG_ENDIAN) && sizeof (int) == 4)
70     return *(const int *) ptr;
71   else if (BYTE_ORDER == LITTLE_ENDIAN && sizeof (int) == 4)
72     return bswap_32 (*(const int *) ptr);
73   else
74     {
75       const unsigned char *p = ptr;
76       int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
77
78       result = (result << 8) | *p++;
79       result = (result << 8) | *p++;
80       result = (result << 8) | *p++;
81       result = (result << 8) | *p++;
82
83       return result;
84     }
85 }
86
87 void
88 __tzfile_read (const char *file, size_t extra, char **extrap)
89 {
90   static const char default_tzdir[] = TZDIR;
91   size_t num_isstd, num_isgmt;
92   register FILE *f;
93   struct tzhead tzhead;
94   size_t chars;
95   register size_t i;
96   size_t total_size;
97   size_t types_idx;
98   size_t leaps_idx;
99
100   __use_tzfile = 0;
101
102   if (transitions != NULL)
103     free ((void *) transitions);
104   transitions = NULL;
105
106   if (file == NULL)
107     /* No user specification; use the site-wide default.  */
108     file = TZDEFAULT;
109   else if (*file == '\0')
110     /* User specified the empty string; use UTC with no leap seconds.  */
111     return;
112   else
113     {
114       /* We must not allow to read an arbitrary file in a setuid
115          program.  So we fail for any file which is not in the
116          directory hierachy starting at TZDIR
117          and which is not the system wide default TZDEFAULT.  */
118       if (__libc_enable_secure
119           && ((*file == '/'
120                && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
121                && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
122               || strstr (file, "../") != NULL))
123         /* This test is certainly a bit too restrictive but it should
124            catch all critical cases.  */
125         return;
126     }
127
128   if (*file != '/')
129     {
130       const char *tzdir;
131       unsigned int len, tzdir_len;
132       char *new, *tmp;
133
134       tzdir = getenv ("TZDIR");
135       if (tzdir == NULL || *tzdir == '\0')
136         {
137           tzdir = default_tzdir;
138           tzdir_len = sizeof (default_tzdir) - 1;
139         }
140       else
141         tzdir_len = strlen (tzdir);
142       len = strlen (file) + 1;
143       new = (char *) __alloca (tzdir_len + 1 + len);
144       tmp = __mempcpy (new, tzdir, tzdir_len);
145       *tmp++ = '/';
146       memcpy (tmp, file, len);
147       file = new;
148     }
149
150   f = fopen (file, "r");
151   if (f == NULL)
152     return;
153
154   /* No threads reading this stream.  */
155   __fsetlocking (f, FSETLOCKING_BYCALLER);
156
157   if (fread_unlocked ((void *) &tzhead, sizeof (tzhead), 1, f) != 1)
158     goto lose;
159
160   num_transitions = (size_t) decode (tzhead.tzh_timecnt);
161   num_types = (size_t) decode (tzhead.tzh_typecnt);
162   chars = (size_t) decode (tzhead.tzh_charcnt);
163   num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
164   num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
165   num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
166
167   total_size = num_transitions * (sizeof (time_t) + 1);
168   total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
169                 & ~(__alignof__ (struct ttinfo) - 1));
170   types_idx = total_size;
171   total_size += num_types * sizeof (struct ttinfo) + chars;
172   total_size = ((total_size + __alignof__ (struct leap) - 1)
173                 & ~(__alignof__ (struct leap) - 1));
174   leaps_idx = total_size;
175   total_size += num_leaps * sizeof (struct leap);
176   /* This is for the extra memory required by the caller.  */
177   total_size += extra;
178
179   transitions = (time_t *) malloc (total_size);
180   if (transitions == NULL)
181     goto lose;
182
183   type_idxs = (unsigned char *) transitions + (num_transitions
184                                                * sizeof (time_t));
185   types = (struct ttinfo *) ((char *) transitions + types_idx);
186   zone_names = (char *) types + num_types * sizeof (struct ttinfo);
187   leaps = (struct leap *) ((char *) transitions + leaps_idx);
188   if (extra > 0)
189     *extrap = (char *) &leaps[num_leaps];
190
191   if (sizeof (time_t) < 4)
192     abort ();
193
194   if (sizeof (time_t) == 4)
195     {
196       if (fread_unlocked (transitions, 1, (4 + 1) * num_transitions, f)
197           != (4 + 1) * num_transitions)
198         goto lose;
199     }
200   else
201     {
202       if (fread_unlocked (transitions, 4, num_transitions, f)
203           != num_transitions
204           || fread_unlocked (type_idxs, 1, num_transitions, f)
205           != num_transitions)
206         goto lose;
207     }
208
209   /* Check for bogus indices in the data file, so we can hereafter
210      safely use type_idxs[T] as indices into `types' and never crash.  */
211   for (i = 0; i < num_transitions; ++i)
212     if (type_idxs[i] >= num_types)
213       goto lose;
214
215   if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4)
216     {
217       /* Decode the transition times, stored as 4-byte integers in
218          network (big-endian) byte order.  We work from the end of
219          the array so as not to clobber the next element to be
220          processed when sizeof (time_t) > 4.  */
221       i = num_transitions;
222       while (i-- > 0)
223         transitions[i] = decode ((char *) transitions + i * 4);
224     }
225
226   for (i = 0; i < num_types; ++i)
227     {
228       unsigned char x[4];
229       int c;
230       if (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x))
231         goto lose;
232       c = getc_unlocked (f);
233       if ((unsigned int) c > 1u)
234         goto lose;
235       types[i].isdst = c;
236       c = getc_unlocked (f);
237       if ((size_t) c > chars) /* Bogus index in data file.  */
238         goto lose;
239       types[i].idx = c;
240       types[i].offset = (long int) decode (x);
241     }
242
243   if (fread_unlocked (zone_names, 1, chars, f) != chars)
244     goto lose;
245
246   for (i = 0; i < num_leaps; ++i)
247     {
248       unsigned char x[4];
249       if (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x))
250         goto lose;
251       leaps[i].transition = (time_t) decode (x);
252       if (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x))
253         goto lose;
254       leaps[i].change = (long int) decode (x);
255     }
256
257   for (i = 0; i < num_isstd; ++i)
258     {
259       int c = getc_unlocked (f);
260       if (c == EOF)
261         goto lose;
262       types[i].isstd = c != 0;
263     }
264   while (i < num_types)
265     types[i++].isstd = 0;
266
267   for (i = 0; i < num_isgmt; ++i)
268     {
269       int c = getc_unlocked (f);
270       if (c == EOF)
271         goto lose;
272       types[i].isgmt = c != 0;
273     }
274   while (i < num_types)
275     types[i++].isgmt = 0;
276
277   fclose (f);
278
279   /* First "register" all timezone names.  */
280   for (i = 0; i < num_types; ++i)
281     (void) __tzstring (&zone_names[types[i].idx]);
282
283   /* Find the standard and daylight time offsets used by the rule file.
284      We choose the offsets in the types of each flavor that are
285      transitioned to earliest in time.  */
286   __tzname[0] = NULL;
287   __tzname[1] = NULL;
288   for (i = num_transitions; i > 0; )
289     {
290       int type = type_idxs[--i];
291       int dst = types[type].isdst;
292
293       if (__tzname[dst] == NULL)
294         {
295           int idx = types[type].idx;
296
297           __tzname[dst] = __tzstring (&zone_names[idx]);
298
299           if (__tzname[1 - dst] != NULL)
300             break;
301         }
302     }
303   if (__tzname[0] == NULL)
304     {
305       /* This should only happen if there are no transition rules.
306          In this case there should be only one single type.  */
307       assert (num_types == 1);
308       __tzname[0] = __tzstring (zone_names);
309     }
310   if (__tzname[1] == NULL)
311     __tzname[1] = __tzname[0];
312
313   compute_tzname_max (chars);
314
315   if (num_transitions == 0)
316     /* Use the first rule (which should also be the only one).  */
317     rule_stdoff = rule_dstoff = types[0].offset;
318   else
319     {
320       int stdoff_set = 0, dstoff_set = 0;
321       rule_stdoff = rule_dstoff = 0;
322       i = num_transitions - 1;
323       do
324         {
325           if (!stdoff_set && !types[type_idxs[i]].isdst)
326             {
327               stdoff_set = 1;
328               rule_stdoff = types[type_idxs[i]].offset;
329             }
330           else if (!dstoff_set && types[type_idxs[i]].isdst)
331             {
332               dstoff_set = 1;
333               rule_dstoff = types[type_idxs[i]].offset;
334             }
335           if (stdoff_set && dstoff_set)
336             break;
337         }
338       while (i-- > 0);
339
340       if (!dstoff_set)
341         rule_dstoff = rule_stdoff;
342     }
343
344   __daylight = rule_stdoff != rule_dstoff;
345   __timezone = -rule_stdoff;
346
347   __use_tzfile = 1;
348   return;
349
350  lose:
351   fclose (f);
352 }
353 \f
354 /* The user specified a hand-made timezone, but not its DST rules.
355    We will use the names and offsets from the user, and the rules
356    from the TZDEFRULES file.  */
357
358 void
359 __tzfile_default (const char *std, const char *dst,
360                   long int stdoff, long int dstoff)
361 {
362   size_t stdlen = strlen (std) + 1;
363   size_t dstlen = strlen (dst) + 1;
364   size_t i;
365   int isdst;
366   char *cp;
367
368   __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
369   if (!__use_tzfile)
370     return;
371
372   if (num_types < 2)
373     {
374       __use_tzfile = 0;
375       return;
376     }
377
378   /* Ignore the zone names read from the file and use the given ones
379      instead.  */
380   __mempcpy (__mempcpy (cp, std, stdlen), dst, dstlen);
381   zone_names = cp;
382
383   /* Now there are only two zones, regardless of what the file contained.  */
384   num_types = 2;
385
386   /* Now correct the transition times for the user-specified standard and
387      daylight offsets from GMT.  */
388   isdst = 0;
389   for (i = 0; i < num_transitions; ++i)
390     {
391       struct ttinfo *trans_type = &types[type_idxs[i]];
392
393       /* We will use only types 0 (standard) and 1 (daylight).
394          Fix up this transition to point to whichever matches
395          the flavor of its original type.  */
396       type_idxs[i] = trans_type->isdst;
397
398       if (trans_type->isgmt)
399         /* The transition time is in GMT.  No correction to apply.  */ ;
400       else if (isdst && !trans_type->isstd)
401         /* The type says this transition is in "local wall clock time", and
402            wall clock time as of the previous transition was DST.  Correct
403            for the difference between the rule's DST offset and the user's
404            DST offset.  */
405         transitions[i] += dstoff - rule_dstoff;
406       else
407         /* This transition is in "local wall clock time", and wall clock
408            time as of this iteration is non-DST.  Correct for the
409            difference between the rule's standard offset and the user's
410            standard offset.  */
411         transitions[i] += stdoff - rule_stdoff;
412
413       /* The DST state of "local wall clock time" for the next iteration is
414          as specified by this transition.  */
415       isdst = trans_type->isdst;
416     }
417
418   /* Reset types 0 and 1 to describe the user's settings.  */
419   types[0].idx = 0;
420   types[0].offset = stdoff;
421   types[0].isdst = 0;
422   types[1].idx = stdlen;
423   types[1].offset = dstoff;
424   types[1].isdst = 1;
425
426   /* Reset the zone names to point to the user's names.  */
427   __tzname[0] = (char *) std;
428   __tzname[1] = (char *) dst;
429
430   /* Set the timezone.  */
431   __timezone = -types[0].offset;
432
433   compute_tzname_max (stdlen + dstlen);
434 }
435 \f
436 static struct ttinfo *
437 internal_function
438 find_transition (time_t timer)
439 {
440   size_t i;
441
442   if (num_transitions == 0 || timer < transitions[0])
443     {
444       /* TIMER is before any transition (or there are no transitions).
445          Choose the first non-DST type
446          (or the first if they're all DST types).  */
447       i = 0;
448       while (i < num_types && types[i].isdst)
449         ++i;
450       if (i == num_types)
451         i = 0;
452     }
453   else
454     {
455       /* Find the first transition after TIMER, and
456          then pick the type of the transition before it.  */
457       for (i = 1; i < num_transitions; ++i)
458         if (timer < transitions[i])
459           break;
460       i = type_idxs[i - 1];
461     }
462
463   return &types[i];
464 }
465 \f
466 int
467 __tzfile_compute (time_t timer, int use_localtime,
468                   long int *leap_correct, int *leap_hit,
469                   struct tm *tp)
470 {
471   register size_t i;
472
473   if (use_localtime)
474     {
475       struct ttinfo *info = find_transition (timer);
476       __daylight = rule_stdoff != rule_dstoff;
477       __timezone = -rule_stdoff;
478       __tzname[0] = NULL;
479       __tzname[1] = NULL;
480       for (i = num_transitions; i > 0; )
481         {
482           int type = type_idxs[--i];
483           int dst = types[type].isdst;
484           int idx = types[type].idx;
485
486           if (__tzname[dst] == NULL)
487             {
488               __tzname[dst] = __tzstring (&zone_names[idx]);
489
490               if (__tzname[1 - dst] != NULL)
491                 break;
492             }
493         }
494       if (__tzname[0] == NULL)
495         {
496           /* This should only happen if there are no transition rules.
497              In this case there should be only one single type.  */
498           assert (num_types == 1);
499           __tzname[0] = __tzstring (zone_names);
500         }
501       if (__tzname[1] == NULL)
502         /* There is no daylight saving time.  */
503         __tzname[1] = __tzname[0];
504       tp->tm_isdst = info->isdst;
505       tp->tm_zone = __tzstring (&zone_names[info->idx]);
506       tp->tm_gmtoff = info->offset;
507     }
508
509   *leap_correct = 0L;
510   *leap_hit = 0;
511
512   /* Find the last leap second correction transition time before TIMER.  */
513   i = num_leaps;
514   do
515     if (i-- == 0)
516       return 1;
517   while (timer < leaps[i].transition);
518
519   /* Apply its correction.  */
520   *leap_correct = leaps[i].change;
521
522   if (timer == leaps[i].transition && /* Exactly at the transition time.  */
523       ((i == 0 && leaps[i].change > 0) ||
524        leaps[i].change > leaps[i - 1].change))
525     {
526       *leap_hit = 1;
527       while (i > 0
528              && leaps[i].transition == leaps[i - 1].transition + 1
529              && leaps[i].change == leaps[i - 1].change + 1)
530         {
531           ++*leap_hit;
532           --i;
533         }
534     }
535
536   return 1;
537 }
538 \f
539 static void
540 internal_function
541 compute_tzname_max (size_t chars)
542 {
543   const char *p;
544
545   p = zone_names;
546   do
547     {
548       const char *start = p;
549       while (*p != '\0')
550         ++p;
551       if ((size_t) (p - start) > __tzname_cur_max)
552         __tzname_cur_max = p - start;
553     }
554   while (++p < &zone_names[chars]);
555 }
556 \f
557 /* This function is only called when we are checking for memory leaks.  */
558 static void
559 freeres (void)
560 {
561   if (transitions != NULL)
562     free ((void *) transitions);
563 }
564
565 /* Make sure all allocated data is freed before exiting.  */
566 text_set_element (__libc_subfreeres, freeres);