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