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