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