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