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