1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * A part of this file comes from public domain source, so
32 * clarified as of June 5, 1996 by Arthur David Olson
33 * (arthur_david_olson@nih.gov).
34 */
35
36 /*
37 * localtime.c
38 *
39 * This file contains routines to convert struct tm to time_t and
40 * back as well as adjust time values based on their timezone, which
41 * is a local offset from GMT (Greenwich Mean Time).
42 *
43 * Many timezones actually consist of more than one offset from GMT.
44 * The GMT offset that is considered the normal offset is referred
45 * to as standard time. The other offset is referred to as alternate
46 * time, but is better known as daylight savings time or summer time.
47 *
48 * The current timezone for an application is derived from the TZ
49 * environment variable either as defined in the environment or in
50 * /etc/default/init. As defined by IEEE 1003.1-1990 (POSIX), the
51 * TZ variable can either be:
52 * :<characters>
53 * or
54 * <std><offset1>[<dst>[<offset2>]][,<start>[/<time>],<end>[/<time>]
55 *
56 * <characters> is an implementation-defined string that somehow describes
57 * a timezone. The implementation-defined description of a timezone used
58 * in Solaris is based on the public domain zoneinfo code available from
59 * elsie.nci.nih.gov and a timezone that is specified in this way is
60 * referred to as a zoneinfo timezone. An example of this is ":US/Pacific".
61 *
62 * The precise definition of the second format can be found in POSIX,
63 * but, basically, <std> is the abbreviation for the timezone in standard
64 * (not daylight savings time), <offset1> is the standard offset from GMT,
65 * <dst> is the abbreviation for the timezone in daylight savings time and
66 * <offset2> is the daylight savings time offset from GMT. The remainder
67 * specifies when daylight savings time begins and ends. A timezone
68 * specified in this way is referred to as a POSIX timezone. An example
69 * of this is "PST7PDT".
70 *
71 * In Solaris, there is an extension to this. If the timezone is not
72 * preceded by a ":" and it does not parse as a POSIX timezone, then it
73 * will be treated as a zoneinfo timezone. Much usage of zoneinfo
74 * timezones in Solaris is done without the leading ":".
75 *
76 * A zoneinfo timezone is a reference to a file that contains a set of
77 * rules that describe the timezone. In Solaris, the file is in
78 * /usr/share/lib/zoneinfo. The file is generated by zic(1M), based
79 * on zoneinfo rules "source" files. This is all described on the zic(1M)
80 * man page.
81 */
82
83 /*
84 * Functions that are common to ctime(3C) and cftime(3C)
85 */
86
87 #pragma weak _tzset = tzset
88
89 #include "lint.h"
90 #include "libc.h"
91 #include "tsd.h"
92 #include <stdarg.h>
93 #include <mtlib.h>
94 #include <sys/types.h>
95 #include <ctype.h>
96 #include <stdio.h>
97 #include <limits.h>
98 #include <sys/param.h>
99 #include <time.h>
100 #include <unistd.h>
101 #include <stdlib.h>
102 #include <string.h>
103 #include <tzfile.h>
104 #include <thread.h>
105 #include <synch.h>
106 #include <fcntl.h>
107 #include <errno.h>
108 #include <deflt.h>
109 #include <sys/stat.h>
110 #include <sys/mman.h>
111
112 /* JAN_01_1902 cast to (int) - negative number of seconds from 1970 */
113 #define JAN_01_1902 (int)0x8017E880
114 #define LEN_TZDIR (sizeof (TZDIR) - 1)
115 #define TIMEZONE "/etc/default/init"
116 #define TZSTRING "TZ="
117 #define HASHTABLE 31
118
119 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
120
121 /* Days since 1/1/70 to 12/31/(1900 + Y - 1) */
122 #define DAYS_SINCE_70(Y) (YR((Y)-1L) - YR(70-1))
123 #define YR(X) /* Calc # days since 0 A.D. X = curr. yr - 1900 */ \
124 ((1900L + (X)) * 365L + (1900L + (X)) / 4L - \
125 (1900L + (X)) / 100L + ((1900L + (X)) - 1600L) / 400L)
126
127
128 /*
129 * The following macros are replacements for detzcode(), which has
130 * been in the public domain versions of the localtime.c code for
131 * a long time. The primatives supporting the CVTZCODE macro are
132 * implemented differently for different endianness (ie. little
133 * vs. big endian) out of necessity, to account for the different
134 * byte ordering of the quantities being fetched. Both versions
135 * are substantially faster than the detzcode() macro. The big
136 * endian version is approx. 6.8x faster than detzcode(), the
137 * little endian version is approximately 3x faster, due to the
138 * extra shifting requiring to change byte order. The micro
139 * benchmarks used to compare were based on the SUNWSpro SC6.1
140 * (and later) compilers.
141 */
142
143 #if defined(__sparc) || defined(__sparcv9) /* big endian */
144
145 #define GET_LONG(p) \
146 *(uint_t *)(p)
147
148 #define GET_SHORTS(p) \
149 *(ushort_t *)(p) << 16 |\
150 *(ushort_t *)((p) + 2)
151
152 #define GET_CHARS(p) \
153 *(uchar_t *)(p) << 24 |\
154 *(uchar_t *)((p) + 1) << 16 |\
155 *(uchar_t *)((p) + 2) << 8 |\
156 *(uchar_t *)((p) + 3)
157
158 #else /* little endian */
159
160 #define GET_BYTE(x) \
161 ((x) & 0xff)
162
163 #define SWAP_BYTES(x) ((\
164 GET_BYTE(x) << 8) |\
165 GET_BYTE((x) >> 8))
166
167 #define SWAP_WORDS(x) ((\
168 SWAP_BYTES(x) << 16) |\
169 SWAP_BYTES((x) >> 16))
170
171 #define GET_LONG(p) \
172 SWAP_WORDS(*(uint_t *)(p))
173
174 #define GET_SHORTS(p) \
175 SWAP_BYTES(*(ushort_t *)(p)) << 16 |\
176 SWAP_BYTES(*(ushort_t *)((p) + 2))
177
178 #define GET_CHARS(p) \
179 GET_BYTE(*(uchar_t *)(p)) << 24 |\
180 GET_BYTE(*(uchar_t *)((p) + 1)) << 16 |\
181 GET_BYTE(*(uchar_t *)((p) + 2)) << 8 |\
182 GET_BYTE(*(uchar_t *)((p) + 3))
183
184 #endif
185
186
187 #define IF_ALIGNED(ptr, byte_alignment) \
188 !((uintptr_t)(ptr) & (byte_alignment - 1))
189
190 #define CVTZCODE(p) (int)(\
191 IF_ALIGNED(p, 4) ? GET_LONG(p) :\
192 IF_ALIGNED(p, 2) ? GET_SHORTS(p) : GET_CHARS(p));\
193 p += 4;
194
195 #ifndef FALSE
196 #define FALSE (0)
197 #endif
198
199 #ifndef TRUE
200 #define TRUE (1)
201 #endif
202
203 extern mutex_t _time_lock;
204
205 extern const int __lyday_to_month[];
206 extern const int __yday_to_month[];
207 extern const int __mon_lengths[2][MONS_PER_YEAR];
208 extern const int __year_lengths[2];
209
210 const char _tz_gmt[4] = "GMT"; /* "GMT" */
211 const char _tz_spaces[4] = " "; /* " " */
212 static const char _posix_gmt0[5] = "GMT0"; /* "GMT0" */
213
214 typedef struct ttinfo { /* Time type information */
215 long tt_gmtoff; /* GMT offset in seconds */
216 int tt_isdst; /* used to set tm_isdst */
217 int tt_abbrind; /* abbreviation list index */
218 int tt_ttisstd; /* TRUE if trans is std time */
219 int tt_ttisgmt; /* TRUE if transition is GMT */
220 } ttinfo_t;
221
222 typedef struct lsinfo { /* Leap second information */
223 time_t ls_trans; /* transition time */
224 long ls_corr; /* correction to apply */
225 } lsinfo_t;
226
227 typedef struct previnfo { /* Info about *prev* trans */
228 ttinfo_t *std; /* Most recent std type */
229 ttinfo_t *alt; /* Most recent alt type */
230 } prev_t;
231
232 typedef enum {
233 MON_WEEK_DOW, /* Mm.n.d - month, week, day of week */
234 JULIAN_DAY, /* Jn - Julian day */
235 DAY_OF_YEAR /* n - day of year */
236 } posrule_type_t;
237
238 typedef struct {
239 posrule_type_t r_type; /* type of rule */
240 int r_day; /* day number of rule */
241 int r_week; /* week number of rule */
242 int r_mon; /* month number of rule */
243 long r_time; /* transition time of rule */
244 } rule_t;
245
246 typedef struct {
247 rule_t *rules[2];
248 long offset[2];
249 long long rtime[2];
250 } posix_daylight_t;
251
252 /*
253 * Note: ZONERULES_INVALID used for global curr_zonerules variable, but not
254 * for zonerules field of state_t.
255 */
256 typedef enum {
257 ZONERULES_INVALID, POSIX, POSIX_USA, ZONEINFO
258 } zone_rules_t;
259
260 /*
261 * The following members are allocated from the libc-internal malloc:
262 *
263 * zonename
264 * chars
265 */
266 typedef struct state {
267 const char *zonename; /* Timezone */
268 struct state *next; /* next state */
269 zone_rules_t zonerules; /* Type of zone */
270 int daylight; /* daylight global */
271 long default_timezone; /* Def. timezone val */
272 long default_altzone; /* Def. altzone val */
273 const char *default_tzname0; /* Def tz..[0] val */
274 const char *default_tzname1; /* Def tz..[1] val */
275 int leapcnt; /* # leap sec trans */
276 int timecnt; /* # transitions */
277 int typecnt; /* # zone types */
278 int charcnt; /* # zone abbv. chars */
279 char *chars; /* Zone abbv. chars */
280 size_t charsbuf_size; /* malloc'ed buflen */
281 prev_t prev[TZ_MAX_TIMES]; /* Pv. trans info */
282 time_t ats[TZ_MAX_TIMES]; /* Trans. times */
283 uchar_t types[TZ_MAX_TIMES]; /* Type indices */
284 ttinfo_t ttis[TZ_MAX_TYPES]; /* Zone types */
285 lsinfo_t lsis[TZ_MAX_LEAPS]; /* Leap sec trans */
286 int last_ats_idx; /* last ats index */
287 rule_t start_rule; /* For POSIX w/rules */
288 rule_t end_rule; /* For POSIX w/rules */
289 } state_t;
290
291 typedef struct tznmlist {
292 struct tznmlist *link;
293 char name[1];
294 } tznmlist_t;
295
296 static const char *systemTZ;
297 static tznmlist_t *systemTZrec;
298
299 static const char *namecache;
300
301 static state_t *tzcache[HASHTABLE];
302
303 #define TZNMC_SZ 43
304 static tznmlist_t *tznmhash[TZNMC_SZ];
305 static const char *last_tzname[2];
306
307 static state_t *lclzonep;
308
309 static struct tm tm; /* For non-reentrant use */
310 static int is_in_dst; /* Set if t is in DST */
311 static zone_rules_t curr_zonerules = ZONERULES_INVALID;
312 static int cached_year; /* mktime() perf. enhancement */
313 static long long cached_secs_since_1970; /* mktime() perf. */
314 static int year_is_cached = FALSE; /* mktime() perf. */
315
316 #define TZSYNC_FILE "/var/run/tzsync"
317 static uint32_t zoneinfo_seqno;
318 static uint32_t zoneinfo_seqno_init = 1;
319 static uint32_t *zoneinfo_seqadr = &zoneinfo_seqno_init;
320 #define RELOAD_INFO() (zoneinfo_seqno != *zoneinfo_seqadr)
321
322 #define _2AM (2 * SECS_PER_HOUR)
323 #define FIRSTWEEK 1
324 #define LASTWEEK 5
325
326 enum wks {
327 _1st_week = 1,
328 _2nd_week,
329 _3rd_week,
330 _4th_week,
331 _Last_week
332 };
333
334 enum dwk {
335 Sun,
336 Mon,
337 Tue,
338 Wed,
339 Thu,
340 Fri,
341 Sat
342 };
343
344 enum mth {
345 Jan = 1,
346 Feb,
347 Mar,
348 Apr,
349 May,
350 Jun,
351 Jul,
352 Aug,
353 Sep,
354 Oct,
355 Nov,
356 Dec
357 };
358
359 /*
360 * The following table defines standard USA DST transitions
361 * as they have been declared throughout history, disregarding
362 * the legally sanctioned local variants.
363 *
364 * Note: At some point, this table may be supplanted by
365 * more popular 'posixrules' logic.
366 */
367 typedef struct {
368 int s_year;
369 int e_year;
370 rule_t start;
371 rule_t end;
372 } __usa_rules_t;
373
374 static const __usa_rules_t __usa_rules[] = {
375 {
376 2007, 2037,
377 { MON_WEEK_DOW, Sun, _2nd_week, Mar, _2AM },
378 { MON_WEEK_DOW, Sun, _1st_week, Nov, _2AM },
379 },
380 {
381 1987, 2006,
382 { MON_WEEK_DOW, Sun, _1st_week, Apr, _2AM },
383 { MON_WEEK_DOW, Sun, _Last_week, Oct, _2AM },
384 },
385 {
386 1976, 1986,
387 { MON_WEEK_DOW, Sun, _Last_week, Apr, _2AM },
388 { MON_WEEK_DOW, Sun, _Last_week, Oct, _2AM },
389 },
390 {
391 1975, 1975,
392 { MON_WEEK_DOW, Sun, _Last_week, Feb, _2AM },
393 { MON_WEEK_DOW, Sun, _Last_week, Oct, _2AM },
394 },
395
396 {
397 1974, 1974,
398 { MON_WEEK_DOW, Sun, _1st_week, Jan, _2AM },
399 { MON_WEEK_DOW, Sun, _Last_week, Nov, _2AM },
400 },
401 /*
402 * The entry below combines two previously separate entries for
403 * 1969-1973 and 1902-1968
404 */
405 {
406 1902, 1973,
407 { MON_WEEK_DOW, Sun, _Last_week, Apr, _2AM },
408 { MON_WEEK_DOW, Sun, _Last_week, Oct, _2AM },
409 }
410 };
411 #define MAX_RULE_TABLE (sizeof (__usa_rules) / sizeof (__usa_rules_t) - 1)
412
413 /*
414 * Prototypes for static functions.
415 */
416 static const char *getsystemTZ(void);
417 static const char *getzname(const char *, int);
418 static const char *getnum(const char *, int *, int, int);
419 static const char *getsecs(const char *, long *);
420 static const char *getoffset(const char *, long *);
421 static const char *getrule(const char *, rule_t *, int);
422 static int load_posixinfo(const char *, state_t *);
423 static int load_zoneinfo(const char *, state_t *);
424 static void load_posix_transitions(state_t *, long, long, zone_rules_t);
425 static void adjust_posix_default(state_t *, long, long);
426 static void *ltzset_u(time_t);
427 static struct tm *offtime_u(time_t, long, struct tm *);
428 static int posix_check_dst(long long, state_t *);
429 static int posix_daylight(long long *, int, posix_daylight_t *);
430 static void set_zone_context(time_t);
431 static void reload_counter(void);
432 static void purge_zone_cache(void);
433 static void set_tzname(const char **);
434
435 /*
436 * definition of difftime
437 *
438 * This code assumes time_t is type long. Note the difference of two
439 * longs in absolute value is representable as an unsigned long. So,
440 * compute the absolute value of the difference, cast the result to
441 * double and attach the sign back on.
442 *
443 * Note this code assumes 2's complement arithmetic. The subtraction
444 * operation may overflow when using signed operands, but when the
445 * result is cast to unsigned long, it yields the desired value
446 * (ie, the absolute value of the difference). The cast to unsigned
447 * long is done using pointers to avoid undefined behavior if casting
448 * a negative value to unsigned.
449 */
450 double
difftime(time_t time1,time_t time0)451 difftime(time_t time1, time_t time0)
452 {
453 if (time1 < time0) {
454 time0 -= time1;
455 return (-(double)*(unsigned long *) &time0);
456 } else {
457 time1 -= time0;
458 return ((double)*(unsigned long *) &time1);
459 }
460 }
461
462 /*
463 * Accepts a time_t, returns a tm struct based on it, with
464 * no local timezone adjustment.
465 *
466 * This routine is the thread-safe variant of gmtime(), and
467 * requires that the call provide the address of their own tm
468 * struct.
469 *
470 * Locking is not done here because set_zone_context()
471 * is not called, thus timezone, altzone, and tzname[] are not
472 * accessed, no memory is allocated, and no common dynamic
473 * data is accessed.
474 *
475 * See ctime(3C)
476 */
477 struct tm *
gmtime_r(const time_t * timep,struct tm * p_tm)478 gmtime_r(const time_t *timep, struct tm *p_tm)
479 {
480 return (offtime_u((time_t)*timep, 0L, p_tm));
481 }
482
483 /*
484 * Accepts a time_t, returns a tm struct based on it, with
485 * no local timezone adjustment.
486 *
487 * This function is explicitly NOT THREAD-SAFE. The standards
488 * indicate it should provide its results in its own statically
489 * allocated tm struct that gets overwritten. The thread-safe
490 * variant is gmtime_r(). We make it mostly thread-safe by
491 * allocating its buffer in thread-specific data.
492 *
493 * See ctime(3C)
494 */
495 struct tm *
gmtime(const time_t * timep)496 gmtime(const time_t *timep)
497 {
498 struct tm *p_tm = tsdalloc(_T_STRUCT_TM, sizeof (struct tm), NULL);
499
500 if (p_tm == NULL) /* memory allocation failure */
501 p_tm = &tm; /* use static buffer and hope for the best */
502 return (gmtime_r(timep, p_tm));
503 }
504
505 /*
506 * This is the hashing function, based on the input timezone name.
507 */
508 static int
get_hashid(const char * id)509 get_hashid(const char *id)
510 {
511 unsigned char c;
512 unsigned int h;
513
514 h = *id++;
515 while ((c = *id++) != '\0')
516 h += c;
517 return ((int)(h % HASHTABLE));
518 }
519
520 /*
521 * find_zone() gets the hashid for zonename, then uses the hashid
522 * to search the hash table for the appropriate timezone entry. If
523 * the entry for zonename is found in the hash table, return a pointer
524 * to the entry.
525 */
526 static state_t *
find_zone(const char * zonename)527 find_zone(const char *zonename)
528 {
529 int hashid;
530 state_t *cur;
531
532 hashid = get_hashid(zonename);
533 cur = tzcache[hashid];
534 while (cur) {
535 int res;
536 res = strcmp(cur->zonename, zonename);
537 if (res == 0) {
538 return (cur);
539 } else if (res > 0) {
540 break;
541 }
542 cur = cur->next;
543 }
544 return (NULL);
545 }
546
547 /*
548 * Register new state in the cache.
549 */
550 static void
reg_zone(state_t * new)551 reg_zone(state_t *new)
552 {
553 int hashid, res;
554 state_t *cur, *prv;
555
556 hashid = get_hashid(new->zonename);
557 cur = tzcache[hashid];
558 prv = NULL;
559 while (cur != NULL) {
560 res = strcmp(cur->zonename, new->zonename);
561 if (res == 0) {
562 /* impossible, but just in case */
563 return;
564 } else if (res > 0) {
565 break;
566 }
567 prv = cur;
568 cur = cur->next;
569 }
570 if (prv != NULL) {
571 new->next = prv->next;
572 prv->next = new;
573 } else {
574 new->next = tzcache[hashid];
575 tzcache[hashid] = new;
576 }
577 }
578
579 /*
580 * Returns tm struct based on input time_t argument, correcting
581 * for the local timezone, producing documented side-effects
582 * to extern global state, timezone, altzone, daylight and tzname[].
583 *
584 * localtime_r() is the thread-safe variant of localtime().
585 *
586 * IMPLEMENTATION NOTE:
587 *
588 * Locking slows multithreaded access and is probably ultimately
589 * unnecessary here. The POSIX specification is a bit vague
590 * as to whether the extern variables set by tzset() need to
591 * set as a result of a call to localtime_r()
592 *
593 * Currently, the spec only mentions that tzname[] doesn't
594 * need to be set. As soon as it becomes unequivocal
595 * that the external zone state doesn't need to be asserted
596 * for this call, and it really doesn't make much sense
597 * to set common state from multi-threaded calls made to this
598 * function, locking can be dispensed with here.
599 *
600 * local zone state would still need to be aquired for the
601 * time in question in order for calculations elicited here
602 * to be correct, but that state wouldn't need to be shared,
603 * thus no multi-threaded synchronization would be required.
604 *
605 * It would be nice if POSIX would approve an ltzset_r()
606 * function, but if not, it wouldn't stop us from making one
607 * privately.
608 *
609 * localtime_r() can now return NULL if overflow is detected.
610 * offtime_u() is the function that detects overflow, and sets
611 * errno appropriately. We unlock before the call to offtime_u(),
612 * so that lmutex_unlock() does not reassign errno. The function
613 * offtime_u() is MT-safe and does not have to be locked. Use
614 * my_is_in_dst to reference local copy of is_in_dst outside locks.
615 *
616 * See ctime(3C)
617 */
618 struct tm *
localtime_r(const time_t * timep,struct tm * p_tm)619 localtime_r(const time_t *timep, struct tm *p_tm)
620 {
621 long offset;
622 struct tm *rt;
623 void *unused;
624 int my_is_in_dst;
625
626 lmutex_lock(&_time_lock);
627 unused = ltzset_u(*timep);
628 if (lclzonep == NULL) {
629 lmutex_unlock(&_time_lock);
630 if (unused != NULL)
631 free(unused);
632 return (offtime_u(*timep, 0L, p_tm));
633 }
634 my_is_in_dst = is_in_dst;
635 offset = (my_is_in_dst) ? -altzone : -timezone;
636 lmutex_unlock(&_time_lock);
637 if (unused != NULL)
638 free(unused);
639 rt = offtime_u(*timep, offset, p_tm);
640 p_tm->tm_isdst = my_is_in_dst;
641 return (rt);
642 }
643
644 /*
645 * Accepts a time_t, returns a tm struct based on it, correcting
646 * for the local timezone. Produces documented side-effects to
647 * extern global timezone state data.
648 *
649 * This function is explicitly NOT THREAD-SAFE. The standards
650 * indicate it should provide its results in its own statically
651 * allocated tm struct that gets overwritten. The thread-safe
652 * variant is localtime_r(). We make it mostly thread-safe by
653 * allocating its buffer in thread-specific data.
654 *
655 * localtime() can now return NULL if overflow is detected.
656 * offtime_u() is the function that detects overflow, and sets
657 * errno appropriately.
658 *
659 * See ctime(3C)
660 */
661 struct tm *
localtime(const time_t * timep)662 localtime(const time_t *timep)
663 {
664 struct tm *p_tm = tsdalloc(_T_STRUCT_TM, sizeof (struct tm), NULL);
665
666 if (p_tm == NULL) /* memory allocation failure */
667 p_tm = &tm; /* use static buffer and hope for the best */
668 return (localtime_r(timep, p_tm));
669 }
670
671 /*
672 * This function takes a pointer to a tm struct and returns a
673 * normalized time_t, also inducing documented side-effects in
674 * extern global zone state variables. (See mktime(3C)).
675 */
676 time_t
mktime(struct tm * tmptr)677 mktime(struct tm *tmptr)
678 {
679 struct tm _tm;
680 long long t; /* must hold more than 32-bit time_t */
681 int temp;
682 int mketimerrno;
683 int overflow;
684 void *unused;
685
686 mketimerrno = errno;
687
688 /* mktime leaves errno unchanged if no error is encountered */
689
690 /* Calculate time_t from tm arg. tm may need to be normalized. */
691 t = tmptr->tm_sec + SECSPERMIN * tmptr->tm_min +
692 SECSPERHOUR * tmptr->tm_hour +
693 SECSPERDAY * (tmptr->tm_mday - 1);
694
695 if (tmptr->tm_mon >= 12) {
696 tmptr->tm_year += tmptr->tm_mon / 12;
697 tmptr->tm_mon %= 12;
698 } else if (tmptr->tm_mon < 0) {
699 temp = -tmptr->tm_mon;
700 tmptr->tm_mon = 0; /* If tm_mon divides by 12. */
701 tmptr->tm_year -= (temp / 12);
702 if (temp %= 12) { /* Remainder... */
703 tmptr->tm_year--;
704 tmptr->tm_mon = 12 - temp;
705 }
706 }
707
708 lmutex_lock(&_time_lock);
709
710 /* Avoid numerous calculations embedded in macro if possible */
711 if (!year_is_cached || (cached_year != tmptr->tm_year)) {
712 cached_year = tmptr->tm_year;
713 year_is_cached = TRUE;
714 /* For boundry values of tm_year, typecasting required */
715 cached_secs_since_1970 =
716 (long long)SECSPERDAY * DAYS_SINCE_70(cached_year);
717 }
718 t += cached_secs_since_1970;
719
720 if (isleap(tmptr->tm_year + TM_YEAR_BASE))
721 t += SECSPERDAY * __lyday_to_month[tmptr->tm_mon];
722 else
723 t += SECSPERDAY * __yday_to_month[tmptr->tm_mon];
724
725 unused = ltzset_u((time_t)t);
726
727 /* Attempt to convert time to GMT based on tm_isdst setting */
728 t += (tmptr->tm_isdst > 0) ? altzone : timezone;
729
730 #ifdef _ILP32
731 overflow = t > LONG_MAX || t < LONG_MIN ||
732 tmptr->tm_year < 1 || tmptr->tm_year > 138;
733 #else
734 overflow = t > LONG_MAX || t < LONG_MIN;
735 #endif
736 set_zone_context((time_t)t);
737 if (tmptr->tm_isdst < 0) {
738 long dst_delta = timezone - altzone;
739 switch (curr_zonerules) {
740 case ZONEINFO:
741 if (is_in_dst) {
742 t -= dst_delta;
743 set_zone_context((time_t)t);
744 if (is_in_dst) {
745 (void) offtime_u((time_t)t,
746 -altzone, &_tm);
747 _tm.tm_isdst = 1;
748 } else {
749 (void) offtime_u((time_t)t,
750 -timezone, &_tm);
751 }
752 } else {
753 (void) offtime_u((time_t)t, -timezone, &_tm);
754 }
755 break;
756 case POSIX_USA:
757 case POSIX:
758 if (is_in_dst) {
759 t -= dst_delta;
760 set_zone_context((time_t)t);
761 if (is_in_dst) {
762 (void) offtime_u((time_t)t,
763 -altzone, &_tm);
764 _tm.tm_isdst = 1;
765 } else {
766 (void) offtime_u((time_t)t,
767 -timezone, &_tm);
768 }
769 } else { /* check for ambiguous 'fallback' transition */
770 set_zone_context((time_t)t - dst_delta);
771 if (is_in_dst) { /* In fallback, force DST */
772 t -= dst_delta;
773 (void) offtime_u((time_t)t,
774 -altzone, &_tm);
775 _tm.tm_isdst = 1;
776 } else {
777 (void) offtime_u((time_t)t,
778 -timezone, &_tm);
779 }
780 }
781 break;
782
783 case ZONERULES_INVALID:
784 (void) offtime_u((time_t)t, 0L, &_tm);
785 break;
786
787 }
788 } else if (is_in_dst) {
789 (void) offtime_u((time_t)t, -altzone, &_tm);
790 _tm.tm_isdst = 1;
791 } else {
792 (void) offtime_u((time_t)t, -timezone, &_tm);
793 }
794
795 if (overflow || t > LONG_MAX || t < LONG_MIN) {
796 mketimerrno = EOVERFLOW;
797 t = -1;
798 } else {
799 *tmptr = _tm;
800 }
801
802 lmutex_unlock(&_time_lock);
803 if (unused != NULL)
804 free(unused);
805
806 errno = mketimerrno;
807 return ((time_t)t);
808 }
809
810 /*
811 * Sets extern global zone state variables based on the current
812 * time. Specifically, tzname[], timezone, altzone, and daylight
813 * are updated. See ctime(3C) manpage.
814 */
815 void
tzset(void)816 tzset(void)
817 {
818 void *unused;
819
820 lmutex_lock(&_time_lock);
821 unused = ltzset_u(time(NULL));
822 lmutex_unlock(&_time_lock);
823 if (unused != NULL)
824 free(unused);
825 }
826
827 void
_ltzset(time_t tim)828 _ltzset(time_t tim)
829 {
830 void *unused;
831
832 lmutex_lock(&_time_lock);
833 unused = ltzset_u(tim);
834 lmutex_unlock(&_time_lock);
835 if (unused != NULL)
836 free(unused);
837 }
838
839 /*
840 * Loads local zone information if TZ changed since last time zone
841 * information was loaded, or if this is the first time thru.
842 * We already hold _time_lock; no further locking is required.
843 * Return a memory block which can be free'd at safe place.
844 */
845 static void *
ltzset_u(time_t t)846 ltzset_u(time_t t)
847 {
848 const char *zonename;
849 state_t *entry, *new_entry;
850 const char *newtzname[2];
851
852 if (RELOAD_INFO()) {
853 reload_counter();
854 purge_zone_cache();
855 }
856
857 if ((zonename = getsystemTZ()) == NULL || *zonename == '\0')
858 zonename = _posix_gmt0;
859
860 if (namecache != NULL && strcmp(namecache, zonename) == 0) {
861 set_zone_context(t);
862 return (NULL);
863 }
864
865 entry = find_zone(zonename);
866 if (entry == NULL) {
867 /*
868 * We need to release _time_lock to call out malloc().
869 * We can release _time_lock as far as global variables
870 * can remain consistent. Here, we haven't touch any
871 * variables, so it's okay to release lock.
872 */
873 lmutex_unlock(&_time_lock);
874 new_entry = malloc(sizeof (state_t));
875 lmutex_lock(&_time_lock);
876
877 /*
878 * check it again, since zone may have been loaded while
879 * time_lock was unlocked.
880 */
881 entry = find_zone(zonename);
882 } else {
883 new_entry = NULL;
884 goto out;
885 }
886
887 /*
888 * We are here because the 1st attemp failed.
889 * new_entry points newly allocated entry. If it was NULL, it
890 * indicates that the memory allocation also failed.
891 */
892 if (entry == NULL) {
893 /*
894 * 2nd attemp also failed.
895 * No timezone entry found in hash table, so load it,
896 * and create a new timezone entry.
897 */
898 char *newzonename, *charsbuf;
899
900 newzonename = libc_strdup(zonename);
901 daylight = 0;
902 entry = new_entry;
903
904 if (entry == NULL || newzonename == NULL) {
905 /* something wrong happened. */
906 failed:
907 if (newzonename != NULL)
908 libc_free(newzonename);
909
910 /* Invalidate the current timezone */
911 curr_zonerules = ZONERULES_INVALID;
912 namecache = NULL;
913
914 timezone = altzone = 0;
915 is_in_dst = 0;
916 newtzname[0] = (char *)_tz_gmt;
917 newtzname[1] = (char *)_tz_spaces;
918 set_tzname(newtzname);
919 return (entry);
920 }
921
922 /*
923 * Builds transition cache and sets up zone state data for zone
924 * specified in TZ, which can be specified as a POSIX zone or an
925 * Olson zoneinfo file reference.
926 *
927 * If local data cannot be parsed or loaded, the local zone
928 * tables are set up for GMT.
929 *
930 * Unless a leading ':' is prepended to TZ, TZ is initially
931 * parsed as a POSIX zone; failing that, it reverts to
932 * a zoneinfo check.
933 * However, if a ':' is prepended, the zone will *only* be
934 * parsed as zoneinfo. If any failure occurs parsing or
935 * loading a zoneinfo TZ, GMT data is loaded for the local zone.
936 *
937 * Example: There is a zoneinfo file in the standard
938 * distribution called 'PST8PDT'. The only way the user can
939 * specify that file under Solaris is to set TZ to ":PST8PDT".
940 * Otherwise the initial parse of PST8PDT as a POSIX zone will
941 * succeed and be used.
942 */
943 if ((charsbuf = libc_malloc(TZ_MAX_CHARS)) == NULL)
944 goto failed;
945
946 entry->zonerules = ZONERULES_INVALID;
947 entry->charsbuf_size = TZ_MAX_CHARS;
948 entry->chars = charsbuf;
949 entry->default_tzname0 = _tz_gmt;
950 entry->default_tzname1 = _tz_spaces;
951 entry->zonename = newzonename;
952
953 if (*zonename == ':') {
954 if (load_zoneinfo(zonename + 1, entry) != 0) {
955 (void) load_posixinfo(_posix_gmt0, entry);
956 }
957 } else if (load_posixinfo(zonename, entry) != 0) {
958 if (load_zoneinfo(zonename, entry) != 0) {
959 (void) load_posixinfo(_posix_gmt0, entry);
960 }
961 }
962 entry->last_ats_idx = -1;
963
964 /*
965 * The pre-allocated buffer is used; reset the free flag
966 * so the buffer won't be freed.
967 */
968 reg_zone(entry);
969 new_entry = NULL;
970 }
971
972 out:
973 curr_zonerules = entry->zonerules;
974 namecache = entry->zonename;
975 daylight = entry->daylight;
976 lclzonep = entry;
977
978 set_zone_context(t);
979
980 /*
981 * We shouldn't release lock beyond this point since lclzonep
982 * can refer to invalid address if cache is invalidated.
983 * We defer the call to free till it can be done safely.
984 */
985 return (new_entry);
986 }
987
988 /*
989 * Sets timezone, altzone, tzname[], extern globals, to represent
990 * disposition of t with respect to TZ; See ctime(3C). is_in_dst,
991 * internal global is also set. daylight is set at zone load time.
992 *
993 * Issues:
994 *
995 * In this function, any time_t not located in the cache is handled
996 * as a miss. To build/update transition cache, load_zoneinfo()
997 * must be called prior to this routine.
998 *
999 * If POSIX zone, cache miss penalty is slightly degraded
1000 * performance. For zoneinfo, penalty is decreased is_in_dst
1001 * accuracy.
1002 *
1003 * POSIX, despite its chicken/egg problem, ie. not knowing DST
1004 * until time known, and not knowing time until DST known, at
1005 * least uses the same algorithm for 64-bit time as 32-bit.
1006 *
1007 * The fact that zoneinfo files only contain transistions for 32-bit
1008 * time space is a well known problem, as yet unresolved.
1009 * Without an official standard for coping with out-of-range
1010 * zoneinfo times, assumptions must be made. For now
1011 * the assumption is: If t exceeds 32-bit boundries and local zone
1012 * is zoneinfo type, is_in_dst is set to to 0 for negative values
1013 * of t, and set to the same DST state as the highest ordered
1014 * transition in cache for positive values of t.
1015 */
1016 static void
set_zone_default_context(void)1017 set_zone_default_context(void)
1018 {
1019 const char *newtzname[2];
1020
1021 /* Retrieve suitable defaults for this zone */
1022 altzone = lclzonep->default_altzone;
1023 timezone = lclzonep->default_timezone;
1024 newtzname[0] = (char *)lclzonep->default_tzname0;
1025 newtzname[1] = (char *)lclzonep->default_tzname1;
1026 is_in_dst = 0;
1027
1028 set_tzname(newtzname);
1029 }
1030
1031 static void
set_zone_context(time_t t)1032 set_zone_context(time_t t)
1033 {
1034 prev_t *prevp;
1035 int lo, hi, tidx, lidx;
1036 ttinfo_t *ttisp, *std, *alt;
1037 const char *newtzname[2];
1038
1039 /* If state data not loaded or TZ busted, just use GMT */
1040 if (lclzonep == NULL || curr_zonerules == ZONERULES_INVALID) {
1041 timezone = altzone = 0;
1042 daylight = is_in_dst = 0;
1043 newtzname[0] = (char *)_tz_gmt;
1044 newtzname[1] = (char *)_tz_spaces;
1045 set_tzname(newtzname);
1046 return;
1047 }
1048
1049 if (lclzonep->timecnt <= 0 || lclzonep->typecnt < 2) {
1050 /* Loaded zone incapable of transitioning. */
1051 set_zone_default_context();
1052 return;
1053 }
1054
1055 /*
1056 * At least one alt. zone and one transistion exist. Locate
1057 * state for 't' quickly as possible. Use defaults as necessary.
1058 */
1059 lo = 0;
1060 hi = lclzonep->timecnt - 1;
1061
1062 if (t < lclzonep->ats[0] || t >= lclzonep->ats[hi]) {
1063 /*
1064 * Date which is out of definition.
1065 * Calculate DST as best as possible
1066 */
1067 if (lclzonep->zonerules == POSIX_USA ||
1068 lclzonep->zonerules == POSIX) {
1069 /* Must invoke calculations to determine DST */
1070 set_zone_default_context();
1071 is_in_dst = (daylight) ?
1072 posix_check_dst(t, lclzonep) : 0;
1073 return;
1074 } else if (t < lclzonep->ats[0]) { /* zoneinfo... */
1075 /* t precedes 1st transition. Use defaults */
1076 set_zone_default_context();
1077 return;
1078 } else { /* zoneinfo */
1079 /* t follows final transistion. Use final */
1080 tidx = hi;
1081 }
1082 } else {
1083 if ((lidx = lclzonep->last_ats_idx) != -1 &&
1084 lidx != hi &&
1085 t >= lclzonep->ats[lidx] &&
1086 t < lclzonep->ats[lidx + 1]) {
1087 /* CACHE HIT. Nothing needs to be done */
1088 tidx = lidx;
1089 } else {
1090 /*
1091 * CACHE MISS. Locate transition using binary search.
1092 */
1093 while (lo <= hi) {
1094 tidx = (lo + hi) / 2;
1095 if (t == lclzonep->ats[tidx])
1096 break;
1097 else if (t < lclzonep->ats[tidx])
1098 hi = tidx - 1;
1099 else
1100 lo = tidx + 1;
1101 }
1102 if (lo > hi)
1103 tidx = hi;
1104 }
1105 }
1106
1107 /*
1108 * Set extern globals based on located transition and summary of
1109 * its previous state, which were cached when zone was loaded
1110 */
1111 ttisp = &lclzonep->ttis[lclzonep->types[tidx]];
1112 prevp = &lclzonep->prev[tidx];
1113
1114 if ((is_in_dst = ttisp->tt_isdst) == 0) { /* std. time */
1115 timezone = -ttisp->tt_gmtoff;
1116 newtzname[0] = &lclzonep->chars[ttisp->tt_abbrind];
1117 if ((alt = prevp->alt) != NULL) {
1118 altzone = -alt->tt_gmtoff;
1119 newtzname[1] = &lclzonep->chars[alt->tt_abbrind];
1120 } else {
1121 altzone = lclzonep->default_altzone;
1122 newtzname[1] = (char *)lclzonep->default_tzname1;
1123 }
1124 } else { /* alt. time */
1125 altzone = -ttisp->tt_gmtoff;
1126 newtzname[1] = &lclzonep->chars[ttisp->tt_abbrind];
1127 if ((std = prevp->std) != NULL) {
1128 timezone = -std->tt_gmtoff;
1129 newtzname[0] = &lclzonep->chars[std->tt_abbrind];
1130 } else {
1131 timezone = lclzonep->default_timezone;
1132 newtzname[0] = (char *)lclzonep->default_tzname0;
1133 }
1134 }
1135
1136 lclzonep->last_ats_idx = tidx;
1137 set_tzname(newtzname);
1138 }
1139
1140 /*
1141 * This function takes a time_t and gmt offset and produces a
1142 * tm struct based on specified time.
1143 *
1144 * The the following fields are calculated, based entirely
1145 * on the offset-adjusted value of t:
1146 *
1147 * tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec
1148 * tm_yday. tm_wday. (tm_isdst is ALWAYS set to 0).
1149 */
1150
1151 static struct tm *
offtime_u(time_t t,long offset,struct tm * tmptr)1152 offtime_u(time_t t, long offset, struct tm *tmptr)
1153 {
1154 long days;
1155 long rem;
1156 long y;
1157 int yleap;
1158 const int *ip;
1159
1160 days = t / SECSPERDAY;
1161 rem = t % SECSPERDAY;
1162 rem += offset;
1163 while (rem < 0) {
1164 rem += SECSPERDAY;
1165 --days;
1166 }
1167 while (rem >= SECSPERDAY) {
1168 rem -= SECSPERDAY;
1169 ++days;
1170 }
1171 tmptr->tm_hour = (int)(rem / SECSPERHOUR);
1172 rem = rem % SECSPERHOUR;
1173 tmptr->tm_min = (int)(rem / SECSPERMIN);
1174 tmptr->tm_sec = (int)(rem % SECSPERMIN);
1175
1176 tmptr->tm_wday = (int)((EPOCH_WDAY + days) % DAYSPERWEEK);
1177 if (tmptr->tm_wday < 0)
1178 tmptr->tm_wday += DAYSPERWEEK;
1179 y = EPOCH_YEAR;
1180 while (days < 0 || days >= (long)__year_lengths[yleap = isleap(y)]) {
1181 long newy;
1182
1183 newy = y + days / DAYSPERNYEAR;
1184 if (days < 0)
1185 --newy;
1186 days -= ((long)newy - (long)y) * DAYSPERNYEAR +
1187 LEAPS_THRU_END_OF(newy > 0 ? newy - 1L : newy) -
1188 LEAPS_THRU_END_OF(y > 0 ? y - 1L : y);
1189 y = newy;
1190 }
1191 tmptr->tm_year = (int)(y - TM_YEAR_BASE);
1192 tmptr->tm_yday = (int)days;
1193 ip = __mon_lengths[yleap];
1194 for (tmptr->tm_mon = 0; days >=
1195 (long)ip[tmptr->tm_mon]; ++(tmptr->tm_mon)) {
1196 days = days - (long)ip[tmptr->tm_mon];
1197 }
1198 tmptr->tm_mday = (int)(days + 1);
1199 tmptr->tm_isdst = 0;
1200
1201 #ifdef _LP64
1202 /* do as much as possible before checking for error. */
1203 if ((y > (long)INT_MAX + TM_YEAR_BASE) ||
1204 (y < (long)INT_MIN + TM_YEAR_BASE)) {
1205 errno = EOVERFLOW;
1206 return (NULL);
1207 }
1208 #endif
1209 return (tmptr);
1210 }
1211
1212 /*
1213 * Check whether DST is set for time in question. Only applies to
1214 * POSIX timezones. If explicit POSIX transition rules were provided
1215 * for the current zone, use those, otherwise use default USA POSIX
1216 * transitions.
1217 */
1218 static int
posix_check_dst(long long t,state_t * sp)1219 posix_check_dst(long long t, state_t *sp)
1220 {
1221 struct tm gmttm;
1222 long long jan01;
1223 int year, i, idx, ridx;
1224 posix_daylight_t pdaylight;
1225
1226 (void) offtime_u(t, 0L, &gmttm);
1227
1228 year = gmttm.tm_year + 1900;
1229 jan01 = t - ((gmttm.tm_yday * SECSPERDAY) +
1230 (gmttm.tm_hour * SECSPERHOUR) +
1231 (gmttm.tm_min * SECSPERMIN) + gmttm.tm_sec);
1232 /*
1233 * If transition rules were provided for this zone,
1234 * use them, otherwise, default to USA daylight rules,
1235 * which are historically correct for the continental USA,
1236 * excluding local provisions. (This logic may be replaced
1237 * at some point in the future with "posixrules" to offer
1238 * more flexibility to the system administrator).
1239 */
1240 if (sp->zonerules == POSIX) { /* POSIX rules */
1241 pdaylight.rules[0] = &sp->start_rule;
1242 pdaylight.rules[1] = &sp->end_rule;
1243 } else { /* POSIX_USA: USA */
1244 i = 0;
1245 while (year < __usa_rules[i].s_year && i < MAX_RULE_TABLE) {
1246 i++;
1247 }
1248 pdaylight.rules[0] = (rule_t *)&__usa_rules[i].start;
1249 pdaylight.rules[1] = (rule_t *)&__usa_rules[i].end;
1250 }
1251 pdaylight.offset[0] = timezone;
1252 pdaylight.offset[1] = altzone;
1253
1254 idx = posix_daylight(&jan01, year, &pdaylight);
1255 ridx = !idx;
1256
1257 /*
1258 * Note: t, rtime[0], and rtime[1] are all bounded within 'year'
1259 * beginning on 'jan01'
1260 */
1261 if (t >= pdaylight.rtime[idx] && t < pdaylight.rtime[ridx]) {
1262 return (ridx);
1263 } else {
1264 return (idx);
1265 }
1266 }
1267
1268 /*
1269 * Given January 1, 00:00:00 GMT for a year as an Epoch-relative time,
1270 * along with the integer year #, a posix_daylight_t that is composed
1271 * of two rules, and two GMT offsets (timezone and altzone), calculate
1272 * the two Epoch-relative times the two rules take effect, and return
1273 * them in the two rtime fields of the posix_daylight_t structure.
1274 * Also update janfirst by a year, by adding the appropriate number of
1275 * seconds depending on whether the year is a leap year or not. (We take
1276 * advantage that this routine knows the leap year status.)
1277 */
1278 static int
posix_daylight(long long * janfirst,int year,posix_daylight_t * pdaylightp)1279 posix_daylight(long long *janfirst, int year, posix_daylight_t *pdaylightp)
1280 {
1281 rule_t *rulep;
1282 long offset;
1283 int idx;
1284 int i, d, m1, yy0, yy1, yy2, dow;
1285 long leapyear;
1286 long long value;
1287
1288 static const int __secs_year_lengths[2] = {
1289 DAYS_PER_NYEAR * SECSPERDAY,
1290 DAYS_PER_LYEAR * SECSPERDAY
1291 };
1292
1293 leapyear = isleap(year);
1294
1295 for (idx = 0; idx < 2; idx++) {
1296 rulep = pdaylightp->rules[idx];
1297 offset = pdaylightp->offset[idx];
1298
1299 switch (rulep->r_type) {
1300
1301 case MON_WEEK_DOW:
1302 /*
1303 * Mm.n.d - nth "dth day" of month m.
1304 */
1305 value = *janfirst;
1306 for (i = 0; i < rulep->r_mon - 1; ++i)
1307 value += __mon_lengths[leapyear][i] *
1308 SECSPERDAY;
1309
1310 /*
1311 * Use Zeller's Congruence to get day-of-week of first
1312 * day of month.
1313 */
1314 m1 = (rulep->r_mon + 9) % 12 + 1;
1315 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
1316 yy1 = yy0 / 100;
1317 yy2 = yy0 % 100;
1318 dow = ((26 * m1 - 2) / 10 +
1319 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
1320
1321 if (dow < 0)
1322 dow += DAYSPERWEEK;
1323
1324 /*
1325 * Following heuristic increases accuracy of USA rules
1326 * for negative years.
1327 */
1328 if (year < 1 && leapyear)
1329 ++dow;
1330 /*
1331 * "dow" is the day-of-week of the first day of the
1332 * month. Get the day-of-month, zero-origin, of the
1333 * first "dow" day of the month.
1334 */
1335 d = rulep->r_day - dow;
1336 if (d < 0)
1337 d += DAYSPERWEEK;
1338 for (i = 1; i < rulep->r_week; ++i) {
1339 if (d + DAYSPERWEEK >=
1340 __mon_lengths[leapyear][rulep->r_mon - 1])
1341 break;
1342 d += DAYSPERWEEK;
1343 }
1344 /*
1345 * "d" is the day-of-month, zero-origin, of the day
1346 * we want.
1347 */
1348 value += d * SECSPERDAY;
1349 break;
1350
1351 case JULIAN_DAY:
1352 /*
1353 * Jn - Julian day, 1 == Jan 1, 60 == March 1 even
1354 * in leap yrs.
1355 */
1356 value = *janfirst + (rulep->r_day - 1) * SECSPERDAY;
1357 if (leapyear && rulep->r_day >= 60)
1358 value += SECSPERDAY;
1359 break;
1360
1361 case DAY_OF_YEAR:
1362 /*
1363 * n - day of year.
1364 */
1365 value = *janfirst + rulep->r_day * SECSPERDAY;
1366 break;
1367 }
1368 pdaylightp->rtime[idx] = value + rulep->r_time + offset;
1369 }
1370 *janfirst += __secs_year_lengths[leapyear];
1371
1372 return ((pdaylightp->rtime[0] > pdaylightp->rtime[1]) ? 1 : 0);
1373 }
1374
1375 /*
1376 * Try to load zoneinfo file into internal transition tables using name
1377 * indicated in TZ, and do validity checks. The format of zic(1M)
1378 * compiled zoneinfo files isdescribed in tzfile.h
1379 */
1380 static int
load_zoneinfo(const char * name,state_t * sp)1381 load_zoneinfo(const char *name, state_t *sp)
1382 {
1383 char *cp;
1384 char *cp2;
1385 int i;
1386 long cnt;
1387 int fid;
1388 int ttisstdcnt;
1389 int ttisgmtcnt;
1390 char *fullname;
1391 size_t namelen;
1392 char *bufp;
1393 size_t flen;
1394 prev_t *prevp;
1395 /* LINTED */
1396 struct tzhead *tzhp;
1397 struct stat64 stbuf;
1398 ttinfo_t *most_recent_alt = NULL;
1399 ttinfo_t *most_recent_std = NULL;
1400 ttinfo_t *ttisp;
1401
1402
1403 if (name == NULL && (name = TZDEFAULT) == NULL)
1404 return (-1);
1405
1406 if ((name[0] == '/') || strstr(name, "../"))
1407 return (-1);
1408
1409 /*
1410 * We allocate fullname this way to avoid having
1411 * a PATH_MAX size buffer in our stack frame.
1412 */
1413 namelen = LEN_TZDIR + 1 + strlen(name) + 1;
1414 if ((fullname = lmalloc(namelen)) == NULL)
1415 return (-1);
1416 (void) strcpy(fullname, TZDIR "/");
1417 (void) strcpy(fullname + LEN_TZDIR + 1, name);
1418 if ((fid = open(fullname, O_RDONLY)) == -1) {
1419 lfree(fullname, namelen);
1420 return (-1);
1421 }
1422 lfree(fullname, namelen);
1423
1424 if (fstat64(fid, &stbuf) == -1) {
1425 (void) close(fid);
1426 return (-1);
1427 }
1428
1429 flen = (size_t)stbuf.st_size;
1430 if (flen < sizeof (struct tzhead)) {
1431 (void) close(fid);
1432 return (-1);
1433 }
1434
1435 /*
1436 * It would be nice to use alloca() to allocate bufp but,
1437 * as above, we wish to avoid allocating a big buffer in
1438 * our stack frame, and also because alloca() gives us no
1439 * opportunity to fail gracefully on allocation failure.
1440 */
1441 cp = bufp = lmalloc(flen);
1442 if (bufp == NULL) {
1443 (void) close(fid);
1444 return (-1);
1445 }
1446
1447 if ((cnt = read(fid, bufp, flen)) != flen) {
1448 lfree(bufp, flen);
1449 (void) close(fid);
1450 return (-1);
1451 }
1452
1453 if (close(fid) != 0) {
1454 lfree(bufp, flen);
1455 return (-1);
1456 }
1457
1458 cp += (sizeof (tzhp->tzh_magic)) + (sizeof (tzhp->tzh_reserved));
1459
1460 /* LINTED: alignment */
1461 ttisstdcnt = CVTZCODE(cp);
1462 /* LINTED: alignment */
1463 ttisgmtcnt = CVTZCODE(cp);
1464 /* LINTED: alignment */
1465 sp->leapcnt = CVTZCODE(cp);
1466 /* LINTED: alignment */
1467 sp->timecnt = CVTZCODE(cp);
1468 /* LINTED: alignment */
1469 sp->typecnt = CVTZCODE(cp);
1470 /* LINTED: alignment */
1471 sp->charcnt = CVTZCODE(cp);
1472
1473 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
1474 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
1475 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
1476 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
1477 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
1478 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) {
1479 lfree(bufp, flen);
1480 return (-1);
1481 }
1482
1483 if (cnt - (cp - bufp) < (long)(sp->timecnt * 4 + /* ats */
1484 sp->timecnt + /* types */
1485 sp->typecnt * (4 + 2) + /* ttinfos */
1486 sp->charcnt + /* chars */
1487 sp->leapcnt * (4 + 4) + /* lsinfos */
1488 ttisstdcnt + /* ttisstds */
1489 ttisgmtcnt)) { /* ttisgmts */
1490 lfree(bufp, flen);
1491 return (-1);
1492 }
1493
1494
1495 for (i = 0; i < sp->timecnt; ++i) {
1496 /* LINTED: alignment */
1497 sp->ats[i] = CVTZCODE(cp);
1498 }
1499
1500 /*
1501 * Skip over types[] for now and load ttis[] so that when
1502 * types[] are loaded we can check for transitions to STD & DST.
1503 * This allows us to shave cycles in ltzset_u(), including
1504 * eliminating the need to check set 'daylight' later.
1505 */
1506
1507 cp2 = (char *)((uintptr_t)cp + sp->timecnt);
1508
1509 for (i = 0; i < sp->typecnt; ++i) {
1510 ttisp = &sp->ttis[i];
1511 /* LINTED: alignment */
1512 ttisp->tt_gmtoff = CVTZCODE(cp2);
1513 ttisp->tt_isdst = (uchar_t)*cp2++;
1514
1515 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) {
1516 lfree(bufp, flen);
1517 return (-1);
1518 }
1519
1520 ttisp->tt_abbrind = (uchar_t)*cp2++;
1521 if (ttisp->tt_abbrind < 0 ||
1522 ttisp->tt_abbrind > sp->charcnt) {
1523 lfree(bufp, flen);
1524 return (-1);
1525 }
1526 }
1527
1528 /*
1529 * Since ttis were loaded ahead of types, it is possible to
1530 * detect whether daylight is ever set for this zone now, and
1531 * also preload other information to avoid repeated lookups later.
1532 * This logic facilitates keeping a running tab on the state of
1533 * std zone and alternate zone transitions such that timezone,
1534 * altzone and tzname[] can be determined quickly via an
1535 * index to any transition.
1536 *
1537 * For transition #0 there are no previous transitions,
1538 * so prev->std and prev->alt will be null, but that's OK,
1539 * because null prev->std/prev->alt effectively
1540 * indicates none existed prior.
1541 */
1542
1543 prevp = &sp->prev[0];
1544
1545 for (i = 0; i < sp->timecnt; ++i) {
1546
1547 sp->types[i] = (uchar_t)*cp++;
1548 ttisp = &sp->ttis[sp->types[i]];
1549
1550 prevp->std = most_recent_std;
1551 prevp->alt = most_recent_alt;
1552
1553 if (ttisp->tt_isdst == 1) {
1554 most_recent_alt = ttisp;
1555 } else {
1556 most_recent_std = ttisp;
1557 }
1558
1559 if ((int)sp->types[i] >= sp->typecnt) {
1560 lfree(bufp, flen);
1561 return (-1);
1562 }
1563
1564 ++prevp;
1565 }
1566 if (most_recent_alt == NULL)
1567 sp->daylight = 0;
1568 else
1569 sp->daylight = 1;
1570
1571 /*
1572 * Set pointer ahead to where it would have been if we
1573 * had read types[] and ttis[] in the same order they
1574 * occurred in the file.
1575 */
1576 cp = cp2;
1577 for (i = 0; i < sp->charcnt; ++i)
1578 sp->chars[i] = *cp++;
1579
1580 sp->chars[i] = '\0'; /* ensure '\0' at end */
1581
1582 for (i = 0; i < sp->leapcnt; ++i) {
1583 struct lsinfo *lsisp;
1584
1585 lsisp = &sp->lsis[i];
1586 /* LINTED: alignment */
1587 lsisp->ls_trans = CVTZCODE(cp);
1588 /* LINTED: alignment */
1589 lsisp->ls_corr = CVTZCODE(cp);
1590 }
1591
1592 for (i = 0; i < sp->typecnt; ++i) {
1593 ttisp = &sp->ttis[i];
1594 if (ttisstdcnt == 0) {
1595 ttisp->tt_ttisstd = FALSE;
1596 } else {
1597 ttisp->tt_ttisstd = *cp++;
1598 if (ttisp->tt_ttisstd != TRUE &&
1599 ttisp->tt_ttisstd != FALSE) {
1600 lfree(bufp, flen);
1601 return (-1);
1602 }
1603 }
1604 }
1605
1606 for (i = 0; i < sp->typecnt; ++i) {
1607 ttisp = &sp->ttis[i];
1608 if (ttisgmtcnt == 0) {
1609 ttisp->tt_ttisgmt = FALSE;
1610 } else {
1611 ttisp->tt_ttisgmt = *cp++;
1612 if (ttisp->tt_ttisgmt != TRUE &&
1613 ttisp->tt_ttisgmt != FALSE) {
1614 lfree(bufp, flen);
1615 return (-1);
1616 }
1617 }
1618 }
1619
1620 /*
1621 * Other defaults set at beginning of this routine
1622 * to cover case where zoneinfo file cannot be loaded
1623 */
1624 sp->default_timezone = -sp->ttis[0].tt_gmtoff;
1625 sp->default_altzone = 0;
1626 sp->default_tzname0 = &sp->chars[0];
1627 sp->default_tzname1 = _tz_spaces;
1628
1629 lfree(bufp, flen);
1630
1631 sp->zonerules = ZONEINFO;
1632
1633 return (0);
1634 }
1635
1636 #ifdef _TZ_DEBUG
1637 static void
print_state(state_t * sp)1638 print_state(state_t *sp)
1639 {
1640 struct tm tmp;
1641 int i, c;
1642
1643 (void) fprintf(stderr, "=========================================\n");
1644 (void) fprintf(stderr, "zonename: \"%s\"\n", sp->zonename);
1645 (void) fprintf(stderr, "next: 0x%p\n", (void *)sp->next);
1646 (void) fprintf(stderr, "zonerules: %s\n",
1647 sp->zonerules == ZONERULES_INVALID ? "ZONERULES_INVALID" :
1648 sp->zonerules == POSIX ? "POSIX" :
1649 sp->zonerules == POSIX_USA ? "POSIX_USA" :
1650 sp->zonerules == ZONEINFO ? "ZONEINFO" : "UNKNOWN");
1651 (void) fprintf(stderr, "daylight: %d\n", sp->daylight);
1652 (void) fprintf(stderr, "default_timezone: %ld\n", sp->default_timezone);
1653 (void) fprintf(stderr, "default_altzone: %ld\n", sp->default_altzone);
1654 (void) fprintf(stderr, "default_tzname0: \"%s\"\n",
1655 sp->default_tzname0);
1656 (void) fprintf(stderr, "default_tzname1: \"%s\"\n",
1657 sp->default_tzname1);
1658 (void) fprintf(stderr, "leapcnt: %d\n", sp->leapcnt);
1659 (void) fprintf(stderr, "timecnt: %d\n", sp->timecnt);
1660 (void) fprintf(stderr, "typecnt: %d\n", sp->typecnt);
1661 (void) fprintf(stderr, "charcnt: %d\n", sp->charcnt);
1662 (void) fprintf(stderr, "chars: \"%s\"\n", sp->chars);
1663 (void) fprintf(stderr, "charsbuf_size: %u\n", sp->charsbuf_size);
1664 (void) fprintf(stderr, "prev: skipping...\n");
1665 (void) fprintf(stderr, "ats = {\n");
1666 for (c = 0, i = 0; i < sp->timecnt; i++) {
1667 char buf[64];
1668 size_t len;
1669 if (c != 0) {
1670 (void) fprintf(stderr, ", ");
1671 }
1672 (void) asctime_r(gmtime_r(&sp->ats[i], &tmp),
1673 buf, sizeof (buf));
1674 len = strlen(buf);
1675 buf[len-1] = '\0';
1676 (void) fprintf(stderr, "%s", buf);
1677 if (c == 1) {
1678 (void) fprintf(stderr, "\n");
1679 c = 0;
1680 } else {
1681 c++;
1682 }
1683 }
1684 (void) fprintf(stderr, "}\n");
1685 (void) fprintf(stderr, "types = {\n");
1686 for (c = 0, i = 0; i < sp->timecnt; i++) {
1687 if (c == 0) {
1688 (void) fprintf(stderr, "\t");
1689 } else {
1690 (void) fprintf(stderr, ", ");
1691 }
1692 (void) fprintf(stderr, "%d", sp->types[i]);
1693 if (c == 7) {
1694 (void) fprintf(stderr, "\n");
1695 c = 0;
1696 } else {
1697 c++;
1698 }
1699 }
1700 (void) fprintf(stderr, "}\n");
1701 (void) fprintf(stderr, "ttis = {\n");
1702 for (i = 0; i < sp->typecnt; i++) {
1703 (void) fprintf(stderr, "\t{\n");
1704 (void) fprintf(stderr, "\t\ttt_gmtoff: %ld\n",
1705 sp->ttis[i].tt_gmtoff);
1706 (void) fprintf(stderr, "\t\ttt_ttisdst: %d\n",
1707 sp->ttis[i].tt_isdst);
1708 (void) fprintf(stderr, "\t\ttt_abbrind: %d\n",
1709 sp->ttis[i].tt_abbrind);
1710 (void) fprintf(stderr, "\t\ttt_tt_isstd: %d\n",
1711 sp->ttis[i].tt_ttisstd);
1712 (void) fprintf(stderr, "\t\ttt_ttisgmt: %d\n",
1713 sp->ttis[i].tt_ttisgmt);
1714 (void) fprintf(stderr, "\t}\n");
1715 }
1716 (void) fprintf(stderr, "}\n");
1717 }
1718 #endif
1719
1720 /*
1721 * Given a POSIX section 8-style TZ string, fill in transition tables.
1722 *
1723 * Examples:
1724 *
1725 * TZ = PST8 or GMT0
1726 * Timecnt set to 0 and typecnt set to 1, reflecting std time only.
1727 *
1728 * TZ = PST8PDT or PST8PDT7
1729 * Create transition times by applying USA transitions from
1730 * Jan 1 of each year covering 1902-2038. POSIX offsets
1731 * as specified in the TZ are used to calculate the tt_gmtoff
1732 * for each of the two zones. If ommitted, DST defaults to
1733 * std. time minus one hour.
1734 *
1735 * TZ = <PST8>8PDT or <PST8>8<PDT9>
1736 * Quoted transition. The values in angled brackets are treated
1737 * as zone name text, not parsed as offsets. The offsets
1738 * occuring following the zonename section. In this way,
1739 * instead of PST being displayed for standard time, it could
1740 * be displayed as PST8 to give an indication of the offset
1741 * of that zone to GMT.
1742 *
1743 * TZ = GMT0BST, M3.5.0/1, M10.5.0/2 or GMT0BST, J23953, J23989
1744 * Create transition times based on the application new-year
1745 * relative POSIX transitions, parsed from TZ, from Jan 1
1746 * for each year covering 1902-2038. POSIX offsets specified
1747 * in TZ are used to calculate tt_gmtoff for each of the two
1748 * zones.
1749 *
1750 */
1751 static int
load_posixinfo(const char * name,state_t * sp)1752 load_posixinfo(const char *name, state_t *sp)
1753 {
1754 const char *stdname;
1755 const char *dstname = 0;
1756 size_t stdlen;
1757 size_t dstlen;
1758 long stdoff = 0;
1759 long dstoff = 0;
1760 char *cp;
1761 int i;
1762 ttinfo_t *dst;
1763 ttinfo_t *std;
1764 int quoted;
1765 zone_rules_t zonetype;
1766
1767
1768 zonetype = POSIX_USA;
1769 stdname = name;
1770
1771 if ((quoted = (*stdname == '<')) != 0)
1772 ++stdname;
1773
1774 /* Parse/extract STD zone name, len and GMT offset */
1775 if (*name != '\0') {
1776 if ((name = getzname(name, quoted)) == NULL)
1777 return (-1);
1778 stdlen = name - stdname;
1779 if (*name == '>')
1780 ++name;
1781 if (*name == '\0' || stdlen < 1) {
1782 return (-1);
1783 } else {
1784 if ((name = getoffset(name, &stdoff)) == NULL)
1785 return (-1);
1786 }
1787 }
1788
1789 /* If DST specified in TZ, extract DST zone details */
1790 if (*name != '\0') {
1791
1792 dstname = name;
1793 if ((quoted = (*dstname == '<')) != 0)
1794 ++dstname;
1795 if ((name = getzname(name, quoted)) == NULL)
1796 return (-1);
1797 dstlen = name - dstname;
1798 if (dstlen < 1)
1799 return (-1);
1800 if (*name == '>')
1801 ++name;
1802 if (*name != '\0' && *name != ',' && *name != ';') {
1803 if ((name = getoffset(name, &dstoff)) == NULL)
1804 return (-1);
1805 } else {
1806 dstoff = stdoff - SECSPERHOUR;
1807 }
1808
1809 if (*name != ',' && *name != ';') {
1810 /* no transtition specified; using default rule */
1811 if (load_zoneinfo(TZDEFRULES, sp) == 0 &&
1812 sp->daylight == 1) {
1813 /* loading TZDEFRULES zoneinfo succeeded */
1814 adjust_posix_default(sp, stdoff, dstoff);
1815 } else {
1816 /* loading TZDEFRULES zoneinfo failed */
1817 load_posix_transitions(sp, stdoff, dstoff,
1818 zonetype);
1819 }
1820 } else {
1821 /* extract POSIX transitions from TZ */
1822 /* Backward compatibility using ';' separator */
1823 int compat_flag = (*name == ';');
1824 ++name;
1825 if ((name = getrule(name, &sp->start_rule, compat_flag))
1826 == NULL)
1827 return (-1);
1828 if (*name++ != ',')
1829 return (-1);
1830 if ((name = getrule(name, &sp->end_rule, compat_flag))
1831 == NULL)
1832 return (-1);
1833 if (*name != '\0')
1834 return (-1);
1835 zonetype = POSIX;
1836 load_posix_transitions(sp, stdoff, dstoff, zonetype);
1837 }
1838 dst = &sp->ttis[0];
1839 std = &sp->ttis[1];
1840 } else { /* DST wasn't specified in POSIX TZ */
1841
1842 /* Since we only have STD time, there are no transitions */
1843 dstlen = 0;
1844 sp->daylight = 0;
1845 sp->typecnt = 1;
1846 sp->timecnt = 0;
1847 std = &sp->ttis[0];
1848 std->tt_gmtoff = -stdoff;
1849 std->tt_isdst = 0;
1850 }
1851
1852 /* Setup zone name character data for state table */
1853 sp->charcnt = (int)(stdlen + 1);
1854 if (dstlen != 0)
1855 sp->charcnt += dstlen + 1;
1856
1857 /* If bigger than zone name abbv. buffer, grow it */
1858 if ((size_t)sp->charcnt > sp->charsbuf_size) {
1859 if ((cp = libc_realloc(sp->chars, sp->charcnt)) == NULL)
1860 return (-1);
1861 sp->chars = cp;
1862 sp->charsbuf_size = sp->charcnt;
1863 }
1864
1865 /*
1866 * Copy zone name text null-terminatedly into state table.
1867 * By doing the copy once during zone loading, setting
1868 * tzname[] subsequently merely involves setting pointer
1869 *
1870 * If either or both std. or alt. zone name < 3 chars,
1871 * space pad the deficient name(s) to right.
1872 */
1873
1874 std->tt_abbrind = 0;
1875 cp = sp->chars;
1876 (void) strncpy(cp, stdname, stdlen);
1877 while (stdlen < 3)
1878 cp[stdlen++] = ' ';
1879 cp[stdlen] = '\0';
1880
1881 i = (int)(stdlen + 1);
1882 if (dstlen != 0) {
1883 dst->tt_abbrind = i;
1884 cp += i;
1885 (void) strncpy(cp, dstname, dstlen);
1886 while (dstlen < 3)
1887 cp[dstlen++] = ' ';
1888 cp[dstlen] = '\0';
1889 }
1890
1891 /* Save default values */
1892 if (sp->typecnt == 1) {
1893 sp->default_timezone = stdoff;
1894 sp->default_altzone = stdoff;
1895 sp->default_tzname0 = &sp->chars[0];
1896 sp->default_tzname1 = _tz_spaces;
1897 } else {
1898 sp->default_timezone = -std->tt_gmtoff;
1899 sp->default_altzone = -dst->tt_gmtoff;
1900 sp->default_tzname0 = &sp->chars[std->tt_abbrind];
1901 sp->default_tzname1 = &sp->chars[dst->tt_abbrind];
1902 }
1903
1904 sp->zonerules = zonetype;
1905
1906 return (0);
1907 }
1908
1909 /*
1910 * We loaded the TZDEFAULT which usually the one in US zones. We
1911 * adjust the GMT offset for the zone which has stdoff/dstoff
1912 * offset.
1913 */
1914 static void
adjust_posix_default(state_t * sp,long stdoff,long dstoff)1915 adjust_posix_default(state_t *sp, long stdoff, long dstoff)
1916 {
1917 long zone_stdoff = 0;
1918 long zone_dstoff = 0;
1919 int zone_stdoff_flag = 0;
1920 int zone_dstoff_flag = 0;
1921 int isdst;
1922 int i;
1923
1924 /*
1925 * Initial values of zone_stdoff and zone_dstoff
1926 */
1927 for (i = 0; (zone_stdoff_flag == 0 || zone_dstoff_flag == 0) &&
1928 i < sp->timecnt; i++) {
1929 ttinfo_t *zone;
1930
1931 zone = &sp->ttis[sp->types[i]];
1932
1933 if (zone_stdoff_flag == 0 && zone->tt_isdst == 0) {
1934 zone_stdoff = -zone->tt_gmtoff;
1935 zone_stdoff_flag = 1;
1936 } else if (zone_dstoff_flag == 0 && zone->tt_isdst != 0) {
1937 zone_dstoff = -zone->tt_gmtoff;
1938 zone_dstoff_flag = 1;
1939 }
1940 }
1941 if (zone_dstoff_flag == 0)
1942 zone_dstoff = zone_stdoff;
1943
1944 /*
1945 * Initially we're assumed to be in standard time.
1946 */
1947 isdst = 0;
1948
1949 for (i = 0; i < sp->timecnt; i++) {
1950 ttinfo_t *zone;
1951 int next_isdst;
1952
1953 zone = &sp->ttis[sp->types[i]];
1954 next_isdst = zone->tt_isdst;
1955
1956 sp->types[i] = next_isdst ? 0 : 1;
1957
1958 if (zone->tt_ttisgmt == 0) {
1959 /*
1960 * If summer time is in effect, and the transition time
1961 * was not specified as standard time, add the summer
1962 * time offset to the transition time;
1963 * otherwise, add the standard time offset to the
1964 * transition time.
1965 */
1966 /*
1967 * Transitions from DST to DDST will effectively
1968 * disappear since POSIX provides for only one DST
1969 * offset.
1970 */
1971 if (isdst != 0 && zone->tt_ttisstd == 0)
1972 sp->ats[i] += dstoff - zone_dstoff;
1973 else
1974 sp->ats[i] += stdoff - zone_stdoff;
1975 }
1976 if (next_isdst != 0)
1977 zone_dstoff = -zone->tt_gmtoff;
1978 else
1979 zone_stdoff = -zone->tt_gmtoff;
1980 isdst = next_isdst;
1981 }
1982 /*
1983 * Finally, fill in ttis.
1984 * ttisstd and ttisgmt need not be handled.
1985 */
1986 sp->ttis[0].tt_gmtoff = -dstoff;
1987 sp->ttis[0].tt_isdst = 1;
1988 sp->ttis[1].tt_gmtoff = -stdoff;
1989 sp->ttis[1].tt_isdst = 0;
1990 sp->typecnt = 2;
1991 sp->daylight = 1;
1992 }
1993
1994 /*
1995 *
1996 */
1997 static void
load_posix_transitions(state_t * sp,long stdoff,long dstoff,zone_rules_t zonetype)1998 load_posix_transitions(state_t *sp, long stdoff, long dstoff,
1999 zone_rules_t zonetype)
2000 {
2001 ttinfo_t *std, *dst;
2002 time_t *tranp;
2003 uchar_t *typep;
2004 prev_t *prevp;
2005 int year;
2006 int i;
2007 long long janfirst;
2008 posix_daylight_t pdaylight;
2009
2010 /*
2011 * We know STD and DST zones are specified with this timezone
2012 * therefore the cache will be set up with 2 transitions per
2013 * year transitioning to their respective std and dst zones.
2014 */
2015 sp->daylight = 1;
2016 sp->typecnt = 2;
2017 sp->timecnt = 272;
2018
2019 /*
2020 * Insert zone data from POSIX TZ into state table
2021 * The Olson public domain POSIX code sets up ttis[0] to be DST,
2022 * as we are doing here. It seems to be the correct behavior.
2023 * The US/Pacific zoneinfo file also lists DST as first type.
2024 */
2025
2026 dst = &sp->ttis[0];
2027 dst->tt_gmtoff = -dstoff;
2028 dst->tt_isdst = 1;
2029
2030 std = &sp->ttis[1];
2031 std->tt_gmtoff = -stdoff;
2032 std->tt_isdst = 0;
2033
2034 sp->prev[0].std = NULL;
2035 sp->prev[0].alt = NULL;
2036
2037 /* Create transition data based on POSIX TZ */
2038 tranp = sp->ats;
2039 prevp = &sp->prev[1];
2040 typep = sp->types;
2041
2042 /*
2043 * We only cache from 1902 to 2037 to avoid transistions
2044 * that wrap at the 32-bit boundries, since 1901 and 2038
2045 * are not full years in 32-bit time. The rough edges
2046 * will be handled as transition cache misses.
2047 */
2048
2049 janfirst = JAN_01_1902;
2050
2051 pdaylight.rules[0] = &sp->start_rule;
2052 pdaylight.rules[1] = &sp->end_rule;
2053 pdaylight.offset[0] = stdoff;
2054 pdaylight.offset[1] = dstoff;
2055
2056 for (i = MAX_RULE_TABLE; i >= 0; i--) {
2057 if (zonetype == POSIX_USA) {
2058 pdaylight.rules[0] = (rule_t *)&__usa_rules[i].start;
2059 pdaylight.rules[1] = (rule_t *)&__usa_rules[i].end;
2060 }
2061 for (year = __usa_rules[i].s_year;
2062 year <= __usa_rules[i].e_year; year++) {
2063 int idx, ridx;
2064 idx = posix_daylight(&janfirst, year, &pdaylight);
2065 ridx = !idx;
2066
2067 /*
2068 * Two transitions per year. Since there are
2069 * only two zone types for this POSIX zone,
2070 * previous std and alt are always set to
2071 * &ttis[0] and &ttis[1].
2072 */
2073 *tranp++ = (time_t)pdaylight.rtime[idx];
2074 *typep++ = idx;
2075 prevp->std = std;
2076 prevp->alt = dst;
2077 ++prevp;
2078
2079 *tranp++ = (time_t)pdaylight.rtime[ridx];
2080 *typep++ = ridx;
2081 prevp->std = std;
2082 prevp->alt = dst;
2083 ++prevp;
2084 }
2085 }
2086 }
2087
2088 /*
2089 * Given a pointer into a time zone string, scan until a character that is not
2090 * a valid character in a zone name is found. Return ptr to that character.
2091 * Return NULL if error (ie. non-printable character located in name)
2092 */
2093 static const char *
getzname(const char * strp,int quoted)2094 getzname(const char *strp, int quoted)
2095 {
2096 char c;
2097
2098 if (quoted) {
2099 while ((c = *strp) != '\0' && c != '>' &&
2100 isgraph((unsigned char)c)) {
2101 ++strp;
2102 }
2103 } else {
2104 while ((c = *strp) != '\0' && isgraph((unsigned char)c) &&
2105 !isdigit((unsigned char)c) && c != ',' && c != '-' &&
2106 c != '+') {
2107 ++strp;
2108 }
2109 }
2110
2111 /* Found an excessively invalid character. Discredit whole name */
2112 if (c != '\0' && !isgraph((unsigned char)c))
2113 return (NULL);
2114
2115 return (strp);
2116 }
2117
2118 /*
2119 * Given pointer into time zone string, extract first
2120 * number pointed to. Validate number within range specified,
2121 * Return ptr to first char following valid numeric sequence.
2122 */
2123 static const char *
getnum(const char * strp,int * nump,int min,int max)2124 getnum(const char *strp, int *nump, int min, int max)
2125 {
2126 char c;
2127 int num;
2128
2129 if (strp == NULL || !isdigit((unsigned char)(c = *strp)))
2130 return (NULL);
2131 num = 0;
2132 do {
2133 num = num * 10 + (c - '0');
2134 if (num > max)
2135 return (NULL); /* illegal value */
2136 c = *++strp;
2137 } while (isdigit((unsigned char)c));
2138 if (num < min)
2139 return (NULL); /* illegal value */
2140 *nump = num;
2141 return (strp);
2142 }
2143
2144 /*
2145 * Given a pointer into a time zone string, extract a number of seconds,
2146 * in hh[:mm[:ss]] form, from the string. If an error occurs, return NULL,
2147 * otherwise, return a pointer to the first character not part of the number
2148 * of seconds.
2149 */
2150 static const char *
getsecs(const char * strp,long * secsp)2151 getsecs(const char *strp, long *secsp)
2152 {
2153 int num;
2154
2155 /*
2156 * `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
2157 * "M10.4.6/26", which does not conform to Posix,
2158 * but which specifies the equivalent of
2159 * ``02:00 on the first Sunday on or after 23 Oct''.
2160 */
2161 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
2162 if (strp == NULL)
2163 return (NULL);
2164 *secsp = num * (long)SECSPERHOUR;
2165 if (*strp == ':') {
2166 ++strp;
2167 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
2168 if (strp == NULL)
2169 return (NULL);
2170 *secsp += num * SECSPERMIN;
2171 if (*strp == ':') {
2172 ++strp;
2173 /* `SECSPERMIN' allows for leap seconds. */
2174 strp = getnum(strp, &num, 0, SECSPERMIN);
2175 if (strp == NULL)
2176 return (NULL);
2177 *secsp += num;
2178 }
2179 }
2180 return (strp);
2181 }
2182
2183 /*
2184 * Given a pointer into a time zone string, extract an offset, in
2185 * [+-]hh[:mm[:ss]] form, from the string.
2186 * If any error occurs, return NULL.
2187 * Otherwise, return a pointer to the first character not part of the time.
2188 */
2189 static const char *
getoffset(const char * strp,long * offsetp)2190 getoffset(const char *strp, long *offsetp)
2191 {
2192 int neg = 0;
2193
2194 if (*strp == '-') {
2195 neg = 1;
2196 ++strp;
2197 } else if (*strp == '+') {
2198 ++strp;
2199 }
2200 strp = getsecs(strp, offsetp);
2201 if (strp == NULL)
2202 return (NULL); /* illegal time */
2203 if (neg)
2204 *offsetp = -*offsetp;
2205 return (strp);
2206 }
2207
2208 /*
2209 * Given a pointer into a time zone string, extract a rule in the form
2210 * date[/time]. See POSIX section 8 for the format of "date" and "time".
2211 * If a valid rule is not found, return NULL.
2212 * Otherwise, return a pointer to the first character not part of the rule.
2213 *
2214 * If compat_flag is set, support old 1-based day of year values.
2215 */
2216 static const char *
getrule(const char * strp,rule_t * rulep,int compat_flag)2217 getrule(const char *strp, rule_t *rulep, int compat_flag)
2218 {
2219 if (compat_flag == 0 && *strp == 'M') {
2220 /*
2221 * Month, week, day.
2222 */
2223 rulep->r_type = MON_WEEK_DOW;
2224 ++strp;
2225 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
2226 if (strp == NULL)
2227 return (NULL);
2228 if (*strp++ != '.')
2229 return (NULL);
2230 strp = getnum(strp, &rulep->r_week, 1, 5);
2231 if (strp == NULL)
2232 return (NULL);
2233 if (*strp++ != '.')
2234 return (NULL);
2235 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
2236 } else if (compat_flag == 0 && *strp == 'J') {
2237 /*
2238 * Julian day.
2239 */
2240 rulep->r_type = JULIAN_DAY;
2241 ++strp;
2242 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
2243
2244 } else if (isdigit((unsigned char)*strp)) {
2245 /*
2246 * Day of year.
2247 */
2248 rulep->r_type = DAY_OF_YEAR;
2249 if (compat_flag == 0) {
2250 /* zero-based day of year */
2251 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
2252 } else {
2253 /* one-based day of year */
2254 strp = getnum(strp, &rulep->r_day, 1, DAYSPERLYEAR);
2255 rulep->r_day--;
2256 }
2257 } else {
2258 return (NULL); /* ZONERULES_INVALID format */
2259 }
2260 if (strp == NULL)
2261 return (NULL);
2262 if (*strp == '/') {
2263 /*
2264 * Time specified.
2265 */
2266 ++strp;
2267 strp = getsecs(strp, &rulep->r_time);
2268 } else {
2269 rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
2270 }
2271 return (strp);
2272 }
2273
2274 /*
2275 * Returns default value for TZ as specified in /etc/default/init file, if
2276 * a default value for TZ is provided there.
2277 */
2278 static char *
get_default_tz(void)2279 get_default_tz(void)
2280 {
2281 char *tz = NULL;
2282 uchar_t *tzp, *tzq;
2283 int flags;
2284 void *defp;
2285
2286 assert_no_libc_locks_held();
2287
2288 if ((defp = defopen_r(TIMEZONE)) != NULL) {
2289 flags = defcntl_r(DC_GETFLAGS, 0, defp);
2290 TURNON(flags, DC_STRIP_QUOTES);
2291 (void) defcntl_r(DC_SETFLAGS, flags, defp);
2292
2293 if ((tzp = (uchar_t *)defread_r(TZSTRING, defp)) != NULL) {
2294 while (isspace(*tzp))
2295 tzp++;
2296 tzq = tzp;
2297 while (!isspace(*tzq) &&
2298 *tzq != ';' &&
2299 *tzq != '#' &&
2300 *tzq != '\0')
2301 tzq++;
2302 *tzq = '\0';
2303 if (*tzp != '\0')
2304 tz = libc_strdup((char *)tzp);
2305 }
2306
2307 defclose_r(defp);
2308 }
2309 return (tz);
2310 }
2311
2312 /*
2313 * Purge all cache'd state_t
2314 */
2315 static void
purge_zone_cache(void)2316 purge_zone_cache(void)
2317 {
2318 int hashid;
2319 state_t *p, *n, *r;
2320
2321 /*
2322 * Create a single list of caches which are detached
2323 * from hash table.
2324 */
2325 r = NULL;
2326 for (hashid = 0; hashid < HASHTABLE; hashid++) {
2327 for (p = tzcache[hashid]; p != NULL; p = n) {
2328 n = p->next;
2329 p->next = r;
2330 r = p;
2331 }
2332 tzcache[hashid] = NULL;
2333 }
2334 namecache = NULL;
2335
2336 /* last_tzname[] may point cache being freed */
2337 last_tzname[0] = NULL;
2338 last_tzname[1] = NULL;
2339
2340 /* We'll reload system TZ as well */
2341 systemTZ = NULL;
2342
2343 /*
2344 * Hash table has been cleared, and all elements are detached from
2345 * the hash table. Now we are safe to release _time_lock.
2346 * We need to unlock _time_lock because we need to call out to
2347 * free().
2348 */
2349 lmutex_unlock(&_time_lock);
2350
2351 assert_no_libc_locks_held();
2352
2353 while (r != NULL) {
2354 n = r->next;
2355 libc_free((char *)r->zonename);
2356 libc_free((char *)r->chars);
2357 free(r);
2358 r = n;
2359 }
2360
2361 lmutex_lock(&_time_lock);
2362 }
2363
2364 /*
2365 * When called first time, open the counter device and load
2366 * the initial value. If counter is updated, copy value to
2367 * private memory.
2368 */
2369 static void
reload_counter(void)2370 reload_counter(void)
2371 {
2372 int fd;
2373 caddr_t addr;
2374
2375 if (zoneinfo_seqadr != &zoneinfo_seqno_init) {
2376 zoneinfo_seqno = *zoneinfo_seqadr;
2377 return;
2378 }
2379
2380 if ((fd = open(TZSYNC_FILE, O_RDONLY)) < 0)
2381 return;
2382
2383 addr = mmap(0, sizeof (uint32_t), PROT_READ, MAP_SHARED, fd, 0);
2384 (void) close(fd);
2385
2386 if (addr == MAP_FAILED)
2387 return;
2388 /*LINTED*/
2389 zoneinfo_seqadr = (uint32_t *)addr;
2390 zoneinfo_seqno = *zoneinfo_seqadr;
2391 }
2392
2393 /*
2394 * getsystemTZ() returns the TZ value if it is set in the environment, or
2395 * it returns the system TZ; if the systemTZ has not yet been set, or
2396 * cleared by tzreload, get_default_tz() is called to read the
2397 * /etc/default/init file to get the value.
2398 */
2399 static const char *
getsystemTZ()2400 getsystemTZ()
2401 {
2402 tznmlist_t *tzn;
2403 char *tz;
2404
2405 tz = getenv("TZ");
2406 if (tz != NULL && *tz != '\0')
2407 return ((const char *)tz);
2408
2409 if (systemTZ != NULL)
2410 return (systemTZ);
2411
2412 /*
2413 * get_default_tz calls out stdio functions via defread.
2414 */
2415 lmutex_unlock(&_time_lock);
2416 tz = get_default_tz();
2417 lmutex_lock(&_time_lock);
2418
2419 if (tz == NULL) {
2420 /* no TZ entry in the file */
2421 systemTZ = _posix_gmt0;
2422 return (systemTZ);
2423 }
2424
2425 /*
2426 * look up timezone used previously. We will not free the
2427 * old timezone name, because ltzset_u() can release _time_lock
2428 * while it has references to systemTZ (via zonename). If we
2429 * free the systemTZ, the reference via zonename can access
2430 * invalid memory when systemTZ is reset.
2431 */
2432 for (tzn = systemTZrec; tzn != NULL; tzn = tzn->link) {
2433 if (strcmp(tz, tzn->name) == 0)
2434 break;
2435 }
2436 if (tzn == NULL) {
2437 /* This is new timezone name */
2438 tzn = lmalloc(sizeof (tznmlist_t *) + strlen(tz) + 1);
2439 (void) strcpy(tzn->name, tz);
2440 tzn->link = systemTZrec;
2441 systemTZrec = tzn;
2442 }
2443
2444 libc_free(tz);
2445
2446 return (systemTZ = tzn->name);
2447 }
2448
2449 /*
2450 * tzname[] is the user visible string which applications may have
2451 * references. Even though TZ was changed, references to the old tzname
2452 * may continue to remain in the application, and those references need
2453 * to be valid. They were valid by our implementation because strings being
2454 * pointed by tzname were never be freed nor altered by the change of TZ.
2455 * However, this will no longer be the case.
2456 *
2457 * state_t is now freed when cache is purged. Therefore, reading string
2458 * from old tzname[] addr may end up with accessing a stale data(freed area).
2459 * To avoid this, we maintain a copy of all timezone name strings which will
2460 * never be freed, and tzname[] will point those copies.
2461 *
2462 */
2463 static int
set_one_tzname(const char * name,int idx)2464 set_one_tzname(const char *name, int idx)
2465 {
2466 const unsigned char *nm;
2467 int hashid, i;
2468 char *s;
2469 tznmlist_t *tzn;
2470
2471 if (name == _tz_gmt || name == _tz_spaces) {
2472 tzname[idx] = (char *)name;
2473 return (0);
2474 }
2475
2476 nm = (const unsigned char *)name;
2477 hashid = (nm[0] * 29 + nm[1] * 3) % TZNMC_SZ;
2478 for (tzn = tznmhash[hashid]; tzn != NULL; tzn = tzn->link) {
2479 s = tzn->name;
2480 /* do the strcmp() */
2481 for (i = 0; s[i] == name[i]; i++) {
2482 if (s[i] == '\0') {
2483 tzname[idx] = tzn->name;
2484 return (0);
2485 }
2486 }
2487 }
2488 /*
2489 * allocate new entry. This entry is never freed, so use lmalloc
2490 */
2491 tzn = lmalloc(sizeof (tznmlist_t *) + strlen(name) + 1);
2492 if (tzn == NULL)
2493 return (1);
2494
2495 (void) strcpy(tzn->name, name);
2496
2497 /* link it */
2498 tzn->link = tznmhash[hashid];
2499 tznmhash[hashid] = tzn;
2500
2501 tzname[idx] = tzn->name;
2502 return (0);
2503 }
2504
2505 /*
2506 * Set tzname[] after testing parameter to see if we are setting
2507 * same zone name. If we got same address, it should be same zone
2508 * name as tzname[], unless cache have been purged.
2509 * Note, purge_zone_cache() resets last_tzname[].
2510 */
2511 static void
set_tzname(const char ** namep)2512 set_tzname(const char **namep)
2513 {
2514 if (namep[0] != last_tzname[0]) {
2515 if (set_one_tzname(namep[0], 0)) {
2516 tzname[0] = (char *)_tz_gmt;
2517 last_tzname[0] = NULL;
2518 } else {
2519 last_tzname[0] = namep[0];
2520 }
2521 }
2522
2523 if (namep[1] != last_tzname[1]) {
2524 if (set_one_tzname(namep[1], 1)) {
2525 tzname[1] = (char *)_tz_spaces;
2526 last_tzname[1] = NULL;
2527 } else {
2528 last_tzname[1] = namep[1];
2529 }
2530 }
2531 }
2532