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