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