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]
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 /* Copyright (c) 1988 AT&T */
32 /* All Rights Reserved */
35 * A part of this file comes from public domain source, so
36 * clarified as of June 5, 1996 by Arthur David Olson
37 * (arthur_david_olson@nih.gov).
43 * This file contains routines to convert struct tm to time_t and
44 * back as well as adjust time values based on their timezone, which
45 * is a local offset from GMT (Greenwich Mean Time).
47 * Many timezones actually consist of more than one offset from GMT.
48 * The GMT offset that is considered the normal offset is referred
49 * to as standard time. The other offset is referred to as alternate
50 * time, but is better known as daylight savings time or summer time.
52 * The current timezone for an application is derived from the TZ
53 * environment variable either as defined in the environment or in
54 * /etc/default/init. As defined by IEEE 1003.1-1990 (POSIX), the
55 * TZ variable can either be:
58 * <std><offset1>[<dst>[<offset2>]][,<start>[/<time>],<end>[/<time>]
60 * <characters> is an implementation-defined string that somehow describes
61 * a timezone. The implementation-defined description of a timezone used
62 * in Solaris is based on the public domain zoneinfo code available from
63 * elsie.nci.nih.gov and a timezone that is specified in this way is
64 * referred to as a zoneinfo timezone. An example of this is ":US/Pacific".
66 * The precise definition of the second format can be found in POSIX,
67 * but, basically, <std> is the abbreviation for the timezone in standard
68 * (not daylight savings time), <offset1> is the standard offset from GMT,
69 * <dst> is the abbreviation for the timezone in daylight savings time and
70 * <offset2> is the daylight savings time offset from GMT. The remainder
71 * specifies when daylight savings time begins and ends. A timezone
72 * specified in this way is referred to as a POSIX timezone. An example
73 * of this is "PST7PDT".
75 * In Solaris, there is an extension to this. If the timezone is not
76 * preceded by a ":" and it does not parse as a POSIX timezone, then it
77 * will be treated as a zoneinfo timezone. Much usage of zoneinfo
78 * timezones in Solaris is done without the leading ":".
80 * A zoneinfo timezone is a reference to a file that contains a set of
81 * rules that describe the timezone. In Solaris, the file is in
82 * /usr/share/lib/zoneinfo. The file is generated by zic(1M), based
83 * on zoneinfo rules "source" files. This is all described on the zic(1M)
88 * Functions that are common to ctime(3C) and cftime(3C)
91 #pragma weak _tzset = tzset
98 #include <sys/types.h>
102 #include <sys/param.h>
113 #include <sys/stat.h>
114 #include <sys/mman.h>
116 /* JAN_01_1902 cast to (int) - negative number of seconds from 1970 */
117 #define JAN_01_1902 (int)0x8017E880
118 #define LEN_TZDIR (sizeof (TZDIR) - 1)
119 #define TIMEZONE "/etc/default/init"
120 #define TZSTRING "TZ="
123 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
125 /* Days since 1/1/70 to 12/31/(1900 + Y - 1) */
126 #define DAYS_SINCE_70(Y) (YR((Y)-1L) - YR(70-1))
127 #define YR(X) /* Calc # days since 0 A.D. X = curr. yr - 1900 */ \
128 ((1900L + (X)) * 365L + (1900L + (X)) / 4L - \
129 (1900L + (X)) / 100L + ((1900L + (X)) - 1600L) / 400L)
133 * The following macros are replacements for detzcode(), which has
134 * been in the public domain versions of the localtime.c code for
135 * a long time. The primatives supporting the CVTZCODE macro are
136 * implemented differently for different endianness (ie. little
137 * vs. big endian) out of necessity, to account for the different
138 * byte ordering of the quantities being fetched. Both versions
139 * are substantially faster than the detzcode() macro. The big
140 * endian version is approx. 6.8x faster than detzcode(), the
141 * little endian version is approximately 3x faster, due to the
142 * extra shifting requiring to change byte order. The micro
143 * benchmarks used to compare were based on the SUNWSpro SC6.1
144 * (and later) compilers.
147 #if defined(__sparc) || defined(__sparcv9) /* big endian */
149 #define GET_LONG(p) \
152 #define GET_SHORTS(p) \
153 *(ushort_t *)(p) << 16 |\
154 *(ushort_t *)((p) + 2)
156 #define GET_CHARS(p) \
157 *(uchar_t *)(p) << 24 |\
158 *(uchar_t *)((p) + 1) << 16 |\
159 *(uchar_t *)((p) + 2) << 8 |\
160 *(uchar_t *)((p) + 3)
162 #else /* little endian */
164 #define GET_BYTE(x) \
167 #define SWAP_BYTES(x) ((\
171 #define SWAP_WORDS(x) ((\
172 SWAP_BYTES(x) << 16) |\
173 SWAP_BYTES((x) >> 16))
175 #define GET_LONG(p) \
176 SWAP_WORDS(*(uint_t *)(p))
178 #define GET_SHORTS(p) \
179 SWAP_BYTES(*(ushort_t *)(p)) << 16 |\
180 SWAP_BYTES(*(ushort_t *)((p) + 2))
182 #define GET_CHARS(p) \
183 GET_BYTE(*(uchar_t *)(p)) << 24 |\
184 GET_BYTE(*(uchar_t *)((p) + 1)) << 16 |\
185 GET_BYTE(*(uchar_t *)((p) + 2)) << 8 |\
186 GET_BYTE(*(uchar_t *)((p) + 3))
191 #define IF_ALIGNED(ptr, byte_alignment) \
192 !((uintptr_t)(ptr) & (byte_alignment - 1))
194 #define CVTZCODE(p) (int)(\
195 IF_ALIGNED(p, 4) ? GET_LONG(p) :\
196 IF_ALIGNED(p, 2) ? GET_SHORTS(p) : GET_CHARS(p));\
207 extern mutex_t _time_lock
;
209 extern const int __lyday_to_month
[];
210 extern const int __yday_to_month
[];
211 extern const int __mon_lengths
[2][MONS_PER_YEAR
];
212 extern const int __year_lengths
[2];
214 const char _tz_gmt
[4] = "GMT"; /* "GMT" */
215 const char _tz_spaces
[4] = " "; /* " " */
216 static const char _posix_gmt0
[5] = "GMT0"; /* "GMT0" */
218 typedef struct ttinfo
{ /* Time type information */
219 long tt_gmtoff
; /* GMT offset in seconds */
220 int tt_isdst
; /* used to set tm_isdst */
221 int tt_abbrind
; /* abbreviation list index */
222 int tt_ttisstd
; /* TRUE if trans is std time */
223 int tt_ttisgmt
; /* TRUE if transition is GMT */
226 typedef struct lsinfo
{ /* Leap second information */
227 time_t ls_trans
; /* transition time */
228 long ls_corr
; /* correction to apply */
231 typedef struct previnfo
{ /* Info about *prev* trans */
232 ttinfo_t
*std
; /* Most recent std type */
233 ttinfo_t
*alt
; /* Most recent alt type */
237 MON_WEEK_DOW
, /* Mm.n.d - month, week, day of week */
238 JULIAN_DAY
, /* Jn - Julian day */
239 DAY_OF_YEAR
/* n - day of year */
243 posrule_type_t r_type
; /* type of rule */
244 int r_day
; /* day number of rule */
245 int r_week
; /* week number of rule */
246 int r_mon
; /* month number of rule */
247 long r_time
; /* transition time of rule */
257 * Note: ZONERULES_INVALID used for global curr_zonerules variable, but not
258 * for zonerules field of state_t.
261 ZONERULES_INVALID
, POSIX
, POSIX_USA
, ZONEINFO
265 * The following members are allocated from the libc-internal malloc:
270 typedef struct state
{
271 const char *zonename
; /* Timezone */
272 struct state
*next
; /* next state */
273 zone_rules_t zonerules
; /* Type of zone */
274 int daylight
; /* daylight global */
275 long default_timezone
; /* Def. timezone val */
276 long default_altzone
; /* Def. altzone val */
277 const char *default_tzname0
; /* Def tz..[0] val */
278 const char *default_tzname1
; /* Def tz..[1] val */
279 int leapcnt
; /* # leap sec trans */
280 int timecnt
; /* # transitions */
281 int typecnt
; /* # zone types */
282 int charcnt
; /* # zone abbv. chars */
283 char *chars
; /* Zone abbv. chars */
284 size_t charsbuf_size
; /* malloc'ed buflen */
285 prev_t prev
[TZ_MAX_TIMES
]; /* Pv. trans info */
286 time_t ats
[TZ_MAX_TIMES
]; /* Trans. times */
287 uchar_t types
[TZ_MAX_TIMES
]; /* Type indices */
288 ttinfo_t ttis
[TZ_MAX_TYPES
]; /* Zone types */
289 lsinfo_t lsis
[TZ_MAX_LEAPS
]; /* Leap sec trans */
290 int last_ats_idx
; /* last ats index */
291 rule_t start_rule
; /* For POSIX w/rules */
292 rule_t end_rule
; /* For POSIX w/rules */
295 typedef struct tznmlist
{
296 struct tznmlist
*link
;
300 static const char *systemTZ
;
301 static tznmlist_t
*systemTZrec
;
303 static const char *namecache
;
305 static state_t
*tzcache
[HASHTABLE
];
308 static tznmlist_t
*tznmhash
[TZNMC_SZ
];
309 static const char *last_tzname
[2];
311 static state_t
*lclzonep
;
313 static struct tm tm
; /* For non-reentrant use */
314 static int is_in_dst
; /* Set if t is in DST */
315 static zone_rules_t curr_zonerules
= ZONERULES_INVALID
;
316 static int cached_year
; /* mktime() perf. enhancement */
317 static long long cached_secs_since_1970
; /* mktime() perf. */
318 static int year_is_cached
= FALSE
; /* mktime() perf. */
320 #define TZSYNC_FILE "/var/run/tzsync"
321 static uint32_t zoneinfo_seqno
;
322 static uint32_t zoneinfo_seqno_init
= 1;
323 static uint32_t *zoneinfo_seqadr
= &zoneinfo_seqno_init
;
324 #define RELOAD_INFO() (zoneinfo_seqno != *zoneinfo_seqadr)
326 #define _2AM (2 * SECS_PER_HOUR)
364 * The following table defines standard USA DST transitions
365 * as they have been declared throughout history, disregarding
366 * the legally sanctioned local variants.
368 * Note: At some point, this table may be supplanted by
369 * more popular 'posixrules' logic.
378 static const __usa_rules_t __usa_rules
[] = {
381 { MON_WEEK_DOW
, Sun
, _2nd_week
, Mar
, _2AM
},
382 { MON_WEEK_DOW
, Sun
, _1st_week
, Nov
, _2AM
},
386 { MON_WEEK_DOW
, Sun
, _1st_week
, Apr
, _2AM
},
387 { MON_WEEK_DOW
, Sun
, _Last_week
, Oct
, _2AM
},
391 { MON_WEEK_DOW
, Sun
, _Last_week
, Apr
, _2AM
},
392 { MON_WEEK_DOW
, Sun
, _Last_week
, Oct
, _2AM
},
396 { MON_WEEK_DOW
, Sun
, _Last_week
, Feb
, _2AM
},
397 { MON_WEEK_DOW
, Sun
, _Last_week
, Oct
, _2AM
},
402 { MON_WEEK_DOW
, Sun
, _1st_week
, Jan
, _2AM
},
403 { MON_WEEK_DOW
, Sun
, _Last_week
, Nov
, _2AM
},
406 * The entry below combines two previously separate entries for
407 * 1969-1973 and 1902-1968
411 { MON_WEEK_DOW
, Sun
, _Last_week
, Apr
, _2AM
},
412 { MON_WEEK_DOW
, Sun
, _Last_week
, Oct
, _2AM
},
415 #define MAX_RULE_TABLE (sizeof (__usa_rules) / sizeof (__usa_rules_t) - 1)
418 * Prototypes for static functions.
420 static const char *getsystemTZ(void);
421 static const char *getzname(const char *, int);
422 static const char *getnum(const char *, int *, int, int);
423 static const char *getsecs(const char *, long *);
424 static const char *getoffset(const char *, long *);
425 static const char *getrule(const char *, rule_t
*, int);
426 static int load_posixinfo(const char *, state_t
*);
427 static int load_zoneinfo(const char *, state_t
*);
428 static void load_posix_transitions(state_t
*, long, long, zone_rules_t
);
429 static void adjust_posix_default(state_t
*, long, long);
430 static void *ltzset_u(time_t);
431 static struct tm
*offtime_u(time_t, long, struct tm
*);
432 static int posix_check_dst(long long, state_t
*);
433 static int posix_daylight(long long *, int, posix_daylight_t
*);
434 static void set_zone_context(time_t);
435 static void reload_counter(void);
436 static void purge_zone_cache(void);
437 static void set_tzname(const char **);
440 * definition of difftime
442 * This code assumes time_t is type long. Note the difference of two
443 * longs in absolute value is representable as an unsigned long. So,
444 * compute the absolute value of the difference, cast the result to
445 * double and attach the sign back on.
447 * Note this code assumes 2's complement arithmetic. The subtraction
448 * operation may overflow when using signed operands, but when the
449 * result is cast to unsigned long, it yields the desired value
450 * (ie, the absolute value of the difference). The cast to unsigned
451 * long is done using pointers to avoid undefined behavior if casting
452 * a negative value to unsigned.
455 difftime(time_t time1
, time_t time0
)
459 return (-(double)*(unsigned long *) &time0
);
462 return ((double)*(unsigned long *) &time1
);
467 * Accepts a time_t, returns a tm struct based on it, with
468 * no local timezone adjustment.
470 * This routine is the thread-safe variant of gmtime(), and
471 * requires that the call provide the address of their own tm
474 * Locking is not done here because set_zone_context()
475 * is not called, thus timezone, altzone, and tzname[] are not
476 * accessed, no memory is allocated, and no common dynamic
482 gmtime_r(const time_t *timep
, struct tm
*p_tm
)
484 return (offtime_u((time_t)*timep
, 0L, p_tm
));
488 * Accepts a time_t, returns a tm struct based on it, with
489 * no local timezone adjustment.
491 * This function is explicitly NOT THREAD-SAFE. The standards
492 * indicate it should provide its results in its own statically
493 * allocated tm struct that gets overwritten. The thread-safe
494 * variant is gmtime_r(). We make it mostly thread-safe by
495 * allocating its buffer in thread-specific data.
500 gmtime(const time_t *timep
)
502 struct tm
*p_tm
= tsdalloc(_T_STRUCT_TM
, sizeof (struct tm
), NULL
);
504 if (p_tm
== NULL
) /* memory allocation failure */
505 p_tm
= &tm
; /* use static buffer and hope for the best */
506 return (gmtime_r(timep
, p_tm
));
510 * This is the hashing function, based on the input timezone name.
513 get_hashid(const char *id
)
519 while ((c
= *id
++) != '\0')
521 return ((int)(h
% HASHTABLE
));
525 * find_zone() gets the hashid for zonename, then uses the hashid
526 * to search the hash table for the appropriate timezone entry. If
527 * the entry for zonename is found in the hash table, return a pointer
531 find_zone(const char *zonename
)
536 hashid
= get_hashid(zonename
);
537 cur
= tzcache
[hashid
];
540 res
= strcmp(cur
->zonename
, zonename
);
543 } else if (res
> 0) {
552 * Register new state in the cache.
555 reg_zone(state_t
*new)
560 hashid
= get_hashid(new->zonename
);
561 cur
= tzcache
[hashid
];
563 while (cur
!= NULL
) {
564 res
= strcmp(cur
->zonename
, new->zonename
);
566 /* impossible, but just in case */
568 } else if (res
> 0) {
575 new->next
= prv
->next
;
578 new->next
= tzcache
[hashid
];
579 tzcache
[hashid
] = new;
584 * Returns tm struct based on input time_t argument, correcting
585 * for the local timezone, producing documented side-effects
586 * to extern global state, timezone, altzone, daylight and tzname[].
588 * localtime_r() is the thread-safe variant of localtime().
590 * IMPLEMENTATION NOTE:
592 * Locking slows multithreaded access and is probably ultimately
593 * unnecessary here. The POSIX specification is a bit vague
594 * as to whether the extern variables set by tzset() need to
595 * set as a result of a call to localtime_r()
597 * Currently, the spec only mentions that tzname[] doesn't
598 * need to be set. As soon as it becomes unequivocal
599 * that the external zone state doesn't need to be asserted
600 * for this call, and it really doesn't make much sense
601 * to set common state from multi-threaded calls made to this
602 * function, locking can be dispensed with here.
604 * local zone state would still need to be aquired for the
605 * time in question in order for calculations elicited here
606 * to be correct, but that state wouldn't need to be shared,
607 * thus no multi-threaded synchronization would be required.
609 * It would be nice if POSIX would approve an ltzset_r()
610 * function, but if not, it wouldn't stop us from making one
613 * localtime_r() can now return NULL if overflow is detected.
614 * offtime_u() is the function that detects overflow, and sets
615 * errno appropriately. We unlock before the call to offtime_u(),
616 * so that lmutex_unlock() does not reassign errno. The function
617 * offtime_u() is MT-safe and does not have to be locked. Use
618 * my_is_in_dst to reference local copy of is_in_dst outside locks.
623 localtime_r(const time_t *timep
, struct tm
*p_tm
)
630 lmutex_lock(&_time_lock
);
631 unused
= ltzset_u(*timep
);
632 if (lclzonep
== NULL
) {
633 lmutex_unlock(&_time_lock
);
636 return (offtime_u(*timep
, 0L, p_tm
));
638 my_is_in_dst
= is_in_dst
;
639 offset
= (my_is_in_dst
) ? -altzone
: -timezone
;
640 lmutex_unlock(&_time_lock
);
643 rt
= offtime_u(*timep
, offset
, p_tm
);
644 p_tm
->tm_isdst
= my_is_in_dst
;
649 * Accepts a time_t, returns a tm struct based on it, correcting
650 * for the local timezone. Produces documented side-effects to
651 * extern global timezone state data.
653 * This function is explicitly NOT THREAD-SAFE. The standards
654 * indicate it should provide its results in its own statically
655 * allocated tm struct that gets overwritten. The thread-safe
656 * variant is localtime_r(). We make it mostly thread-safe by
657 * allocating its buffer in thread-specific data.
659 * localtime() can now return NULL if overflow is detected.
660 * offtime_u() is the function that detects overflow, and sets
661 * errno appropriately.
666 localtime(const time_t *timep
)
668 struct tm
*p_tm
= tsdalloc(_T_STRUCT_TM
, sizeof (struct tm
), NULL
);
670 if (p_tm
== NULL
) /* memory allocation failure */
671 p_tm
= &tm
; /* use static buffer and hope for the best */
672 return (localtime_r(timep
, p_tm
));
676 * This function takes a pointer to a tm struct and returns a
677 * normalized time_t, also inducing documented side-effects in
678 * extern global zone state variables. (See mktime(3C)).
681 mktime1(struct tm
*tmptr
, int usetz
)
684 long long t
; /* must hold more than 32-bit time_t */
692 /* mktime leaves errno unchanged if no error is encountered */
694 /* Calculate time_t from tm arg. tm may need to be normalized. */
695 t
= tmptr
->tm_sec
+ SECSPERMIN
* tmptr
->tm_min
+
696 SECSPERHOUR
* tmptr
->tm_hour
+
697 SECSPERDAY
* (tmptr
->tm_mday
- 1);
699 if (tmptr
->tm_mon
>= 12) {
700 tmptr
->tm_year
+= tmptr
->tm_mon
/ 12;
702 } else if (tmptr
->tm_mon
< 0) {
703 temp
= -tmptr
->tm_mon
;
704 tmptr
->tm_mon
= 0; /* If tm_mon divides by 12. */
705 tmptr
->tm_year
-= (temp
/ 12);
706 if (temp
%= 12) { /* Remainder... */
708 tmptr
->tm_mon
= 12 - temp
;
712 lmutex_lock(&_time_lock
);
714 /* Avoid numerous calculations embedded in macro if possible */
715 if (!year_is_cached
|| (cached_year
!= tmptr
->tm_year
)) {
716 cached_year
= tmptr
->tm_year
;
717 year_is_cached
= TRUE
;
718 /* For boundry values of tm_year, typecasting required */
719 cached_secs_since_1970
=
720 (long long)SECSPERDAY
* DAYS_SINCE_70(cached_year
);
722 t
+= cached_secs_since_1970
;
724 if (isleap(tmptr
->tm_year
+ TM_YEAR_BASE
))
725 t
+= SECSPERDAY
* __lyday_to_month
[tmptr
->tm_mon
];
727 t
+= SECSPERDAY
* __yday_to_month
[tmptr
->tm_mon
];
732 * If called from mktime(), then we need to do the TZ
733 * related transformations.
736 unused
= ltzset_u((time_t)t
);
738 /* Attempt to convert time to GMT based on tm_isdst setting */
739 t
+= (tmptr
->tm_isdst
> 0) ? altzone
: timezone
;
742 overflow
= t
> LONG_MAX
|| t
< LONG_MIN
||
743 tmptr
->tm_year
< 1 || tmptr
->tm_year
> 138;
745 overflow
= t
> LONG_MAX
|| t
< LONG_MIN
;
747 set_zone_context((time_t)t
);
748 if (tmptr
->tm_isdst
< 0) {
749 long dst_delta
= timezone
- altzone
;
750 switch (curr_zonerules
) {
754 set_zone_context((time_t)t
);
756 (void) offtime_u((time_t)t
,
760 (void) offtime_u((time_t)t
,
764 (void) offtime_u((time_t)t
, -timezone
,
772 set_zone_context((time_t)t
);
774 (void) offtime_u((time_t)t
,
778 (void) offtime_u((time_t)t
,
783 * check for ambiguous
784 * 'fallback' transition
786 set_zone_context((time_t)t
- dst_delta
);
788 /* In fallback, force DST */
790 (void) offtime_u((time_t)t
,
794 (void) offtime_u((time_t)t
,
800 case ZONERULES_INVALID
:
801 (void) offtime_u((time_t)t
, 0L, &_tm
);
805 } else if (is_in_dst
) {
806 (void) offtime_u((time_t)t
, -altzone
, &_tm
);
809 (void) offtime_u((time_t)t
, -timezone
, &_tm
);
812 } else { /* !usetz, i.e. using UTC */
814 /* Normalize the TM structure */
815 (void) offtime_u((time_t)t
, 0, &_tm
);
818 if (overflow
|| t
> LONG_MAX
|| t
< LONG_MIN
) {
819 mketimerrno
= EOVERFLOW
;
825 lmutex_unlock(&_time_lock
);
834 mktime(struct tm
*tmptr
)
836 return (mktime1(tmptr
, TRUE
));
840 timegm(struct tm
*tmptr
)
842 return (mktime1(tmptr
, FALSE
));
847 * Sets extern global zone state variables based on the current
848 * time. Specifically, tzname[], timezone, altzone, and daylight
849 * are updated. See ctime(3C) manpage.
856 lmutex_lock(&_time_lock
);
857 unused
= ltzset_u(time(NULL
));
858 lmutex_unlock(&_time_lock
);
868 lmutex_lock(&_time_lock
);
869 unused
= ltzset_u(tim
);
870 lmutex_unlock(&_time_lock
);
876 * Loads local zone information if TZ changed since last time zone
877 * information was loaded, or if this is the first time thru.
878 * We already hold _time_lock; no further locking is required.
879 * Return a memory block which can be free'd at safe place.
884 const char *zonename
;
885 state_t
*entry
, *new_entry
;
886 const char *newtzname
[2];
893 if ((zonename
= getsystemTZ()) == NULL
|| *zonename
== '\0')
894 zonename
= _posix_gmt0
;
896 if (namecache
!= NULL
&& strcmp(namecache
, zonename
) == 0) {
901 entry
= find_zone(zonename
);
904 * We need to release _time_lock to call out malloc().
905 * We can release _time_lock as far as global variables
906 * can remain consistent. Here, we haven't touch any
907 * variables, so it's okay to release lock.
909 lmutex_unlock(&_time_lock
);
910 new_entry
= malloc(sizeof (state_t
));
911 lmutex_lock(&_time_lock
);
914 * check it again, since zone may have been loaded while
915 * time_lock was unlocked.
917 entry
= find_zone(zonename
);
924 * We are here because the 1st attemp failed.
925 * new_entry points newly allocated entry. If it was NULL, it
926 * indicates that the memory allocation also failed.
930 * 2nd attemp also failed.
931 * No timezone entry found in hash table, so load it,
932 * and create a new timezone entry.
934 char *newzonename
, *charsbuf
;
936 newzonename
= libc_strdup(zonename
);
940 if (entry
== NULL
|| newzonename
== NULL
) {
941 /* something wrong happened. */
943 if (newzonename
!= NULL
)
944 libc_free(newzonename
);
946 /* Invalidate the current timezone */
947 curr_zonerules
= ZONERULES_INVALID
;
950 timezone
= altzone
= 0;
952 newtzname
[0] = (char *)_tz_gmt
;
953 newtzname
[1] = (char *)_tz_spaces
;
954 set_tzname(newtzname
);
959 * Builds transition cache and sets up zone state data for zone
960 * specified in TZ, which can be specified as a POSIX zone or an
961 * Olson zoneinfo file reference.
963 * If local data cannot be parsed or loaded, the local zone
964 * tables are set up for GMT.
966 * Unless a leading ':' is prepended to TZ, TZ is initially
967 * parsed as a POSIX zone; failing that, it reverts to
969 * However, if a ':' is prepended, the zone will *only* be
970 * parsed as zoneinfo. If any failure occurs parsing or
971 * loading a zoneinfo TZ, GMT data is loaded for the local zone.
973 * Example: There is a zoneinfo file in the standard
974 * distribution called 'PST8PDT'. The only way the user can
975 * specify that file under Solaris is to set TZ to ":PST8PDT".
976 * Otherwise the initial parse of PST8PDT as a POSIX zone will
977 * succeed and be used.
979 if ((charsbuf
= libc_malloc(TZ_MAX_CHARS
)) == NULL
)
982 entry
->zonerules
= ZONERULES_INVALID
;
983 entry
->charsbuf_size
= TZ_MAX_CHARS
;
984 entry
->chars
= charsbuf
;
985 entry
->default_tzname0
= _tz_gmt
;
986 entry
->default_tzname1
= _tz_spaces
;
987 entry
->zonename
= newzonename
;
989 if (*zonename
== ':') {
990 if (load_zoneinfo(zonename
+ 1, entry
) != 0) {
991 (void) load_posixinfo(_posix_gmt0
, entry
);
993 } else if (load_posixinfo(zonename
, entry
) != 0) {
994 if (load_zoneinfo(zonename
, entry
) != 0) {
995 (void) load_posixinfo(_posix_gmt0
, entry
);
998 entry
->last_ats_idx
= -1;
1001 * The pre-allocated buffer is used; reset the free flag
1002 * so the buffer won't be freed.
1009 curr_zonerules
= entry
->zonerules
;
1010 namecache
= entry
->zonename
;
1011 daylight
= entry
->daylight
;
1014 set_zone_context(t
);
1017 * We shouldn't release lock beyond this point since lclzonep
1018 * can refer to invalid address if cache is invalidated.
1019 * We defer the call to free till it can be done safely.
1025 * Sets timezone, altzone, tzname[], extern globals, to represent
1026 * disposition of t with respect to TZ; See ctime(3C). is_in_dst,
1027 * internal global is also set. daylight is set at zone load time.
1031 * In this function, any time_t not located in the cache is handled
1032 * as a miss. To build/update transition cache, load_zoneinfo()
1033 * must be called prior to this routine.
1035 * If POSIX zone, cache miss penalty is slightly degraded
1036 * performance. For zoneinfo, penalty is decreased is_in_dst
1039 * POSIX, despite its chicken/egg problem, ie. not knowing DST
1040 * until time known, and not knowing time until DST known, at
1041 * least uses the same algorithm for 64-bit time as 32-bit.
1043 * The fact that zoneinfo files only contain transistions for 32-bit
1044 * time space is a well known problem, as yet unresolved.
1045 * Without an official standard for coping with out-of-range
1046 * zoneinfo times, assumptions must be made. For now
1047 * the assumption is: If t exceeds 32-bit boundries and local zone
1048 * is zoneinfo type, is_in_dst is set to to 0 for negative values
1049 * of t, and set to the same DST state as the highest ordered
1050 * transition in cache for positive values of t.
1053 set_zone_default_context(void)
1055 const char *newtzname
[2];
1057 /* Retrieve suitable defaults for this zone */
1058 altzone
= lclzonep
->default_altzone
;
1059 timezone
= lclzonep
->default_timezone
;
1060 newtzname
[0] = (char *)lclzonep
->default_tzname0
;
1061 newtzname
[1] = (char *)lclzonep
->default_tzname1
;
1064 set_tzname(newtzname
);
1068 set_zone_context(time_t t
)
1071 int lo
, hi
, tidx
, lidx
;
1072 ttinfo_t
*ttisp
, *std
, *alt
;
1073 const char *newtzname
[2];
1075 /* If state data not loaded or TZ busted, just use GMT */
1076 if (lclzonep
== NULL
|| curr_zonerules
== ZONERULES_INVALID
) {
1077 timezone
= altzone
= 0;
1078 daylight
= is_in_dst
= 0;
1079 newtzname
[0] = (char *)_tz_gmt
;
1080 newtzname
[1] = (char *)_tz_spaces
;
1081 set_tzname(newtzname
);
1085 if (lclzonep
->timecnt
<= 0 || lclzonep
->typecnt
< 2) {
1086 /* Loaded zone incapable of transitioning. */
1087 set_zone_default_context();
1092 * At least one alt. zone and one transistion exist. Locate
1093 * state for 't' quickly as possible. Use defaults as necessary.
1096 hi
= lclzonep
->timecnt
- 1;
1098 if (t
< lclzonep
->ats
[0] || t
>= lclzonep
->ats
[hi
]) {
1100 * Date which is out of definition.
1101 * Calculate DST as best as possible
1103 if (lclzonep
->zonerules
== POSIX_USA
||
1104 lclzonep
->zonerules
== POSIX
) {
1105 /* Must invoke calculations to determine DST */
1106 set_zone_default_context();
1107 is_in_dst
= (daylight
) ?
1108 posix_check_dst(t
, lclzonep
) : 0;
1110 } else if (t
< lclzonep
->ats
[0]) { /* zoneinfo... */
1111 /* t precedes 1st transition. Use defaults */
1112 set_zone_default_context();
1114 } else { /* zoneinfo */
1115 /* t follows final transistion. Use final */
1119 if ((lidx
= lclzonep
->last_ats_idx
) != -1 &&
1121 t
>= lclzonep
->ats
[lidx
] &&
1122 t
< lclzonep
->ats
[lidx
+ 1]) {
1123 /* CACHE HIT. Nothing needs to be done */
1127 * CACHE MISS. Locate transition using binary search.
1130 tidx
= (lo
+ hi
) / 2;
1131 if (t
== lclzonep
->ats
[tidx
])
1133 else if (t
< lclzonep
->ats
[tidx
])
1144 * Set extern globals based on located transition and summary of
1145 * its previous state, which were cached when zone was loaded
1147 ttisp
= &lclzonep
->ttis
[lclzonep
->types
[tidx
]];
1148 prevp
= &lclzonep
->prev
[tidx
];
1150 if ((is_in_dst
= ttisp
->tt_isdst
) == 0) { /* std. time */
1151 timezone
= -ttisp
->tt_gmtoff
;
1152 newtzname
[0] = &lclzonep
->chars
[ttisp
->tt_abbrind
];
1153 if ((alt
= prevp
->alt
) != NULL
) {
1154 altzone
= -alt
->tt_gmtoff
;
1155 newtzname
[1] = &lclzonep
->chars
[alt
->tt_abbrind
];
1157 altzone
= lclzonep
->default_altzone
;
1158 newtzname
[1] = (char *)lclzonep
->default_tzname1
;
1160 } else { /* alt. time */
1161 altzone
= -ttisp
->tt_gmtoff
;
1162 newtzname
[1] = &lclzonep
->chars
[ttisp
->tt_abbrind
];
1163 if ((std
= prevp
->std
) != NULL
) {
1164 timezone
= -std
->tt_gmtoff
;
1165 newtzname
[0] = &lclzonep
->chars
[std
->tt_abbrind
];
1167 timezone
= lclzonep
->default_timezone
;
1168 newtzname
[0] = (char *)lclzonep
->default_tzname0
;
1172 lclzonep
->last_ats_idx
= tidx
;
1173 set_tzname(newtzname
);
1177 * This function takes a time_t and gmt offset and produces a
1178 * tm struct based on specified time.
1180 * The the following fields are calculated, based entirely
1181 * on the offset-adjusted value of t:
1183 * tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec
1184 * tm_yday. tm_wday. (tm_isdst is ALWAYS set to 0).
1188 offtime_u(time_t t
, long offset
, struct tm
*tmptr
)
1196 days
= t
/ SECSPERDAY
;
1197 rem
= t
% SECSPERDAY
;
1203 while (rem
>= SECSPERDAY
) {
1207 tmptr
->tm_hour
= (int)(rem
/ SECSPERHOUR
);
1208 rem
= rem
% SECSPERHOUR
;
1209 tmptr
->tm_min
= (int)(rem
/ SECSPERMIN
);
1210 tmptr
->tm_sec
= (int)(rem
% SECSPERMIN
);
1212 tmptr
->tm_wday
= (int)((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
1213 if (tmptr
->tm_wday
< 0)
1214 tmptr
->tm_wday
+= DAYSPERWEEK
;
1216 while (days
< 0 || days
>= (long)__year_lengths
[yleap
= isleap(y
)]) {
1219 newy
= y
+ days
/ DAYSPERNYEAR
;
1222 days
-= ((long)newy
- (long)y
) * DAYSPERNYEAR
+
1223 LEAPS_THRU_END_OF(newy
> 0 ? newy
- 1L : newy
) -
1224 LEAPS_THRU_END_OF(y
> 0 ? y
- 1L : y
);
1227 tmptr
->tm_year
= (int)(y
- TM_YEAR_BASE
);
1228 tmptr
->tm_yday
= (int)days
;
1229 ip
= __mon_lengths
[yleap
];
1230 for (tmptr
->tm_mon
= 0; days
>=
1231 (long)ip
[tmptr
->tm_mon
]; ++(tmptr
->tm_mon
)) {
1232 days
= days
- (long)ip
[tmptr
->tm_mon
];
1234 tmptr
->tm_mday
= (int)(days
+ 1);
1235 tmptr
->tm_isdst
= 0;
1238 /* do as much as possible before checking for error. */
1239 if ((y
> (long)INT_MAX
+ TM_YEAR_BASE
) ||
1240 (y
< (long)INT_MIN
+ TM_YEAR_BASE
)) {
1249 * Check whether DST is set for time in question. Only applies to
1250 * POSIX timezones. If explicit POSIX transition rules were provided
1251 * for the current zone, use those, otherwise use default USA POSIX
1255 posix_check_dst(long long t
, state_t
*sp
)
1259 int year
, i
, idx
, ridx
;
1260 posix_daylight_t pdaylight
;
1262 (void) offtime_u(t
, 0L, &gmttm
);
1264 year
= gmttm
.tm_year
+ 1900;
1265 jan01
= t
- ((gmttm
.tm_yday
* SECSPERDAY
) +
1266 (gmttm
.tm_hour
* SECSPERHOUR
) +
1267 (gmttm
.tm_min
* SECSPERMIN
) + gmttm
.tm_sec
);
1269 * If transition rules were provided for this zone,
1270 * use them, otherwise, default to USA daylight rules,
1271 * which are historically correct for the continental USA,
1272 * excluding local provisions. (This logic may be replaced
1273 * at some point in the future with "posixrules" to offer
1274 * more flexibility to the system administrator).
1276 if (sp
->zonerules
== POSIX
) { /* POSIX rules */
1277 pdaylight
.rules
[0] = &sp
->start_rule
;
1278 pdaylight
.rules
[1] = &sp
->end_rule
;
1279 } else { /* POSIX_USA: USA */
1281 while (year
< __usa_rules
[i
].s_year
&& i
< MAX_RULE_TABLE
) {
1284 pdaylight
.rules
[0] = (rule_t
*)&__usa_rules
[i
].start
;
1285 pdaylight
.rules
[1] = (rule_t
*)&__usa_rules
[i
].end
;
1287 pdaylight
.offset
[0] = timezone
;
1288 pdaylight
.offset
[1] = altzone
;
1290 idx
= posix_daylight(&jan01
, year
, &pdaylight
);
1294 * Note: t, rtime[0], and rtime[1] are all bounded within 'year'
1295 * beginning on 'jan01'
1297 if (t
>= pdaylight
.rtime
[idx
] && t
< pdaylight
.rtime
[ridx
]) {
1305 * Given January 1, 00:00:00 GMT for a year as an Epoch-relative time,
1306 * along with the integer year #, a posix_daylight_t that is composed
1307 * of two rules, and two GMT offsets (timezone and altzone), calculate
1308 * the two Epoch-relative times the two rules take effect, and return
1309 * them in the two rtime fields of the posix_daylight_t structure.
1310 * Also update janfirst by a year, by adding the appropriate number of
1311 * seconds depending on whether the year is a leap year or not. (We take
1312 * advantage that this routine knows the leap year status.)
1315 posix_daylight(long long *janfirst
, int year
, posix_daylight_t
*pdaylightp
)
1320 int i
, d
, m1
, yy0
, yy1
, yy2
, dow
;
1324 static const int __secs_year_lengths
[2] = {
1325 DAYS_PER_NYEAR
* SECSPERDAY
,
1326 DAYS_PER_LYEAR
* SECSPERDAY
1329 leapyear
= isleap(year
);
1331 for (idx
= 0; idx
< 2; idx
++) {
1332 rulep
= pdaylightp
->rules
[idx
];
1333 offset
= pdaylightp
->offset
[idx
];
1335 switch (rulep
->r_type
) {
1339 * Mm.n.d - nth "dth day" of month m.
1342 for (i
= 0; i
< rulep
->r_mon
- 1; ++i
)
1343 value
+= __mon_lengths
[leapyear
][i
] *
1347 * Use Zeller's Congruence to get day-of-week of first
1350 m1
= (rulep
->r_mon
+ 9) % 12 + 1;
1351 yy0
= (rulep
->r_mon
<= 2) ? (year
- 1) : year
;
1354 dow
= ((26 * m1
- 2) / 10 +
1355 1 + yy2
+ yy2
/ 4 + yy1
/ 4 - 2 * yy1
) % 7;
1361 * Following heuristic increases accuracy of USA rules
1362 * for negative years.
1364 if (year
< 1 && leapyear
)
1367 * "dow" is the day-of-week of the first day of the
1368 * month. Get the day-of-month, zero-origin, of the
1369 * first "dow" day of the month.
1371 d
= rulep
->r_day
- dow
;
1374 for (i
= 1; i
< rulep
->r_week
; ++i
) {
1375 if (d
+ DAYSPERWEEK
>=
1376 __mon_lengths
[leapyear
][rulep
->r_mon
- 1])
1381 * "d" is the day-of-month, zero-origin, of the day
1384 value
+= d
* SECSPERDAY
;
1389 * Jn - Julian day, 1 == Jan 1, 60 == March 1 even
1392 value
= *janfirst
+ (rulep
->r_day
- 1) * SECSPERDAY
;
1393 if (leapyear
&& rulep
->r_day
>= 60)
1394 value
+= SECSPERDAY
;
1401 value
= *janfirst
+ rulep
->r_day
* SECSPERDAY
;
1404 pdaylightp
->rtime
[idx
] = value
+ rulep
->r_time
+ offset
;
1406 *janfirst
+= __secs_year_lengths
[leapyear
];
1408 return ((pdaylightp
->rtime
[0] > pdaylightp
->rtime
[1]) ? 1 : 0);
1412 * Try to load zoneinfo file into internal transition tables using name
1413 * indicated in TZ, and do validity checks. The format of zic(1M)
1414 * compiled zoneinfo files isdescribed in tzfile.h
1417 load_zoneinfo(const char *name
, state_t
*sp
)
1432 struct tzhead
*tzhp
;
1433 struct stat64 stbuf
;
1434 ttinfo_t
*most_recent_alt
= NULL
;
1435 ttinfo_t
*most_recent_std
= NULL
;
1439 if (name
== NULL
&& (name
= TZDEFAULT
) == NULL
)
1442 if ((name
[0] == '/') || strstr(name
, "../"))
1446 * We allocate fullname this way to avoid having
1447 * a PATH_MAX size buffer in our stack frame.
1449 namelen
= LEN_TZDIR
+ 1 + strlen(name
) + 1;
1450 if ((fullname
= lmalloc(namelen
)) == NULL
)
1452 (void) strcpy(fullname
, TZDIR
"/");
1453 (void) strcpy(fullname
+ LEN_TZDIR
+ 1, name
);
1454 if ((fid
= open(fullname
, O_RDONLY
)) == -1) {
1455 lfree(fullname
, namelen
);
1458 lfree(fullname
, namelen
);
1460 if (fstat64(fid
, &stbuf
) == -1) {
1465 flen
= (size_t)stbuf
.st_size
;
1466 if (flen
< sizeof (struct tzhead
)) {
1472 * It would be nice to use alloca() to allocate bufp but,
1473 * as above, we wish to avoid allocating a big buffer in
1474 * our stack frame, and also because alloca() gives us no
1475 * opportunity to fail gracefully on allocation failure.
1477 cp
= bufp
= lmalloc(flen
);
1483 if ((cnt
= read(fid
, bufp
, flen
)) != flen
) {
1489 if (close(fid
) != 0) {
1494 cp
+= (sizeof (tzhp
->tzh_magic
)) + (sizeof (tzhp
->tzh_reserved
));
1496 /* LINTED: alignment */
1497 ttisstdcnt
= CVTZCODE(cp
);
1498 /* LINTED: alignment */
1499 ttisgmtcnt
= CVTZCODE(cp
);
1500 /* LINTED: alignment */
1501 sp
->leapcnt
= CVTZCODE(cp
);
1502 /* LINTED: alignment */
1503 sp
->timecnt
= CVTZCODE(cp
);
1504 /* LINTED: alignment */
1505 sp
->typecnt
= CVTZCODE(cp
);
1506 /* LINTED: alignment */
1507 sp
->charcnt
= CVTZCODE(cp
);
1509 if (sp
->leapcnt
< 0 || sp
->leapcnt
> TZ_MAX_LEAPS
||
1510 sp
->typecnt
<= 0 || sp
->typecnt
> TZ_MAX_TYPES
||
1511 sp
->timecnt
< 0 || sp
->timecnt
> TZ_MAX_TIMES
||
1512 sp
->charcnt
< 0 || sp
->charcnt
> TZ_MAX_CHARS
||
1513 (ttisstdcnt
!= sp
->typecnt
&& ttisstdcnt
!= 0) ||
1514 (ttisgmtcnt
!= sp
->typecnt
&& ttisgmtcnt
!= 0)) {
1519 if (cnt
- (cp
- bufp
) < (long)(sp
->timecnt
* 4 + /* ats */
1520 sp
->timecnt
+ /* types */
1521 sp
->typecnt
* (4 + 2) + /* ttinfos */
1522 sp
->charcnt
+ /* chars */
1523 sp
->leapcnt
* (4 + 4) + /* lsinfos */
1524 ttisstdcnt
+ /* ttisstds */
1525 ttisgmtcnt
)) { /* ttisgmts */
1531 for (i
= 0; i
< sp
->timecnt
; ++i
) {
1532 /* LINTED: alignment */
1533 sp
->ats
[i
] = CVTZCODE(cp
);
1537 * Skip over types[] for now and load ttis[] so that when
1538 * types[] are loaded we can check for transitions to STD & DST.
1539 * This allows us to shave cycles in ltzset_u(), including
1540 * eliminating the need to check set 'daylight' later.
1543 cp2
= (char *)((uintptr_t)cp
+ sp
->timecnt
);
1545 for (i
= 0; i
< sp
->typecnt
; ++i
) {
1546 ttisp
= &sp
->ttis
[i
];
1547 /* LINTED: alignment */
1548 ttisp
->tt_gmtoff
= CVTZCODE(cp2
);
1549 ttisp
->tt_isdst
= (uchar_t
)*cp2
++;
1551 if (ttisp
->tt_isdst
!= 0 && ttisp
->tt_isdst
!= 1) {
1556 ttisp
->tt_abbrind
= (uchar_t
)*cp2
++;
1557 if (ttisp
->tt_abbrind
< 0 ||
1558 ttisp
->tt_abbrind
> sp
->charcnt
) {
1565 * Since ttis were loaded ahead of types, it is possible to
1566 * detect whether daylight is ever set for this zone now, and
1567 * also preload other information to avoid repeated lookups later.
1568 * This logic facilitates keeping a running tab on the state of
1569 * std zone and alternate zone transitions such that timezone,
1570 * altzone and tzname[] can be determined quickly via an
1571 * index to any transition.
1573 * For transition #0 there are no previous transitions,
1574 * so prev->std and prev->alt will be null, but that's OK,
1575 * because null prev->std/prev->alt effectively
1576 * indicates none existed prior.
1579 prevp
= &sp
->prev
[0];
1581 for (i
= 0; i
< sp
->timecnt
; ++i
) {
1583 sp
->types
[i
] = (uchar_t
)*cp
++;
1584 ttisp
= &sp
->ttis
[sp
->types
[i
]];
1586 prevp
->std
= most_recent_std
;
1587 prevp
->alt
= most_recent_alt
;
1589 if (ttisp
->tt_isdst
== 1) {
1590 most_recent_alt
= ttisp
;
1592 most_recent_std
= ttisp
;
1595 if ((int)sp
->types
[i
] >= sp
->typecnt
) {
1602 if (most_recent_alt
== NULL
)
1608 * Set pointer ahead to where it would have been if we
1609 * had read types[] and ttis[] in the same order they
1610 * occurred in the file.
1613 for (i
= 0; i
< sp
->charcnt
; ++i
)
1614 sp
->chars
[i
] = *cp
++;
1616 sp
->chars
[i
] = '\0'; /* ensure '\0' at end */
1618 for (i
= 0; i
< sp
->leapcnt
; ++i
) {
1619 struct lsinfo
*lsisp
;
1621 lsisp
= &sp
->lsis
[i
];
1622 /* LINTED: alignment */
1623 lsisp
->ls_trans
= CVTZCODE(cp
);
1624 /* LINTED: alignment */
1625 lsisp
->ls_corr
= CVTZCODE(cp
);
1628 for (i
= 0; i
< sp
->typecnt
; ++i
) {
1629 ttisp
= &sp
->ttis
[i
];
1630 if (ttisstdcnt
== 0) {
1631 ttisp
->tt_ttisstd
= FALSE
;
1633 ttisp
->tt_ttisstd
= *cp
++;
1634 if (ttisp
->tt_ttisstd
!= TRUE
&&
1635 ttisp
->tt_ttisstd
!= FALSE
) {
1642 for (i
= 0; i
< sp
->typecnt
; ++i
) {
1643 ttisp
= &sp
->ttis
[i
];
1644 if (ttisgmtcnt
== 0) {
1645 ttisp
->tt_ttisgmt
= FALSE
;
1647 ttisp
->tt_ttisgmt
= *cp
++;
1648 if (ttisp
->tt_ttisgmt
!= TRUE
&&
1649 ttisp
->tt_ttisgmt
!= FALSE
) {
1657 * Other defaults set at beginning of this routine
1658 * to cover case where zoneinfo file cannot be loaded
1660 sp
->default_timezone
= -sp
->ttis
[0].tt_gmtoff
;
1661 sp
->default_altzone
= 0;
1662 sp
->default_tzname0
= &sp
->chars
[0];
1663 sp
->default_tzname1
= _tz_spaces
;
1667 sp
->zonerules
= ZONEINFO
;
1674 print_state(state_t
*sp
)
1679 (void) fprintf(stderr
, "=========================================\n");
1680 (void) fprintf(stderr
, "zonename: \"%s\"\n", sp
->zonename
);
1681 (void) fprintf(stderr
, "next: 0x%p\n", (void *)sp
->next
);
1682 (void) fprintf(stderr
, "zonerules: %s\n",
1683 sp
->zonerules
== ZONERULES_INVALID
? "ZONERULES_INVALID" :
1684 sp
->zonerules
== POSIX
? "POSIX" :
1685 sp
->zonerules
== POSIX_USA
? "POSIX_USA" :
1686 sp
->zonerules
== ZONEINFO
? "ZONEINFO" : "UNKNOWN");
1687 (void) fprintf(stderr
, "daylight: %d\n", sp
->daylight
);
1688 (void) fprintf(stderr
, "default_timezone: %ld\n", sp
->default_timezone
);
1689 (void) fprintf(stderr
, "default_altzone: %ld\n", sp
->default_altzone
);
1690 (void) fprintf(stderr
, "default_tzname0: \"%s\"\n",
1691 sp
->default_tzname0
);
1692 (void) fprintf(stderr
, "default_tzname1: \"%s\"\n",
1693 sp
->default_tzname1
);
1694 (void) fprintf(stderr
, "leapcnt: %d\n", sp
->leapcnt
);
1695 (void) fprintf(stderr
, "timecnt: %d\n", sp
->timecnt
);
1696 (void) fprintf(stderr
, "typecnt: %d\n", sp
->typecnt
);
1697 (void) fprintf(stderr
, "charcnt: %d\n", sp
->charcnt
);
1698 (void) fprintf(stderr
, "chars: \"%s\"\n", sp
->chars
);
1699 (void) fprintf(stderr
, "charsbuf_size: %u\n", sp
->charsbuf_size
);
1700 (void) fprintf(stderr
, "prev: skipping...\n");
1701 (void) fprintf(stderr
, "ats = {\n");
1702 for (c
= 0, i
= 0; i
< sp
->timecnt
; i
++) {
1706 (void) fprintf(stderr
, ", ");
1708 (void) asctime_r(gmtime_r(&sp
->ats
[i
], &tmp
),
1712 (void) fprintf(stderr
, "%s", buf
);
1714 (void) fprintf(stderr
, "\n");
1720 (void) fprintf(stderr
, "}\n");
1721 (void) fprintf(stderr
, "types = {\n");
1722 for (c
= 0, i
= 0; i
< sp
->timecnt
; i
++) {
1724 (void) fprintf(stderr
, "\t");
1726 (void) fprintf(stderr
, ", ");
1728 (void) fprintf(stderr
, "%d", sp
->types
[i
]);
1730 (void) fprintf(stderr
, "\n");
1736 (void) fprintf(stderr
, "}\n");
1737 (void) fprintf(stderr
, "ttis = {\n");
1738 for (i
= 0; i
< sp
->typecnt
; i
++) {
1739 (void) fprintf(stderr
, "\t{\n");
1740 (void) fprintf(stderr
, "\t\ttt_gmtoff: %ld\n",
1741 sp
->ttis
[i
].tt_gmtoff
);
1742 (void) fprintf(stderr
, "\t\ttt_ttisdst: %d\n",
1743 sp
->ttis
[i
].tt_isdst
);
1744 (void) fprintf(stderr
, "\t\ttt_abbrind: %d\n",
1745 sp
->ttis
[i
].tt_abbrind
);
1746 (void) fprintf(stderr
, "\t\ttt_tt_isstd: %d\n",
1747 sp
->ttis
[i
].tt_ttisstd
);
1748 (void) fprintf(stderr
, "\t\ttt_ttisgmt: %d\n",
1749 sp
->ttis
[i
].tt_ttisgmt
);
1750 (void) fprintf(stderr
, "\t}\n");
1752 (void) fprintf(stderr
, "}\n");
1757 * Given a POSIX section 8-style TZ string, fill in transition tables.
1762 * Timecnt set to 0 and typecnt set to 1, reflecting std time only.
1764 * TZ = PST8PDT or PST8PDT7
1765 * Create transition times by applying USA transitions from
1766 * Jan 1 of each year covering 1902-2038. POSIX offsets
1767 * as specified in the TZ are used to calculate the tt_gmtoff
1768 * for each of the two zones. If ommitted, DST defaults to
1769 * std. time minus one hour.
1771 * TZ = <PST8>8PDT or <PST8>8<PDT9>
1772 * Quoted transition. The values in angled brackets are treated
1773 * as zone name text, not parsed as offsets. The offsets
1774 * occuring following the zonename section. In this way,
1775 * instead of PST being displayed for standard time, it could
1776 * be displayed as PST8 to give an indication of the offset
1777 * of that zone to GMT.
1779 * TZ = GMT0BST, M3.5.0/1, M10.5.0/2 or GMT0BST, J23953, J23989
1780 * Create transition times based on the application new-year
1781 * relative POSIX transitions, parsed from TZ, from Jan 1
1782 * for each year covering 1902-2038. POSIX offsets specified
1783 * in TZ are used to calculate tt_gmtoff for each of the two
1788 load_posixinfo(const char *name
, state_t
*sp
)
1790 const char *stdname
;
1791 const char *dstname
= 0;
1801 zone_rules_t zonetype
;
1804 zonetype
= POSIX_USA
;
1807 if ((quoted
= (*stdname
== '<')) != 0)
1810 /* Parse/extract STD zone name, len and GMT offset */
1811 if (*name
!= '\0') {
1812 if ((name
= getzname(name
, quoted
)) == NULL
)
1814 stdlen
= name
- stdname
;
1817 if (*name
== '\0' || stdlen
< 1) {
1820 if ((name
= getoffset(name
, &stdoff
)) == NULL
)
1825 /* If DST specified in TZ, extract DST zone details */
1826 if (*name
!= '\0') {
1829 if ((quoted
= (*dstname
== '<')) != 0)
1831 if ((name
= getzname(name
, quoted
)) == NULL
)
1833 dstlen
= name
- dstname
;
1838 if (*name
!= '\0' && *name
!= ',' && *name
!= ';') {
1839 if ((name
= getoffset(name
, &dstoff
)) == NULL
)
1842 dstoff
= stdoff
- SECSPERHOUR
;
1845 if (*name
!= ',' && *name
!= ';') {
1846 /* no transtition specified; using default rule */
1847 if (load_zoneinfo(TZDEFRULES
, sp
) == 0 &&
1848 sp
->daylight
== 1) {
1849 /* loading TZDEFRULES zoneinfo succeeded */
1850 adjust_posix_default(sp
, stdoff
, dstoff
);
1852 /* loading TZDEFRULES zoneinfo failed */
1853 load_posix_transitions(sp
, stdoff
, dstoff
,
1857 /* extract POSIX transitions from TZ */
1858 /* Backward compatibility using ';' separator */
1859 int compat_flag
= (*name
== ';');
1861 if ((name
= getrule(name
, &sp
->start_rule
, compat_flag
))
1866 if ((name
= getrule(name
, &sp
->end_rule
, compat_flag
))
1872 load_posix_transitions(sp
, stdoff
, dstoff
, zonetype
);
1876 } else { /* DST wasn't specified in POSIX TZ */
1878 /* Since we only have STD time, there are no transitions */
1884 std
->tt_gmtoff
= -stdoff
;
1888 /* Setup zone name character data for state table */
1889 sp
->charcnt
= (int)(stdlen
+ 1);
1891 sp
->charcnt
+= dstlen
+ 1;
1893 /* If bigger than zone name abbv. buffer, grow it */
1894 if ((size_t)sp
->charcnt
> sp
->charsbuf_size
) {
1895 if ((cp
= libc_realloc(sp
->chars
, sp
->charcnt
)) == NULL
)
1898 sp
->charsbuf_size
= sp
->charcnt
;
1902 * Copy zone name text null-terminatedly into state table.
1903 * By doing the copy once during zone loading, setting
1904 * tzname[] subsequently merely involves setting pointer
1906 * If either or both std. or alt. zone name < 3 chars,
1907 * space pad the deficient name(s) to right.
1910 std
->tt_abbrind
= 0;
1912 (void) strncpy(cp
, stdname
, stdlen
);
1917 i
= (int)(stdlen
+ 1);
1919 dst
->tt_abbrind
= i
;
1921 (void) strncpy(cp
, dstname
, dstlen
);
1927 /* Save default values */
1928 if (sp
->typecnt
== 1) {
1929 sp
->default_timezone
= stdoff
;
1930 sp
->default_altzone
= stdoff
;
1931 sp
->default_tzname0
= &sp
->chars
[0];
1932 sp
->default_tzname1
= _tz_spaces
;
1934 sp
->default_timezone
= -std
->tt_gmtoff
;
1935 sp
->default_altzone
= -dst
->tt_gmtoff
;
1936 sp
->default_tzname0
= &sp
->chars
[std
->tt_abbrind
];
1937 sp
->default_tzname1
= &sp
->chars
[dst
->tt_abbrind
];
1940 sp
->zonerules
= zonetype
;
1946 * We loaded the TZDEFAULT which usually the one in US zones. We
1947 * adjust the GMT offset for the zone which has stdoff/dstoff
1951 adjust_posix_default(state_t
*sp
, long stdoff
, long dstoff
)
1953 long zone_stdoff
= 0;
1954 long zone_dstoff
= 0;
1955 int zone_stdoff_flag
= 0;
1956 int zone_dstoff_flag
= 0;
1961 * Initial values of zone_stdoff and zone_dstoff
1963 for (i
= 0; (zone_stdoff_flag
== 0 || zone_dstoff_flag
== 0) &&
1964 i
< sp
->timecnt
; i
++) {
1967 zone
= &sp
->ttis
[sp
->types
[i
]];
1969 if (zone_stdoff_flag
== 0 && zone
->tt_isdst
== 0) {
1970 zone_stdoff
= -zone
->tt_gmtoff
;
1971 zone_stdoff_flag
= 1;
1972 } else if (zone_dstoff_flag
== 0 && zone
->tt_isdst
!= 0) {
1973 zone_dstoff
= -zone
->tt_gmtoff
;
1974 zone_dstoff_flag
= 1;
1977 if (zone_dstoff_flag
== 0)
1978 zone_dstoff
= zone_stdoff
;
1981 * Initially we're assumed to be in standard time.
1985 for (i
= 0; i
< sp
->timecnt
; i
++) {
1989 zone
= &sp
->ttis
[sp
->types
[i
]];
1990 next_isdst
= zone
->tt_isdst
;
1992 sp
->types
[i
] = next_isdst
? 0 : 1;
1994 if (zone
->tt_ttisgmt
== 0) {
1996 * If summer time is in effect, and the transition time
1997 * was not specified as standard time, add the summer
1998 * time offset to the transition time;
1999 * otherwise, add the standard time offset to the
2003 * Transitions from DST to DDST will effectively
2004 * disappear since POSIX provides for only one DST
2007 if (isdst
!= 0 && zone
->tt_ttisstd
== 0)
2008 sp
->ats
[i
] += dstoff
- zone_dstoff
;
2010 sp
->ats
[i
] += stdoff
- zone_stdoff
;
2012 if (next_isdst
!= 0)
2013 zone_dstoff
= -zone
->tt_gmtoff
;
2015 zone_stdoff
= -zone
->tt_gmtoff
;
2019 * Finally, fill in ttis.
2020 * ttisstd and ttisgmt need not be handled.
2022 sp
->ttis
[0].tt_gmtoff
= -dstoff
;
2023 sp
->ttis
[0].tt_isdst
= 1;
2024 sp
->ttis
[1].tt_gmtoff
= -stdoff
;
2025 sp
->ttis
[1].tt_isdst
= 0;
2034 load_posix_transitions(state_t
*sp
, long stdoff
, long dstoff
,
2035 zone_rules_t zonetype
)
2037 ttinfo_t
*std
, *dst
;
2044 posix_daylight_t pdaylight
;
2047 * We know STD and DST zones are specified with this timezone
2048 * therefore the cache will be set up with 2 transitions per
2049 * year transitioning to their respective std and dst zones.
2056 * Insert zone data from POSIX TZ into state table
2057 * The Olson public domain POSIX code sets up ttis[0] to be DST,
2058 * as we are doing here. It seems to be the correct behavior.
2059 * The US/Pacific zoneinfo file also lists DST as first type.
2063 dst
->tt_gmtoff
= -dstoff
;
2067 std
->tt_gmtoff
= -stdoff
;
2070 sp
->prev
[0].std
= NULL
;
2071 sp
->prev
[0].alt
= NULL
;
2073 /* Create transition data based on POSIX TZ */
2075 prevp
= &sp
->prev
[1];
2079 * We only cache from 1902 to 2037 to avoid transistions
2080 * that wrap at the 32-bit boundries, since 1901 and 2038
2081 * are not full years in 32-bit time. The rough edges
2082 * will be handled as transition cache misses.
2085 janfirst
= JAN_01_1902
;
2087 pdaylight
.rules
[0] = &sp
->start_rule
;
2088 pdaylight
.rules
[1] = &sp
->end_rule
;
2089 pdaylight
.offset
[0] = stdoff
;
2090 pdaylight
.offset
[1] = dstoff
;
2092 for (i
= MAX_RULE_TABLE
; i
>= 0; i
--) {
2093 if (zonetype
== POSIX_USA
) {
2094 pdaylight
.rules
[0] = (rule_t
*)&__usa_rules
[i
].start
;
2095 pdaylight
.rules
[1] = (rule_t
*)&__usa_rules
[i
].end
;
2097 for (year
= __usa_rules
[i
].s_year
;
2098 year
<= __usa_rules
[i
].e_year
; year
++) {
2100 idx
= posix_daylight(&janfirst
, year
, &pdaylight
);
2104 * Two transitions per year. Since there are
2105 * only two zone types for this POSIX zone,
2106 * previous std and alt are always set to
2107 * &ttis[0] and &ttis[1].
2109 *tranp
++ = (time_t)pdaylight
.rtime
[idx
];
2115 *tranp
++ = (time_t)pdaylight
.rtime
[ridx
];
2125 * Given a pointer into a time zone string, scan until a character that is not
2126 * a valid character in a zone name is found. Return ptr to that character.
2127 * Return NULL if error (ie. non-printable character located in name)
2130 getzname(const char *strp
, int quoted
)
2135 while ((c
= *strp
) != '\0' && c
!= '>' &&
2136 isgraph((unsigned char)c
)) {
2140 while ((c
= *strp
) != '\0' && isgraph((unsigned char)c
) &&
2141 !isdigit((unsigned char)c
) && c
!= ',' && c
!= '-' &&
2147 /* Found an excessively invalid character. Discredit whole name */
2148 if (c
!= '\0' && !isgraph((unsigned char)c
))
2155 * Given pointer into time zone string, extract first
2156 * number pointed to. Validate number within range specified,
2157 * Return ptr to first char following valid numeric sequence.
2160 getnum(const char *strp
, int *nump
, int min
, int max
)
2165 if (strp
== NULL
|| !isdigit((unsigned char)(c
= *strp
)))
2169 num
= num
* 10 + (c
- '0');
2171 return (NULL
); /* illegal value */
2173 } while (isdigit((unsigned char)c
));
2175 return (NULL
); /* illegal value */
2181 * Given a pointer into a time zone string, extract a number of seconds,
2182 * in hh[:mm[:ss]] form, from the string. If an error occurs, return NULL,
2183 * otherwise, return a pointer to the first character not part of the number
2187 getsecs(const char *strp
, long *secsp
)
2192 * `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
2193 * "M10.4.6/26", which does not conform to Posix,
2194 * but which specifies the equivalent of
2195 * ``02:00 on the first Sunday on or after 23 Oct''.
2197 strp
= getnum(strp
, &num
, 0, HOURSPERDAY
* DAYSPERWEEK
- 1);
2200 *secsp
= num
* (long)SECSPERHOUR
;
2203 strp
= getnum(strp
, &num
, 0, MINSPERHOUR
- 1);
2206 *secsp
+= num
* SECSPERMIN
;
2209 /* `SECSPERMIN' allows for leap seconds. */
2210 strp
= getnum(strp
, &num
, 0, SECSPERMIN
);
2220 * Given a pointer into a time zone string, extract an offset, in
2221 * [+-]hh[:mm[:ss]] form, from the string.
2222 * If any error occurs, return NULL.
2223 * Otherwise, return a pointer to the first character not part of the time.
2226 getoffset(const char *strp
, long *offsetp
)
2233 } else if (*strp
== '+') {
2236 strp
= getsecs(strp
, offsetp
);
2238 return (NULL
); /* illegal time */
2240 *offsetp
= -*offsetp
;
2245 * Given a pointer into a time zone string, extract a rule in the form
2246 * date[/time]. See POSIX section 8 for the format of "date" and "time".
2247 * If a valid rule is not found, return NULL.
2248 * Otherwise, return a pointer to the first character not part of the rule.
2250 * If compat_flag is set, support old 1-based day of year values.
2253 getrule(const char *strp
, rule_t
*rulep
, int compat_flag
)
2255 if (compat_flag
== 0 && *strp
== 'M') {
2259 rulep
->r_type
= MON_WEEK_DOW
;
2261 strp
= getnum(strp
, &rulep
->r_mon
, 1, MONSPERYEAR
);
2266 strp
= getnum(strp
, &rulep
->r_week
, 1, 5);
2271 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERWEEK
- 1);
2272 } else if (compat_flag
== 0 && *strp
== 'J') {
2276 rulep
->r_type
= JULIAN_DAY
;
2278 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERNYEAR
);
2280 } else if (isdigit((unsigned char)*strp
)) {
2284 rulep
->r_type
= DAY_OF_YEAR
;
2285 if (compat_flag
== 0) {
2286 /* zero-based day of year */
2287 strp
= getnum(strp
, &rulep
->r_day
, 0, DAYSPERLYEAR
- 1);
2289 /* one-based day of year */
2290 strp
= getnum(strp
, &rulep
->r_day
, 1, DAYSPERLYEAR
);
2294 return (NULL
); /* ZONERULES_INVALID format */
2303 strp
= getsecs(strp
, &rulep
->r_time
);
2305 rulep
->r_time
= 2 * SECSPERHOUR
; /* default = 2:00:00 */
2311 * Returns default value for TZ as specified in /etc/default/init file, if
2312 * a default value for TZ is provided there.
2315 get_default_tz(void)
2322 assert_no_libc_locks_held();
2324 if ((defp
= defopen_r(TIMEZONE
)) != NULL
) {
2325 flags
= defcntl_r(DC_GETFLAGS
, 0, defp
);
2326 TURNON(flags
, DC_STRIP_QUOTES
);
2327 (void) defcntl_r(DC_SETFLAGS
, flags
, defp
);
2329 if ((tzp
= (uchar_t
*)defread_r(TZSTRING
, defp
)) != NULL
) {
2330 while (isspace(*tzp
))
2333 while (!isspace(*tzq
) &&
2340 tz
= libc_strdup((char *)tzp
);
2349 * Purge all cache'd state_t
2352 purge_zone_cache(void)
2358 * Create a single list of caches which are detached
2362 for (hashid
= 0; hashid
< HASHTABLE
; hashid
++) {
2363 for (p
= tzcache
[hashid
]; p
!= NULL
; p
= n
) {
2368 tzcache
[hashid
] = NULL
;
2372 /* last_tzname[] may point cache being freed */
2373 last_tzname
[0] = NULL
;
2374 last_tzname
[1] = NULL
;
2376 /* We'll reload system TZ as well */
2380 * Hash table has been cleared, and all elements are detached from
2381 * the hash table. Now we are safe to release _time_lock.
2382 * We need to unlock _time_lock because we need to call out to
2385 lmutex_unlock(&_time_lock
);
2387 assert_no_libc_locks_held();
2391 libc_free((char *)r
->zonename
);
2392 libc_free((char *)r
->chars
);
2397 lmutex_lock(&_time_lock
);
2401 * When called first time, open the counter device and load
2402 * the initial value. If counter is updated, copy value to
2406 reload_counter(void)
2411 if (zoneinfo_seqadr
!= &zoneinfo_seqno_init
) {
2412 zoneinfo_seqno
= *zoneinfo_seqadr
;
2416 if ((fd
= open(TZSYNC_FILE
, O_RDONLY
)) < 0)
2419 addr
= mmap(0, sizeof (uint32_t), PROT_READ
, MAP_SHARED
, fd
, 0);
2422 if (addr
== MAP_FAILED
)
2425 zoneinfo_seqadr
= (uint32_t *)addr
;
2426 zoneinfo_seqno
= *zoneinfo_seqadr
;
2430 * getsystemTZ() returns the TZ value if it is set in the environment, or
2431 * it returns the system TZ; if the systemTZ has not yet been set, or
2432 * cleared by tzreload, get_default_tz() is called to read the
2433 * /etc/default/init file to get the value.
2442 if (tz
!= NULL
&& *tz
!= '\0')
2443 return ((const char *)tz
);
2445 if (systemTZ
!= NULL
)
2449 * get_default_tz calls out stdio functions via defread.
2451 lmutex_unlock(&_time_lock
);
2452 tz
= get_default_tz();
2453 lmutex_lock(&_time_lock
);
2456 /* no TZ entry in the file */
2457 systemTZ
= _posix_gmt0
;
2462 * look up timezone used previously. We will not free the
2463 * old timezone name, because ltzset_u() can release _time_lock
2464 * while it has references to systemTZ (via zonename). If we
2465 * free the systemTZ, the reference via zonename can access
2466 * invalid memory when systemTZ is reset.
2468 for (tzn
= systemTZrec
; tzn
!= NULL
; tzn
= tzn
->link
) {
2469 if (strcmp(tz
, tzn
->name
) == 0)
2473 /* This is new timezone name */
2474 tzn
= lmalloc(sizeof (tznmlist_t
*) + strlen(tz
) + 1);
2475 (void) strcpy(tzn
->name
, tz
);
2476 tzn
->link
= systemTZrec
;
2482 return (systemTZ
= tzn
->name
);
2486 * tzname[] is the user visible string which applications may have
2487 * references. Even though TZ was changed, references to the old tzname
2488 * may continue to remain in the application, and those references need
2489 * to be valid. They were valid by our implementation because strings being
2490 * pointed by tzname were never be freed nor altered by the change of TZ.
2491 * However, this will no longer be the case.
2493 * state_t is now freed when cache is purged. Therefore, reading string
2494 * from old tzname[] addr may end up with accessing a stale data(freed area).
2495 * To avoid this, we maintain a copy of all timezone name strings which will
2496 * never be freed, and tzname[] will point those copies.
2500 set_one_tzname(const char *name
, int idx
)
2502 const unsigned char *nm
;
2507 if (name
== _tz_gmt
|| name
== _tz_spaces
) {
2508 tzname
[idx
] = (char *)name
;
2512 nm
= (const unsigned char *)name
;
2513 hashid
= (nm
[0] * 29 + nm
[1] * 3) % TZNMC_SZ
;
2514 for (tzn
= tznmhash
[hashid
]; tzn
!= NULL
; tzn
= tzn
->link
) {
2516 /* do the strcmp() */
2517 for (i
= 0; s
[i
] == name
[i
]; i
++) {
2519 tzname
[idx
] = tzn
->name
;
2525 * allocate new entry. This entry is never freed, so use lmalloc
2527 tzn
= lmalloc(sizeof (tznmlist_t
*) + strlen(name
) + 1);
2531 (void) strcpy(tzn
->name
, name
);
2534 tzn
->link
= tznmhash
[hashid
];
2535 tznmhash
[hashid
] = tzn
;
2537 tzname
[idx
] = tzn
->name
;
2542 * Set tzname[] after testing parameter to see if we are setting
2543 * same zone name. If we got same address, it should be same zone
2544 * name as tzname[], unless cache have been purged.
2545 * Note, purge_zone_cache() resets last_tzname[].
2548 set_tzname(const char **namep
)
2550 if (namep
[0] != last_tzname
[0]) {
2551 if (set_one_tzname(namep
[0], 0)) {
2552 tzname
[0] = (char *)_tz_gmt
;
2553 last_tzname
[0] = NULL
;
2555 last_tzname
[0] = namep
[0];
2559 if (namep
[1] != last_tzname
[1]) {
2560 if (set_one_tzname(namep
[1], 1)) {
2561 tzname
[1] = (char *)_tz_spaces
;
2562 last_tzname
[1] = NULL
;
2564 last_tzname
[1] = namep
[1];