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