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