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