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