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