]> git.ipfire.org Git - thirdparty/glibc.git/blame - time/tzfile.c
Update.
[thirdparty/glibc.git] / time / tzfile.c
CommitLineData
14ea22e9 1/* Copyright (C) 1991, 92, 93, 95, 96, 97, 98 Free Software Foundation, Inc.
860d3729 2 This file is part of the GNU C Library.
28f540f4 3
860d3729
UD
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.
28f540f4 8
860d3729
UD
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.
28f540f4 13
860d3729
UD
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. */
28f540f4 18
a3e0e9ae
UD
19#include <assert.h>
20#include <limits.h>
28f540f4 21#include <stdio.h>
a3e0e9ae 22#include <stdlib.h>
28f540f4 23#include <string.h>
a3e0e9ae 24#include <time.h>
9d187dd4 25#include <unistd.h>
28f540f4
RM
26
27#define NOID
14ea22e9 28#include <timezone/tzfile.h>
28f540f4 29
28f540f4
RM
30int __use_tzfile = 0;
31
32struct 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'. */
98fa1d6e
RM
37 unsigned char isstd; /* Transition times are in standard time. */
38 unsigned char isgmt; /* Transition times are in GMT. */
28f540f4
RM
39 };
40
41struct leap
42 {
43 time_t transition; /* Time the transition takes effect. */
44 long int change; /* Seconds of correction to apply. */
45 };
46
dfd2257a
UD
47static struct ttinfo *find_transition (time_t timer) internal_function;
48static void compute_tzname_max (size_t) internal_function;
28f540f4
RM
49
50static size_t num_transitions;
51static time_t *transitions = NULL;
52static unsigned char *type_idxs = NULL;
53static size_t num_types;
54static struct ttinfo *types = NULL;
55static char *zone_names = NULL;
ff152e3f
UD
56static long int rule_stdoff;
57static long int rule_dstoff;
28f540f4
RM
58static size_t num_leaps;
59static struct leap *leaps = NULL;
60
a2cafe30 61#include <endian.h>
ba9234d9 62#include <byteswap.h>
a2cafe30
RM
63
64/* Decode the four bytes at PTR as a signed integer in network byte order. */
65static inline int
66decode (const void *ptr)
67{
b20e47cb
RM
68 if ((BYTE_ORDER == BIG_ENDIAN) && sizeof (int) == 4)
69 return *(const int *) ptr;
ba9234d9
UD
70 else if (BYTE_ORDER == LITTLE_ENDIAN && sizeof (int) == 4)
71 return bswap_32 (*(const int *) ptr);
b20e47cb
RM
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 }
a2cafe30 84}
28f540f4
RM
85
86void
860d3729 87__tzfile_read (const char *file)
28f540f4 88{
9d187dd4 89 static const char default_tzdir[] = TZDIR;
98fa1d6e 90 size_t num_isstd, num_isgmt;
28f540f4
RM
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)
860d3729 99 free ((void *) transitions);
28f540f4
RM
100 transitions = NULL;
101 if (type_idxs != NULL)
860d3729 102 free ((void *) type_idxs);
28f540f4
RM
103 type_idxs = NULL;
104 if (types != NULL)
860d3729 105 free ((void *) types);
28f540f4
RM
106 types = NULL;
107 if (zone_names != NULL)
860d3729 108 free ((void *) zone_names);
28f540f4
RM
109 zone_names = NULL;
110 if (leaps != NULL)
860d3729 111 free ((void *) leaps);
28f540f4
RM
112 leaps = NULL;
113
a3b58440
RM
114 if (file == NULL)
115 /* No user specification; use the site-wide default. */
28f540f4 116 file = TZDEFAULT;
a3b58440 117 else if (*file == '\0')
9a0a462c
UD
118 /* User specified the empty string; use UTC with no leap seconds. */
119 return;
1228ed5c
UD
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
7434ccad
UD
124 directory hierachy starting at TZDIR
125 and which is not the system wide default TZDEFAULT. */
1228ed5c
UD
126 if (__libc_enable_secure
127 && ((*file == '/'
4cca6b86 128 && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
1228ed5c
UD
129 && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
130 || strstr (file, "../") != NULL))
7434ccad
UD
131 /* This test is certainly a bit too restrictive but it should
132 catch all critical cases. */
1228ed5c
UD
133 return;
134 }
9d187dd4 135
28f540f4
RM
136 if (*file != '/')
137 {
5290baf0
UD
138 const char *tzdir;
139 unsigned int len, tzdir_len;
86187531 140 char *new, *tmp;
5290baf0
UD
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);
86187531
UD
152 tmp = __mempcpy (new, tzdir, tzdir_len);
153 *tmp++ = '/';
154 __mempcpy (tmp, file, len);
28f540f4
RM
155 file = new;
156 }
157
5290baf0 158 f = fopen (file, "r");
28f540f4
RM
159 if (f == NULL)
160 return;
161
ba9234d9 162 if (fread_unlocked ((void *) &tzhead, sizeof (tzhead), 1, f) != 1)
28f540f4
RM
163 goto lose;
164
a2cafe30
RM
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);
28f540f4
RM
171
172 if (num_transitions > 0)
173 {
a3e0e9ae 174 transitions = (time_t *) malloc (num_transitions * sizeof (time_t));
28f540f4
RM
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
b20e47cb
RM
200 if (sizeof (time_t) < 4)
201 abort ();
202
ba9234d9
UD
203 if (fread_unlocked (transitions, 4, num_transitions, f) != num_transitions
204 || fread_unlocked (type_idxs, 1, num_transitions, f) != num_transitions)
28f540f4
RM
205 goto lose;
206
5290baf0
UD
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
a2cafe30
RM
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;
b20e47cb 220 while (i-- > 0)
a3e0e9ae 221 transitions[i] = decode ((char *) transitions + i * 4);
a2cafe30 222 }
28f540f4
RM
223
224 for (i = 0; i < num_types; ++i)
225 {
226 unsigned char x[4];
ba9234d9
UD
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)
28f540f4 230 goto lose;
8b7fb588
UD
231 if (types[i].isdst > 1)
232 goto lose;
5290baf0
UD
233 if (types[i].idx >= chars) /* Bogus index in data file. */
234 goto lose;
a2cafe30 235 types[i].offset = (long int) decode (x);
28f540f4
RM
236 }
237
ba9234d9 238 if (fread_unlocked (zone_names, 1, chars, f) != chars)
28f540f4
RM
239 goto lose;
240
241 for (i = 0; i < num_leaps; ++i)
242 {
243 unsigned char x[4];
ba9234d9 244 if (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x))
28f540f4 245 goto lose;
a2cafe30 246 leaps[i].transition = (time_t) decode (x);
ba9234d9 247 if (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x))
28f540f4 248 goto lose;
a2cafe30 249 leaps[i].change = (long int) decode (x);
28f540f4
RM
250 }
251
252 for (i = 0; i < num_isstd; ++i)
253 {
ba9234d9 254 int c = getc_unlocked (f);
28f540f4
RM
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
98fa1d6e
RM
262 for (i = 0; i < num_isgmt; ++i)
263 {
ba9234d9 264 int c = getc_unlocked (f);
98fa1d6e
RM
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
860d3729
UD
272 fclose (f);
273
a3e0e9ae
UD
274 /* First "register" all timezone names. */
275 for (i = 0; i < num_types; ++i)
276 (void) __tzstring (&zone_names[types[i].idx]);
277
ff152e3f
UD
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. */
a3e0e9ae 281 __tzname[0] = NULL;
ff152e3f 282 __tzname[1] = NULL;
a3e0e9ae
UD
283 for (i = num_transitions; i > 0; )
284 {
285 int type = type_idxs[--i];
286 int dst = types[type].isdst;
287 int idx = types[type].idx;
288
289 if (__tzname[dst] == NULL)
290 {
291 __tzname[dst] = __tzstring (&zone_names[idx]);
292
293 if (__tzname[1 - dst] != NULL)
294 break;
295 }
296 }
297 if (__tzname[0] == NULL)
298 {
299 /* This should only happen if there are no transition rules.
300 In this case there should be only one single type. */
301 assert (num_types == 1);
302 __tzname[0] = __tzstring (zone_names);
303 }
ff152e3f
UD
304 if (__tzname[1] == NULL)
305 __tzname[1] = __tzname[0];
28f540f4
RM
306
307 compute_tzname_max (chars);
a3b58440 308
90865aa8 309 if (num_transitions == 0)
0155a773 310 /* Use the first rule (which should also be the only one). */
90865aa8
UD
311 rule_stdoff = rule_dstoff = types[0].offset;
312 else
ff152e3f 313 {
d16e36e0 314 int stdoff_set = 0, dstoff_set = 0;
90865aa8
UD
315 rule_stdoff = rule_dstoff = 0;
316 for (i = 0; i < num_transitions; ++i)
317 {
d16e36e0
AS
318 if (!stdoff_set && !types[type_idxs[i]].isdst)
319 {
320 stdoff_set = 1;
321 rule_stdoff = types[type_idxs[i]].offset;
322 }
323 if (!dstoff_set && types[type_idxs[i]].isdst)
324 {
325 dstoff_set = 1;
326 rule_dstoff = types[type_idxs[i]].offset;
327 }
328 if (stdoff_set && dstoff_set)
90865aa8
UD
329 break;
330 }
d16e36e0
AS
331 if (!dstoff_set)
332 rule_dstoff = rule_stdoff;
ff152e3f
UD
333 }
334
335 __daylight = rule_stdoff != rule_dstoff;
336 __timezone = -rule_stdoff;
337
28f540f4
RM
338 __use_tzfile = 1;
339 return;
340
ba9234d9
UD
341 lose:
342 fclose (f);
28f540f4
RM
343}
344\f
98fa1d6e
RM
345/* The user specified a hand-made timezone, but not its DST rules.
346 We will use the names and offsets from the user, and the rules
347 from the TZDEFRULES file. */
348
28f540f4 349void
cd6ede75
UD
350__tzfile_default (const char *std, const char *dst,
351 long int stdoff, long int dstoff)
28f540f4
RM
352{
353 size_t stdlen, dstlen, i;
98fa1d6e 354 int isdst;
28f540f4
RM
355
356 __tzfile_read (TZDEFRULES);
357 if (!__use_tzfile)
358 return;
359
360 if (num_types < 2)
361 {
362 __use_tzfile = 0;
363 return;
364 }
365
98fa1d6e 366 /* Ignore the zone names read from the file. */
28f540f4
RM
367 free (zone_names);
368
98fa1d6e 369 /* Use the names the user specified. */
28f540f4
RM
370 stdlen = strlen (std) + 1;
371 dstlen = strlen (dst) + 1;
372 zone_names = malloc (stdlen + dstlen);
373 if (zone_names == NULL)
374 {
375 __use_tzfile = 0;
376 return;
377 }
86187531 378 __mempcpy (__mempcpy (zone_names, std, stdlen), dst, dstlen);
28f540f4 379
88455219
UD
380 /* Now there are only two zones, regardless of what the file contained. */
381 num_types = 2;
382
98fa1d6e
RM
383 /* Now correct the transition times for the user-specified standard and
384 daylight offsets from GMT. */
385 isdst = 0;
98fa1d6e
RM
386 for (i = 0; i < num_transitions; ++i)
387 {
388 struct ttinfo *trans_type = &types[type_idxs[i]];
389
390 /* We will use only types 0 (standard) and 1 (daylight).
391 Fix up this transition to point to whichever matches
392 the flavor of its original type. */
393 type_idxs[i] = trans_type->isdst;
394
395 if (trans_type->isgmt)
396 /* The transition time is in GMT. No correction to apply. */ ;
397 else if (isdst && !trans_type->isstd)
398 /* The type says this transition is in "local wall clock time", and
399 wall clock time as of the previous transition was DST. Correct
400 for the difference between the rule's DST offset and the user's
401 DST offset. */
402 transitions[i] += dstoff - rule_dstoff;
403 else
404 /* This transition is in "local wall clock time", and wall clock
405 time as of this iteration is non-DST. Correct for the
406 difference between the rule's standard offset and the user's
407 standard offset. */
408 transitions[i] += stdoff - rule_stdoff;
409
410 /* The DST state of "local wall clock time" for the next iteration is
411 as specified by this transition. */
412 isdst = trans_type->isdst;
413 }
414
415 /* Reset types 0 and 1 to describe the user's settings. */
416 types[0].idx = 0;
417 types[0].offset = stdoff;
418 types[0].isdst = 0;
419 types[1].idx = stdlen;
420 types[1].offset = dstoff;
421 types[1].isdst = 1;
28f540f4 422
5290baf0 423 /* Reset the zone names to point to the user's names. */
cd6ede75
UD
424 __tzname[0] = (char *) std;
425 __tzname[1] = (char *) dst;
5290baf0 426
90865aa8
UD
427 /* Set the timezone. */
428 __timezone = -types[0].offset;
429
28f540f4
RM
430 compute_tzname_max (stdlen + dstlen);
431}
432\f
860d3729 433static struct ttinfo *
dfd2257a 434internal_function
860d3729 435find_transition (time_t timer)
28f540f4 436{
860d3729 437 size_t i;
28f540f4
RM
438
439 if (num_transitions == 0 || timer < transitions[0])
440 {
441 /* TIMER is before any transition (or there are no transitions).
442 Choose the first non-DST type
443 (or the first if they're all DST types). */
444 i = 0;
445 while (i < num_types && types[i].isdst)
446 ++i;
447 if (i == num_types)
448 i = 0;
449 }
450 else
451 {
452 /* Find the first transition after TIMER, and
453 then pick the type of the transition before it. */
454 for (i = 1; i < num_transitions; ++i)
455 if (timer < transitions[i])
456 break;
457 i = type_idxs[i - 1];
458 }
459
860d3729
UD
460 return &types[i];
461}
462\f
463int
9a0a462c 464__tzfile_compute (time_t timer, int use_localtime,
b17277cf 465 long int *leap_correct, int *leap_hit,
a709dd43 466 struct tm *tp)
860d3729 467{
860d3729
UD
468 register size_t i;
469
9a0a462c
UD
470 if (use_localtime)
471 {
a709dd43 472 struct ttinfo *info = find_transition (timer);
ff152e3f
UD
473 __daylight = rule_stdoff != rule_dstoff;
474 __timezone = -rule_stdoff;
a3e0e9ae 475 __tzname[0] = NULL;
ff152e3f 476 __tzname[1] = NULL;
a3e0e9ae
UD
477 for (i = num_transitions; i > 0; )
478 {
479 int type = type_idxs[--i];
480 int dst = types[type].isdst;
481 int idx = types[type].idx;
482
483 if (__tzname[dst] == NULL)
484 {
485 __tzname[dst] = __tzstring (&zone_names[idx]);
486
487 if (__tzname[1 - dst] != NULL)
488 break;
489 }
490 }
491 if (__tzname[0] == NULL)
492 {
493 /* This should only happen if there are no transition rules.
494 In this case there should be only one single type. */
495 assert (num_types == 1);
496 __tzname[0] = __tzstring (zone_names);
497 }
ff152e3f
UD
498 if (__tzname[1] == NULL)
499 /* There is no daylight saving time. */
500 __tzname[1] = __tzname[0];
a709dd43
UD
501 tp->tm_isdst = info->isdst;
502 tp->tm_zone = &zone_names[info->idx];
503 tp->tm_gmtoff = info->offset;
9a0a462c 504 }
28f540f4
RM
505
506 *leap_correct = 0L;
507 *leap_hit = 0;
508
509 /* Find the last leap second correction transition time before TIMER. */
510 i = num_leaps;
511 do
512 if (i-- == 0)
513 return 1;
514 while (timer < leaps[i].transition);
515
516 /* Apply its correction. */
517 *leap_correct = leaps[i].change;
518
519 if (timer == leaps[i].transition && /* Exactly at the transition time. */
520 ((i == 0 && leaps[i].change > 0) ||
521 leaps[i].change > leaps[i - 1].change))
522 {
523 *leap_hit = 1;
ba9234d9
UD
524 while (i > 0
525 && leaps[i].transition == leaps[i - 1].transition + 1
526 && leaps[i].change == leaps[i - 1].change + 1)
28f540f4
RM
527 {
528 ++*leap_hit;
529 --i;
530 }
531 }
532
533 return 1;
534}
535\f
9a0a462c 536static void
dfd2257a 537internal_function
860d3729 538compute_tzname_max (size_t chars)
28f540f4 539{
28f540f4
RM
540 const char *p;
541
542 p = zone_names;
543 do
544 {
545 const char *start = p;
546 while (*p != '\0')
547 ++p;
5290baf0 548 if ((size_t) (p - start) > __tzname_cur_max)
28f540f4 549 __tzname_cur_max = p - start;
ba9234d9
UD
550 }
551 while (++p < &zone_names[chars]);
28f540f4 552}