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