6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libc / port / gen / localtime.c
blobed94ba5dc19c9d07c1125d7169e522de00686240
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
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).
37 * localtime.c
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).
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.
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>]
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".
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".
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 ":".
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.
84 * Functions that are common to ctime(3C) and cftime(3C)
87 #pragma weak _tzset = tzset
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>
111 /* JAN_01_1902 cast to (int) - negative number of seconds from 1970 */
112 #define JAN_01_1902 (int)0x8017E880
113 #define LEN_TZDIR (sizeof (TZDIR) - 1)
114 #define TIMEZONE "/etc/default/init"
115 #define TZSTRING "TZ="
116 #define HASHTABLE 109
118 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
120 /* Days since 1/1/70 to 12/31/(1900 + Y - 1) */
121 #define DAYS_SINCE_70(Y) (YR((Y)-1L) - YR(70-1))
122 #define YR(X) /* Calc # days since 0 A.D. X = curr. yr - 1900 */ \
123 ((1900L + (X)) * 365L + (1900L + (X)) / 4L - \
124 (1900L + (X)) / 100L + ((1900L + (X)) - 1600L) / 400L)
128 * The following macros are replacements for detzcode(), which has
129 * been in the public domain versions of the localtime.c code for
130 * a long time. The primatives supporting the CVTZCODE macro are
131 * implemented differently for different endianness (ie. little
132 * vs. big endian) out of necessity, to account for the different
133 * byte ordering of the quantities being fetched. Both versions
134 * are substantially faster than the detzcode() macro. The big
135 * endian version is approx. 6.8x faster than detzcode(), the
136 * little endian version is approximately 3x faster, due to the
137 * extra shifting requiring to change byte order. The micro
138 * benchmarks used to compare were based on the SUNWSpro SC6.1
139 * (and later) compilers.
142 #if defined(__sparc) || defined(__sparcv9) /* big endian */
144 #define GET_LONG(p) \
145 *(uint_t *)(p)
147 #define GET_SHORTS(p) \
148 *(ushort_t *)(p) << 16 |\
149 *(ushort_t *)((p) + 2)
151 #define GET_CHARS(p) \
152 *(uchar_t *)(p) << 24 |\
153 *(uchar_t *)((p) + 1) << 16 |\
154 *(uchar_t *)((p) + 2) << 8 |\
155 *(uchar_t *)((p) + 3)
157 #else /* little endian */
159 #define GET_BYTE(x) \
160 ((x) & 0xff)
162 #define SWAP_BYTES(x) ((\
163 GET_BYTE(x) << 8) |\
164 GET_BYTE((x) >> 8))
166 #define SWAP_WORDS(x) ((\
167 SWAP_BYTES(x) << 16) |\
168 SWAP_BYTES((x) >> 16))
170 #define GET_LONG(p) \
171 SWAP_WORDS(*(uint_t *)(p))
173 #define GET_SHORTS(p) \
174 SWAP_BYTES(*(ushort_t *)(p)) << 16 |\
175 SWAP_BYTES(*(ushort_t *)((p) + 2))
177 #define GET_CHARS(p) \
178 GET_BYTE(*(uchar_t *)(p)) << 24 |\
179 GET_BYTE(*(uchar_t *)((p) + 1)) << 16 |\
180 GET_BYTE(*(uchar_t *)((p) + 2)) << 8 |\
181 GET_BYTE(*(uchar_t *)((p) + 3))
183 #endif
186 #define IF_ALIGNED(ptr, byte_alignment) \
187 !((uintptr_t)(ptr) & (byte_alignment - 1))
189 #define CVTZCODE(p) (int)(\
190 IF_ALIGNED(p, 4) ? GET_LONG(p) :\
191 IF_ALIGNED(p, 2) ? GET_SHORTS(p) : GET_CHARS(p));\
192 p += 4;
194 #ifndef FALSE
195 #define FALSE (0)
196 #endif
198 #ifndef TRUE
199 #define TRUE (1)
200 #endif
202 extern mutex_t _time_lock;
204 extern const int __lyday_to_month[];
205 extern const int __yday_to_month[];
206 extern const int __mon_lengths[2][MONS_PER_YEAR];
207 extern const int __year_lengths[2];
209 const char _tz_gmt[4] = "GMT"; /* "GMT" */
210 const char _tz_spaces[4] = " "; /* " " */
211 static const char _posix_gmt0[5] = "GMT0"; /* "GMT0" */
213 typedef struct ttinfo { /* Time type information */
214 long tt_gmtoff; /* GMT offset in seconds */
215 int tt_isdst; /* used to set tm_isdst */
216 int tt_abbrind; /* abbreviation list index */
217 int tt_ttisstd; /* TRUE if trans is std time */
218 int tt_ttisgmt; /* TRUE if transition is GMT */
219 } ttinfo_t;
221 typedef struct lsinfo { /* Leap second information */
222 time_t ls_trans; /* transition time */
223 long ls_corr; /* correction to apply */
224 } lsinfo_t;
226 typedef struct previnfo { /* Info about *prev* trans */
227 ttinfo_t *std; /* Most recent std type */
228 ttinfo_t *alt; /* Most recent alt type */
229 } prev_t;
231 typedef enum {
232 MON_WEEK_DOW, /* Mm.n.d - month, week, day of week */
233 JULIAN_DAY, /* Jn - Julian day */
234 DAY_OF_YEAR /* n - day of year */
235 } posrule_type_t;
237 typedef struct {
238 posrule_type_t r_type; /* type of rule */
239 int r_day; /* day number of rule */
240 int r_week; /* week number of rule */
241 int r_mon; /* month number of rule */
242 long r_time; /* transition time of rule */
243 } rule_t;
245 typedef struct {
246 rule_t *rules[2];
247 long offset[2];
248 long long rtime[2];
249 } posix_daylight_t;
252 * Note: ZONERULES_INVALID used for global curr_zonerules variable, but not
253 * for zonerules field of state_t.
255 typedef enum {
256 ZONERULES_INVALID, POSIX, POSIX_USA, ZONEINFO
257 } zone_rules_t;
260 * The following members are allocated from the libc-internal malloc:
262 * zonename
263 * chars
265 typedef struct state {
266 const char *zonename; /* Timezone */
267 struct state *next; /* next state */
268 zone_rules_t zonerules; /* Type of zone */
269 int daylight; /* daylight global */
270 long default_timezone; /* Def. timezone val */
271 long default_altzone; /* Def. altzone val */
272 const char *default_tzname0; /* Def tz..[0] val */
273 const char *default_tzname1; /* Def tz..[1] val */
274 int leapcnt; /* # leap sec trans */
275 int timecnt; /* # transitions */
276 int typecnt; /* # zone types */
277 int charcnt; /* # zone abbv. chars */
278 char *chars; /* Zone abbv. chars */
279 size_t charsbuf_size; /* malloc'ed buflen */
280 prev_t prev[TZ_MAX_TIMES]; /* Pv. trans info */
281 time_t ats[TZ_MAX_TIMES]; /* Trans. times */
282 uchar_t types[TZ_MAX_TIMES]; /* Type indices */
283 ttinfo_t ttis[TZ_MAX_TYPES]; /* Zone types */
284 lsinfo_t lsis[TZ_MAX_LEAPS]; /* Leap sec trans */
285 rule_t start_rule; /* For POSIX w/rules */
286 rule_t end_rule; /* For POSIX w/rules */
287 } state_t;
289 typedef struct systemtz {
290 const char *tz;
291 state_t *entry;
292 int flag;
293 } systemtz_t;
295 static const char *namecache;
297 static state_t *tzcache[HASHTABLE];
299 static state_t *lclzonep;
301 static struct tm tm; /* For non-reentrant use */
302 static int is_in_dst; /* Set if t is in DST */
303 static zone_rules_t curr_zonerules = ZONERULES_INVALID;
304 static int cached_year; /* mktime() perf. enhancement */
305 static long long cached_secs_since_1970; /* mktime() perf. */
306 static int year_is_cached = FALSE; /* mktime() perf. */
309 #define _2AM (2 * SECS_PER_HOUR)
310 #define FIRSTWEEK 1
311 #define LASTWEEK 5
313 enum wks {
314 _1st_week = 1,
315 _2nd_week,
316 _3rd_week,
317 _4th_week,
318 _Last_week
321 enum dwk {
322 Sun,
323 Mon,
324 Tue,
325 Wed,
326 Thu,
327 Fri,
331 enum mth {
332 Jan = 1,
333 Feb,
334 Mar,
335 Apr,
336 May,
337 Jun,
338 Jul,
339 Aug,
340 Sep,
341 Oct,
342 Nov,
347 * The following table defines standard USA DST transitions
348 * as they have been declared throughout history, disregarding
349 * the legally sanctioned local variants.
351 * Note: At some point, this table may be supplanted by
352 * more popular 'posixrules' logic.
354 typedef struct {
355 int s_year;
356 int e_year;
357 rule_t start;
358 rule_t end;
359 } __usa_rules_t;
361 static const __usa_rules_t __usa_rules[] = {
363 2007, 2037,
364 { MON_WEEK_DOW, Sun, _2nd_week, Mar, _2AM },
365 { MON_WEEK_DOW, Sun, _1st_week, Nov, _2AM },
368 1987, 2006,
369 { MON_WEEK_DOW, Sun, _1st_week, Apr, _2AM },
370 { MON_WEEK_DOW, Sun, _Last_week, Oct, _2AM },
373 1976, 1986,
374 { MON_WEEK_DOW, Sun, _Last_week, Apr, _2AM },
375 { MON_WEEK_DOW, Sun, _Last_week, Oct, _2AM },
378 1975, 1975,
379 { MON_WEEK_DOW, Sun, _Last_week, Feb, _2AM },
380 { MON_WEEK_DOW, Sun, _Last_week, Oct, _2AM },
384 1974, 1974,
385 { MON_WEEK_DOW, Sun, _1st_week, Jan, _2AM },
386 { MON_WEEK_DOW, Sun, _Last_week, Nov, _2AM },
389 * The entry below combines two previously separate entries for
390 * 1969-1973 and 1902-1968
393 1902, 1973,
394 { MON_WEEK_DOW, Sun, _Last_week, Apr, _2AM },
395 { MON_WEEK_DOW, Sun, _Last_week, Oct, _2AM },
398 #define MAX_RULE_TABLE (sizeof (__usa_rules) / sizeof (__usa_rules_t) - 1)
401 * Prototypes for static functions.
403 static systemtz_t *getsystemTZ(systemtz_t *);
404 static const char *getzname(const char *, int);
405 static const char *getnum(const char *, int *, int, int);
406 static const char *getsecs(const char *, long *);
407 static const char *getoffset(const char *, long *);
408 static const char *getrule(const char *, rule_t *, int);
409 static int load_posixinfo(const char *, state_t *);
410 static int load_zoneinfo(const char *, state_t *);
411 static void ltzset_u(time_t, systemtz_t *);
412 static struct tm *offtime_u(time_t, long, struct tm *);
413 static int posix_check_dst(long long, state_t *);
414 static int posix_daylight(long long *, int, posix_daylight_t *);
415 static void set_zone_context(time_t);
418 * definition of difftime
420 * This code assumes time_t is type long. Note the difference of two
421 * longs in absolute value is representable as an unsigned long. So,
422 * compute the absolute value of the difference, cast the result to
423 * double and attach the sign back on.
425 * Note this code assumes 2's complement arithmetic. The subtraction
426 * operation may overflow when using signed operands, but when the
427 * result is cast to unsigned long, it yields the desired value
428 * (ie, the absolute value of the difference). The cast to unsigned
429 * long is done using pointers to avoid undefined behavior if casting
430 * a negative value to unsigned.
432 double
433 difftime(time_t time1, time_t time0)
435 if (time1 < time0) {
436 time0 -= time1;
437 return (-(double)*(unsigned long *) &time0);
438 } else {
439 time1 -= time0;
440 return ((double)*(unsigned long *) &time1);
445 * Accepts a time_t, returns a tm struct based on it, with
446 * no local timezone adjustment.
448 * This routine is the thread-safe variant of gmtime(), and
449 * requires that the call provide the address of their own tm
450 * struct.
452 * Locking is not done here because set_zone_context()
453 * is not called, thus timezone, altzone, and tzname[] are not
454 * accessed, no memory is allocated, and no common dynamic
455 * data is accessed.
457 * See ctime(3C)
459 struct tm *
460 gmtime_r(const time_t *timep, struct tm *p_tm)
462 return (offtime_u((time_t)*timep, 0L, p_tm));
466 * Accepts a time_t, returns a tm struct based on it, with
467 * no local timezone adjustment.
469 * This function is explicitly NOT THREAD-SAFE. The standards
470 * indicate it should provide its results in its own statically
471 * allocated tm struct that gets overwritten. The thread-safe
472 * variant is gmtime_r(). We make it mostly thread-safe by
473 * allocating its buffer in thread-specific data.
475 * See ctime(3C)
477 struct tm *
478 gmtime(const time_t *timep)
480 struct tm *p_tm = tsdalloc(_T_STRUCT_TM, sizeof (struct tm), NULL);
482 if (p_tm == NULL) /* memory allocation failure */
483 p_tm = &tm; /* use static buffer and hope for the best */
484 return (gmtime_r(timep, p_tm));
488 * This is the hashing function, based on the input timezone name.
490 static int
491 get_hashid(const char *id)
493 const unsigned char *s = (const unsigned char *)id;
494 unsigned char c;
495 unsigned int h;
497 h = *s++;
498 while ((c = *s++) != '\0') {
499 h = (h << 5) - h + c;
501 return ((int)(h % HASHTABLE));
505 * find_zone() gets the hashid for zonename, then uses the hashid
506 * to search the hash table for the appropriate timezone entry. If
507 * the entry for zonename is found in the hash table, return a pointer
508 * to the entry. Otherwise, update the input link_prev and link_next
509 * to the addresses of pointers for the caller to update to add the new
510 * entry to the hash table.
512 static state_t *
513 find_zone(const char *zonename, state_t ***link_prev, state_t **link_next)
515 int hashid;
516 state_t *cur, *prv;
518 hashid = get_hashid(zonename);
519 cur = tzcache[hashid];
520 prv = NULL;
521 while (cur) {
522 int res;
523 res = strcmp(cur->zonename, zonename);
524 if (res == 0) {
525 return (cur);
526 } else if (res > 0) {
527 break;
529 prv = cur;
530 cur = cur->next;
532 if (prv) {
533 *link_prev = &prv->next;
534 *link_next = cur;
535 } else {
536 *link_prev = &tzcache[hashid];
537 *link_next = NULL;
539 return (NULL);
544 * Returns tm struct based on input time_t argument, correcting
545 * for the local timezone, producing documented side-effects
546 * to extern global state, timezone, altzone, daylight and tzname[].
548 * localtime_r() is the thread-safe variant of localtime().
550 * IMPLEMENTATION NOTE:
552 * Locking slows multithreaded access and is probably ultimately
553 * unnecessary here. The POSIX specification is a bit vague
554 * as to whether the extern variables set by tzset() need to
555 * set as a result of a call to localtime_r()
557 * Currently, the spec only mentions that tzname[] doesn't
558 * need to be set. As soon as it becomes unequivocal
559 * that the external zone state doesn't need to be asserted
560 * for this call, and it really doesn't make much sense
561 * to set common state from multi-threaded calls made to this
562 * function, locking can be dispensed with here.
564 * local zone state would still need to be aquired for the
565 * time in question in order for calculations elicited here
566 * to be correct, but that state wouldn't need to be shared,
567 * thus no multi-threaded synchronization would be required.
569 * It would be nice if POSIX would approve an ltzset_r()
570 * function, but if not, it wouldn't stop us from making one
571 * privately.
573 * localtime_r() can now return NULL if overflow is detected.
574 * offtime_u() is the function that detects overflow, and sets
575 * errno appropriately. We unlock before the call to offtime_u(),
576 * so that lmutex_unlock() does not reassign errno. The function
577 * offtime_u() is MT-safe and does not have to be locked. Use
578 * my_is_in_dst to reference local copy of is_in_dst outside locks.
580 * See ctime(3C)
582 struct tm *
583 localtime_r(const time_t *timep, struct tm *p_tm)
585 long offset;
586 struct tm *rt;
587 int my_is_in_dst;
588 systemtz_t stz;
589 systemtz_t *tzp;
591 tzp = getsystemTZ(&stz);
593 lmutex_lock(&_time_lock);
594 ltzset_u(*timep, tzp);
595 if (lclzonep == NULL) {
596 lmutex_unlock(&_time_lock);
597 if (tzp->flag)
598 free(tzp->entry);
599 return (offtime_u(*timep, 0L, p_tm));
601 my_is_in_dst = is_in_dst;
602 offset = (my_is_in_dst) ? -altzone : -timezone;
603 lmutex_unlock(&_time_lock);
604 rt = offtime_u(*timep, offset, p_tm);
605 p_tm->tm_isdst = my_is_in_dst;
606 if (tzp->flag)
607 free(tzp->entry);
608 return (rt);
612 * Accepts a time_t, returns a tm struct based on it, correcting
613 * for the local timezone. Produces documented side-effects to
614 * extern global timezone state data.
616 * This function is explicitly NOT THREAD-SAFE. The standards
617 * indicate it should provide its results in its own statically
618 * allocated tm struct that gets overwritten. The thread-safe
619 * variant is localtime_r(). We make it mostly thread-safe by
620 * allocating its buffer in thread-specific data.
622 * localtime() can now return NULL if overflow is detected.
623 * offtime_u() is the function that detects overflow, and sets
624 * errno appropriately.
626 * See ctime(3C)
628 struct tm *
629 localtime(const time_t *timep)
631 struct tm *p_tm = tsdalloc(_T_STRUCT_TM, sizeof (struct tm), NULL);
633 if (p_tm == NULL) /* memory allocation failure */
634 p_tm = &tm; /* use static buffer and hope for the best */
635 return (localtime_r(timep, p_tm));
639 * This function takes a pointer to a tm struct and returns a
640 * normalized time_t, also inducing documented side-effects in
641 * extern global zone state variables. (See mktime(3C)).
643 time_t
644 mktime(struct tm *tmptr)
646 struct tm _tm;
647 long long t; /* must hold more than 32-bit time_t */
648 int temp;
649 int mketimerrno;
650 int overflow;
651 systemtz_t stz;
652 systemtz_t *tzp;
654 mketimerrno = errno;
656 tzp = getsystemTZ(&stz);
658 /* mktime leaves errno unchanged if no error is encountered */
660 lmutex_lock(&_time_lock);
662 /* Calculate time_t from tm arg. tm may need to be normalized. */
663 t = tmptr->tm_sec + SECSPERMIN * tmptr->tm_min +
664 SECSPERHOUR * tmptr->tm_hour +
665 SECSPERDAY * (tmptr->tm_mday - 1);
667 if (tmptr->tm_mon >= 12) {
668 tmptr->tm_year += tmptr->tm_mon / 12;
669 tmptr->tm_mon %= 12;
670 } else if (tmptr->tm_mon < 0) {
671 temp = -tmptr->tm_mon;
672 tmptr->tm_mon = 0; /* If tm_mon divides by 12. */
673 tmptr->tm_year -= (temp / 12);
674 if (temp %= 12) { /* Remainder... */
675 tmptr->tm_year--;
676 tmptr->tm_mon = 12 - temp;
680 /* Avoid numerous calculations embedded in macro if possible */
681 if (!year_is_cached || (cached_year != tmptr->tm_year)) {
682 cached_year = tmptr->tm_year;
683 year_is_cached = TRUE;
684 /* For boundry values of tm_year, typecasting required */
685 cached_secs_since_1970 =
686 (long long)SECSPERDAY * DAYS_SINCE_70(cached_year);
688 t += cached_secs_since_1970;
690 if (isleap(tmptr->tm_year + TM_YEAR_BASE))
691 t += SECSPERDAY * __lyday_to_month[tmptr->tm_mon];
692 else
693 t += SECSPERDAY * __yday_to_month[tmptr->tm_mon];
695 ltzset_u((time_t)t, tzp);
696 /* Attempt to convert time to GMT based on tm_isdst setting */
697 t += (tmptr->tm_isdst > 0) ? altzone : timezone;
699 #ifdef _ILP32
700 overflow = t > LONG_MAX || t < LONG_MIN ||
701 tmptr->tm_year < 1 || tmptr->tm_year > 138;
702 #else
703 overflow = t > LONG_MAX || t < LONG_MIN;
704 #endif
705 set_zone_context((time_t)t);
706 if (tmptr->tm_isdst < 0) {
707 long dst_delta = timezone - altzone;
708 switch (curr_zonerules) {
709 case ZONEINFO:
710 if (is_in_dst) {
711 t -= dst_delta;
712 set_zone_context((time_t)t);
713 if (is_in_dst) {
714 (void) offtime_u((time_t)t,
715 -altzone, &_tm);
716 _tm.tm_isdst = 1;
717 } else {
718 (void) offtime_u((time_t)t,
719 -timezone, &_tm);
721 } else {
722 (void) offtime_u((time_t)t, -timezone, &_tm);
724 break;
725 case POSIX_USA:
726 case POSIX:
727 if (is_in_dst) {
728 t -= dst_delta;
729 set_zone_context((time_t)t);
730 if (is_in_dst) {
731 (void) offtime_u((time_t)t,
732 -altzone, &_tm);
733 _tm.tm_isdst = 1;
734 } else {
735 (void) offtime_u((time_t)t,
736 -timezone, &_tm);
738 } else { /* check for ambiguous 'fallback' transition */
739 set_zone_context((time_t)t - dst_delta);
740 if (is_in_dst) { /* In fallback, force DST */
741 t -= dst_delta;
742 (void) offtime_u((time_t)t,
743 -altzone, &_tm);
744 _tm.tm_isdst = 1;
745 } else {
746 (void) offtime_u((time_t)t,
747 -timezone, &_tm);
750 break;
752 case ZONERULES_INVALID:
753 (void) offtime_u((time_t)t, 0L, &_tm);
754 break;
757 } else if (is_in_dst) {
758 (void) offtime_u((time_t)t, -altzone, &_tm);
759 _tm.tm_isdst = 1;
760 } else {
761 (void) offtime_u((time_t)t, -timezone, &_tm);
764 if (overflow || t > LONG_MAX || t < LONG_MIN) {
765 mketimerrno = EOVERFLOW;
766 t = -1;
767 } else {
768 *tmptr = _tm;
771 lmutex_unlock(&_time_lock);
773 if (tzp->flag)
774 free(tzp->entry);
775 errno = mketimerrno;
776 return ((time_t)t);
780 * Sets extern global zone state variables based on the current
781 * time. Specifically, tzname[], timezone, altzone, and daylight
782 * are updated. See ctime(3C) manpage.
784 void
785 tzset(void)
787 systemtz_t stz;
788 systemtz_t *tzp;
790 tzp = getsystemTZ(&stz);
792 lmutex_lock(&_time_lock);
793 ltzset_u(time(NULL), tzp);
794 lmutex_unlock(&_time_lock);
795 if (tzp->flag)
796 free(tzp->entry);
799 void
800 _ltzset(time_t tim)
802 systemtz_t stz;
803 systemtz_t *tzp;
805 tzp = getsystemTZ(&stz);
807 lmutex_lock(&_time_lock);
808 ltzset_u(tim, tzp);
809 lmutex_unlock(&_time_lock);
810 if (tzp->flag)
811 free(tzp->entry);
815 * Loads local zone information if TZ changed since last time zone
816 * information was loaded, or if this is the first time thru.
817 * We already hold _time_lock; no further locking is required.
819 static void
820 ltzset_u(time_t t, systemtz_t *tzp)
822 const char *zonename = tzp->tz;
823 state_t *entry, **p, *q;
825 if (zonename == NULL || *zonename == '\0')
826 zonename = _posix_gmt0;
828 if (curr_zonerules != ZONERULES_INVALID &&
829 strcmp(namecache, zonename) == 0) {
830 set_zone_context(t);
831 return;
834 entry = find_zone(zonename, &p, &q);
835 if (entry == NULL) {
837 * No timezone entry found in hash table, so load it,
838 * and create a new timezone entry.
840 char *newzonename, *charsbuf;
842 /* Invalidate the current timezone */
843 curr_zonerules = ZONERULES_INVALID;
845 newzonename = libc_strdup(zonename);
846 daylight = 0;
847 entry = tzp->entry;
849 if (entry == NULL || newzonename == NULL) {
850 /* something wrong happened. */
851 if (newzonename != NULL)
852 libc_free(newzonename);
853 timezone = altzone = 0;
854 is_in_dst = 0;
855 tzname[0] = (char *)_tz_gmt;
856 tzname[1] = (char *)_tz_spaces;
857 return;
861 * Builds transition cache and sets up zone state data for zone
862 * specified in TZ, which can be specified as a POSIX zone or an
863 * Olson zoneinfo file reference.
865 * If local data cannot be parsed or loaded, the local zone
866 * tables are set up for GMT.
868 * Unless a leading ':' is prepended to TZ, TZ is initially
869 * parsed as a POSIX zone; failing that, it reverts to
870 * a zoneinfo check.
871 * However, if a ':' is prepended, the zone will *only* be
872 * parsed as zoneinfo. If any failure occurs parsing or
873 * loading a zoneinfo TZ, GMT data is loaded for the local zone.
875 * Example: There is a zoneinfo file in the standard
876 * distribution called 'PST8PDT'. The only way the user can
877 * specify that file under Solaris is to set TZ to ":PST8PDT".
878 * Otherwise the initial parse of PST8PDT as a POSIX zone will
879 * succeed and be used.
881 if ((charsbuf = libc_malloc(TZ_MAX_CHARS)) == NULL) {
882 libc_free(newzonename);
884 timezone = altzone = 0;
885 is_in_dst = 0;
886 tzname[0] = (char *)_tz_gmt;
887 tzname[1] = (char *)_tz_spaces;
888 return;
890 entry->charsbuf_size = TZ_MAX_CHARS;
891 entry->chars = charsbuf;
892 entry->default_tzname0 = _tz_gmt;
893 entry->default_tzname1 = _tz_spaces;
894 entry->zonename = newzonename;
896 if (*zonename == ':') {
897 if (load_zoneinfo(zonename + 1, entry) != 0) {
898 (void) load_posixinfo(_posix_gmt0, entry);
900 } else if (load_posixinfo(zonename, entry) != 0) {
901 if (load_zoneinfo(zonename, entry) != 0) {
902 (void) load_posixinfo(_posix_gmt0, entry);
906 * The pre-allocated buffer is used; reset the free flag
907 * so the buffer won't be freed.
909 tzp->flag = 0;
910 entry->next = q;
911 *p = entry;
914 curr_zonerules = entry->zonerules;
915 namecache = entry->zonename;
916 daylight = entry->daylight;
917 lclzonep = entry;
919 set_zone_context(t);
923 * Sets timezone, altzone, tzname[], extern globals, to represent
924 * disposition of t with respect to TZ; See ctime(3C). is_in_dst,
925 * internal global is also set. daylight is set at zone load time.
927 * Issues:
929 * In this function, any time_t not located in the cache is handled
930 * as a miss. To build/update transition cache, load_zoneinfo()
931 * must be called prior to this routine.
933 * If POSIX zone, cache miss penalty is slightly degraded
934 * performance. For zoneinfo, penalty is decreased is_in_dst
935 * accuracy.
937 * POSIX, despite its chicken/egg problem, ie. not knowing DST
938 * until time known, and not knowing time until DST known, at
939 * least uses the same algorithm for 64-bit time as 32-bit.
941 * The fact that zoneinfo files only contain transistions for 32-bit
942 * time space is a well known problem, as yet unresolved.
943 * Without an official standard for coping with out-of-range
944 * zoneinfo times, assumptions must be made. For now
945 * the assumption is: If t exceeds 32-bit boundries and local zone
946 * is zoneinfo type, is_in_dst is set to to 0 for negative values
947 * of t, and set to the same DST state as the highest ordered
948 * transition in cache for positive values of t.
950 static void
951 set_zone_context(time_t t)
953 prev_t *prevp;
954 int lo, hi, tidx;
955 ttinfo_t *ttisp, *std, *alt;
957 /* If state data not loaded or TZ busted, just use GMT */
958 if (lclzonep == NULL || curr_zonerules == ZONERULES_INVALID) {
959 timezone = altzone = 0;
960 daylight = is_in_dst = 0;
961 tzname[0] = (char *)_tz_gmt;
962 tzname[1] = (char *)_tz_spaces;
963 return;
966 /* Retrieve suitable defaults for this zone */
967 altzone = lclzonep->default_altzone;
968 timezone = lclzonep->default_timezone;
969 tzname[0] = (char *)lclzonep->default_tzname0;
970 tzname[1] = (char *)lclzonep->default_tzname1;
971 is_in_dst = 0;
973 if (lclzonep->timecnt <= 0 || lclzonep->typecnt < 2)
974 /* Loaded zone incapable of transitioning. */
975 return;
978 * At least one alt. zone and one transistion exist. Locate
979 * state for 't' quickly as possible. Use defaults as necessary.
981 lo = 0;
982 hi = lclzonep->timecnt - 1;
984 if (t < lclzonep->ats[0] || t >= lclzonep->ats[hi]) {
986 /* CACHE MISS. Calculate DST as best as possible */
987 if (lclzonep->zonerules == POSIX_USA ||
988 lclzonep->zonerules == POSIX) {
989 /* Must nvoke calculations to determine DST */
990 is_in_dst = (daylight) ?
991 posix_check_dst(t, lclzonep) : 0;
992 return;
993 } else if (t < lclzonep->ats[0]) { /* zoneinfo... */
994 /* t precedes 1st transition. Use defaults */
995 return;
996 } else { /* zoneinfo */
997 /* t follows final transistion. Use final */
998 tidx = hi;
1001 } else {
1003 /* CACHE HIT. Locate transition using binary search. */
1005 while (lo <= hi) {
1006 tidx = (lo + hi) / 2;
1007 if (t == lclzonep->ats[tidx])
1008 break;
1009 else if (t < lclzonep->ats[tidx])
1010 hi = tidx - 1;
1011 else
1012 lo = tidx + 1;
1014 if (lo > hi)
1015 tidx = hi;
1019 * Set extern globals based on located transition and summary of
1020 * its previous state, which were cached when zone was loaded
1022 ttisp = &lclzonep->ttis[lclzonep->types[tidx]];
1023 prevp = &lclzonep->prev[tidx];
1025 if ((is_in_dst = ttisp->tt_isdst) == 0) { /* std. time */
1026 timezone = -ttisp->tt_gmtoff;
1027 tzname[0] = &lclzonep->chars[ttisp->tt_abbrind];
1028 if ((alt = prevp->alt) != NULL) {
1029 altzone = -alt->tt_gmtoff;
1030 tzname[1] = &lclzonep->chars[alt->tt_abbrind];
1032 } else { /* alt. time */
1033 altzone = -ttisp->tt_gmtoff;
1034 tzname[1] = &lclzonep->chars[ttisp->tt_abbrind];
1035 if ((std = prevp->std) != NULL) {
1036 timezone = -std->tt_gmtoff;
1037 tzname[0] = &lclzonep->chars[std->tt_abbrind];
1043 * This function takes a time_t and gmt offset and produces a
1044 * tm struct based on specified time.
1046 * The the following fields are calculated, based entirely
1047 * on the offset-adjusted value of t:
1049 * tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec
1050 * tm_yday. tm_wday. (tm_isdst is ALWAYS set to 0).
1053 static struct tm *
1054 offtime_u(time_t t, long offset, struct tm *tmptr)
1056 long days;
1057 long rem;
1058 long y;
1059 int yleap;
1060 const int *ip;
1062 days = t / SECSPERDAY;
1063 rem = t % SECSPERDAY;
1064 rem += offset;
1065 while (rem < 0) {
1066 rem += SECSPERDAY;
1067 --days;
1069 while (rem >= SECSPERDAY) {
1070 rem -= SECSPERDAY;
1071 ++days;
1073 tmptr->tm_hour = (int)(rem / SECSPERHOUR);
1074 rem = rem % SECSPERHOUR;
1075 tmptr->tm_min = (int)(rem / SECSPERMIN);
1076 tmptr->tm_sec = (int)(rem % SECSPERMIN);
1078 tmptr->tm_wday = (int)((EPOCH_WDAY + days) % DAYSPERWEEK);
1079 if (tmptr->tm_wday < 0)
1080 tmptr->tm_wday += DAYSPERWEEK;
1081 y = EPOCH_YEAR;
1082 while (days < 0 || days >= (long)__year_lengths[yleap = isleap(y)]) {
1083 long newy;
1085 newy = y + days / DAYSPERNYEAR;
1086 if (days < 0)
1087 --newy;
1088 days -= ((long)newy - (long)y) * DAYSPERNYEAR +
1089 LEAPS_THRU_END_OF(newy > 0 ? newy - 1L : newy) -
1090 LEAPS_THRU_END_OF(y > 0 ? y - 1L : y);
1091 y = newy;
1093 tmptr->tm_year = (int)(y - TM_YEAR_BASE);
1094 tmptr->tm_yday = (int)days;
1095 ip = __mon_lengths[yleap];
1096 for (tmptr->tm_mon = 0; days >=
1097 (long)ip[tmptr->tm_mon]; ++(tmptr->tm_mon))
1098 days = days - (long)ip[tmptr->tm_mon];
1099 tmptr->tm_mday = (int)(days + 1);
1100 tmptr->tm_isdst = 0;
1102 #ifdef _LP64
1103 /* do as much as possible before checking for error. */
1104 if ((y > (long)INT_MAX + TM_YEAR_BASE) ||
1105 (y < (long)INT_MIN + TM_YEAR_BASE)) {
1106 errno = EOVERFLOW;
1107 return (NULL);
1109 #endif
1110 return (tmptr);
1114 * Check whether DST is set for time in question. Only applies to
1115 * POSIX timezones. If explicit POSIX transition rules were provided
1116 * for the current zone, use those, otherwise use default USA POSIX
1117 * transitions.
1119 static int
1120 posix_check_dst(long long t, state_t *sp)
1122 struct tm gmttm;
1123 long long jan01;
1124 int year, i, idx, ridx;
1125 posix_daylight_t pdaylight;
1127 (void) offtime_u(t, 0L, &gmttm);
1129 year = gmttm.tm_year + 1900;
1130 jan01 = t - ((gmttm.tm_yday * SECSPERDAY) +
1131 (gmttm.tm_hour * SECSPERHOUR) +
1132 (gmttm.tm_min * SECSPERMIN) + gmttm.tm_sec);
1134 * If transition rules were provided for this zone,
1135 * use them, otherwise, default to USA daylight rules,
1136 * which are historically correct for the continental USA,
1137 * excluding local provisions. (This logic may be replaced
1138 * at some point in the future with "posixrules" to offer
1139 * more flexibility to the system administrator).
1141 if (sp->zonerules == POSIX) { /* POSIX rules */
1142 pdaylight.rules[0] = &sp->start_rule;
1143 pdaylight.rules[1] = &sp->end_rule;
1144 } else { /* POSIX_USA: USA */
1145 i = 0;
1146 while (year < __usa_rules[i].s_year && i < MAX_RULE_TABLE) {
1147 i++;
1149 pdaylight.rules[0] = (rule_t *)&__usa_rules[i].start;
1150 pdaylight.rules[1] = (rule_t *)&__usa_rules[i].end;
1152 pdaylight.offset[0] = timezone;
1153 pdaylight.offset[1] = altzone;
1155 idx = posix_daylight(&jan01, year, &pdaylight);
1156 ridx = !idx;
1159 * Note: t, rtime[0], and rtime[1] are all bounded within 'year'
1160 * beginning on 'jan01'
1162 if (t >= pdaylight.rtime[idx] && t < pdaylight.rtime[ridx]) {
1163 return (ridx);
1164 } else {
1165 return (idx);
1170 * Given January 1, 00:00:00 GMT for a year as an Epoch-relative time,
1171 * along with the integer year #, a posix_daylight_t that is composed
1172 * of two rules, and two GMT offsets (timezone and altzone), calculate
1173 * the two Epoch-relative times the two rules take effect, and return
1174 * them in the two rtime fields of the posix_daylight_t structure.
1175 * Also update janfirst by a year, by adding the appropriate number of
1176 * seconds depending on whether the year is a leap year or not. (We take
1177 * advantage that this routine knows the leap year status.)
1179 static int
1180 posix_daylight(long long *janfirst, int year, posix_daylight_t *pdaylightp)
1182 rule_t *rulep;
1183 long offset;
1184 int idx;
1185 int i, d, m1, yy0, yy1, yy2, dow;
1186 long leapyear;
1187 long long value;
1189 static const int __secs_year_lengths[2] = {
1190 DAYS_PER_NYEAR * SECSPERDAY,
1191 DAYS_PER_LYEAR * SECSPERDAY
1194 leapyear = isleap(year);
1196 for (idx = 0; idx < 2; idx++) {
1197 rulep = pdaylightp->rules[idx];
1198 offset = pdaylightp->offset[idx];
1200 switch (rulep->r_type) {
1202 case MON_WEEK_DOW:
1204 * Mm.n.d - nth "dth day" of month m.
1206 value = *janfirst;
1207 for (i = 0; i < rulep->r_mon - 1; ++i)
1208 value += __mon_lengths[leapyear][i] *
1209 SECSPERDAY;
1212 * Use Zeller's Congruence to get day-of-week of first
1213 * day of month.
1215 m1 = (rulep->r_mon + 9) % 12 + 1;
1216 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
1217 yy1 = yy0 / 100;
1218 yy2 = yy0 % 100;
1219 dow = ((26 * m1 - 2) / 10 +
1220 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
1222 if (dow < 0)
1223 dow += DAYSPERWEEK;
1226 * Following heuristic increases accuracy of USA rules
1227 * for negative years.
1229 if (year < 1 && leapyear)
1230 ++dow;
1232 * "dow" is the day-of-week of the first day of the
1233 * month. Get the day-of-month, zero-origin, of the
1234 * first "dow" day of the month.
1236 d = rulep->r_day - dow;
1237 if (d < 0)
1238 d += DAYSPERWEEK;
1239 for (i = 1; i < rulep->r_week; ++i) {
1240 if (d + DAYSPERWEEK >=
1241 __mon_lengths[leapyear][rulep->r_mon - 1])
1242 break;
1243 d += DAYSPERWEEK;
1246 * "d" is the day-of-month, zero-origin, of the day
1247 * we want.
1249 value += d * SECSPERDAY;
1250 break;
1252 case JULIAN_DAY:
1254 * Jn - Julian day, 1 == Jan 1, 60 == March 1 even
1255 * in leap yrs.
1257 value = *janfirst + (rulep->r_day - 1) * SECSPERDAY;
1258 if (leapyear && rulep->r_day >= 60)
1259 value += SECSPERDAY;
1260 break;
1262 case DAY_OF_YEAR:
1264 * n - day of year.
1266 value = *janfirst + rulep->r_day * SECSPERDAY;
1267 break;
1269 pdaylightp->rtime[idx] = value + rulep->r_time + offset;
1271 *janfirst += __secs_year_lengths[leapyear];
1273 return ((pdaylightp->rtime[0] > pdaylightp->rtime[1]) ? 1 : 0);
1277 * Try to load zoneinfo file into internal transition tables using name
1278 * indicated in TZ, and do validity checks. The format of zic(1M)
1279 * compiled zoneinfo files isdescribed in tzfile.h
1281 static int
1282 load_zoneinfo(const char *name, state_t *sp)
1284 char *cp;
1285 char *cp2;
1286 int i;
1287 long cnt;
1288 int fid;
1289 int ttisstdcnt;
1290 int ttisgmtcnt;
1291 char *fullname;
1292 size_t namelen;
1293 char *bufp;
1294 size_t flen;
1295 prev_t *prevp;
1296 /* LINTED */
1297 struct tzhead *tzhp;
1298 struct stat64 stbuf;
1299 ttinfo_t *most_recent_alt = NULL;
1300 ttinfo_t *most_recent_std = NULL;
1301 ttinfo_t *ttisp;
1304 if (name == NULL && (name = TZDEFAULT) == NULL)
1305 return (-1);
1307 if ((name[0] == '/') || strstr(name, "../"))
1308 return (-1);
1311 * We allocate fullname this way to avoid having
1312 * a PATH_MAX size buffer in our stack frame.
1314 namelen = LEN_TZDIR + 1 + strlen(name) + 1;
1315 if ((fullname = lmalloc(namelen)) == NULL)
1316 return (-1);
1317 (void) strcpy(fullname, TZDIR "/");
1318 (void) strcpy(fullname + LEN_TZDIR + 1, name);
1319 if ((fid = open(fullname, O_RDONLY)) == -1) {
1320 lfree(fullname, namelen);
1321 return (-1);
1323 lfree(fullname, namelen);
1325 if (fstat64(fid, &stbuf) == -1) {
1326 (void) close(fid);
1327 return (-1);
1330 flen = (size_t)stbuf.st_size;
1331 if (flen < sizeof (struct tzhead)) {
1332 (void) close(fid);
1333 return (-1);
1337 * It would be nice to use alloca() to allocate bufp but,
1338 * as above, we wish to avoid allocating a big buffer in
1339 * our stack frame, and also because alloca() gives us no
1340 * opportunity to fail gracefully on allocation failure.
1342 cp = bufp = lmalloc(flen);
1343 if (bufp == NULL) {
1344 (void) close(fid);
1345 return (-1);
1348 if ((cnt = read(fid, bufp, flen)) != flen) {
1349 lfree(bufp, flen);
1350 (void) close(fid);
1351 return (-1);
1354 if (close(fid) != 0) {
1355 lfree(bufp, flen);
1356 return (-1);
1359 cp += (sizeof (tzhp->tzh_magic)) + (sizeof (tzhp->tzh_reserved));
1361 /* LINTED: alignment */
1362 ttisstdcnt = CVTZCODE(cp);
1363 /* LINTED: alignment */
1364 ttisgmtcnt = CVTZCODE(cp);
1365 /* LINTED: alignment */
1366 sp->leapcnt = CVTZCODE(cp);
1367 /* LINTED: alignment */
1368 sp->timecnt = CVTZCODE(cp);
1369 /* LINTED: alignment */
1370 sp->typecnt = CVTZCODE(cp);
1371 /* LINTED: alignment */
1372 sp->charcnt = CVTZCODE(cp);
1374 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
1375 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
1376 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
1377 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
1378 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
1379 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) {
1380 lfree(bufp, flen);
1381 return (-1);
1384 if (cnt - (cp - bufp) < (long)(sp->timecnt * 4 + /* ats */
1385 sp->timecnt + /* types */
1386 sp->typecnt * (4 + 2) + /* ttinfos */
1387 sp->charcnt + /* chars */
1388 sp->leapcnt * (4 + 4) + /* lsinfos */
1389 ttisstdcnt + /* ttisstds */
1390 ttisgmtcnt)) { /* ttisgmts */
1391 lfree(bufp, flen);
1392 return (-1);
1396 for (i = 0; i < sp->timecnt; ++i) {
1397 /* LINTED: alignment */
1398 sp->ats[i] = CVTZCODE(cp);
1402 * Skip over types[] for now and load ttis[] so that when
1403 * types[] are loaded we can check for transitions to STD & DST.
1404 * This allows us to shave cycles in ltzset_u(), including
1405 * eliminating the need to check set 'daylight' later.
1408 cp2 = (char *)((uintptr_t)cp + sp->timecnt);
1410 for (i = 0; i < sp->typecnt; ++i) {
1411 ttisp = &sp->ttis[i];
1412 /* LINTED: alignment */
1413 ttisp->tt_gmtoff = CVTZCODE(cp2);
1414 ttisp->tt_isdst = (uchar_t)*cp2++;
1416 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) {
1417 lfree(bufp, flen);
1418 return (-1);
1421 ttisp->tt_abbrind = (uchar_t)*cp2++;
1422 if (ttisp->tt_abbrind < 0 ||
1423 ttisp->tt_abbrind > sp->charcnt) {
1424 lfree(bufp, flen);
1425 return (-1);
1430 * Since ttis were loaded ahead of types, it is possible to
1431 * detect whether daylight is ever set for this zone now, and
1432 * also preload other information to avoid repeated lookups later.
1433 * This logic facilitates keeping a running tab on the state of
1434 * std zone and alternate zone transitions such that timezone,
1435 * altzone and tzname[] can be determined quickly via an
1436 * index to any transition.
1438 * For transition #0 there are no previous transitions,
1439 * so prev->std and prev->alt will be null, but that's OK,
1440 * because null prev->std/prev->alt effectively
1441 * indicates none existed prior.
1444 prevp = &sp->prev[0];
1446 for (i = 0; i < sp->timecnt; ++i) {
1448 sp->types[i] = (uchar_t)*cp++;
1449 ttisp = &sp->ttis[sp->types[i]];
1451 prevp->std = most_recent_std;
1452 prevp->alt = most_recent_alt;
1454 if (ttisp->tt_isdst == 1) {
1455 most_recent_alt = ttisp;
1456 } else {
1457 most_recent_std = ttisp;
1460 if ((int)sp->types[i] >= sp->typecnt) {
1461 lfree(bufp, flen);
1462 return (-1);
1465 ++prevp;
1467 if (most_recent_alt == NULL)
1468 sp->daylight = 0;
1469 else
1470 sp->daylight = 1;
1473 * Set pointer ahead to where it would have been if we
1474 * had read types[] and ttis[] in the same order they
1475 * occurred in the file.
1477 cp = cp2;
1478 for (i = 0; i < sp->charcnt; ++i)
1479 sp->chars[i] = *cp++;
1481 sp->chars[i] = '\0'; /* ensure '\0' at end */
1483 for (i = 0; i < sp->leapcnt; ++i) {
1484 struct lsinfo *lsisp;
1486 lsisp = &sp->lsis[i];
1487 /* LINTED: alignment */
1488 lsisp->ls_trans = CVTZCODE(cp);
1489 /* LINTED: alignment */
1490 lsisp->ls_corr = CVTZCODE(cp);
1493 for (i = 0; i < sp->typecnt; ++i) {
1494 ttisp = &sp->ttis[i];
1495 if (ttisstdcnt == 0) {
1496 ttisp->tt_ttisstd = FALSE;
1497 } else {
1498 ttisp->tt_ttisstd = *cp++;
1499 if (ttisp->tt_ttisstd != TRUE &&
1500 ttisp->tt_ttisstd != FALSE) {
1501 lfree(bufp, flen);
1502 return (-1);
1507 for (i = 0; i < sp->typecnt; ++i) {
1508 ttisp = &sp->ttis[i];
1509 if (ttisgmtcnt == 0) {
1510 ttisp->tt_ttisgmt = FALSE;
1511 } else {
1512 ttisp->tt_ttisgmt = *cp++;
1513 if (ttisp->tt_ttisgmt != TRUE &&
1514 ttisp->tt_ttisgmt != FALSE) {
1515 lfree(bufp, flen);
1516 return (-1);
1522 * Other defaults set at beginning of this routine
1523 * to cover case where zoneinfo file cannot be loaded
1525 sp->default_timezone = -sp->ttis[0].tt_gmtoff;
1526 sp->default_altzone = 0;
1527 sp->default_tzname0 = &sp->chars[0];
1528 sp->default_tzname1 = _tz_spaces;
1530 lfree(bufp, flen);
1532 sp->zonerules = ZONEINFO;
1534 return (0);
1538 * Given a POSIX section 8-style TZ string, fill in transition tables.
1540 * Examples:
1542 * TZ = PST8 or GMT0
1543 * Timecnt set to 0 and typecnt set to 1, reflecting std time only.
1545 * TZ = PST8PDT or PST8PDT7
1546 * Create transition times by applying USA transitions from
1547 * Jan 1 of each year covering 1902-2038. POSIX offsets
1548 * as specified in the TZ are used to calculate the tt_gmtoff
1549 * for each of the two zones. If ommitted, DST defaults to
1550 * std. time minus one hour.
1552 * TZ = <PST8>8PDT or <PST8>8<PDT9>
1553 * Quoted transition. The values in angled brackets are treated
1554 * as zone name text, not parsed as offsets. The offsets
1555 * occuring following the zonename section. In this way,
1556 * instead of PST being displayed for standard time, it could
1557 * be displayed as PST8 to give an indication of the offset
1558 * of that zone to GMT.
1560 * TZ = GMT0BST, M3.5.0/1, M10.5.0/2 or GMT0BST, J23953, J23989
1561 * Create transition times based on the application new-year
1562 * relative POSIX transitions, parsed from TZ, from Jan 1
1563 * for each year covering 1902-2038. POSIX offsets specified
1564 * in TZ are used to calculate tt_gmtoff for each of the two
1565 * zones.
1568 static int
1569 load_posixinfo(const char *name, state_t *sp)
1571 const char *stdname;
1572 const char *dstname = 0;
1573 size_t stdlen;
1574 size_t dstlen;
1575 long stdoff = 0;
1576 long dstoff = 0;
1577 time_t *tranp;
1578 uchar_t *typep;
1579 prev_t *prevp;
1580 char *cp;
1581 int year;
1582 int i;
1583 long long janfirst;
1584 ttinfo_t *dst;
1585 ttinfo_t *std;
1586 int quoted;
1587 zone_rules_t zonetype;
1588 posix_daylight_t pdaylight;
1590 zonetype = POSIX_USA;
1591 stdname = name;
1593 if ((quoted = (*stdname == '<')) != 0)
1594 ++stdname;
1596 /* Parse/extract STD zone name, len and GMT offset */
1597 if (*name != '\0') {
1598 if ((name = getzname(name, quoted)) == NULL)
1599 return (-1);
1600 stdlen = name - stdname;
1601 if (*name == '>')
1602 ++name;
1603 if (*name == '\0' || stdlen < 1) {
1604 return (-1);
1605 } else {
1606 if ((name = getoffset(name, &stdoff)) == NULL)
1607 return (-1);
1611 /* If DST specified in TZ, extract DST zone details */
1612 if (*name != '\0') {
1614 dstname = name;
1615 if ((quoted = (*dstname == '<')) != 0)
1616 ++dstname;
1617 if ((name = getzname(name, quoted)) == NULL)
1618 return (-1);
1619 dstlen = name - dstname;
1620 if (dstlen < 1)
1621 return (-1);
1622 if (*name == '>')
1623 ++name;
1624 if (*name != '\0' && *name != ',' && *name != ';') {
1625 if ((name = getoffset(name, &dstoff)) == NULL)
1626 return (-1);
1627 } else {
1628 dstoff = stdoff - SECSPERHOUR;
1631 /* If any present, extract POSIX transitions from TZ */
1632 if (*name == ',' || *name == ';') {
1633 /* Backward compatibility using ';' separator */
1634 int compat_flag = (*name == ';');
1635 ++name;
1636 if ((name = getrule(name, &sp->start_rule, compat_flag))
1637 == NULL)
1638 return (-1);
1639 if (*name++ != ',')
1640 return (-1);
1641 if ((name = getrule(name, &sp->end_rule, compat_flag))
1642 == NULL)
1643 return (-1);
1644 if (*name != '\0')
1645 return (-1);
1646 zonetype = POSIX;
1650 * We know STD and DST zones are specified with this timezone
1651 * therefore the cache will be set up with 2 transitions per
1652 * year transitioning to their respective std and dst zones.
1654 sp->daylight = 1;
1655 sp->typecnt = 2;
1656 sp->timecnt = 272;
1659 * Insert zone data from POSIX TZ into state table
1660 * The Olson public domain POSIX code sets up ttis[0] to be DST,
1661 * as we are doing here. It seems to be the correct behavior.
1662 * The US/Pacific zoneinfo file also lists DST as first type.
1664 dst = &sp->ttis[0];
1665 dst->tt_gmtoff = -dstoff;
1666 dst->tt_isdst = 1;
1668 std = &sp->ttis[1];
1669 std->tt_gmtoff = -stdoff;
1670 std->tt_isdst = 0;
1672 sp->prev[0].std = NULL;
1673 sp->prev[0].alt = NULL;
1675 /* Create transition data based on POSIX TZ */
1676 tranp = sp->ats;
1677 prevp = &sp->prev[1];
1678 typep = sp->types;
1681 * We only cache from 1902 to 2037 to avoid transistions
1682 * that wrap at the 32-bit boundries, since 1901 and 2038
1683 * are not full years in 32-bit time. The rough edges
1684 * will be handled as transition cache misses.
1687 janfirst = JAN_01_1902;
1689 pdaylight.rules[0] = &sp->start_rule;
1690 pdaylight.rules[1] = &sp->end_rule;
1691 pdaylight.offset[0] = stdoff;
1692 pdaylight.offset[1] = dstoff;
1694 for (i = MAX_RULE_TABLE; i >= 0; i--) {
1695 if (zonetype == POSIX_USA) {
1696 pdaylight.rules[0] =
1697 (rule_t *)&__usa_rules[i].start;
1698 pdaylight.rules[1] =
1699 (rule_t *)&__usa_rules[i].end;
1701 for (year = __usa_rules[i].s_year;
1702 year <= __usa_rules[i].e_year;
1703 year++) {
1704 int idx, ridx;
1705 idx =
1706 posix_daylight(&janfirst, year, &pdaylight);
1707 ridx = !idx;
1710 * Two transitions per year. Since there are
1711 * only two zone types for this POSIX zone,
1712 * previous std and alt are always set to
1713 * &ttis[0] and &ttis[1].
1715 *tranp++ = (time_t)pdaylight.rtime[idx];
1716 *typep++ = idx;
1717 prevp->std = std;
1718 prevp->alt = dst;
1719 ++prevp;
1721 *tranp++ = (time_t)pdaylight.rtime[ridx];
1722 *typep++ = ridx;
1723 prevp->std = std;
1724 prevp->alt = dst;
1725 ++prevp;
1728 } else { /* DST wasn't specified in POSIX TZ */
1730 /* Since we only have STD time, there are no transitions */
1731 dstlen = 0;
1732 sp->daylight = 0;
1733 sp->typecnt = 1;
1734 sp->timecnt = 0;
1735 std = &sp->ttis[0];
1736 std->tt_gmtoff = -stdoff;
1737 std->tt_isdst = 0;
1741 /* Setup zone name character data for state table */
1742 sp->charcnt = (int)(stdlen + 1);
1743 if (dstlen != 0)
1744 sp->charcnt += dstlen + 1;
1746 /* If bigger than zone name abbv. buffer, grow it */
1747 if ((size_t)sp->charcnt > sp->charsbuf_size) {
1748 if ((cp = libc_realloc(sp->chars, sp->charcnt)) == NULL)
1749 return (-1);
1750 sp->chars = cp;
1751 sp->charsbuf_size = sp->charcnt;
1755 * Copy zone name text null-terminatedly into state table.
1756 * By doing the copy once during zone loading, setting
1757 * tzname[] subsequently merely involves setting pointer
1759 * If either or both std. or alt. zone name < 3 chars,
1760 * space pad the deficient name(s) to right.
1763 std->tt_abbrind = 0;
1764 cp = sp->chars;
1765 (void) strncpy(cp, stdname, stdlen);
1766 while (stdlen < 3)
1767 cp[stdlen++] = ' ';
1768 cp[stdlen] = '\0';
1770 i = (int)(stdlen + 1);
1771 if (dstlen != 0) {
1772 dst->tt_abbrind = i;
1773 cp += i;
1774 (void) strncpy(cp, dstname, dstlen);
1775 while (dstlen < 3)
1776 cp[dstlen++] = ' ';
1777 cp[dstlen] = '\0';
1780 /* Save default values */
1781 if (sp->typecnt == 1) {
1782 sp->default_timezone = stdoff;
1783 sp->default_altzone = stdoff;
1784 sp->default_tzname0 = &sp->chars[0];
1785 sp->default_tzname1 = _tz_spaces;
1786 } else {
1787 sp->default_timezone = -std->tt_gmtoff;
1788 sp->default_altzone = -dst->tt_gmtoff;
1789 sp->default_tzname0 = &sp->chars[std->tt_abbrind];
1790 sp->default_tzname1 = &sp->chars[dst->tt_abbrind];
1793 sp->zonerules = zonetype;
1795 return (0);
1800 * Given a pointer into a time zone string, scan until a character that is not
1801 * a valid character in a zone name is found. Return ptr to that character.
1802 * Return NULL if error (ie. non-printable character located in name)
1804 static const char *
1805 getzname(const char *strp, int quoted)
1807 char c;
1809 if (quoted) {
1810 while ((c = *strp) != '\0' && c != '>' &&
1811 isgraph((unsigned char)c))
1812 ++strp;
1813 } else {
1814 while ((c = *strp) != '\0' && isgraph((unsigned char)c) &&
1815 !isdigit((unsigned char)c) && c != ',' && c != '-' &&
1816 c != '+')
1817 ++strp;
1820 /* Found an excessively invalid character. Discredit whole name */
1821 if (c != '\0' && !isgraph((unsigned char)c))
1822 return (NULL);
1824 return (strp);
1828 * Given pointer into time zone string, extract first
1829 * number pointed to. Validate number within range specified,
1830 * Return ptr to first char following valid numeric sequence.
1832 static const char *
1833 getnum(const char *strp, int *nump, int min, int max)
1835 char c;
1836 int num;
1838 if (strp == NULL || !isdigit((unsigned char)(c = *strp)))
1839 return (NULL);
1840 num = 0;
1841 do {
1842 num = num * 10 + (c - '0');
1843 if (num > max)
1844 return (NULL); /* illegal value */
1845 c = *++strp;
1846 } while (isdigit((unsigned char)c));
1847 if (num < min)
1848 return (NULL); /* illegal value */
1849 *nump = num;
1850 return (strp);
1854 * Given a pointer into a time zone string, extract a number of seconds,
1855 * in hh[:mm[:ss]] form, from the string. If an error occurs, return NULL,
1856 * otherwise, return a pointer to the first character not part of the number
1857 * of seconds.
1859 static const char *
1860 getsecs(const char *strp, long *secsp)
1862 int num;
1865 * `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
1866 * "M10.4.6/26", which does not conform to Posix,
1867 * but which specifies the equivalent of
1868 * ``02:00 on the first Sunday on or after 23 Oct''.
1870 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
1871 if (strp == NULL)
1872 return (NULL);
1873 *secsp = num * (long)SECSPERHOUR;
1874 if (*strp == ':') {
1875 ++strp;
1876 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
1877 if (strp == NULL)
1878 return (NULL);
1879 *secsp += num * SECSPERMIN;
1880 if (*strp == ':') {
1881 ++strp;
1882 /* `SECSPERMIN' allows for leap seconds. */
1883 strp = getnum(strp, &num, 0, SECSPERMIN);
1884 if (strp == NULL)
1885 return (NULL);
1886 *secsp += num;
1889 return (strp);
1893 * Given a pointer into a time zone string, extract an offset, in
1894 * [+-]hh[:mm[:ss]] form, from the string.
1895 * If any error occurs, return NULL.
1896 * Otherwise, return a pointer to the first character not part of the time.
1898 static const char *
1899 getoffset(const char *strp, long *offsetp)
1901 int neg = 0;
1903 if (*strp == '-') {
1904 neg = 1;
1905 ++strp;
1906 } else if (*strp == '+') {
1907 ++strp;
1909 strp = getsecs(strp, offsetp);
1910 if (strp == NULL)
1911 return (NULL); /* illegal time */
1912 if (neg)
1913 *offsetp = -*offsetp;
1914 return (strp);
1918 * Given a pointer into a time zone string, extract a rule in the form
1919 * date[/time]. See POSIX section 8 for the format of "date" and "time".
1920 * If a valid rule is not found, return NULL.
1921 * Otherwise, return a pointer to the first character not part of the rule.
1923 * If compat_flag is set, support old 1-based day of year values.
1925 static const char *
1926 getrule(const char *strp, rule_t *rulep, int compat_flag)
1928 if (compat_flag == 0 && *strp == 'M') {
1930 * Month, week, day.
1932 rulep->r_type = MON_WEEK_DOW;
1933 ++strp;
1934 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
1935 if (strp == NULL)
1936 return (NULL);
1937 if (*strp++ != '.')
1938 return (NULL);
1939 strp = getnum(strp, &rulep->r_week, 1, 5);
1940 if (strp == NULL)
1941 return (NULL);
1942 if (*strp++ != '.')
1943 return (NULL);
1944 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
1945 } else if (compat_flag == 0 && *strp == 'J') {
1947 * Julian day.
1949 rulep->r_type = JULIAN_DAY;
1950 ++strp;
1951 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
1953 } else if (isdigit((unsigned char)*strp)) {
1955 * Day of year.
1957 rulep->r_type = DAY_OF_YEAR;
1958 if (compat_flag == 0) {
1959 /* zero-based day of year */
1960 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
1961 } else {
1962 /* one-based day of year */
1963 strp = getnum(strp, &rulep->r_day, 1, DAYSPERLYEAR);
1964 rulep->r_day--;
1966 } else {
1967 return (NULL); /* ZONERULES_INVALID format */
1969 if (strp == NULL)
1970 return (NULL);
1971 if (*strp == '/') {
1973 * Time specified.
1975 ++strp;
1976 strp = getsecs(strp, &rulep->r_time);
1977 } else {
1978 rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
1980 return (strp);
1984 * Returns default value for TZ as specified in /etc/default/init file, if
1985 * a default value for TZ is provided there.
1987 static char *
1988 get_default_tz(void)
1990 char *tz = NULL;
1991 uchar_t *tzp, *tzq;
1992 int flags;
1993 void *defp;
1995 if ((defp = defopen_r(TIMEZONE)) != NULL) {
1996 flags = defcntl_r(DC_GETFLAGS, 0, defp);
1997 TURNON(flags, DC_STRIP_QUOTES);
1998 (void) defcntl_r(DC_SETFLAGS, flags, defp);
2000 if ((tzp = (uchar_t *)defread_r(TZSTRING, defp)) != NULL) {
2001 while (isspace(*tzp))
2002 tzp++;
2003 tzq = tzp;
2004 while (!isspace(*tzq) &&
2005 *tzq != ';' &&
2006 *tzq != '#' &&
2007 *tzq != '\0')
2008 tzq++;
2009 *tzq = '\0';
2010 if (*tzp != '\0')
2011 tz = strdup((char *)tzp);
2014 defclose_r(defp);
2016 return (tz);
2019 static state_t *
2020 get_zone(systemtz_t *tzp)
2022 int hashid;
2023 state_t *m, *p;
2024 const char *zonename = tzp->tz;
2026 hashid = get_hashid(zonename);
2027 m = tzcache[hashid];
2028 while (m) {
2029 int r;
2030 r = strcmp(m->zonename, zonename);
2031 if (r == 0) {
2032 /* matched */
2033 return (NULL);
2034 } else if (r > 0) {
2035 break;
2037 m = m->next;
2039 /* malloc() return value is also checked for NULL in ltzset_u() */
2040 p = malloc(sizeof (state_t));
2042 /* ltzset_u() resets the free flag to 0 if it uses the p buffer */
2043 if (p != NULL)
2044 tzp->flag = 1;
2045 return (p);
2049 * getsystemTZ() returns the TZ value if it is set in the environment, or
2050 * it returns the system TZ; if the systemTZ has not yet been set,
2051 * get_default_tz() is called to read the /etc/default/init file to get
2052 * the value.
2054 * getsystemTZ() also calls get_zone() to do an initial check to see if the
2055 * timezone is the current timezone, or one that is already loaded in the
2056 * hash table. If get_zone() determines the timezone has not yet been loaded,
2057 * it pre-allocates a buffer for a state_t struct, which ltzset_u() can use
2058 * later to load the timezone and add to the hash table.
2060 * The large state_t buffer is allocated here to avoid calls to malloc()
2061 * within mutex_locks.
2063 static systemtz_t *
2064 getsystemTZ(systemtz_t *stzp)
2066 static const char *systemTZ = NULL;
2067 char *tz;
2069 assert_no_libc_locks_held();
2071 stzp->flag = 0;
2073 tz = getenv("TZ");
2074 if (tz != NULL && *tz != '\0') {
2075 stzp->tz = (const char *)tz;
2076 goto get_entry;
2079 if (systemTZ != NULL) {
2080 stzp->tz = systemTZ;
2081 goto get_entry;
2084 tz = get_default_tz();
2085 lmutex_lock(&_time_lock);
2086 if (systemTZ == NULL) {
2087 if ((systemTZ = tz) != NULL) /* found TZ entry in the file */
2088 tz = NULL;
2089 else
2090 systemTZ = _posix_gmt0; /* no TZ entry in the file */
2092 lmutex_unlock(&_time_lock);
2094 if (tz != NULL) /* someone beat us to it; free our entry */
2095 free(tz);
2097 stzp->tz = systemTZ;
2099 get_entry:
2101 * The object referred to by the 1st 'namecache'
2102 * may be different from the one by the 2nd 'namecache' below.
2103 * But, it does not matter. The bottomline is at this point
2104 * 'namecache' points to non-NULL and whether the string pointed
2105 * to by 'namecache' is equivalent to stzp->tz or not.
2107 if (namecache != NULL && strcmp(namecache, stzp->tz) == 0) {
2109 * At this point, we found the entry having the same
2110 * zonename as stzp->tz exists. Later we will find
2111 * the exact one, so we don't need to allocate
2112 * the memory here.
2114 stzp->entry = NULL;
2115 } else {
2117 * At this point, we could not get the evidence that this
2118 * zonename had been cached. We will look into the cache
2119 * further.
2121 stzp->entry = get_zone(stzp);
2123 return (stzp);