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