Generic clock.c.
[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   /* If we were already using tzfile, check whether the file changed.  */
153   struct stat64 st;
154   if (was_using_tzfile
155       && stat64 (file, &st) == 0
156       && tzfile_ino == st.st_ino && tzfile_dev == st.st_dev
157       && tzfile_mtime == st.st_mtime)
158     {
159       /* Nothing to do.  */
160       __use_tzfile = 1;
161       return;
162     }
163
164   /* Note the file is opened with cancellation in the I/O functions
165      disabled.  */
166   f = fopen (file, "rc");
167   if (f == NULL)
168     goto ret_free_transitions;
169
170   /* Get information about the file we are actually using.  */
171   if (fstat64 (fileno (f), &st) != 0)
172     {
173       fclose (f);
174       goto ret_free_transitions;
175     }
176
177   free ((void *) transitions);
178   transitions = NULL;
179
180   /* Remember the inode and device number and modification time.  */
181   tzfile_dev = st.st_dev;
182   tzfile_ino = st.st_ino;
183   tzfile_mtime = st.st_mtime;
184
185   /* No threads reading this stream.  */
186   __fsetlocking (f, FSETLOCKING_BYCALLER);
187
188   if (__builtin_expect (fread_unlocked ((void *) &tzhead, sizeof (tzhead),
189                                         1, f) != 1, 0))
190     goto lose;
191
192   num_transitions = (size_t) decode (tzhead.tzh_timecnt);
193   num_types = (size_t) decode (tzhead.tzh_typecnt);
194   chars = (size_t) decode (tzhead.tzh_charcnt);
195   num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
196   num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
197   num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
198
199   total_size = num_transitions * (sizeof (time_t) + 1);
200   total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
201                 & ~(__alignof__ (struct ttinfo) - 1));
202   types_idx = total_size;
203   total_size += num_types * sizeof (struct ttinfo) + chars;
204   total_size = ((total_size + __alignof__ (struct leap) - 1)
205                 & ~(__alignof__ (struct leap) - 1));
206   leaps_idx = total_size;
207   total_size += num_leaps * sizeof (struct leap);
208   /* This is for the extra memory required by the caller.  */
209   total_size += extra;
210
211   transitions = (time_t *) malloc (total_size);
212   if (transitions == NULL)
213     goto lose;
214
215   type_idxs = (unsigned char *) transitions + (num_transitions
216                                                * sizeof (time_t));
217   types = (struct ttinfo *) ((char *) transitions + types_idx);
218   zone_names = (char *) types + num_types * sizeof (struct ttinfo);
219   leaps = (struct leap *) ((char *) transitions + leaps_idx);
220   if (extra > 0)
221     *extrap = (char *) &leaps[num_leaps];
222
223   if (sizeof (time_t) < 4)
224     abort ();
225
226   if (sizeof (time_t) == 4)
227     {
228       if (__builtin_expect (fread_unlocked (transitions, 1,
229                                             (4 + 1) * num_transitions, f)
230                             != (4 + 1) * num_transitions, 0))
231         goto lose;
232     }
233   else
234     {
235       if (__builtin_expect (fread_unlocked (transitions, 4, num_transitions, f)
236                             != num_transitions, 0)
237           || __builtin_expect (fread_unlocked (type_idxs, 1, num_transitions,
238                                                f) != num_transitions, 0))
239         goto lose;
240     }
241
242   /* Check for bogus indices in the data file, so we can hereafter
243      safely use type_idxs[T] as indices into `types' and never crash.  */
244   for (i = 0; i < num_transitions; ++i)
245     if (__builtin_expect (type_idxs[i] >= num_types, 0))
246       goto lose;
247
248   if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4)
249     {
250       /* Decode the transition times, stored as 4-byte integers in
251          network (big-endian) byte order.  We work from the end of
252          the array so as not to clobber the next element to be
253          processed when sizeof (time_t) > 4.  */
254       i = num_transitions;
255       while (i-- > 0)
256         transitions[i] = decode ((char *) transitions + i * 4);
257     }
258
259   for (i = 0; i < num_types; ++i)
260     {
261       unsigned char x[4];
262       int c;
263       if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
264                             0))
265         goto lose;
266       c = getc_unlocked (f);
267       if (__builtin_expect ((unsigned int) c > 1u, 0))
268         goto lose;
269       types[i].isdst = c;
270       c = getc_unlocked (f);
271       if (__builtin_expect ((size_t) c > chars, 0))
272         /* Bogus index in data file.  */
273         goto lose;
274       types[i].idx = c;
275       types[i].offset = (long int) decode (x);
276     }
277
278   if (__builtin_expect (fread_unlocked (zone_names, 1, chars, f) != chars, 0))
279     goto lose;
280
281   for (i = 0; i < num_leaps; ++i)
282     {
283       unsigned char x[4];
284       if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
285                             0))
286         goto lose;
287       leaps[i].transition = (time_t) decode (x);
288       if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
289                             0))
290         goto lose;
291       leaps[i].change = (long int) decode (x);
292     }
293
294   for (i = 0; i < num_isstd; ++i)
295     {
296       int c = getc_unlocked (f);
297       if (__builtin_expect (c == EOF, 0))
298         goto lose;
299       types[i].isstd = c != 0;
300     }
301   while (i < num_types)
302     types[i++].isstd = 0;
303
304   for (i = 0; i < num_isgmt; ++i)
305     {
306       int c = getc_unlocked (f);
307       if (__builtin_expect (c == EOF, 0))
308         goto lose;
309       types[i].isgmt = c != 0;
310     }
311   while (i < num_types)
312     types[i++].isgmt = 0;
313
314   fclose (f);
315
316   /* First "register" all timezone names.  */
317   for (i = 0; i < num_types; ++i)
318     (void) __tzstring (&zone_names[types[i].idx]);
319
320   /* Find the standard and daylight time offsets used by the rule file.
321      We choose the offsets in the types of each flavor that are
322      transitioned to earliest in time.  */
323   __tzname[0] = NULL;
324   __tzname[1] = NULL;
325   for (i = num_transitions; i > 0; )
326     {
327       int type = type_idxs[--i];
328       int dst = types[type].isdst;
329
330       if (__tzname[dst] == NULL)
331         {
332           int idx = types[type].idx;
333
334           __tzname[dst] = __tzstring (&zone_names[idx]);
335
336           if (__tzname[1 - dst] != NULL)
337             break;
338         }
339     }
340   if (__tzname[0] == NULL)
341     {
342       /* This should only happen if there are no transition rules.
343          In this case there should be only one single type.  */
344       assert (num_types == 1);
345       __tzname[0] = __tzstring (zone_names);
346     }
347   if (__tzname[1] == NULL)
348     __tzname[1] = __tzname[0];
349
350   compute_tzname_max (chars);
351
352   if (num_transitions == 0)
353     /* Use the first rule (which should also be the only one).  */
354     rule_stdoff = rule_dstoff = types[0].offset;
355   else
356     {
357       int stdoff_set = 0, dstoff_set = 0;
358       rule_stdoff = rule_dstoff = 0;
359       i = num_transitions - 1;
360       do
361         {
362           if (!stdoff_set && !types[type_idxs[i]].isdst)
363             {
364               stdoff_set = 1;
365               rule_stdoff = types[type_idxs[i]].offset;
366             }
367           else if (!dstoff_set && types[type_idxs[i]].isdst)
368             {
369               dstoff_set = 1;
370               rule_dstoff = types[type_idxs[i]].offset;
371             }
372           if (stdoff_set && dstoff_set)
373             break;
374         }
375       while (i-- > 0);
376
377       if (!dstoff_set)
378         rule_dstoff = rule_stdoff;
379     }
380
381   __daylight = rule_stdoff != rule_dstoff;
382   __timezone = -rule_stdoff;
383
384   __use_tzfile = 1;
385   return;
386
387  lose:
388   fclose (f);
389  ret_free_transitions:
390   free ((void *) transitions);
391   transitions = NULL;
392 }
393 \f
394 /* The user specified a hand-made timezone, but not its DST rules.
395    We will use the names and offsets from the user, and the rules
396    from the TZDEFRULES file.  */
397
398 void
399 __tzfile_default (const char *std, const char *dst,
400                   long int stdoff, long int dstoff)
401 {
402   size_t stdlen = strlen (std) + 1;
403   size_t dstlen = strlen (dst) + 1;
404   size_t i;
405   int isdst;
406   char *cp;
407
408   __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
409   if (!__use_tzfile)
410     return;
411
412   if (num_types < 2)
413     {
414       __use_tzfile = 0;
415       return;
416     }
417
418   /* Ignore the zone names read from the file and use the given ones
419      instead.  */
420   __mempcpy (__mempcpy (cp, std, stdlen), dst, dstlen);
421   zone_names = cp;
422
423   /* Now there are only two zones, regardless of what the file contained.  */
424   num_types = 2;
425
426   /* Now correct the transition times for the user-specified standard and
427      daylight offsets from GMT.  */
428   isdst = 0;
429   for (i = 0; i < num_transitions; ++i)
430     {
431       struct ttinfo *trans_type = &types[type_idxs[i]];
432
433       /* We will use only types 0 (standard) and 1 (daylight).
434          Fix up this transition to point to whichever matches
435          the flavor of its original type.  */
436       type_idxs[i] = trans_type->isdst;
437
438       if (trans_type->isgmt)
439         /* The transition time is in GMT.  No correction to apply.  */ ;
440       else if (isdst && !trans_type->isstd)
441         /* The type says this transition is in "local wall clock time", and
442            wall clock time as of the previous transition was DST.  Correct
443            for the difference between the rule's DST offset and the user's
444            DST offset.  */
445         transitions[i] += dstoff - rule_dstoff;
446       else
447         /* This transition is in "local wall clock time", and wall clock
448            time as of this iteration is non-DST.  Correct for the
449            difference between the rule's standard offset and the user's
450            standard offset.  */
451         transitions[i] += stdoff - rule_stdoff;
452
453       /* The DST state of "local wall clock time" for the next iteration is
454          as specified by this transition.  */
455       isdst = trans_type->isdst;
456     }
457
458   /* Now that we adjusted the transitions to the requested offsets,
459      reset the rule_stdoff and rule_dstoff values appropriately.  They
460      are used elsewhere.  */
461   rule_stdoff = stdoff;
462   rule_dstoff = dstoff;
463
464   /* Reset types 0 and 1 to describe the user's settings.  */
465   types[0].idx = 0;
466   types[0].offset = stdoff;
467   types[0].isdst = 0;
468   types[1].idx = stdlen;
469   types[1].offset = dstoff;
470   types[1].isdst = 1;
471
472   /* Reset the zone names to point to the user's names.  */
473   __tzname[0] = (char *) std;
474   __tzname[1] = (char *) dst;
475
476   /* Set the timezone.  */
477   __timezone = -types[0].offset;
478
479   compute_tzname_max (stdlen + dstlen);
480 }
481 \f
482 static struct ttinfo *
483 internal_function
484 find_transition (time_t timer)
485 {
486   size_t i;
487
488   if (num_transitions == 0 || timer < transitions[0])
489     {
490       /* TIMER is before any transition (or there are no transitions).
491          Choose the first non-DST type
492          (or the first if they're all DST types).  */
493       i = 0;
494       while (i < num_types && types[i].isdst)
495         ++i;
496       if (i == num_types)
497         i = 0;
498     }
499   else
500     {
501       /* Find the first transition after TIMER, and
502          then pick the type of the transition before it.  */
503       for (i = 1; i < num_transitions; ++i)
504         if (timer < transitions[i])
505           break;
506       i = type_idxs[i - 1];
507     }
508
509   return &types[i];
510 }
511 \f
512 void
513 __tzfile_compute (time_t timer, int use_localtime,
514                   long int *leap_correct, int *leap_hit,
515                   struct tm *tp)
516 {
517   register size_t i;
518
519   if (use_localtime)
520     {
521       struct ttinfo *info = find_transition (timer);
522       __daylight = rule_stdoff != rule_dstoff;
523       __timezone = -rule_stdoff;
524       __tzname[0] = NULL;
525       __tzname[1] = NULL;
526       for (i = num_transitions; i > 0; )
527         {
528           int type = type_idxs[--i];
529           int dst = types[type].isdst;
530           int idx = types[type].idx;
531
532           if (__tzname[dst] == NULL)
533             {
534               __tzname[dst] = __tzstring (&zone_names[idx]);
535
536               if (__tzname[1 - dst] != NULL)
537                 break;
538             }
539         }
540       if (__tzname[0] == NULL)
541         {
542           /* This should only happen if there are no transition rules.
543              In this case there should be only one single type.  */
544           assert (num_types == 1);
545           __tzname[0] = __tzstring (zone_names);
546         }
547       if (__tzname[1] == NULL)
548         /* There is no daylight saving time.  */
549         __tzname[1] = __tzname[0];
550       tp->tm_isdst = info->isdst;
551       tp->tm_zone = __tzstring (&zone_names[info->idx]);
552       tp->tm_gmtoff = info->offset;
553     }
554
555   *leap_correct = 0L;
556   *leap_hit = 0;
557
558   /* Find the last leap second correction transition time before TIMER.  */
559   i = num_leaps;
560   do
561     if (i-- == 0)
562       return;
563   while (timer < leaps[i].transition);
564
565   /* Apply its correction.  */
566   *leap_correct = leaps[i].change;
567
568   if (timer == leaps[i].transition && /* Exactly at the transition time.  */
569       ((i == 0 && leaps[i].change > 0) ||
570        leaps[i].change > leaps[i - 1].change))
571     {
572       *leap_hit = 1;
573       while (i > 0
574              && leaps[i].transition == leaps[i - 1].transition + 1
575              && leaps[i].change == leaps[i - 1].change + 1)
576         {
577           ++*leap_hit;
578           --i;
579         }
580     }
581 }
582 \f
583 static void
584 internal_function
585 compute_tzname_max (size_t chars)
586 {
587   const char *p;
588
589   p = zone_names;
590   do
591     {
592       const char *start = p;
593       while (*p != '\0')
594         ++p;
595       if ((size_t) (p - start) > __tzname_cur_max)
596         __tzname_cur_max = p - start;
597     }
598   while (++p < &zone_names[chars]);
599 }