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