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