1/* 2** This file is in the public domain, so clarified as of 3** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). 4*/ 5 6#include <sys/cdefs.h> 7#ifndef lint 8#ifndef NOID 9static char elsieid[] __unused = "@(#)localtime.c 7.78"; 10#endif /* !defined NOID */ 11#endif /* !defined lint */ 12__FBSDID("$FreeBSD: src/lib/libc/stdtime/localtime.c,v 1.43 2008/04/01 06:56:11 davidxu Exp $"); 13 14/* 15** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). 16** POSIX-style TZ environment variable handling from Guy Harris 17** (guy@auspex.com). 18*/ 19 20/*LINTLIBRARY*/ 21 22#include "namespace.h" 23#include <sys/types.h> 24#include <sys/stat.h> 25#include <time.h> 26#include <fcntl.h> 27#include <pthread.h> 28#include <errno.h> 29#ifdef NOTIFY_TZ 30//#define NOTIFY_TZ_DEBUG 31//#define NOTIFY_TZ_DEBUG_FILE "/var/log/localtime.debug" 32//#define NOTIFY_TZ_LOG "/var/log/localtime.log" 33/* force ALL_STATE if NOTIFY_TZ is set */ 34#ifndef ALL_STATE 35#define ALL_STATE 36#endif /* ALL_STATE */ 37#include <mach/mach_init.h> 38#include <notify.h> 39#include <alloca.h> 40#endif /* NOTIFY_TZ */ 41#include "private.h" 42#include "un-namespace.h" 43 44#include "tzfile.h" 45 46#include "libc_private.h" 47 48#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) 49#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) 50 51#define _RWLOCK_RDLOCK(x) \ 52 do { \ 53 if (__isthreaded) _pthread_rwlock_rdlock(x); \ 54 } while (0) 55 56#define _RWLOCK_WRLOCK(x) \ 57 do { \ 58 if (__isthreaded) _pthread_rwlock_wrlock(x); \ 59 } while (0) 60 61#define _RWLOCK_UNLOCK(x) \ 62 do { \ 63 if (__isthreaded) _pthread_rwlock_unlock(x); \ 64 } while (0) 65 66/* 67** SunOS 4.1.1 headers lack O_BINARY. 68*/ 69 70#ifdef O_BINARY 71#define OPEN_MODE (O_RDONLY | O_BINARY) 72#endif /* defined O_BINARY */ 73#ifndef O_BINARY 74#define OPEN_MODE O_RDONLY 75#endif /* !defined O_BINARY */ 76 77#ifndef WILDABBR 78/* 79** Someone might make incorrect use of a time zone abbreviation: 80** 1. They might reference tzname[0] before calling tzset (explicitly 81** or implicitly). 82** 2. They might reference tzname[1] before calling tzset (explicitly 83** or implicitly). 84** 3. They might reference tzname[1] after setting to a time zone 85** in which Daylight Saving Time is never observed. 86** 4. They might reference tzname[0] after setting to a time zone 87** in which Standard Time is never observed. 88** 5. They might reference tm.TM_ZONE after calling offtime. 89** What's best to do in the above cases is open to debate; 90** for now, we just set things up so that in any of the five cases 91** WILDABBR is used. Another possibility: initialize tzname[0] to the 92** string "tzname[0] used before set", and similarly for the other cases. 93** And another: initialize tzname[0] to "ERA", with an explanation in the 94** manual page of what this "time zone abbreviation" means (doing this so 95** that tzname[0] has the "normal" length of three characters). 96*/ 97#define WILDABBR " " 98#endif /* !defined WILDABBR */ 99 100static const char wildabbr[] = "WILDABBR"; 101 102/* 103 * In June 2004 it was decided UTC was a more appropriate default time 104 * zone than GMT. 105 */ 106 107static const char gmt[] = "UTC"; 108 109/* 110** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. 111** We default to US rules as of 1999-08-17. 112** POSIX 1003.1 section 8.1.1 says that the default DST rules are 113** implementation dependent; for historical reasons, US rules are a 114** common default. 115*/ 116#ifndef TZDEFRULESTRING 117#define TZDEFRULESTRING ",M4.1.0,M10.5.0" 118#endif /* !defined TZDEFDST */ 119 120struct ttinfo { /* time type information */ 121 long tt_gmtoff; /* UTC offset in seconds */ 122 int tt_isdst; /* used to set tm_isdst */ 123 int tt_abbrind; /* abbreviation list index */ 124 int tt_ttisstd; /* TRUE if transition is std time */ 125 int tt_ttisgmt; /* TRUE if transition is UTC */ 126}; 127 128struct lsinfo { /* leap second information */ 129 time_t ls_trans; /* transition time */ 130 long ls_corr; /* correction to apply */ 131}; 132 133#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) 134 135#ifdef TZNAME_MAX 136#define MY_TZNAME_MAX TZNAME_MAX 137#endif /* defined TZNAME_MAX */ 138#ifndef TZNAME_MAX 139#define MY_TZNAME_MAX 255 140#endif /* !defined TZNAME_MAX */ 141 142struct state { 143 int leapcnt; 144 int timecnt; 145 int typecnt; 146 int charcnt; 147 time_t ats[TZ_MAX_TIMES]; 148 unsigned char types[TZ_MAX_TIMES]; 149 struct ttinfo ttis[TZ_MAX_TYPES]; 150 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), 151 (2 * (MY_TZNAME_MAX + 1)))]; 152 struct lsinfo lsis[TZ_MAX_LEAPS]; 153}; 154 155struct rule { 156 int r_type; /* type of rule--see below */ 157 int r_day; /* day number of rule */ 158 int r_week; /* week number of rule */ 159 int r_mon; /* month number of rule */ 160 long r_time; /* transition time of rule */ 161}; 162 163#define JULIAN_DAY 0 /* Jn - Julian day */ 164#define DAY_OF_YEAR 1 /* n - day of year */ 165#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 166 167#ifdef NOTIFY_TZ 168typedef struct { 169 int token; 170 int is_set; 171} notify_tz_t; 172 173#define NOTIFY_TZ_NAME "com.apple.system.timezone" 174#endif /* NOTIFY_TZ */ 175 176/* 177** Prototypes for static functions. 178*/ 179#define localsub _st_localsub 180#define time1 _st_time1 181#define tzset_basic _st_tzset_basic 182__private_extern__ 183#ifdef __LP64__ 184struct tm * localsub(const time_t * timep, long offset, 185 struct tm * tmp); 186#else /* !__LP64__ */ 187void localsub(const time_t * timep, long offset, 188 struct tm * tmp); 189#endif /* __LP64__ */ 190__private_extern__ 191time_t time1(struct tm * tmp, 192#ifdef __LP64__ 193 struct tm *(*funcp) (const time_t *, 194 long, struct tm *), 195#else /* !__LP64__ */ 196 void(*funcp) (const time_t *, 197 long, struct tm *), 198#endif /* __LP64__ */ 199 long offset, 200 int unix03); 201__private_extern__ 202void tzset_basic(int); 203 204#if !BUILDING_VARIANT 205static long detzcode(const char * codep); 206static const char * getzname(const char * strp, char **name, size_t *len); 207static const char * getnum(const char * strp, int * nump, int min, 208 int max); 209static const char * getsecs(const char * strp, long * secsp); 210static const char * getoffset(const char * strp, long * offsetp); 211static const char * getrule(const char * strp, struct rule * rulep); 212#ifdef NOTIFY_TZ 213static void gmtload(struct state * sp, char *path); 214#else /* ! NOTIFY_TZ */ 215static void gmtload(struct state * sp); 216#endif /* NOTIFY_TZ */ 217#ifdef __LP64__ 218static struct tm * gmtsub(const time_t * timep, long offset, 219 struct tm * tmp); 220#else /* !__LP64__ */ 221static void gmtsub(const time_t * timep, long offset, 222 struct tm * tmp); 223#endif /* __LP64__ */ 224static int increment_overflow(int * number, int delta); 225static int normalize_overflow(int * tensptr, int * unitsptr, 226 int base); 227#ifdef NOTIFY_TZ 228static void notify_check_tz(notify_tz_t *p); 229static void notify_register_tz(char *file, notify_tz_t *p); 230#endif /* NOTIFY_TZ */ 231static void settzname(void); 232static time_t time2(struct tm *tmp, 233#ifdef __LP64__ 234 struct tm *(*funcp) (const time_t *, 235 long, struct tm*), 236#else /* !__LP64__ */ 237 void(*funcp) (const time_t *, 238 long, struct tm*), 239#endif /* __LP64__ */ 240 long offset, int * okayp, int unix03); 241static time_t time2sub(struct tm *tmp, 242#ifdef __LP64__ 243 struct tm *(*funcp) (const time_t *, 244 long, struct tm*), 245#else /* !__LP64__ */ 246 void(*funcp) (const time_t *, 247 long, struct tm*), 248#endif /* __LP64__ */ 249 long offset, int * okayp, int do_norm_secs, 250 int unix03); 251#ifdef __LP64__ 252static struct tm * timesub(const time_t * timep, long offset, 253 const struct state * sp, struct tm * tmp); 254#else /* !__LP64__ */ 255static void timesub(const time_t * timep, long offset, 256 const struct state * sp, struct tm * tmp); 257#endif /* __LP64__ */ 258static int tmcomp(const struct tm * atmp, 259 const struct tm * btmp); 260static time_t transtime(time_t janfirst, int year, 261 const struct rule * rulep, long offset); 262#ifdef NOTIFY_TZ 263static int tzload(const char * name, struct state * sp, char *path); 264#else /* ! NOTIFY_TZ */ 265static int tzload(const char * name, struct state * sp); 266#endif /* NOTIFY_TZ */ 267static int tzparse(const char * name, struct state * sp, 268 int lastditch); 269 270#ifdef ALL_STATE 271static struct state * lclptr; 272static struct state * gmtptr; 273#endif /* defined ALL_STATE */ 274 275#ifndef ALL_STATE 276static struct state lclmem; 277static struct state gmtmem; 278#define lclptr (&lclmem) 279#define gmtptr (&gmtmem) 280#endif /* State Farm */ 281 282#ifndef TZ_STRLEN_MAX 283#define TZ_STRLEN_MAX 255 284#endif /* !defined TZ_STRLEN_MAX */ 285 286static char lcl_TZname[TZ_STRLEN_MAX + 1]; 287#ifdef NOTIFY_TZ 288#define lcl_is_set (lcl_notify.is_set) 289#define gmt_is_set (gmt_notify.is_set) 290#else /* ! NOTIFY_TZ */ 291static int lcl_is_set; 292static int gmt_is_set; 293#endif /* NOTIFY_TZ */ 294__private_extern__ pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; 295static pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER; 296 297char * tzname[2] = { 298 (char *)wildabbr, 299 (char *)wildabbr 300}; 301 302/* 303** Section 4.12.3 of X3.159-1989 requires that 304** Except for the strftime function, these functions [asctime, 305** ctime, gmtime, localtime] return values in one of two static 306** objects: a broken-down time structure and an array of char. 307** Thanks to Paul Eggert (eggert@twinsun.com) for noting this. 308*/ 309 310static struct tm tm; 311 312#define USG_COMPAT 313#define ALTZONE 314#ifdef USG_COMPAT 315int daylight = 0; 316__private_extern__ void _st_set_timezone(long); 317#endif /* defined USG_COMPAT */ 318 319#ifdef ALTZONE 320__private_extern__ long __darwin_altzone = 0; 321#define altzone __darwin_altzone 322#endif /* defined ALTZONE */ 323 324#ifdef NOTIFY_TZ 325#ifdef NOTIFY_TZ_DEBUG 326#ifdef NOTIFY_TZ_DEBUG_FILE 327#define NOTIFY_TZ_PRINTF(fmt, args...) \ 328{ \ 329 FILE *_notify_tz_fp_; \ 330 if((_notify_tz_fp_ = fopen(NOTIFY_TZ_DEBUG_FILE, "a")) != NULL) { \ 331 fprintf(_notify_tz_fp_, "%d: " fmt, getpid(), ## args); \ 332 fclose(_notify_tz_fp_); \ 333 } \ 334} 335#else /* ! NOTIFY_TZ_DEBUG_FILE */ 336#define NOTIFY_TZ_PRINTF(args...) fprintf(stdout, ## args) 337#endif /* NOTIFY_TZ_DEBUG_FILE */ 338#endif /* NOTIFY_TZ_DEBUG */ 339#ifdef NOTIFY_TZ_LOG 340#define NOTIFY_LOG(fmt, args...) \ 341{ \ 342 FILE *_notify_log_fp_; \ 343 if((_notify_log_fp_ = fopen(NOTIFY_TZ_LOG, "a")) != NULL) { \ 344 fprintf(_notify_log_fp_, "%d: " fmt, getpid(), ## args); \ 345 fclose(_notify_log_fp_); \ 346 } \ 347} 348#endif /* NOTIFY_TZ_LOG */ 349 350static notify_tz_t gmt_notify = {-1, 0}; 351static notify_tz_t lcl_notify = {-1, 0}; 352static const char notify_tz_name[] = NOTIFY_TZ_NAME; 353#endif /* NOTIFY_TZ */ 354 355static long 356detzcode(codep) 357const char * const codep; 358{ 359 long result; 360 int i; 361 362 result = (codep[0] & 0x80) ? ~0L : 0L; 363 for (i = 0; i < 4; ++i) 364 result = (result << 8) | (codep[i] & 0xff); 365 return result; 366} 367 368static void 369settzname(void) 370{ 371 struct state * sp = lclptr; 372 int i, need; 373 unsigned char * types; 374#define NEED_STD 1 375#define NEED_DST 2 376#define NEED_DAYLIGHT 4 377#define NEED_ALL (NEED_STD | NEED_DST | NEED_DAYLIGHT) 378 379 tzname[0] = (char *)wildabbr; 380 tzname[1] = (char *)wildabbr; 381#ifdef USG_COMPAT 382 daylight = 0; 383 _st_set_timezone(0); 384#endif /* defined USG_COMPAT */ 385#ifdef ALTZONE 386 altzone = 0; 387#endif /* defined ALTZONE */ 388#ifdef ALL_STATE 389 if (sp == NULL) { 390 tzname[0] = tzname[1] = (char *)gmt; 391 return; 392 } 393#endif /* defined ALL_STATE */ 394 /* 395 * PR-3765457: The original settzname went sequentially through the ttis 396 * array, rather than correctly indexing via the types array, to get 397 * the real order of the timezone changes. In addition, as a speed up, 398 * we start at the end of the changes, and work back, so that most of 399 * the time, we don't have to look through the entire array. 400 */ 401 if (sp->timecnt == 0 && sp->typecnt == 1) { 402 /* 403 * Unfortunately, there is an edge case when typecnt == 1 and 404 * timecnt == 0, which would cause the loop to never run. So 405 * in that case, we fudge things up so that it is as if 406 * timecnt == 1. 407 */ 408 i = 0; 409 types = (unsigned char *)""; /* we use the null as index */ 410 } else { 411 /* the usual case */ 412 i = sp->timecnt - 1; 413 types = sp->types; 414 } 415 need = NEED_ALL; 416 for (; i >= 0 && need; --i) { 417 const struct ttinfo * const ttisp = &sp->ttis[types[i]]; 418 419#ifdef USG_COMPAT 420 if ((need & NEED_DAYLIGHT) && ttisp->tt_isdst) { 421 need &= ~NEED_DAYLIGHT; 422 daylight = 1; 423 } 424#endif /* defined USG_COMPAT */ 425 if (ttisp->tt_isdst) { 426 if (need & NEED_DST) { 427 need &= ~NEED_DST; 428 tzname[1] = &sp->chars[ttisp->tt_abbrind]; 429#ifdef ALTZONE 430 altzone = -(ttisp->tt_gmtoff); 431#endif /* defined ALTZONE */ 432 } 433 } else if (need & NEED_STD) { 434 need &= ~NEED_STD; 435 tzname[0] = &sp->chars[ttisp->tt_abbrind]; 436#ifdef USG_COMPAT 437 _st_set_timezone(-(ttisp->tt_gmtoff)); 438#endif /* defined USG_COMPAT */ 439 } 440#if defined(ALTZONE) || defined(USG_COMPAT) 441 if (i == 0) { 442#endif /* defined(ALTZONE) || defined(USG_COMPAT) */ 443#ifdef ALTZONE 444 if (need & NEED_DST) 445 altzone = -(ttisp->tt_gmtoff); 446#endif /* defined ALTZONE */ 447#ifdef USG_COMPAT 448 if (need & NEED_STD) 449 _st_set_timezone(-(ttisp->tt_gmtoff)); 450#endif /* defined USG_COMPAT */ 451#if defined(ALTZONE) || defined(USG_COMPAT) 452 } 453#endif /* defined(ALTZONE) || defined(USG_COMPAT) */ 454 } 455} 456 457#ifdef NOTIFY_TZ 458static void 459notify_check_tz(notify_tz_t *p) 460{ 461 unsigned int nstat; 462 int ncheck; 463 464 if (p->token < 0) 465 return; 466 nstat = notify_check(p->token, &ncheck); 467 if (nstat || ncheck) { 468 p->is_set = 0; 469#ifdef NOTIFY_TZ_DEBUG 470 NOTIFY_TZ_PRINTF("notify_check_tz: %s changed\n", (p == &lcl_notify) ? "lcl" : "gmt"); 471#endif /* NOTIFY_TZ_DEBUG */ 472 } 473#ifdef NOTIFY_TZ_DEBUG 474 NOTIFY_TZ_PRINTF("notify_check_tz: %s unchanged\n", (p == &lcl_notify) ? "lcl" : "gmt"); 475#endif /* NOTIFY_TZ_DEBUG */ 476} 477 478extern uint32_t notify_monitor_file(int token, char *path, int flags); 479 480static void 481notify_register_tz(char *file, notify_tz_t *p) 482{ 483 char *name; 484 unsigned int nstat; 485 int ncheck; 486 487 /*---------------------------------------------------------------- 488 * Since we don't record the last time zone filename, just cancel 489 * (which should remove the file monitor) and setup from scratch 490 *----------------------------------------------------------------*/ 491 if (p->token >= 0) 492 notify_cancel(p->token); 493 if (!file || *file == 0) { 494 /* no time zone file to monitor */ 495 p->token = -1; 496 return; 497 } 498 /*---------------------------------------------------------------- 499 * Just use com.apple.system.timezone if the path is /etc/localtime. 500 * Otherwise use com.apple.system.timezone.<fullpath> 501 *----------------------------------------------------------------*/ 502 if (TZDEFAULT && strcmp(file, TZDEFAULT) == 0) 503 name = (char *)notify_tz_name; 504 else { 505 name = alloca(sizeof(notify_tz_name) + strlen(file) + 1); 506 if (name == NULL) { 507 p->token = -1; 508 return; 509 } 510 strcpy(name, notify_tz_name); 511 strcat(name, "."); 512 strcat(name, file); 513 } 514#ifdef NOTIFY_TZ_DEBUG 515 NOTIFY_TZ_PRINTF("notify_register_tz: file=%s name=%s\n", file, name); 516#endif /* NOTIFY_TZ_DEBUG */ 517 nstat = notify_register_check(name, &p->token); 518 if (nstat != 0) { 519 p->token = -1; 520 p->is_set = 0; 521#ifdef NOTIFY_TZ_DEBUG 522 NOTIFY_TZ_PRINTF("***notify_register_tz: notify_register_check failed: %u\n", nstat); 523#endif /* NOTIFY_TZ_DEBUG */ 524#ifdef NOTIFY_TZ_LOG 525 NOTIFY_LOG("notify_register_check(%s) failed: %u\n", name, nstat); 526#endif /* NOTIFY_TZ_LOG */ 527 return; 528 } 529 /* don't need to request monitoring /etc/localtime */ 530 if (name != notify_tz_name) { 531#ifdef NOTIFY_TZ_DEBUG 532 NOTIFY_TZ_PRINTF("notify_register_tz: monitor %s\n", file); 533#endif /* NOTIFY_TZ_DEBUG */ 534 nstat = notify_monitor_file(p->token, file, 0); 535 if (nstat != 0) { 536 notify_cancel(p->token); 537 p->token = -1; 538 p->is_set = 0; 539#ifdef NOTIFY_TZ_DEBUG 540 NOTIFY_TZ_PRINTF("***notify_register_tz: notify_monitor_file failed: %u\n", nstat); 541#endif /* NOTIFY_TZ_DEBUG */ 542#ifdef NOTIFY_TZ_LOG 543 NOTIFY_LOG("notify_monitor_file(%s) failed: %u\n", file, nstat); 544#endif /* NOTIFY_TZ_LOG */ 545 return; 546 } 547 } 548 notify_check(p->token, &ncheck); /* this always returns true */ 549} 550#endif /* NOTIFY_TZ */ 551 552static int 553#ifdef NOTIFY_TZ 554tzload(name, sp, path) 555#else /* ! NOTIFY_TZ */ 556tzload(name, sp) 557#endif /* NOTIFY_TZ */ 558const char * name; 559struct state * const sp; 560#ifdef NOTIFY_TZ 561char * path; /* copy full path if non-NULL */ 562#endif /* NOTIFY_TZ */ 563{ 564 const char * p; 565 int i; 566 int fid; 567 568#ifdef NOTIFY_TZ_DEBUG 569 NOTIFY_TZ_PRINTF("tzload: name=%s\n", name); 570#endif /* NOTIFY_TZ_DEBUG */ 571 /* XXX The following is from OpenBSD, and I'm not sure it is correct */ 572 if (name != NULL && issetugid() != 0) 573 if ((name[0] == ':' && name[1] == '/') || 574 name[0] == '/' || strchr(name, '.')) 575 name = NULL; 576#ifdef NOTIFY_TZ 577 if (path) 578 *path = 0; /* default to empty string on error */ 579#endif /* NOTIFY_TZ */ 580 if (name == NULL && (name = TZDEFAULT) == NULL) 581 return -1; 582 { 583 int doaccess; 584 struct stat stab; 585 /* 586 ** Section 4.9.1 of the C standard says that 587 ** "FILENAME_MAX expands to an integral constant expression 588 ** that is the size needed for an array of char large enough 589 ** to hold the longest file name string that the implementation 590 ** guarantees can be opened." 591 */ 592 char fullname[FILENAME_MAX + 1]; 593 594 if (name[0] == ':') 595 ++name; 596 doaccess = name[0] == '/'; 597 if (!doaccess) { 598 if ((p = TZDIR) == NULL) 599 return -1; 600 if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname) 601 return -1; 602 (void) strcpy(fullname, p); 603 (void) strcat(fullname, "/"); 604 (void) strcat(fullname, name); 605 /* 606 ** Set doaccess if '.' (as in "../") shows up in name. 607 */ 608 if (strchr(name, '.') != NULL) 609 doaccess = TRUE; 610 name = fullname; 611 } 612#ifdef NOTIFY_TZ 613 if (path) { 614 if (strlen(name) > FILENAME_MAX) 615 return -1; 616 strcpy(path, name); 617 } 618#endif /* NOTIFY_TZ */ 619 if (doaccess && access(name, R_OK) != 0) 620 return -1; 621 if ((fid = _open(name, OPEN_MODE)) == -1) 622 return -1; 623 if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) { 624 _close(fid); 625 return -1; 626 } 627 } 628 { 629 struct tzhead * tzhp; 630 union { 631 struct tzhead tzhead; 632 char buf[sizeof *sp + sizeof *tzhp]; 633 } u; 634 int ttisstdcnt; 635 int ttisgmtcnt; 636 637#ifdef NOTIFY_TZ_DEBUG 638 NOTIFY_TZ_PRINTF("tzload: reading %s\n", name); 639#endif /* NOTIFY_TZ_DEBUG */ 640 i = _read(fid, u.buf, sizeof u.buf); 641 if (_close(fid) != 0) 642 return -1; 643 ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt); 644 ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt); 645 sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt); 646 sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt); 647 sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt); 648 sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt); 649 p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt; 650 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || 651 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 652 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 653 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 654 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || 655 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) 656 return -1; 657 if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */ 658 sp->timecnt + /* types */ 659 sp->typecnt * (4 + 2) + /* ttinfos */ 660 sp->charcnt + /* chars */ 661 sp->leapcnt * (4 + 4) + /* lsinfos */ 662 ttisstdcnt + /* ttisstds */ 663 ttisgmtcnt) /* ttisgmts */ 664 return -1; 665 for (i = 0; i < sp->timecnt; ++i) { 666 sp->ats[i] = detzcode(p); 667 p += 4; 668 } 669 for (i = 0; i < sp->timecnt; ++i) { 670 sp->types[i] = (unsigned char) *p++; 671 if (sp->types[i] >= sp->typecnt) 672 return -1; 673 } 674 for (i = 0; i < sp->typecnt; ++i) { 675 struct ttinfo * ttisp; 676 677 ttisp = &sp->ttis[i]; 678 ttisp->tt_gmtoff = detzcode(p); 679 p += 4; 680 ttisp->tt_isdst = (unsigned char) *p++; 681 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 682 return -1; 683 ttisp->tt_abbrind = (unsigned char) *p++; 684 if (ttisp->tt_abbrind < 0 || 685 ttisp->tt_abbrind > sp->charcnt) 686 return -1; 687 } 688 for (i = 0; i < sp->charcnt; ++i) 689 sp->chars[i] = *p++; 690 sp->chars[i] = '\0'; /* ensure '\0' at end */ 691 for (i = 0; i < sp->leapcnt; ++i) { 692 struct lsinfo * lsisp; 693 694 lsisp = &sp->lsis[i]; 695 lsisp->ls_trans = detzcode(p); 696 p += 4; 697 lsisp->ls_corr = detzcode(p); 698 p += 4; 699 } 700 for (i = 0; i < sp->typecnt; ++i) { 701 struct ttinfo * ttisp; 702 703 ttisp = &sp->ttis[i]; 704 if (ttisstdcnt == 0) 705 ttisp->tt_ttisstd = FALSE; 706 else { 707 ttisp->tt_ttisstd = *p++; 708 if (ttisp->tt_ttisstd != TRUE && 709 ttisp->tt_ttisstd != FALSE) 710 return -1; 711 } 712 } 713 for (i = 0; i < sp->typecnt; ++i) { 714 struct ttinfo * ttisp; 715 716 ttisp = &sp->ttis[i]; 717 if (ttisgmtcnt == 0) 718 ttisp->tt_ttisgmt = FALSE; 719 else { 720 ttisp->tt_ttisgmt = *p++; 721 if (ttisp->tt_ttisgmt != TRUE && 722 ttisp->tt_ttisgmt != FALSE) 723 return -1; 724 } 725 } 726 } 727 return 0; 728} 729 730static const int mon_lengths[2][MONSPERYEAR] = { 731 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 732 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 733}; 734 735static const int year_lengths[2] = { 736 DAYSPERNYEAR, DAYSPERLYEAR 737}; 738 739/* 740** Given a pointer into a time zone string, scan until a character that is not 741** a valid character in a zone name is found. Return a pointer to that 742** character. 743*/ 744 745static const char * 746getzname(strp, name, len) 747const char * strp; 748char ** name; 749size_t * len; 750{ 751 char c; 752 char * ket; 753 754 if (*strp == '<' && (ket = strchr(strp, '>')) != NULL) { 755 *name = (char *)(strp + 1); 756 *len = ket - strp - 1; 757 return ket + 1; 758 } 759 *name = (char *)strp; 760 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && 761 c != '+') 762 ++strp; 763 *len = strp - *name; 764 return strp; 765} 766 767/* 768** Given a pointer into a time zone string, extract a number from that string. 769** Check that the number is within a specified range; if it is not, return 770** NULL. 771** Otherwise, return a pointer to the first character not part of the number. 772*/ 773 774static const char * 775getnum(strp, nump, min, max) 776const char * strp; 777int * const nump; 778const int min; 779const int max; 780{ 781 char c; 782 int num; 783 784 if (strp == NULL || !is_digit(c = *strp)) 785 return NULL; 786 num = 0; 787 do { 788 num = num * 10 + (c - '0'); 789 if (num > max) 790 return NULL; /* illegal value */ 791 c = *++strp; 792 } while (is_digit(c)); 793 if (num < min) 794 return NULL; /* illegal value */ 795 *nump = num; 796 return strp; 797} 798 799/* 800** Given a pointer into a time zone string, extract a number of seconds, 801** in hh[:mm[:ss]] form, from the string. 802** If any error occurs, return NULL. 803** Otherwise, return a pointer to the first character not part of the number 804** of seconds. 805*/ 806 807static const char * 808getsecs(strp, secsp) 809const char * strp; 810long * const secsp; 811{ 812 int num; 813 814 /* 815 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like 816 ** "M10.4.6/26", which does not conform to Posix, 817 ** but which specifies the equivalent of 818 ** ``02:00 on the first Sunday on or after 23 Oct''. 819 */ 820 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); 821 if (strp == NULL) 822 return NULL; 823 *secsp = num * (long) SECSPERHOUR; 824 if (*strp == ':') { 825 ++strp; 826 strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 827 if (strp == NULL) 828 return NULL; 829 *secsp += num * SECSPERMIN; 830 if (*strp == ':') { 831 ++strp; 832 /* `SECSPERMIN' allows for leap seconds. */ 833 strp = getnum(strp, &num, 0, SECSPERMIN); 834 if (strp == NULL) 835 return NULL; 836 *secsp += num; 837 } 838 } 839 return strp; 840} 841 842/* 843** Given a pointer into a time zone string, extract an offset, in 844** [+-]hh[:mm[:ss]] form, from the string. 845** If any error occurs, return NULL. 846** Otherwise, return a pointer to the first character not part of the time. 847*/ 848 849static const char * 850getoffset(strp, offsetp) 851const char * strp; 852long * const offsetp; 853{ 854 int neg = 0; 855 856 if (*strp == '-') { 857 neg = 1; 858 ++strp; 859 } else if (*strp == '+') 860 ++strp; 861 strp = getsecs(strp, offsetp); 862 if (strp == NULL) 863 return NULL; /* illegal time */ 864 if (neg) 865 *offsetp = -*offsetp; 866 return strp; 867} 868 869/* 870** Given a pointer into a time zone string, extract a rule in the form 871** date[/time]. See POSIX section 8 for the format of "date" and "time". 872** If a valid rule is not found, return NULL. 873** Otherwise, return a pointer to the first character not part of the rule. 874*/ 875 876static const char * 877getrule(strp, rulep) 878const char * strp; 879struct rule * const rulep; 880{ 881 if (*strp == 'J') { 882 /* 883 ** Julian day. 884 */ 885 rulep->r_type = JULIAN_DAY; 886 ++strp; 887 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 888 } else if (*strp == 'M') { 889 /* 890 ** Month, week, day. 891 */ 892 rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 893 ++strp; 894 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 895 if (strp == NULL) 896 return NULL; 897 if (*strp++ != '.') 898 return NULL; 899 strp = getnum(strp, &rulep->r_week, 1, 5); 900 if (strp == NULL) 901 return NULL; 902 if (*strp++ != '.') 903 return NULL; 904 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 905 } else if (is_digit(*strp)) { 906 /* 907 ** Day of year. 908 */ 909 rulep->r_type = DAY_OF_YEAR; 910 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 911 } else return NULL; /* invalid format */ 912 if (strp == NULL) 913 return NULL; 914 if (*strp == '/') { 915 /* 916 ** Time specified. 917 */ 918 ++strp; 919 strp = getsecs(strp, &rulep->r_time); 920 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 921 return strp; 922} 923 924/* 925** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the 926** year, a rule, and the offset from UTC at the time that rule takes effect, 927** calculate the Epoch-relative time that rule takes effect. 928*/ 929 930static time_t 931transtime(janfirst, year, rulep, offset) 932const time_t janfirst; 933const int year; 934const struct rule * const rulep; 935const long offset; 936{ 937 int leapyear; 938 time_t value; 939 int i; 940 int d, m1, yy0, yy1, yy2, dow; 941 942 INITIALIZE(value); 943 leapyear = isleap(year); 944 switch (rulep->r_type) { 945 946 case JULIAN_DAY: 947 /* 948 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 949 ** years. 950 ** In non-leap years, or if the day number is 59 or less, just 951 ** add SECSPERDAY times the day number-1 to the time of 952 ** January 1, midnight, to get the day. 953 */ 954 value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 955 if (leapyear && rulep->r_day >= 60) 956 value += SECSPERDAY; 957 break; 958 959 case DAY_OF_YEAR: 960 /* 961 ** n - day of year. 962 ** Just add SECSPERDAY times the day number to the time of 963 ** January 1, midnight, to get the day. 964 */ 965 value = janfirst + rulep->r_day * SECSPERDAY; 966 break; 967 968 case MONTH_NTH_DAY_OF_WEEK: 969 /* 970 ** Mm.n.d - nth "dth day" of month m. 971 */ 972 value = janfirst; 973 for (i = 0; i < rulep->r_mon - 1; ++i) 974 value += mon_lengths[leapyear][i] * SECSPERDAY; 975 976 /* 977 ** Use Zeller's Congruence to get day-of-week of first day of 978 ** month. 979 */ 980 m1 = (rulep->r_mon + 9) % 12 + 1; 981 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 982 yy1 = yy0 / 100; 983 yy2 = yy0 % 100; 984 dow = ((26 * m1 - 2) / 10 + 985 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 986 if (dow < 0) 987 dow += DAYSPERWEEK; 988 989 /* 990 ** "dow" is the day-of-week of the first day of the month. Get 991 ** the day-of-month (zero-origin) of the first "dow" day of the 992 ** month. 993 */ 994 d = rulep->r_day - dow; 995 if (d < 0) 996 d += DAYSPERWEEK; 997 for (i = 1; i < rulep->r_week; ++i) { 998 if (d + DAYSPERWEEK >= 999 mon_lengths[leapyear][rulep->r_mon - 1]) 1000 break; 1001 d += DAYSPERWEEK; 1002 } 1003 1004 /* 1005 ** "d" is the day-of-month (zero-origin) of the day we want. 1006 */ 1007 value += d * SECSPERDAY; 1008 break; 1009 } 1010 1011 /* 1012 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in 1013 ** question. To get the Epoch-relative time of the specified local 1014 ** time on that day, add the transition time and the current offset 1015 ** from UTC. 1016 */ 1017 return value + rulep->r_time + offset; 1018} 1019 1020/* 1021** Given a POSIX section 8-style TZ string, fill in the rule tables as 1022** appropriate. 1023*/ 1024 1025static int 1026tzparse(name, sp, lastditch) 1027const char * name; 1028struct state * const sp; 1029const int lastditch; 1030{ 1031 const char * stdname; 1032 const char * dstname; 1033 size_t stdlen; 1034 size_t dstlen; 1035 long stdoffset; 1036 long dstoffset; 1037 time_t * atp; 1038 unsigned char * typep; 1039 char * cp; 1040 int load_result; 1041 1042 INITIALIZE(dstname); 1043 if (lastditch) { 1044 stdname = name; 1045 stdlen = strlen(name); /* length of standard zone name */ 1046 name += stdlen; 1047 if (stdlen >= sizeof sp->chars) 1048 stdlen = (sizeof sp->chars) - 1; 1049 stdoffset = 0; 1050 } else { 1051 name = getzname(name, (char **)&stdname, &stdlen); 1052 if (stdlen < 3) 1053 return -1; 1054 if (*name == '\0') 1055 return -1; /* was "stdoffset = 0;" */ 1056 else { 1057 name = getoffset(name, &stdoffset); 1058 if (name == NULL) 1059 return -1; 1060 } 1061 } 1062#ifdef NOTIFY_TZ 1063 load_result = tzload(TZDEFRULES, sp, NULL); 1064#else /* !NOTIFY_TZ */ 1065 load_result = tzload(TZDEFRULES, sp); 1066#endif /* NOTIFY_TZ */ 1067 if (load_result != 0) 1068 sp->leapcnt = 0; /* so, we're off a little */ 1069 if (*name != '\0') { 1070 dstname = name; 1071 name = getzname(name, (char **)&dstname, &dstlen); 1072 if (dstlen < 3) 1073 return -1; 1074 if (*name != '\0' && *name != ',' && *name != ';') { 1075 name = getoffset(name, &dstoffset); 1076 if (name == NULL) 1077 return -1; 1078 } else dstoffset = stdoffset - SECSPERHOUR; 1079 if (*name == '\0' && load_result != 0) 1080 name = TZDEFRULESTRING; 1081 if (*name == ',' || *name == ';') { 1082 struct rule start; 1083 struct rule end; 1084 int year; 1085 time_t janfirst; 1086 time_t starttime; 1087 time_t endtime; 1088 1089 ++name; 1090 if ((name = getrule(name, &start)) == NULL) 1091 return -1; 1092 if (*name++ != ',') 1093 return -1; 1094 if ((name = getrule(name, &end)) == NULL) 1095 return -1; 1096 if (*name != '\0') 1097 return -1; 1098 sp->typecnt = 2; /* standard time and DST */ 1099 /* 1100 ** Two transitions per year, from EPOCH_YEAR to 2037. 1101 */ 1102 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); 1103 if (sp->timecnt > TZ_MAX_TIMES) 1104 return -1; 1105 sp->ttis[0].tt_gmtoff = -dstoffset; 1106 sp->ttis[0].tt_isdst = 1; 1107 sp->ttis[0].tt_abbrind = stdlen + 1; 1108 sp->ttis[1].tt_gmtoff = -stdoffset; 1109 sp->ttis[1].tt_isdst = 0; 1110 sp->ttis[1].tt_abbrind = 0; 1111 atp = sp->ats; 1112 typep = sp->types; 1113 janfirst = 0; 1114 for (year = EPOCH_YEAR; year <= 2037; ++year) { 1115 starttime = transtime(janfirst, year, &start, 1116 stdoffset); 1117 endtime = transtime(janfirst, year, &end, 1118 dstoffset); 1119 if (starttime > endtime) { 1120 *atp++ = endtime; 1121 *typep++ = 1; /* DST ends */ 1122 *atp++ = starttime; 1123 *typep++ = 0; /* DST begins */ 1124 } else { 1125 *atp++ = starttime; 1126 *typep++ = 0; /* DST begins */ 1127 *atp++ = endtime; 1128 *typep++ = 1; /* DST ends */ 1129 } 1130 janfirst += year_lengths[isleap(year)] * 1131 SECSPERDAY; 1132 } 1133 } else { 1134 long theirstdoffset; 1135 long theirdstoffset; 1136 long theiroffset; 1137 int isdst; 1138 int i; 1139 int j; 1140 1141 if (*name != '\0') 1142 return -1; 1143 /* 1144 ** Initial values of theirstdoffset and theirdstoffset. 1145 */ 1146 theirstdoffset = 0; 1147 for (i = 0; i < sp->timecnt; ++i) { 1148 j = sp->types[i]; 1149 if (!sp->ttis[j].tt_isdst) { 1150 theirstdoffset = 1151 -sp->ttis[j].tt_gmtoff; 1152 break; 1153 } 1154 } 1155 theirdstoffset = 0; 1156 for (i = 0; i < sp->timecnt; ++i) { 1157 j = sp->types[i]; 1158 if (sp->ttis[j].tt_isdst) { 1159 theirdstoffset = 1160 -sp->ttis[j].tt_gmtoff; 1161 break; 1162 } 1163 } 1164 /* 1165 ** Initially we're assumed to be in standard time. 1166 */ 1167 isdst = FALSE; 1168 theiroffset = theirstdoffset; 1169 /* 1170 ** Now juggle transition times and types 1171 ** tracking offsets as you do. 1172 */ 1173 for (i = 0; i < sp->timecnt; ++i) { 1174 j = sp->types[i]; 1175 sp->types[i] = sp->ttis[j].tt_isdst; 1176 if (sp->ttis[j].tt_ttisgmt) { 1177 /* No adjustment to transition time */ 1178 } else { 1179 /* 1180 ** If summer time is in effect, and the 1181 ** transition time was not specified as 1182 ** standard time, add the summer time 1183 ** offset to the transition time; 1184 ** otherwise, add the standard time 1185 ** offset to the transition time. 1186 */ 1187 /* 1188 ** Transitions from DST to DDST 1189 ** will effectively disappear since 1190 ** POSIX provides for only one DST 1191 ** offset. 1192 */ 1193 if (isdst && !sp->ttis[j].tt_ttisstd) { 1194 sp->ats[i] += dstoffset - 1195 theirdstoffset; 1196 } else { 1197 sp->ats[i] += stdoffset - 1198 theirstdoffset; 1199 } 1200 } 1201 theiroffset = -sp->ttis[j].tt_gmtoff; 1202 if (sp->ttis[j].tt_isdst) 1203 theirdstoffset = theiroffset; 1204 else theirstdoffset = theiroffset; 1205 } 1206 /* 1207 ** Finally, fill in ttis. 1208 ** ttisstd and ttisgmt need not be handled. 1209 */ 1210 sp->ttis[0].tt_gmtoff = -stdoffset; 1211 sp->ttis[0].tt_isdst = FALSE; 1212 sp->ttis[0].tt_abbrind = 0; 1213 sp->ttis[1].tt_gmtoff = -dstoffset; 1214 sp->ttis[1].tt_isdst = TRUE; 1215 sp->ttis[1].tt_abbrind = stdlen + 1; 1216 sp->typecnt = 2; 1217 } 1218 } else { 1219 dstlen = 0; 1220 sp->typecnt = 1; /* only standard time */ 1221 sp->timecnt = 0; 1222 sp->ttis[0].tt_gmtoff = -stdoffset; 1223 sp->ttis[0].tt_isdst = 0; 1224 sp->ttis[0].tt_abbrind = 0; 1225 } 1226 sp->charcnt = stdlen + 1; 1227 if (dstlen != 0) 1228 sp->charcnt += dstlen + 1; 1229 if ((size_t) sp->charcnt > sizeof sp->chars) 1230 return -1; 1231 cp = sp->chars; 1232 (void) strncpy(cp, stdname, stdlen); 1233 cp += stdlen; 1234 *cp++ = '\0'; 1235 if (dstlen != 0) { 1236 (void) strncpy(cp, dstname, dstlen); 1237 *(cp + dstlen) = '\0'; 1238 } 1239 return 0; 1240} 1241 1242static void 1243#ifdef NOTIFY_TZ 1244gmtload(sp, path) 1245#else /* ! NOTIFY_TZ */ 1246gmtload(sp) 1247#endif /* NOTIFY_TZ */ 1248struct state * const sp; 1249#ifdef NOTIFY_TZ 1250char *path; 1251#endif /* NOTIFY_TZ */ 1252{ 1253#ifdef NOTIFY_TZ 1254 if (tzload(gmt, sp, path) != 0) 1255#else /* ! NOTIFY_TZ */ 1256 if (tzload(gmt, sp) != 0) 1257#endif /* NOTIFY_TZ */ 1258 (void) tzparse(gmt, sp, TRUE); 1259} 1260 1261static void 1262tzsetwall_basic(int rdlocked) 1263{ 1264#ifdef NOTIFY_TZ 1265 notify_check_tz(&lcl_notify); 1266#else 1267 if (TZDEFAULT) { 1268 static struct timespec last_mtimespec = {0, 0}; 1269 struct stat statbuf; 1270 1271 if (lstat(TZDEFAULT, &statbuf) == 0) { 1272 if (statbuf.st_mtimespec.tv_sec > last_mtimespec.tv_sec || 1273 (statbuf.st_mtimespec.tv_sec == last_mtimespec.tv_sec && 1274 statbuf.st_mtimespec.tv_nsec > last_mtimespec.tv_nsec)) { 1275 /* Trigger resetting the local TZ */ 1276 lcl_is_set = 0; 1277 } 1278 last_mtimespec = statbuf.st_mtimespec; 1279 } 1280 } 1281#endif /* NOTIFY_TZ */ 1282 if (!rdlocked) 1283 _RWLOCK_RDLOCK(&lcl_rwlock); 1284 if (lcl_is_set < 0) { 1285#ifdef NOTIFY_TZ_DEBUG 1286 NOTIFY_TZ_PRINTF("tzsetwall_basic lcl_is_set < 0\n"); 1287#endif 1288 if (!rdlocked) 1289 _RWLOCK_UNLOCK(&lcl_rwlock); 1290 return; 1291 } 1292#ifdef NOTIFY_TZ_DEBUG 1293 NOTIFY_TZ_PRINTF("tzsetwall_basic not set\n"); 1294#endif 1295 _RWLOCK_UNLOCK(&lcl_rwlock); 1296 1297 _RWLOCK_WRLOCK(&lcl_rwlock); 1298 lcl_is_set = -1; 1299 1300#ifdef ALL_STATE 1301 if (lclptr == NULL) { 1302 lclptr = (struct state *) malloc(sizeof *lclptr); 1303 if (lclptr == NULL) { 1304 settzname(); /* all we can do */ 1305 _RWLOCK_UNLOCK(&lcl_rwlock); 1306 if (rdlocked) 1307 _RWLOCK_RDLOCK(&lcl_rwlock); 1308 return; 1309 } 1310 } 1311#endif /* defined ALL_STATE */ 1312#ifdef NOTIFY_TZ 1313 { 1314 char fullname[FILENAME_MAX + 1]; 1315 if (tzload((char *) NULL, lclptr, fullname) != 0) 1316 /* 1317 * If fullname is empty (an error occurred) then 1318 * default to the UTC path 1319 */ 1320 gmtload(lclptr, *fullname ? NULL : fullname); 1321 notify_register_tz(fullname, &lcl_notify); 1322 } 1323#else /* ! NOTIFY_TZ */ 1324 if (tzload((char *) NULL, lclptr) != 0) 1325 gmtload(lclptr); 1326#endif /* NOTIFY_TZ */ 1327 settzname(); 1328 _RWLOCK_UNLOCK(&lcl_rwlock); 1329 1330 if (rdlocked) 1331 _RWLOCK_RDLOCK(&lcl_rwlock); 1332} 1333 1334void 1335tzsetwall(void) 1336{ 1337#ifdef NOTIFY_TZ_DEBUG 1338 NOTIFY_TZ_PRINTF("tzsetwall called\n"); 1339#endif /* NOTIFY_TZ_DEBUG */ 1340 tzsetwall_basic(0); 1341} 1342 1343__private_extern__ void 1344tzset_basic(int rdlocked) 1345{ 1346 const char * name; 1347 1348 name = getenv("TZ"); 1349 if (name == NULL) { 1350 tzsetwall_basic(rdlocked); 1351 return; 1352 } 1353 1354#ifdef NOTIFY_TZ 1355 notify_check_tz(&lcl_notify); 1356#endif /* NOTIFY_TZ */ 1357 if (!rdlocked) 1358 _RWLOCK_RDLOCK(&lcl_rwlock); 1359 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) { 1360 if (!rdlocked) 1361 _RWLOCK_UNLOCK(&lcl_rwlock); 1362#ifdef NOTIFY_TZ_DEBUG 1363 NOTIFY_TZ_PRINTF("tzset_basic matched %s\n", lcl_TZname); 1364#endif 1365 return; 1366 } 1367 _RWLOCK_UNLOCK(&lcl_rwlock); 1368 1369 _RWLOCK_WRLOCK(&lcl_rwlock); 1370 lcl_is_set = strlen(name) < sizeof lcl_TZname; 1371 if (lcl_is_set) 1372 (void) strcpy(lcl_TZname, name); 1373 1374#ifdef ALL_STATE 1375 if (lclptr == NULL) { 1376 lclptr = (struct state *) malloc(sizeof *lclptr); 1377 if (lclptr == NULL) { 1378 settzname(); /* all we can do */ 1379 _RWLOCK_UNLOCK(&lcl_rwlock); 1380 if (rdlocked) 1381 _RWLOCK_RDLOCK(&lcl_rwlock); 1382 return; 1383 } 1384 } 1385#endif /* defined ALL_STATE */ 1386 if (*name == '\0') { 1387 /* 1388 ** User wants it fast rather than right. 1389 */ 1390 lclptr->leapcnt = 0; /* so, we're off a little */ 1391 lclptr->timecnt = 0; 1392 lclptr->typecnt = 0; 1393 lclptr->ttis[0].tt_isdst = 0; 1394 lclptr->ttis[0].tt_gmtoff = 0; 1395 lclptr->ttis[0].tt_abbrind = 0; 1396 (void) strcpy(lclptr->chars, gmt); 1397#ifdef NOTIFY_TZ 1398 notify_register_tz(NULL, &lcl_notify); 1399#endif /* NOTIFY_TZ */ 1400 } else 1401#ifdef NOTIFY_TZ 1402 { 1403 char fullname[FILENAME_MAX + 1]; 1404 /* 1405 * parsedOK indicates whether tzparse() was called and 1406 * succeeded. This means that TZ is a time conversion 1407 * specification, so we don't need to register for 1408 * notifications. 1409 */ 1410 int parsedOK = FALSE; 1411 if (tzload(name, lclptr, fullname) != 0) 1412 if (name[0] == ':' || !(parsedOK = tzparse(name, lclptr, FALSE) == 0)) 1413 /* 1414 * If fullname is empty (an error occurred) then 1415 * default to the UTC path 1416 */ 1417 (void) gmtload(lclptr, *fullname ? NULL : fullname); 1418 notify_register_tz(parsedOK ? NULL : fullname, &lcl_notify); 1419 } 1420#else /* ! NOTIFY_TZ */ 1421 if (tzload(name, lclptr) != 0) 1422 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 1423 (void) gmtload(lclptr); 1424#endif /* NOTIFY_TZ */ 1425 settzname(); 1426 _RWLOCK_UNLOCK(&lcl_rwlock); 1427 1428 if (rdlocked) 1429 _RWLOCK_RDLOCK(&lcl_rwlock); 1430} 1431 1432void 1433tzset(void) 1434{ 1435#ifdef NOTIFY_TZ_DEBUG 1436 NOTIFY_TZ_PRINTF("tzset called TZ=%s\n", getenv("TZ")); 1437#endif /* NOTIFY_TZ_DEBUG */ 1438 tzset_basic(0); 1439} 1440 1441/* 1442** The easy way to behave "as if no library function calls" localtime 1443** is to not call it--so we drop its guts into "localsub", which can be 1444** freely called. (And no, the PANS doesn't require the above behavior-- 1445** but it *is* desirable.) 1446** 1447** The unused offset argument is for the benefit of mktime variants. 1448*/ 1449 1450/*ARGSUSED*/ 1451#ifdef __LP64__ 1452__private_extern__ struct tm * 1453#else /* !__LP64__ */ 1454__private_extern__ void 1455#endif /* __LP64__ */ 1456localsub(timep, offset, tmp) 1457const time_t * const timep; 1458const long offset; 1459struct tm * const tmp; 1460{ 1461 struct state * sp; 1462 const struct ttinfo * ttisp; 1463 int i; 1464 const time_t t = *timep; 1465 1466#ifdef NOTIFY_TZ_DEBUG 1467 NOTIFY_TZ_PRINTF("localsub called\n"); 1468#endif /* NOTIFY_TZ_DEBUG */ 1469 sp = lclptr; 1470#ifdef ALL_STATE 1471 if (sp == NULL) { 1472#ifdef __LP64__ 1473 return gmtsub(timep, offset, tmp); 1474#else /* !__LP64__ */ 1475 gmtsub(timep, offset, tmp); 1476 return; 1477#endif /* __LP64__ */ 1478 } 1479#endif /* defined ALL_STATE */ 1480 if (sp->timecnt == 0 || t < sp->ats[0]) { 1481 i = 0; 1482 while (sp->ttis[i].tt_isdst) 1483 if (++i >= sp->typecnt) { 1484 i = 0; 1485 break; 1486 } 1487 } else { 1488 for (i = 1; i < sp->timecnt; ++i) 1489 if (t < sp->ats[i]) 1490 break; 1491 i = sp->types[i - 1]; 1492 } 1493 ttisp = &sp->ttis[i]; 1494 /* 1495 ** To get (wrong) behavior that's compatible with System V Release 2.0 1496 ** you'd replace the statement below with 1497 ** t += ttisp->tt_gmtoff; 1498 ** timesub(&t, 0L, sp, tmp); 1499 */ 1500#ifdef __LP64__ 1501 if (timesub(&t, ttisp->tt_gmtoff, sp, tmp) == NULL) 1502 return NULL; 1503#else /* !__LP64__ */ 1504 timesub(&t, ttisp->tt_gmtoff, sp, tmp); 1505#endif /* __LP64__ */ 1506 tmp->tm_isdst = ttisp->tt_isdst; 1507 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; 1508#ifdef TM_ZONE 1509 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; 1510#endif /* defined TM_ZONE */ 1511#ifdef __LP64__ 1512 return tmp; 1513#endif /* __LP64__ */ 1514} 1515 1516struct tm * 1517localtime(timep) 1518const time_t * const timep; 1519{ 1520 static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER; 1521 static pthread_key_t localtime_key = -1; 1522 struct tm *p_tm; 1523 1524 if (__isthreaded != 0) { 1525 if (localtime_key == (pthread_key_t)-1) { 1526 _pthread_mutex_lock(&localtime_mutex); 1527 if (localtime_key == (pthread_key_t)-1) { 1528 localtime_key = __LIBC_PTHREAD_KEY_LOCALTIME; 1529 if (pthread_key_init_np(localtime_key, free) < 0) { 1530 _pthread_mutex_unlock(&localtime_mutex); 1531 return(NULL); 1532 } 1533 } 1534 _pthread_mutex_unlock(&localtime_mutex); 1535 } 1536 p_tm = _pthread_getspecific(localtime_key); 1537 if (p_tm == NULL) { 1538 if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) 1539 == NULL) 1540 return(NULL); 1541 _pthread_setspecific(localtime_key, p_tm); 1542 } 1543 _RWLOCK_RDLOCK(&lcl_rwlock); 1544 tzset_basic(1); 1545#ifdef __LP64__ 1546 p_tm = localsub(timep, 0L, p_tm); 1547#else /* !__LP64__ */ 1548 localsub(timep, 0L, p_tm); 1549#endif /* __LP64__ */ 1550 _RWLOCK_UNLOCK(&lcl_rwlock); 1551 return(p_tm); 1552 } else { 1553 tzset_basic(0); 1554#ifdef __LP64__ 1555 return localsub(timep, 0L, &tm); 1556#else /* !__LP64__ */ 1557 localsub(timep, 0L, &tm); 1558 return(&tm); 1559#endif /* __LP64__ */ 1560 } 1561} 1562 1563/* 1564** Re-entrant version of localtime. 1565*/ 1566 1567struct tm * 1568localtime_r(const time_t * const __restrict timep, struct tm * __restrict tm) 1569{ 1570 _RWLOCK_RDLOCK(&lcl_rwlock); 1571 tzset_basic(1); 1572#ifdef __LP64__ 1573 tm = localsub(timep, 0L, tm); 1574#else /* !__LP64__ */ 1575 localsub(timep, 0L, tm); 1576#endif /* __LP64__ */ 1577 _RWLOCK_UNLOCK(&lcl_rwlock); 1578 return tm; 1579} 1580 1581/* 1582** gmtsub is to gmtime as localsub is to localtime. 1583*/ 1584 1585#ifdef __LP64__ 1586static struct tm * 1587#else /* !__LP64__ */ 1588static void 1589#endif /* __LP64__ */ 1590gmtsub(timep, offset, tmp) 1591const time_t * const timep; 1592const long offset; 1593struct tm * const tmp; 1594{ 1595#ifdef NOTIFY_TZ_DEBUG 1596 NOTIFY_TZ_PRINTF("gmtsub called\n"); 1597#endif /* NOTIFY_TZ_DEBUG */ 1598#ifdef NOTIFY_TZ 1599 notify_check_tz(&gmt_notify); 1600#endif /* NOTIFY_TZ */ 1601 if (!gmt_is_set) { 1602 _MUTEX_LOCK(&gmt_mutex); 1603 if (!gmt_is_set) { 1604#ifdef ALL_STATE 1605#ifdef NOTIFY_TZ 1606 if (gmtptr == NULL) 1607#endif /* NOTIFY_TZ */ 1608 gmtptr = (struct state *) malloc(sizeof *gmtptr); 1609 if (gmtptr != NULL) 1610#endif /* defined ALL_STATE */ 1611#ifdef NOTIFY_TZ 1612 { 1613 char fullname[FILENAME_MAX + 1]; 1614 gmtload(gmtptr, fullname); 1615 notify_register_tz(fullname, &gmt_notify); 1616 } 1617#else /* ! NOTIFY_TZ */ 1618 gmtload(gmtptr); 1619#endif /* NOTIFY_TZ */ 1620 gmt_is_set = TRUE; 1621 } 1622 _MUTEX_UNLOCK(&gmt_mutex); 1623 } 1624#ifdef __LP64__ 1625 if(timesub(timep, offset, gmtptr, tmp) == NULL) 1626 return NULL; 1627#else /* !__LP64__ */ 1628 timesub(timep, offset, gmtptr, tmp); 1629#endif /* __LP64__ */ 1630#ifdef TM_ZONE 1631 /* 1632 ** Could get fancy here and deliver something such as 1633 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, 1634 ** but this is no time for a treasure hunt. 1635 */ 1636 if (offset != 0) 1637 tmp->TM_ZONE = wildabbr; 1638 else { 1639#ifdef ALL_STATE 1640 if (gmtptr == NULL) 1641 tmp->TM_ZONE = (char *)gmt; 1642 else tmp->TM_ZONE = gmtptr->chars; 1643#endif /* defined ALL_STATE */ 1644#ifndef ALL_STATE 1645 tmp->TM_ZONE = gmtptr->chars; 1646#endif /* State Farm */ 1647 } 1648#endif /* defined TM_ZONE */ 1649#ifdef __LP64__ 1650 return tmp; 1651#endif /* __LP64__ */ 1652} 1653 1654struct tm * 1655gmtime(timep) 1656const time_t * const timep; 1657{ 1658 static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER; 1659 static pthread_key_t gmtime_key = -1; 1660 struct tm *p_tm; 1661 1662 if (__isthreaded != 0) { 1663 if (gmtime_key == (pthread_key_t)-1) { 1664 _pthread_mutex_lock(&gmtime_mutex); 1665 if (gmtime_key == (pthread_key_t)-1) { 1666 gmtime_key = __LIBC_PTHREAD_KEY_GMTIME; 1667 if (pthread_key_init_np(gmtime_key, free) < 0) { 1668 _pthread_mutex_unlock(&gmtime_mutex); 1669 return(NULL); 1670 } 1671 } 1672 _pthread_mutex_unlock(&gmtime_mutex); 1673 } 1674 /* 1675 * Changed to follow POSIX.1 threads standard, which 1676 * is what BSD currently has. 1677 */ 1678 if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) { 1679 if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) 1680 == NULL) { 1681 return(NULL); 1682 } 1683 _pthread_setspecific(gmtime_key, p_tm); 1684 } 1685#ifdef __LP64__ 1686 return gmtsub(timep, 0L, p_tm); 1687#else /* !__LP64__ */ 1688 gmtsub(timep, 0L, p_tm); 1689 return(p_tm); 1690#endif /* __LP64__ */ 1691 } 1692 else { 1693#ifdef __LP64__ 1694 return gmtsub(timep, 0L, &tm); 1695#else /* !__LP64__ */ 1696 gmtsub(timep, 0L, &tm); 1697 return(&tm); 1698#endif /* __LP64__ */ 1699 } 1700} 1701 1702/* 1703* Re-entrant version of gmtime. 1704*/ 1705 1706struct tm * 1707gmtime_r(timep, tm) 1708const time_t * const timep; 1709struct tm * tm; 1710{ 1711 1712#ifdef __LP64__ 1713 return gmtsub(timep, 0L, tm); 1714#else /* !__LP64__ */ 1715 gmtsub(timep, 0L, tm); 1716 return tm; 1717#endif /* __LP64__ */ 1718} 1719 1720#ifdef STD_INSPIRED 1721 1722struct tm * 1723offtime(timep, offset) 1724const time_t * const timep; 1725const long offset; 1726{ 1727#ifdef __LP64__ 1728 return gmtsub(timep, offset, &tm); 1729#else /* !__LP64__ */ 1730 gmtsub(timep, offset, &tm); 1731 return &tm; 1732#endif /* __LP64__ */ 1733} 1734 1735#endif /* defined STD_INSPIRED */ 1736 1737#ifdef __LP64__ 1738static struct tm * 1739#else /* !__LP64__ */ 1740static void 1741#endif /* __LP64__ */ 1742timesub(timep, offset, sp, tmp) 1743const time_t * const timep; 1744const long offset; 1745const struct state * const sp; 1746struct tm * const tmp; 1747{ 1748 const struct lsinfo * lp; 1749 long days; 1750 long rem; 1751 long y; 1752 int yleap; 1753 const int * ip; 1754 long corr; 1755 int hit; 1756 int i; 1757 1758 corr = 0; 1759 hit = 0; 1760#ifdef ALL_STATE 1761 i = (sp == NULL) ? 0 : sp->leapcnt; 1762#endif /* defined ALL_STATE */ 1763#ifndef ALL_STATE 1764 i = sp->leapcnt; 1765#endif /* State Farm */ 1766 while (--i >= 0) { 1767 lp = &sp->lsis[i]; 1768 if (*timep >= lp->ls_trans) { 1769 if (*timep == lp->ls_trans) { 1770 hit = ((i == 0 && lp->ls_corr > 0) || 1771 lp->ls_corr > sp->lsis[i - 1].ls_corr); 1772 if (hit) 1773 while (i > 0 && 1774 sp->lsis[i].ls_trans == 1775 sp->lsis[i - 1].ls_trans + 1 && 1776 sp->lsis[i].ls_corr == 1777 sp->lsis[i - 1].ls_corr + 1) { 1778 ++hit; 1779 --i; 1780 } 1781 } 1782 corr = lp->ls_corr; 1783 break; 1784 } 1785 } 1786 days = *timep / SECSPERDAY; 1787 rem = *timep % SECSPERDAY; 1788#ifdef mc68k 1789 if (*timep == 0x80000000) { 1790 /* 1791 ** A 3B1 muffs the division on the most negative number. 1792 */ 1793 days = -24855; 1794 rem = -11648; 1795 } 1796#endif /* defined mc68k */ 1797 rem += (offset - corr); 1798 while (rem < 0) { 1799 rem += SECSPERDAY; 1800 --days; 1801 } 1802 while (rem >= SECSPERDAY) { 1803 rem -= SECSPERDAY; 1804 ++days; 1805 } 1806 tmp->tm_hour = (int) (rem / SECSPERHOUR); 1807 rem = rem % SECSPERHOUR; 1808 tmp->tm_min = (int) (rem / SECSPERMIN); 1809 /* 1810 ** A positive leap second requires a special 1811 ** representation. This uses "... ??:59:60" et seq. 1812 */ 1813 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; 1814 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); 1815 if (tmp->tm_wday < 0) 1816 tmp->tm_wday += DAYSPERWEEK; 1817 y = EPOCH_YEAR; 1818#define _LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) 1819#ifdef __LP64__ 1820#define LEAPS_THRU_END_OF(y) ((y) >= 0 ? _LEAPS_THRU_END_OF(y) : _LEAPS_THRU_END_OF((y) + 1) - 1) 1821#else /* !__LP64__ */ 1822#define LEAPS_THRU_END_OF(y) _LEAPS_THRU_END_OF(y) 1823#endif /* __LP64__ */ 1824 while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { 1825 long newy; 1826 1827 newy = y + days / DAYSPERNYEAR; 1828 if (days < 0) 1829 --newy; 1830 days -= (newy - y) * DAYSPERNYEAR + 1831 LEAPS_THRU_END_OF(newy - 1) - 1832 LEAPS_THRU_END_OF(y - 1); 1833 y = newy; 1834 } 1835#ifdef __LP64__ 1836 y -= TM_YEAR_BASE; 1837 if (y < INT_MIN || y > INT_MAX) { 1838 errno = EOVERFLOW; 1839 return NULL; 1840 } 1841 tmp->tm_year = y; 1842#else /* !__LP64__ */ 1843 tmp->tm_year = y - TM_YEAR_BASE; 1844#endif /* __LP64__ */ 1845 tmp->tm_yday = (int) days; 1846 ip = mon_lengths[yleap]; 1847 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 1848 days = days - (long) ip[tmp->tm_mon]; 1849 tmp->tm_mday = (int) (days + 1); 1850 tmp->tm_isdst = 0; 1851#ifdef TM_GMTOFF 1852 tmp->TM_GMTOFF = offset; 1853#endif /* defined TM_GMTOFF */ 1854#ifdef __LP64__ 1855 return tmp; 1856#endif /* __LP64__ */ 1857} 1858 1859char * 1860ctime(timep) 1861const time_t * const timep; 1862{ 1863/* 1864** Section 4.12.3.2 of X3.159-1989 requires that 1865** The ctime function converts the calendar time pointed to by timer 1866** to local time in the form of a string. It is equivalent to 1867** asctime(localtime(timer)) 1868*/ 1869#ifdef __LP64__ 1870 /* 1871 * In 64-bit, the timep value may produce a time value with a year 1872 * that exceeds 32-bits in size (won't fit in struct tm), so localtime 1873 * will return NULL. 1874 */ 1875 struct tm *tm = localtime(timep); 1876 1877 if (tm == NULL) 1878 return NULL; 1879 return asctime(tm); 1880#else /* !__LP64__ */ 1881 return asctime(localtime(timep)); 1882#endif /* __LP64__ */ 1883} 1884 1885char * 1886ctime_r(timep, buf) 1887const time_t * const timep; 1888char * buf; 1889{ 1890 struct tm tm; 1891 1892#ifdef __LP64__ 1893 /* 1894 * In 64-bit, the timep value may produce a time value with a year 1895 * that exceeds 32-bits in size (won't fit in struct tm), so localtime_r 1896 * will return NULL. 1897 */ 1898 if (localtime_r(timep, &tm) == NULL) 1899 return NULL; 1900 return asctime_r(&tm, buf); 1901#else /* !__LP64__ */ 1902 return asctime_r(localtime_r(timep, &tm), buf); 1903#endif /* __LP64__ */ 1904} 1905 1906/* 1907** Adapted from code provided by Robert Elz, who writes: 1908** The "best" way to do mktime I think is based on an idea of Bob 1909** Kridle's (so its said...) from a long time ago. 1910** [kridle@xinet.com as of 1996-01-16.] 1911** It does a binary search of the time_t space. Since time_t's are 1912** just 32 bits, its a max of 32 iterations (even at 64 bits it 1913** would still be very reasonable). 1914*/ 1915 1916#ifndef WRONG 1917#define WRONG (-1) 1918#endif /* !defined WRONG */ 1919 1920/* 1921** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com). 1922*/ 1923 1924static int 1925increment_overflow(number, delta) 1926int * number; 1927int delta; 1928{ 1929 int number0; 1930 1931 number0 = *number; 1932 *number += delta; 1933 return (*number < number0) != (delta < 0); 1934} 1935 1936static int 1937normalize_overflow(tensptr, unitsptr, base) 1938int * const tensptr; 1939int * const unitsptr; 1940const int base; 1941{ 1942 int tensdelta; 1943 1944 tensdelta = (*unitsptr >= 0) ? 1945 (*unitsptr / base) : 1946 (-1 - (-1 - *unitsptr) / base); 1947 *unitsptr -= tensdelta * base; 1948 return increment_overflow(tensptr, tensdelta); 1949} 1950 1951static int 1952tmcomp(atmp, btmp) 1953const struct tm * const atmp; 1954const struct tm * const btmp; 1955{ 1956 int result; 1957 1958 /* 1959 * Assume that atmp and btmp point to normalized tm strutures. 1960 * So only arithmetic with tm_year could overflow in 64-bit. 1961 */ 1962 if (atmp->tm_year != btmp->tm_year) { 1963 return (atmp->tm_year > btmp->tm_year ? 1 : -1); 1964 } 1965 if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 1966 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 1967 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 1968 (result = (atmp->tm_min - btmp->tm_min)) == 0) 1969 result = atmp->tm_sec - btmp->tm_sec; 1970 return result; 1971} 1972 1973static time_t 1974time2sub(tmp, funcp, offset, okayp, do_norm_secs, unix03) 1975struct tm * const tmp; 1976#ifdef __LP64__ 1977struct tm *(* const funcp)(const time_t*, long, struct tm*); 1978#else /* !__LP64__ */ 1979void (* const funcp)(const time_t*, long, struct tm*); 1980#endif /* __LP64__ */ 1981const long offset; 1982int * const okayp; 1983const int do_norm_secs; 1984int unix03; 1985{ 1986 const struct state * sp; 1987 int dir; 1988 int bits; 1989 int i, j ; 1990 int saved_seconds; 1991 time_t newt; 1992 time_t t; 1993 struct tm yourtm, mytm; 1994#ifdef __LP64__ 1995 long year, il; 1996#endif /* __LP64__ */ 1997 1998 *okayp = FALSE; 1999 yourtm = *tmp; 2000 if (do_norm_secs) { 2001 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, 2002 SECSPERMIN)) 2003 return WRONG; 2004 } 2005 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) 2006 return WRONG; 2007 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) 2008 return WRONG; 2009 if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) 2010 return WRONG; 2011 /* 2012 ** Turn yourtm.tm_year into an actual year number for now. 2013 ** It is converted back to an offset from TM_YEAR_BASE later. 2014 */ 2015#ifdef __LP64__ 2016 year = (long)yourtm.tm_year + TM_YEAR_BASE; 2017#else /* !__LP64__ */ 2018 if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) 2019 return WRONG; 2020#endif /* __LP64__ */ 2021 while (yourtm.tm_mday <= 0) { 2022#ifdef __LP64__ 2023 year--; 2024 il = year + (1 < yourtm.tm_mon); 2025 yourtm.tm_mday += year_lengths[isleap(il)]; 2026#else /* !__LP64__ */ 2027 if (increment_overflow(&yourtm.tm_year, -1)) 2028 return WRONG; 2029 i = yourtm.tm_year + (1 < yourtm.tm_mon); 2030 yourtm.tm_mday += year_lengths[isleap(i)]; 2031#endif /* __LP64__ */ 2032 } 2033 while (yourtm.tm_mday > DAYSPERLYEAR) { 2034#ifdef __LP64__ 2035 il = year + (1 < yourtm.tm_mon); 2036 yourtm.tm_mday -= year_lengths[isleap(il)]; 2037 year++; 2038#else /* !__LP64__ */ 2039 i = yourtm.tm_year + (1 < yourtm.tm_mon); 2040 yourtm.tm_mday -= year_lengths[isleap(i)]; 2041 if (increment_overflow(&yourtm.tm_year, 1)) 2042 return WRONG; 2043#endif /* __LP64__ */ 2044 } 2045 for ( ; ; ) { 2046#ifdef __LP64__ 2047 i = mon_lengths[isleap(year)][yourtm.tm_mon]; 2048#else /* !__LP64__ */ 2049 i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; 2050#endif /* __LP64__ */ 2051 if (yourtm.tm_mday <= i) 2052 break; 2053 yourtm.tm_mday -= i; 2054 if (++yourtm.tm_mon >= MONSPERYEAR) { 2055 yourtm.tm_mon = 0; 2056#ifdef __LP64__ 2057 year++; 2058#else /* !__LP64__ */ 2059 if (increment_overflow(&yourtm.tm_year, 1)) 2060 return WRONG; 2061#endif /* __LP64__ */ 2062 } 2063 } 2064#ifdef __LP64__ 2065 year -= TM_YEAR_BASE; 2066 if (year > INT_MAX || year < INT_MIN) 2067 return WRONG; 2068 yourtm.tm_year = year; 2069#else /* !__LP64__ */ 2070 if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) 2071 return WRONG; 2072#endif /* __LP64__ */ 2073 /* Don't go below 1900 for POLA */ 2074 if (yourtm.tm_year < 0) 2075 return WRONG; 2076 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) 2077 saved_seconds = 0; 2078 else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { 2079 /* 2080 ** We can't set tm_sec to 0, because that might push the 2081 ** time below the minimum representable time. 2082 ** Set tm_sec to 59 instead. 2083 ** This assumes that the minimum representable time is 2084 ** not in the same minute that a leap second was deleted from, 2085 ** which is a safer assumption than using 58 would be. 2086 */ 2087 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) 2088 return WRONG; 2089 saved_seconds = yourtm.tm_sec; 2090 yourtm.tm_sec = SECSPERMIN - 1; 2091 } else { 2092 saved_seconds = yourtm.tm_sec; 2093 yourtm.tm_sec = 0; 2094 } 2095 /* 2096 ** Divide the search space in half 2097 ** (this works whether time_t is signed or unsigned). 2098 */ 2099#ifdef __LP64__ 2100 /* optimization: see if the value is 31-bit (signed) */ 2101 t = (((time_t) 1) << (TYPE_BIT(int) - 1)) - 1; 2102 bits = ((*funcp)(&t, offset, &mytm) == NULL || tmcomp(&mytm, &yourtm) < 0) ? TYPE_BIT(time_t) - 1 : TYPE_BIT(int) - 1; 2103#else /* !__LP64__ */ 2104 bits = TYPE_BIT(time_t) - 1; 2105#endif /* __LP64__ */ 2106 /* 2107 ** In 64-bit, we now return an error if we cannot represent the 2108 ** struct tm value in a time_t. And tmcomp() is fixed to avoid 2109 ** overflow in tm_year. So we only put a cap on bits because time_t 2110 ** can't be larger that 56 bit (when tm_year == INT_MAX). 2111 */ 2112 if (bits > 56) 2113 bits = 56; 2114 /* 2115 ** If time_t is signed, then 0 is just above the median, 2116 ** assuming two's complement arithmetic. 2117 ** If time_t is unsigned, then (1 << bits) is just above the median. 2118 */ 2119 t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); 2120 for ( ; ; ) { 2121#ifdef __LP64__ 2122 if ((*funcp)(&t, offset, &mytm) == NULL) { 2123 /* we overflowed, so t is too big */ 2124 dir = 1; 2125 goto skip_tmcomp; 2126 } 2127#else /* !__LP64__ */ 2128 (*funcp)(&t, offset, &mytm); 2129#endif /* __LP64__ */ 2130 dir = tmcomp(&mytm, &yourtm); 2131#ifdef __LP64__ 2132skip_tmcomp: 2133#endif /* __LP64__ */ 2134 if (dir != 0) { 2135 if (bits-- < 0) 2136 return WRONG; 2137 if (bits < 0) 2138 --t; /* may be needed if new t is minimal */ 2139 else if (dir > 0) 2140 t -= ((time_t) 1) << bits; 2141 else t += ((time_t) 1) << bits; 2142 continue; 2143 } 2144 sp = (funcp == localsub) ? lclptr : gmtptr; 2145 if (unix03 && sp->typecnt == 1 && yourtm.tm_isdst > 0) 2146 yourtm.tm_isdst = 0; /* alternative time does not apply */ 2147 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 2148 break; 2149 /* 2150 ** Right time, wrong type. 2151 ** Hunt for right time, right type. 2152 ** It's okay to guess wrong since the guess 2153 ** gets checked. 2154 */ 2155#ifdef ALL_STATE 2156 if (sp == NULL) 2157 return WRONG; 2158#endif /* defined ALL_STATE */ 2159 for (i = sp->typecnt - 1; i >= 0; --i) { 2160 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 2161 continue; 2162 for (j = sp->typecnt - 1; j >= 0; --j) { 2163 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 2164 continue; 2165 newt = t + sp->ttis[j].tt_gmtoff - 2166 sp->ttis[i].tt_gmtoff; 2167#ifdef __LP64__ 2168 if ((*funcp)(&newt, offset, &mytm) == NULL) 2169 return WRONG; 2170#else /* !__LP64__ */ 2171 (*funcp)(&newt, offset, &mytm); 2172#endif /* __LP64__ */ 2173 if (tmcomp(&mytm, &yourtm) != 0) 2174 continue; 2175 if (mytm.tm_isdst != yourtm.tm_isdst) 2176 continue; 2177 /* 2178 ** We have a match. 2179 */ 2180 t = newt; 2181 goto label; 2182 } 2183 } 2184 return WRONG; 2185 } 2186label: 2187 newt = t + saved_seconds; 2188 if ((newt < t) != (saved_seconds < 0)) 2189 return WRONG; 2190 t = newt; 2191#ifdef __LP64__ 2192 if ((*funcp)(&t, offset, tmp) == NULL) 2193 return WRONG; 2194#else /* !__LP64__ */ 2195 (*funcp)(&t, offset, tmp); 2196#endif /* __LP64__ */ 2197 *okayp = TRUE; 2198 return t; 2199} 2200 2201static time_t 2202time2(tmp, funcp, offset, okayp, unix03) 2203struct tm * const tmp; 2204#ifdef __LP64__ 2205struct tm *(* const funcp)(const time_t*, long, struct tm*); 2206#else /* !__LP64__ */ 2207void (* const funcp)(const time_t*, long, struct tm*); 2208#endif /* __LP64__ */ 2209const long offset; 2210int * const okayp; 2211int unix03; 2212{ 2213 time_t t; 2214 2215 /* 2216 ** First try without normalization of seconds 2217 ** (in case tm_sec contains a value associated with a leap second). 2218 ** If that fails, try with normalization of seconds. 2219 */ 2220 t = time2sub(tmp, funcp, offset, okayp, FALSE, unix03); 2221 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, unix03); 2222} 2223 2224__private_extern__ time_t 2225time1(tmp, funcp, offset, unix03) 2226struct tm * const tmp; 2227#ifdef __LP64__ 2228struct tm *(* const funcp)(const time_t *, long, struct tm *); 2229#else /* !__LP64__ */ 2230void (* const funcp)(const time_t *, long, struct tm *); 2231#endif /* __LP64__ */ 2232const long offset; 2233int unix03; 2234{ 2235 time_t t; 2236 const struct state * sp; 2237 int samei, otheri; 2238 int sameind, otherind; 2239 int i; 2240 int nseen; 2241 int seen[TZ_MAX_TYPES]; 2242 int types[TZ_MAX_TYPES]; 2243 int okay; 2244 2245 if (tmp->tm_isdst > 1) 2246 tmp->tm_isdst = 1; 2247 t = time2(tmp, funcp, offset, &okay, unix03); 2248#ifdef PCTS 2249 /* 2250 ** PCTS code courtesy Grant Sullivan (grant@osf.org). 2251 */ 2252 if (okay) 2253 return t; 2254 if (tmp->tm_isdst < 0) 2255 tmp->tm_isdst = 0; /* reset to std and try again */ 2256#endif /* defined PCTS */ 2257#ifndef PCTS 2258 if (okay || tmp->tm_isdst < 0) 2259 return t; 2260#endif /* !defined PCTS */ 2261 /* 2262 ** We're supposed to assume that somebody took a time of one type 2263 ** and did some math on it that yielded a "struct tm" that's bad. 2264 ** We try to divine the type they started from and adjust to the 2265 ** type they need. 2266 */ 2267 sp = (funcp == localsub) ? lclptr : gmtptr; 2268#ifdef ALL_STATE 2269 if (sp == NULL) 2270 return WRONG; 2271#endif /* defined ALL_STATE */ 2272 for (i = 0; i < sp->typecnt; ++i) 2273 seen[i] = FALSE; 2274 nseen = 0; 2275 for (i = sp->timecnt - 1; i >= 0; --i) 2276 if (!seen[sp->types[i]]) { 2277 seen[sp->types[i]] = TRUE; 2278 types[nseen++] = sp->types[i]; 2279 } 2280 for (sameind = 0; sameind < nseen; ++sameind) { 2281 samei = types[sameind]; 2282 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 2283 continue; 2284 for (otherind = 0; otherind < nseen; ++otherind) { 2285 otheri = types[otherind]; 2286 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 2287 continue; 2288 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 2289 sp->ttis[samei].tt_gmtoff; 2290 tmp->tm_isdst = !tmp->tm_isdst; 2291 t = time2(tmp, funcp, offset, &okay, unix03); 2292 if (okay) 2293 return t; 2294 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 2295 sp->ttis[samei].tt_gmtoff; 2296 tmp->tm_isdst = !tmp->tm_isdst; 2297 } 2298 } 2299 return WRONG; 2300} 2301#else /* BUILDING_VARIANT */ 2302__private_extern__ pthread_rwlock_t lcl_rwlock; 2303#endif /* BUILDING_VARIANT */ 2304 2305time_t 2306mktime(tmp) 2307struct tm * const tmp; 2308{ 2309 time_t mktime_return_value; 2310 int serrno = errno; 2311 _RWLOCK_RDLOCK(&lcl_rwlock); 2312 tzset_basic(1); 2313 mktime_return_value = time1(tmp, localsub, 0L, __DARWIN_UNIX03); 2314 _RWLOCK_UNLOCK(&lcl_rwlock); 2315 errno = serrno; 2316 return(mktime_return_value); 2317} 2318 2319#if !BUILDING_VARIANT 2320#ifdef STD_INSPIRED 2321 2322time_t 2323timelocal(tmp) 2324struct tm * const tmp; 2325{ 2326 tmp->tm_isdst = -1; /* in case it wasn't initialized */ 2327 return mktime(tmp); 2328} 2329 2330time_t 2331timegm(tmp) 2332struct tm * const tmp; 2333{ 2334 tmp->tm_isdst = 0; 2335 return time1(tmp, gmtsub, 0L, __DARWIN_UNIX03); 2336} 2337 2338time_t 2339timeoff(tmp, offset) 2340struct tm * const tmp; 2341const long offset; 2342{ 2343 tmp->tm_isdst = 0; 2344 return time1(tmp, gmtsub, offset, __DARWIN_UNIX03); 2345} 2346 2347#endif /* defined STD_INSPIRED */ 2348 2349#ifdef CMUCS 2350 2351/* 2352** The following is supplied for compatibility with 2353** previous versions of the CMUCS runtime library. 2354*/ 2355 2356long 2357gtime(tmp) 2358struct tm * const tmp; 2359{ 2360 const time_t t = mktime(tmp); 2361 2362 if (t == WRONG) 2363 return -1; 2364 return t; 2365} 2366 2367#endif /* defined CMUCS */ 2368 2369/* 2370** XXX--is the below the right way to conditionalize?? 2371*/ 2372 2373#ifdef STD_INSPIRED 2374 2375/* 2376** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 2377** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which 2378** is not the case if we are accounting for leap seconds. 2379** So, we provide the following conversion routines for use 2380** when exchanging timestamps with POSIX conforming systems. 2381*/ 2382 2383static long 2384leapcorr(timep) 2385time_t * timep; 2386{ 2387 struct state * sp; 2388 struct lsinfo * lp; 2389 int i; 2390 2391 sp = lclptr; 2392 i = sp->leapcnt; 2393 while (--i >= 0) { 2394 lp = &sp->lsis[i]; 2395 if (*timep >= lp->ls_trans) 2396 return lp->ls_corr; 2397 } 2398 return 0; 2399} 2400 2401time_t 2402time2posix(t) 2403time_t t; 2404{ 2405 tzset(); 2406 return t - leapcorr(&t); 2407} 2408 2409time_t 2410posix2time(t) 2411time_t t; 2412{ 2413 time_t x; 2414 time_t y; 2415 2416 tzset(); 2417 /* 2418 ** For a positive leap second hit, the result 2419 ** is not unique. For a negative leap second 2420 ** hit, the corresponding time doesn't exist, 2421 ** so we return an adjacent second. 2422 */ 2423 x = t + leapcorr(&t); 2424 y = x - leapcorr(&x); 2425 if (y < t) { 2426 do { 2427 x++; 2428 y = x - leapcorr(&x); 2429 } while (y < t); 2430 if (t != y) 2431 return x - 1; 2432 } else if (y > t) { 2433 do { 2434 --x; 2435 y = x - leapcorr(&x); 2436 } while (y > t); 2437 if (t != y) 2438 return x + 1; 2439 } 2440 return x; 2441} 2442 2443#endif /* defined STD_INSPIRED */ 2444#endif /* !BUILDING_VARIANT */ 2445