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