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