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 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 * 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 * 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 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 * 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 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 * 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 * 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 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 836 mktime(struct tm *tmptr) 837 { 838 return (mktime1(tmptr, TRUE)); 839 } 840 841 time_t 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 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 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 * 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 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 1070 state_is_posix(const state_t *state) 1071 { 1072 return (state->zonerules == POSIX || state->zonerules == POSIX_USA); 1073 } 1074 1075 static void 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 * 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 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 * 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 * 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 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 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 * 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 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 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