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