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