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