1 /* $OpenBSD: zic.c,v 1.22 2016/03/15 19:50:47 millert Exp $ */ 2 /* 3 ** This file is in the public domain, so clarified as of 4 ** 2006-07-17 by Arthur David Olson. 5 */ 6 7 #include <sys/types.h> 8 #include <sys/wait.h> 9 #include <sys/stat.h> 10 #include <ctype.h> 11 #include <err.h> 12 #include <errno.h> 13 #include <limits.h> 14 #include <locale.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <stdint.h> 19 #include <unistd.h> 20 #include <time.h> 21 22 #include "tzfile.h" 23 24 #define TRUE 1 25 #define FALSE 0 26 27 #define TYPE_SIGNED(type) (((type) -1) < 0) 28 29 #define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ 30 31 #define GRANDPARENTED "Local time zone must be set--see zic manual page" 32 33 #define ZIC_VERSION '2' 34 35 typedef int_fast64_t zic_t; 36 37 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN 38 #define ZIC_MAX_ABBR_LEN_WO_WARN 6 39 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ 40 41 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 42 43 #define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long)) 44 #define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */ 45 46 #define end(cp, n) (memchr((cp), '\0', (n))) 47 48 struct rule { 49 const char *r_filename; 50 int r_linenum; 51 const char *r_name; 52 53 int r_loyear; /* for example, 1986 */ 54 int r_hiyear; /* for example, 1986 */ 55 const char *r_yrtype; 56 int r_lowasnum; 57 int r_hiwasnum; 58 59 int r_month; /* 0..11 */ 60 61 int r_dycode; /* see below */ 62 int r_dayofmonth; 63 int r_wday; 64 65 long r_tod; /* time from midnight */ 66 int r_todisstd; /* above is standard time if TRUE */ 67 /* or wall clock time if FALSE */ 68 int r_todisgmt; /* above is GMT if TRUE */ 69 /* or local time if FALSE */ 70 long r_stdoff; /* offset from standard time */ 71 const char *r_abbrvar; /* variable part of abbreviation */ 72 73 int r_todo; /* a rule to do (used in outzone) */ 74 zic_t r_temp; /* used in outzone */ 75 }; 76 77 /* 78 ** r_dycode r_dayofmonth r_wday 79 */ 80 81 #define DC_DOM 0 /* 1..31 */ /* unused */ 82 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 83 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 84 85 struct zone { 86 const char *z_filename; 87 int z_linenum; 88 89 const char *z_name; 90 long z_gmtoff; 91 const char *z_rule; 92 const char *z_format; 93 94 long z_stdoff; 95 96 struct rule *z_rules; 97 int z_nrules; 98 99 struct rule z_untilrule; 100 zic_t z_untiltime; 101 }; 102 103 static void addtt(zic_t starttime, int type); 104 static int addtype(long gmtoff, const char *abbr, int isdst, 105 int ttisstd, int ttisgmt); 106 static void leapadd(zic_t t, int positive, int rolling, int count); 107 static void adjleap(void); 108 static void associate(void); 109 static void convert(long val, char *buf); 110 static void convert64(zic_t val, char *buf); 111 static void dolink(const char *fromfield, const char *tofield); 112 static void doabbr(char *abbr, size_t size, const char *format, 113 const char *letters, int isdst, int doquotes); 114 static void eat(const char *name, int num); 115 static void eats(const char *name, int num, const char *rname, int rnum); 116 static long eitol(int i); 117 static void error(const char *message); 118 static char **getfields(char *buf); 119 static long gethms(const char *string, const char *errstrng, int signable); 120 static void infile(const char *filename); 121 static void inleap(char **fields, int nfields); 122 static void inlink(char **fields, int nfields); 123 static void inrule(char **fields, int nfields); 124 static int inzcont(char **fields, int nfields); 125 static int inzone(char **fields, int nfields); 126 static int inzsub(char **fields, int nfields, int iscont); 127 static int is32(zic_t x); 128 static int itsabbr(const char *abbr, const char *word); 129 static int itsdir(const char *name); 130 static int mkdirs(char *filename); 131 static void newabbr(const char *abbr); 132 static long oadd(long t1, long t2); 133 static void outzone(const struct zone *zp, int ntzones); 134 static void puttzcode(long code, FILE *fp); 135 static void puttzcode64(zic_t code, FILE *fp); 136 static int rcomp(const void *leftp, const void *rightp); 137 static zic_t rpytime(const struct rule *rp, int wantedy); 138 static void rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, 139 const char *typep, const char *monthp, 140 const char *dayp, const char *timep); 141 static int stringoffset(char *result, size_t size, long offset); 142 static int stringrule(char *result, size_t size, const struct rule *rp, 143 long dstoff, long gmtoff); 144 static void stringzone(char *result, size_t size, 145 const struct zone *zp, int ntzones); 146 static void setboundaries(void); 147 static zic_t tadd(zic_t t1, long t2); 148 static void usage(void); 149 static void writezone(const char *name, const char *string); 150 static int yearistype(int year, const char *type); 151 152 extern char *__progname; 153 154 static int charcnt; 155 static int errors; 156 static const char *filename; 157 static int leapcnt; 158 static int leapseen; 159 static int leapminyear; 160 static int leapmaxyear; 161 static int linenum; 162 static int max_abbrvar_len; 163 static int max_format_len; 164 static zic_t max_time; 165 static int max_year; 166 static zic_t min_time; 167 static int min_year; 168 static int noise; 169 static const char *rfilename; 170 static int rlinenum; 171 static int timecnt; 172 static int typecnt; 173 174 /* 175 ** Line codes. 176 */ 177 178 #define LC_RULE 0 179 #define LC_ZONE 1 180 #define LC_LINK 2 181 #define LC_LEAP 3 182 183 /* 184 ** Which fields are which on a Zone line. 185 */ 186 187 #define ZF_NAME 1 188 #define ZF_GMTOFF 2 189 #define ZF_RULE 3 190 #define ZF_FORMAT 4 191 #define ZF_TILYEAR 5 192 #define ZF_TILMONTH 6 193 #define ZF_TILDAY 7 194 #define ZF_TILTIME 8 195 #define ZONE_MINFIELDS 5 196 #define ZONE_MAXFIELDS 9 197 198 /* 199 ** Which fields are which on a Zone continuation line. 200 */ 201 202 #define ZFC_GMTOFF 0 203 #define ZFC_RULE 1 204 #define ZFC_FORMAT 2 205 #define ZFC_TILYEAR 3 206 #define ZFC_TILMONTH 4 207 #define ZFC_TILDAY 5 208 #define ZFC_TILTIME 6 209 #define ZONEC_MINFIELDS 3 210 #define ZONEC_MAXFIELDS 7 211 212 /* 213 ** Which files are which on a Rule line. 214 */ 215 216 #define RF_NAME 1 217 #define RF_LOYEAR 2 218 #define RF_HIYEAR 3 219 #define RF_COMMAND 4 220 #define RF_MONTH 5 221 #define RF_DAY 6 222 #define RF_TOD 7 223 #define RF_STDOFF 8 224 #define RF_ABBRVAR 9 225 #define RULE_FIELDS 10 226 227 /* 228 ** Which fields are which on a Link line. 229 */ 230 231 #define LF_FROM 1 232 #define LF_TO 2 233 #define LINK_FIELDS 3 234 235 /* 236 ** Which fields are which on a Leap line. 237 */ 238 239 #define LP_YEAR 1 240 #define LP_MONTH 2 241 #define LP_DAY 3 242 #define LP_TIME 4 243 #define LP_CORR 5 244 #define LP_ROLL 6 245 #define LEAP_FIELDS 7 246 247 /* 248 ** Year synonyms. 249 */ 250 251 #define YR_MINIMUM 0 252 #define YR_MAXIMUM 1 253 #define YR_ONLY 2 254 255 static struct rule *rules; 256 static int nrules; /* number of rules */ 257 258 static struct zone *zones; 259 static int nzones; /* number of zones */ 260 261 struct link { 262 const char *l_filename; 263 int l_linenum; 264 const char *l_from; 265 const char *l_to; 266 }; 267 268 static struct link *links; 269 static int nlinks; 270 271 struct lookup { 272 const char *l_word; 273 const int l_value; 274 }; 275 276 static struct lookup const *byword(const char *string, const struct lookup *lp); 277 278 static struct lookup const line_codes[] = { 279 { "Rule", LC_RULE }, 280 { "Zone", LC_ZONE }, 281 { "Link", LC_LINK }, 282 { "Leap", LC_LEAP }, 283 { NULL, 0} 284 }; 285 286 static struct lookup const mon_names[] = { 287 { "January", TM_JANUARY }, 288 { "February", TM_FEBRUARY }, 289 { "March", TM_MARCH }, 290 { "April", TM_APRIL }, 291 { "May", TM_MAY }, 292 { "June", TM_JUNE }, 293 { "July", TM_JULY }, 294 { "August", TM_AUGUST }, 295 { "September", TM_SEPTEMBER }, 296 { "October", TM_OCTOBER }, 297 { "November", TM_NOVEMBER }, 298 { "December", TM_DECEMBER }, 299 { NULL, 0 } 300 }; 301 302 static struct lookup const wday_names[] = { 303 { "Sunday", TM_SUNDAY }, 304 { "Monday", TM_MONDAY }, 305 { "Tuesday", TM_TUESDAY }, 306 { "Wednesday", TM_WEDNESDAY }, 307 { "Thursday", TM_THURSDAY }, 308 { "Friday", TM_FRIDAY }, 309 { "Saturday", TM_SATURDAY }, 310 { NULL, 0 } 311 }; 312 313 static struct lookup const lasts[] = { 314 { "last-Sunday", TM_SUNDAY }, 315 { "last-Monday", TM_MONDAY }, 316 { "last-Tuesday", TM_TUESDAY }, 317 { "last-Wednesday", TM_WEDNESDAY }, 318 { "last-Thursday", TM_THURSDAY }, 319 { "last-Friday", TM_FRIDAY }, 320 { "last-Saturday", TM_SATURDAY }, 321 { NULL, 0 } 322 }; 323 324 static struct lookup const begin_years[] = { 325 { "minimum", YR_MINIMUM }, 326 { "maximum", YR_MAXIMUM }, 327 { NULL, 0 } 328 }; 329 330 static struct lookup const end_years[] = { 331 { "minimum", YR_MINIMUM }, 332 { "maximum", YR_MAXIMUM }, 333 { "only", YR_ONLY }, 334 { NULL, 0 } 335 }; 336 337 static struct lookup const leap_types[] = { 338 { "Rolling", TRUE }, 339 { "Stationary", FALSE }, 340 { NULL, 0 } 341 }; 342 343 static const int len_months[2][MONSPERYEAR] = { 344 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 345 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 346 }; 347 348 static const int len_years[2] = { 349 DAYSPERNYEAR, DAYSPERLYEAR 350 }; 351 352 static struct attype { 353 zic_t at; 354 unsigned char type; 355 } attypes[TZ_MAX_TIMES]; 356 357 static long gmtoffs[TZ_MAX_TYPES]; 358 static char isdsts[TZ_MAX_TYPES]; 359 static unsigned char abbrinds[TZ_MAX_TYPES]; 360 static char ttisstds[TZ_MAX_TYPES]; 361 static char ttisgmts[TZ_MAX_TYPES]; 362 static char chars[TZ_MAX_CHARS]; 363 static zic_t trans[TZ_MAX_LEAPS]; 364 static long corr[TZ_MAX_LEAPS]; 365 static char roll[TZ_MAX_LEAPS]; 366 367 /* 368 ** Memory allocation. 369 */ 370 371 static void * 372 memcheck(void *ptr) 373 { 374 if (ptr == NULL) 375 err(1, "Memory exhausted"); 376 return ptr; 377 } 378 379 static char * 380 ecatalloc(char *start, const char *tail) 381 { 382 size_t len; 383 char *str; 384 385 len = strlen(start) + strlen(tail) + 1; 386 str = memcheck(realloc(start, len)); 387 strlcat(str, tail, len); 388 return str; 389 } 390 391 #define emalloc(size) memcheck(malloc(size)) 392 #define ereallocarray(ptr, nmemb, size) memcheck(reallocarray(ptr, nmemb, size)) 393 #define erealloc(ptr, size) memcheck(realloc((ptr), (size))) 394 #define ecpyalloc(ptr) memcheck(strdup(ptr)) 395 396 /* 397 ** Error handling. 398 */ 399 400 static void 401 eats(const char *name, int num, const char *rname, int rnum) 402 { 403 filename = name; 404 linenum = num; 405 rfilename = rname; 406 rlinenum = rnum; 407 } 408 409 static void 410 eat(const char *name, int num) 411 { 412 eats(name, num, NULL, -1); 413 } 414 415 static void 416 error(const char *string) 417 { 418 /* 419 ** Match the format of "cc" to allow sh users to 420 ** zic ... 2>&1 | error -t "*" -v 421 ** on BSD systems. 422 */ 423 fprintf(stderr, "\"%s\", line %d: %s", 424 filename, linenum, string); 425 if (rfilename != NULL) 426 fprintf(stderr, " (rule from \"%s\", line %d)", 427 rfilename, rlinenum); 428 fprintf(stderr, "\n"); 429 ++errors; 430 } 431 432 static void 433 warning(const char *string) 434 { 435 char *cp; 436 437 cp = ecpyalloc("warning: "); 438 cp = ecatalloc(cp, string); 439 error(cp); 440 free(cp); 441 --errors; 442 } 443 444 445 static const char * 446 scheck(const char *string, const char *format) 447 { 448 const char *fp, *result; 449 char *fbuf, *tp, dummy; 450 int c; 451 452 result = ""; 453 if (string == NULL || format == NULL) 454 return result; 455 fbuf = reallocarray(NULL, strlen(format) + 2, 2); 456 if (fbuf == NULL) 457 return result; 458 fp = format; 459 tp = fbuf; 460 while ((*tp++ = c = *fp++) != '\0') { 461 if (c != '%') 462 continue; 463 if (*fp == '%') { 464 *tp++ = *fp++; 465 continue; 466 } 467 *tp++ = '*'; 468 if (*fp == '*') 469 ++fp; 470 while (isdigit((unsigned char)*fp)) 471 *tp++ = *fp++; 472 if (*fp == 'l' || *fp == 'h') 473 *tp++ = *fp++; 474 else if (*fp == '[') 475 do { 476 *tp++ = *fp++; 477 } while (*fp != '\0' && *fp != ']'); 478 if ((*tp++ = *fp++) == '\0') 479 break; 480 } 481 *(tp - 1) = '%'; 482 *tp++ = 'c'; 483 *tp = '\0'; 484 if (sscanf(string, fbuf, &dummy) != 1) 485 result = format; 486 free(fbuf); 487 return result; 488 } 489 490 static void 491 usage(void) 492 { 493 fprintf(stderr, 494 "usage: %s [-v] [-d directory] [-L leapsecondfilename] [-l timezone]\n" 495 "\t\t[-p timezone] [-y command] [filename ...]\n", 496 __progname); 497 exit(EXIT_FAILURE); 498 } 499 500 static const char *psxrules; 501 static const char *lcltime; 502 static const char *directory; 503 static const char *leapsec; 504 static const char *yitcommand; 505 506 int 507 main(int argc, char **argv) 508 { 509 int i, j, c; 510 511 if (pledge("stdio rpath wpath cpath proc exec", NULL) == -1) 512 err(1, "pledge"); 513 514 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 515 while ((c = getopt(argc, argv, "d:l:p:L:vy:")) != -1) 516 switch (c) { 517 default: 518 usage(); 519 case 'd': 520 if (directory == NULL) 521 directory = optarg; 522 else 523 errx(1, "More than one -d option specified"); 524 break; 525 case 'l': 526 if (lcltime == NULL) 527 lcltime = optarg; 528 else 529 errx(1, "More than one -l option specified"); 530 break; 531 case 'p': 532 if (psxrules == NULL) 533 psxrules = optarg; 534 else 535 errx(1, "More than one -p option specified"); 536 break; 537 case 'y': 538 if (yitcommand == NULL) 539 yitcommand = optarg; 540 else 541 errx(1, "More than one -y option specified"); 542 break; 543 case 'L': 544 if (leapsec == NULL) 545 leapsec = optarg; 546 else 547 errx(1, "More than one -L option specified"); 548 break; 549 case 'v': 550 noise = TRUE; 551 break; 552 } 553 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 554 usage(); /* usage message by request */ 555 if (directory == NULL) 556 directory = TZDIR; 557 if (yitcommand == NULL) 558 yitcommand = "yearistype"; 559 560 setboundaries(); 561 562 if (optind < argc && leapsec != NULL) { 563 infile(leapsec); 564 adjleap(); 565 } 566 567 for (i = optind; i < argc; ++i) 568 infile(argv[i]); 569 if (errors) 570 exit(EXIT_FAILURE); 571 associate(); 572 for (i = 0; i < nzones; i = j) { 573 /* 574 ** Find the next non-continuation zone entry. 575 */ 576 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 577 continue; 578 outzone(&zones[i], j - i); 579 } 580 /* 581 ** Make links. 582 */ 583 for (i = 0; i < nlinks; ++i) { 584 eat(links[i].l_filename, links[i].l_linenum); 585 dolink(links[i].l_from, links[i].l_to); 586 if (noise) 587 for (j = 0; j < nlinks; ++j) 588 if (strcmp(links[i].l_to, 589 links[j].l_from) == 0) 590 warning("link to link"); 591 } 592 if (lcltime != NULL) { 593 eat("command line", 1); 594 dolink(lcltime, TZDEFAULT); 595 } 596 if (psxrules != NULL) { 597 eat("command line", 1); 598 dolink(psxrules, TZDEFRULES); 599 } 600 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 601 } 602 603 static void 604 dolink(const char *fromfield, const char *tofield) 605 { 606 char *fromname, *toname; 607 608 if (fromfield[0] == '/') 609 fromname = ecpyalloc(fromfield); 610 else { 611 fromname = ecpyalloc(directory); 612 fromname = ecatalloc(fromname, "/"); 613 fromname = ecatalloc(fromname, fromfield); 614 } 615 if (tofield[0] == '/') 616 toname = ecpyalloc(tofield); 617 else { 618 toname = ecpyalloc(directory); 619 toname = ecatalloc(toname, "/"); 620 toname = ecatalloc(toname, tofield); 621 } 622 /* 623 ** We get to be careful here since 624 ** there's a fair chance of root running us. 625 */ 626 if (!itsdir(toname)) 627 remove(toname); 628 if (link(fromname, toname) != 0) { 629 int result; 630 631 if (mkdirs(toname) != 0) 632 exit(EXIT_FAILURE); 633 634 result = link(fromname, toname); 635 if (result != 0 && errno == EXDEV) 636 result = symlink(fromname, toname); 637 if (result != 0) 638 err(1, "Can't link from %s to %s", fromname, toname); 639 } 640 free(fromname); 641 free(toname); 642 } 643 644 #define TIME_T_BITS_IN_FILE 64 645 646 static void 647 setboundaries(void) 648 { 649 int i; 650 651 min_time = -1; 652 for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i) 653 min_time *= 2; 654 max_time = -(min_time + 1); 655 } 656 657 static int 658 itsdir(const char *name) 659 { 660 char *myname; 661 int accres; 662 663 myname = ecpyalloc(name); 664 myname = ecatalloc(myname, "/."); 665 accres = access(myname, F_OK); 666 free(myname); 667 return accres == 0; 668 } 669 670 /* 671 ** Associate sets of rules with zones. 672 */ 673 674 /* 675 ** Sort by rule name. 676 */ 677 678 static int 679 rcomp(const void *cp1, const void *cp2) 680 { 681 return strcmp(((const struct rule *) cp1)->r_name, 682 ((const struct rule *) cp2)->r_name); 683 } 684 685 static void 686 associate(void) 687 { 688 struct zone *zp; 689 struct rule *rp; 690 int base, out, i, j; 691 692 if (nrules != 0) { 693 qsort(rules, nrules, sizeof *rules, rcomp); 694 for (i = 0; i < nrules - 1; ++i) { 695 if (strcmp(rules[i].r_name, 696 rules[i + 1].r_name) != 0) 697 continue; 698 if (strcmp(rules[i].r_filename, 699 rules[i + 1].r_filename) == 0) 700 continue; 701 eat(rules[i].r_filename, rules[i].r_linenum); 702 warning("same rule name in multiple files"); 703 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); 704 warning("same rule name in multiple files"); 705 for (j = i + 2; j < nrules; ++j) { 706 if (strcmp(rules[i].r_name, 707 rules[j].r_name) != 0) 708 break; 709 if (strcmp(rules[i].r_filename, 710 rules[j].r_filename) == 0) 711 continue; 712 if (strcmp(rules[i + 1].r_filename, 713 rules[j].r_filename) == 0) 714 continue; 715 break; 716 } 717 i = j - 1; 718 } 719 } 720 for (i = 0; i < nzones; ++i) { 721 zp = &zones[i]; 722 zp->z_rules = NULL; 723 zp->z_nrules = 0; 724 } 725 for (base = 0; base < nrules; base = out) { 726 rp = &rules[base]; 727 for (out = base + 1; out < nrules; ++out) 728 if (strcmp(rp->r_name, rules[out].r_name) != 0) 729 break; 730 for (i = 0; i < nzones; ++i) { 731 zp = &zones[i]; 732 if (strcmp(zp->z_rule, rp->r_name) != 0) 733 continue; 734 zp->z_rules = rp; 735 zp->z_nrules = out - base; 736 } 737 } 738 for (i = 0; i < nzones; ++i) { 739 zp = &zones[i]; 740 if (zp->z_nrules == 0) { 741 /* 742 ** Maybe we have a local standard time offset. 743 */ 744 eat(zp->z_filename, zp->z_linenum); 745 zp->z_stdoff = gethms(zp->z_rule, "unruly zone", 746 TRUE); 747 /* 748 ** Note, though, that if there's no rule, 749 ** a '%s' in the format is a bad thing. 750 */ 751 if (strchr(zp->z_format, '%') != 0) 752 error("%s in ruleless zone"); 753 } 754 } 755 if (errors) 756 exit(EXIT_FAILURE); 757 } 758 759 static void 760 infile(const char *name) 761 { 762 FILE *fp; 763 char **fields, *cp; 764 const struct lookup *lp; 765 int nfields, wantcont, num; 766 char buf[BUFSIZ]; 767 768 if (strcmp(name, "-") == 0) { 769 name = "standard input"; 770 fp = stdin; 771 } else if ((fp = fopen(name, "r")) == NULL) 772 err(1, "Can't open %s", name); 773 wantcont = FALSE; 774 for (num = 1; ; ++num) { 775 eat(name, num); 776 if (fgets(buf, sizeof buf, fp) != buf) 777 break; 778 cp = strchr(buf, '\n'); 779 if (cp == NULL) { 780 error("line too long"); 781 exit(EXIT_FAILURE); 782 } 783 *cp = '\0'; 784 fields = getfields(buf); 785 nfields = 0; 786 while (fields[nfields] != NULL) { 787 static char nada; 788 789 if (strcmp(fields[nfields], "-") == 0) 790 fields[nfields] = &nada; 791 ++nfields; 792 } 793 if (nfields == 0) { 794 /* nothing to do */ 795 } else if (wantcont) { 796 wantcont = inzcont(fields, nfields); 797 } else { 798 lp = byword(fields[0], line_codes); 799 if (lp == NULL) 800 error("input line of unknown type"); 801 else switch ((int) (lp->l_value)) { 802 case LC_RULE: 803 inrule(fields, nfields); 804 wantcont = FALSE; 805 break; 806 case LC_ZONE: 807 wantcont = inzone(fields, nfields); 808 break; 809 case LC_LINK: 810 inlink(fields, nfields); 811 wantcont = FALSE; 812 break; 813 case LC_LEAP: 814 if (name != leapsec) 815 fprintf(stderr, 816 "%s: Leap line in non leap seconds file %s\n", 817 __progname, name); 818 /* no exit? */ 819 else 820 inleap(fields, nfields); 821 wantcont = FALSE; 822 break; 823 default: /* "cannot happen" */ 824 errx(1, "panic: Invalid l_value %d", lp->l_value); 825 } 826 } 827 free(fields); 828 } 829 if (ferror(fp)) 830 errx(1, "Error reading %s", filename); 831 if (fp != stdin && fclose(fp)) 832 err(1, "Error closing %s", filename); 833 if (wantcont) 834 error("expected continuation line not found"); 835 } 836 837 /* 838 ** Convert a string of one of the forms 839 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 840 ** into a number of seconds. 841 ** A null string maps to zero. 842 ** Call error with errstring and return zero on errors. 843 */ 844 845 static long 846 gethms(const char *string, const char *errstring, int signable) 847 { 848 long hh; 849 int mm, ss, sign; 850 851 if (string == NULL || *string == '\0') 852 return 0; 853 if (!signable) 854 sign = 1; 855 else if (*string == '-') { 856 sign = -1; 857 ++string; 858 } else 859 sign = 1; 860 if (sscanf(string, scheck(string, "%ld"), &hh) == 1) 861 mm = ss = 0; 862 else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2) 863 ss = 0; 864 else if (sscanf(string, scheck(string, "%ld:%d:%d"), 865 &hh, &mm, &ss) != 3) { 866 error(errstring); 867 return 0; 868 } 869 if (hh < 0 || 870 mm < 0 || mm >= MINSPERHOUR || 871 ss < 0 || ss > SECSPERMIN) { 872 error(errstring); 873 return 0; 874 } 875 if (LONG_MAX / SECSPERHOUR < hh) { 876 error("time overflow"); 877 return 0; 878 } 879 return oadd(eitol(sign) * hh * eitol(SECSPERHOUR), 880 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss))); 881 } 882 883 static void 884 inrule(char **fields, int nfields) 885 { 886 static struct rule r; 887 888 if (nfields != RULE_FIELDS) { 889 error("wrong number of fields on Rule line"); 890 return; 891 } 892 if (*fields[RF_NAME] == '\0') { 893 error("nameless rule"); 894 return; 895 } 896 r.r_filename = filename; 897 r.r_linenum = linenum; 898 r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE); 899 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 900 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 901 r.r_name = ecpyalloc(fields[RF_NAME]); 902 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 903 if (max_abbrvar_len < strlen(r.r_abbrvar)) 904 max_abbrvar_len = strlen(r.r_abbrvar); 905 rules = ereallocarray(rules, nrules + 1, sizeof *rules); 906 rules[nrules++] = r; 907 } 908 909 static int 910 inzone(char **fields, int nfields) 911 { 912 int i; 913 static char *buf; 914 size_t len; 915 916 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 917 error("wrong number of fields on Zone line"); 918 return FALSE; 919 } 920 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 921 len = 132 + strlen(TZDEFAULT); 922 buf = erealloc(buf, len); 923 snprintf(buf, len, 924 "\"Zone %s\" line and -l option are mutually exclusive", 925 TZDEFAULT); 926 error(buf); 927 return FALSE; 928 } 929 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 930 len = 132 + strlen(TZDEFRULES); 931 buf = erealloc(buf, len); 932 snprintf(buf, len, 933 "\"Zone %s\" line and -p option are mutually exclusive", 934 TZDEFRULES); 935 error(buf); 936 return FALSE; 937 } 938 for (i = 0; i < nzones; ++i) 939 if (zones[i].z_name != NULL && 940 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 941 len = 132 + strlen(fields[ZF_NAME]) + 942 strlen(zones[i].z_filename); 943 buf = erealloc(buf, len); 944 snprintf(buf, len, 945 "duplicate zone name %s (file \"%s\", line %d)", 946 fields[ZF_NAME], 947 zones[i].z_filename, 948 zones[i].z_linenum); 949 error(buf); 950 return FALSE; 951 } 952 return inzsub(fields, nfields, FALSE); 953 } 954 955 static int 956 inzcont(char **fields, int nfields) 957 { 958 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 959 error("wrong number of fields on Zone continuation line"); 960 return FALSE; 961 } 962 return inzsub(fields, nfields, TRUE); 963 } 964 965 static int 966 inzsub(char **fields, int nfields, int iscont) 967 { 968 char *cp; 969 static struct zone z; 970 int i_gmtoff, i_rule, i_format; 971 int i_untilyear, i_untilmonth; 972 int i_untilday, i_untiltime; 973 int hasuntil; 974 975 if (iscont) { 976 i_gmtoff = ZFC_GMTOFF; 977 i_rule = ZFC_RULE; 978 i_format = ZFC_FORMAT; 979 i_untilyear = ZFC_TILYEAR; 980 i_untilmonth = ZFC_TILMONTH; 981 i_untilday = ZFC_TILDAY; 982 i_untiltime = ZFC_TILTIME; 983 z.z_name = NULL; 984 } else { 985 i_gmtoff = ZF_GMTOFF; 986 i_rule = ZF_RULE; 987 i_format = ZF_FORMAT; 988 i_untilyear = ZF_TILYEAR; 989 i_untilmonth = ZF_TILMONTH; 990 i_untilday = ZF_TILDAY; 991 i_untiltime = ZF_TILTIME; 992 z.z_name = ecpyalloc(fields[ZF_NAME]); 993 } 994 z.z_filename = filename; 995 z.z_linenum = linenum; 996 z.z_gmtoff = gethms(fields[i_gmtoff], "invalid UTC offset", TRUE); 997 if ((cp = strchr(fields[i_format], '%')) != 0) { 998 if (*++cp != 's' || strchr(cp, '%') != 0) { 999 error("invalid abbreviation format"); 1000 return FALSE; 1001 } 1002 } 1003 z.z_rule = ecpyalloc(fields[i_rule]); 1004 z.z_format = ecpyalloc(fields[i_format]); 1005 if (max_format_len < strlen(z.z_format)) 1006 max_format_len = strlen(z.z_format); 1007 hasuntil = nfields > i_untilyear; 1008 if (hasuntil) { 1009 z.z_untilrule.r_filename = filename; 1010 z.z_untilrule.r_linenum = linenum; 1011 rulesub(&z.z_untilrule, 1012 fields[i_untilyear], 1013 "only", 1014 "", 1015 (nfields > i_untilmonth) ? 1016 fields[i_untilmonth] : "Jan", 1017 (nfields > i_untilday) ? fields[i_untilday] : "1", 1018 (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 1019 z.z_untiltime = rpytime(&z.z_untilrule, 1020 z.z_untilrule.r_loyear); 1021 if (iscont && nzones > 0 && 1022 z.z_untiltime > min_time && 1023 z.z_untiltime < max_time && 1024 zones[nzones - 1].z_untiltime > min_time && 1025 zones[nzones - 1].z_untiltime < max_time && 1026 zones[nzones - 1].z_untiltime >= z.z_untiltime) { 1027 error("Zone continuation line end time is not after end time of previous line"); 1028 return FALSE; 1029 } 1030 } 1031 zones = ereallocarray(zones, nzones + 1, sizeof *zones); 1032 zones[nzones++] = z; 1033 /* 1034 ** If there was an UNTIL field on this line, 1035 ** there's more information about the zone on the next line. 1036 */ 1037 return hasuntil; 1038 } 1039 1040 static void 1041 inleap(char **fields, int nfields) 1042 { 1043 const char *cp; 1044 const struct lookup *lp; 1045 int i, j; 1046 int year, month, day; 1047 long dayoff, tod; 1048 zic_t t; 1049 1050 if (nfields != LEAP_FIELDS) { 1051 error("wrong number of fields on Leap line"); 1052 return; 1053 } 1054 dayoff = 0; 1055 cp = fields[LP_YEAR]; 1056 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { 1057 /* 1058 ** Leapin' Lizards! 1059 */ 1060 error("invalid leaping year"); 1061 return; 1062 } 1063 if (!leapseen || leapmaxyear < year) 1064 leapmaxyear = year; 1065 if (!leapseen || leapminyear > year) 1066 leapminyear = year; 1067 leapseen = TRUE; 1068 j = EPOCH_YEAR; 1069 while (j != year) { 1070 if (year > j) { 1071 i = len_years[isleap(j)]; 1072 ++j; 1073 } else { 1074 --j; 1075 i = -len_years[isleap(j)]; 1076 } 1077 dayoff = oadd(dayoff, eitol(i)); 1078 } 1079 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1080 error("invalid month name"); 1081 return; 1082 } 1083 month = lp->l_value; 1084 j = TM_JANUARY; 1085 while (j != month) { 1086 i = len_months[isleap(year)][j]; 1087 dayoff = oadd(dayoff, eitol(i)); 1088 ++j; 1089 } 1090 cp = fields[LP_DAY]; 1091 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || 1092 day <= 0 || day > len_months[isleap(year)][month]) { 1093 error("invalid day of month"); 1094 return; 1095 } 1096 dayoff = oadd(dayoff, eitol(day - 1)); 1097 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) { 1098 error("time before zero"); 1099 return; 1100 } 1101 if (dayoff < min_time / SECSPERDAY) { 1102 error("time too small"); 1103 return; 1104 } 1105 if (dayoff > max_time / SECSPERDAY) { 1106 error("time too large"); 1107 return; 1108 } 1109 t = (zic_t) dayoff * SECSPERDAY; 1110 tod = gethms(fields[LP_TIME], "invalid time of day", FALSE); 1111 cp = fields[LP_CORR]; 1112 { 1113 int positive; 1114 int count; 1115 1116 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 1117 positive = FALSE; 1118 count = 1; 1119 } else if (strcmp(cp, "--") == 0) { 1120 positive = FALSE; 1121 count = 2; 1122 } else if (strcmp(cp, "+") == 0) { 1123 positive = TRUE; 1124 count = 1; 1125 } else if (strcmp(cp, "++") == 0) { 1126 positive = TRUE; 1127 count = 2; 1128 } else { 1129 error("illegal CORRECTION field on Leap line"); 1130 return; 1131 } 1132 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 1133 error("illegal Rolling/Stationary field on Leap line"); 1134 return; 1135 } 1136 leapadd(tadd(t, tod), positive, lp->l_value, count); 1137 } 1138 } 1139 1140 static void 1141 inlink(char **fields, int nfields) 1142 { 1143 struct link l; 1144 1145 if (nfields != LINK_FIELDS) { 1146 error("wrong number of fields on Link line"); 1147 return; 1148 } 1149 if (*fields[LF_FROM] == '\0') { 1150 error("blank FROM field on Link line"); 1151 return; 1152 } 1153 if (*fields[LF_TO] == '\0') { 1154 error("blank TO field on Link line"); 1155 return; 1156 } 1157 l.l_filename = filename; 1158 l.l_linenum = linenum; 1159 l.l_from = ecpyalloc(fields[LF_FROM]); 1160 l.l_to = ecpyalloc(fields[LF_TO]); 1161 links = ereallocarray(links, nlinks + 1, sizeof *links); 1162 links[nlinks++] = l; 1163 } 1164 1165 static void 1166 rulesub(struct rule * const rp, const char * const loyearp, 1167 const char * const hiyearp, const char * const typep, 1168 const char * const monthp, const char * const dayp, 1169 const char * const timep) 1170 { 1171 const struct lookup *lp; 1172 const char *cp; 1173 char *dp, *ep; 1174 1175 if ((lp = byword(monthp, mon_names)) == NULL) { 1176 error("invalid month name"); 1177 return; 1178 } 1179 rp->r_month = lp->l_value; 1180 rp->r_todisstd = FALSE; 1181 rp->r_todisgmt = FALSE; 1182 dp = ecpyalloc(timep); 1183 if (*dp != '\0') { 1184 ep = dp + strlen(dp) - 1; 1185 switch (tolower((unsigned char)*ep)) { 1186 case 's': /* Standard */ 1187 rp->r_todisstd = TRUE; 1188 rp->r_todisgmt = FALSE; 1189 *ep = '\0'; 1190 break; 1191 case 'w': /* Wall */ 1192 rp->r_todisstd = FALSE; 1193 rp->r_todisgmt = FALSE; 1194 *ep = '\0'; 1195 break; 1196 case 'g': /* Greenwich */ 1197 case 'u': /* Universal */ 1198 case 'z': /* Zulu */ 1199 rp->r_todisstd = TRUE; 1200 rp->r_todisgmt = TRUE; 1201 *ep = '\0'; 1202 break; 1203 } 1204 } 1205 rp->r_tod = gethms(dp, "invalid time of day", FALSE); 1206 free(dp); 1207 /* 1208 ** Year work. 1209 */ 1210 cp = loyearp; 1211 lp = byword(cp, begin_years); 1212 rp->r_lowasnum = lp == NULL; 1213 if (!rp->r_lowasnum) switch ((int) lp->l_value) { 1214 case YR_MINIMUM: 1215 rp->r_loyear = INT_MIN; 1216 break; 1217 case YR_MAXIMUM: 1218 rp->r_loyear = INT_MAX; 1219 break; 1220 default: /* "cannot happen" */ 1221 errx(1, "panic: Invalid l_value %d", lp->l_value); 1222 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { 1223 error("invalid starting year"); 1224 return; 1225 } 1226 cp = hiyearp; 1227 lp = byword(cp, end_years); 1228 rp->r_hiwasnum = lp == NULL; 1229 if (!rp->r_hiwasnum) switch ((int) lp->l_value) { 1230 case YR_MINIMUM: 1231 rp->r_hiyear = INT_MIN; 1232 break; 1233 case YR_MAXIMUM: 1234 rp->r_hiyear = INT_MAX; 1235 break; 1236 case YR_ONLY: 1237 rp->r_hiyear = rp->r_loyear; 1238 break; 1239 default: /* "cannot happen" */ 1240 errx(1, "panic: Invalid l_value %d", lp->l_value); 1241 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { 1242 error("invalid ending year"); 1243 return; 1244 } 1245 if (rp->r_loyear > rp->r_hiyear) { 1246 error("starting year greater than ending year"); 1247 return; 1248 } 1249 if (*typep == '\0') 1250 rp->r_yrtype = NULL; 1251 else { 1252 if (rp->r_loyear == rp->r_hiyear) { 1253 error("typed single year"); 1254 return; 1255 } 1256 rp->r_yrtype = ecpyalloc(typep); 1257 } 1258 /* 1259 ** Day work. 1260 ** Accept things such as: 1261 ** 1 1262 ** last-Sunday 1263 ** Sun<=20 1264 ** Sun>=7 1265 */ 1266 dp = ecpyalloc(dayp); 1267 if ((lp = byword(dp, lasts)) != NULL) { 1268 rp->r_dycode = DC_DOWLEQ; 1269 rp->r_wday = lp->l_value; 1270 rp->r_dayofmonth = len_months[1][rp->r_month]; 1271 } else { 1272 if ((ep = strchr(dp, '<')) != 0) 1273 rp->r_dycode = DC_DOWLEQ; 1274 else if ((ep = strchr(dp, '>')) != 0) 1275 rp->r_dycode = DC_DOWGEQ; 1276 else { 1277 ep = dp; 1278 rp->r_dycode = DC_DOM; 1279 } 1280 if (rp->r_dycode != DC_DOM) { 1281 *ep++ = 0; 1282 if (*ep++ != '=') { 1283 error("invalid day of month"); 1284 free(dp); 1285 return; 1286 } 1287 if ((lp = byword(dp, wday_names)) == NULL) { 1288 error("invalid weekday name"); 1289 free(dp); 1290 return; 1291 } 1292 rp->r_wday = lp->l_value; 1293 } 1294 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || 1295 rp->r_dayofmonth <= 0 || 1296 (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1297 error("invalid day of month"); 1298 free(dp); 1299 return; 1300 } 1301 } 1302 free(dp); 1303 } 1304 1305 static void 1306 convert(long val, char *buf) 1307 { 1308 int i; 1309 int shift; 1310 1311 for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1312 buf[i] = val >> shift; 1313 } 1314 1315 static void 1316 convert64(zic_t val, char *buf) 1317 { 1318 int i; 1319 int shift; 1320 1321 for (i = 0, shift = 56; i < 8; ++i, shift -= 8) 1322 buf[i] = val >> shift; 1323 } 1324 1325 static void 1326 puttzcode(long val, FILE *fp) 1327 { 1328 char buf[4]; 1329 1330 convert(val, buf); 1331 fwrite(buf, sizeof buf, 1, fp); 1332 } 1333 1334 static void 1335 puttzcode64(zic_t val, FILE *fp) 1336 { 1337 char buf[8]; 1338 1339 convert64(val, buf); 1340 fwrite(buf, sizeof buf, 1, fp); 1341 } 1342 1343 static int 1344 atcomp(const void *avp, const void *bvp) 1345 { 1346 const zic_t a = ((const struct attype *) avp)->at; 1347 const zic_t b = ((const struct attype *) bvp)->at; 1348 1349 return (a < b) ? -1 : (a > b); 1350 } 1351 1352 static int 1353 is32(zic_t x) 1354 { 1355 return INT32_MIN <= x && x <= INT32_MAX; 1356 } 1357 1358 static void 1359 writezone(const char *name, const char *string) 1360 { 1361 FILE *fp; 1362 int i, j; 1363 int leapcnt32, leapi32; 1364 int timecnt32, timei32; 1365 int pass; 1366 static char *fullname; 1367 static const struct tzhead tzh0; 1368 static struct tzhead tzh; 1369 zic_t ats[TZ_MAX_TIMES]; 1370 unsigned char types[TZ_MAX_TIMES]; 1371 size_t len; 1372 1373 /* 1374 ** Sort. 1375 */ 1376 if (timecnt > 1) 1377 qsort(attypes, timecnt, sizeof *attypes, atcomp); 1378 /* 1379 ** Optimize. 1380 */ 1381 { 1382 int fromi; 1383 int toi; 1384 1385 toi = 0; 1386 fromi = 0; 1387 while (fromi < timecnt && attypes[fromi].at < min_time) 1388 ++fromi; 1389 if (isdsts[0] == 0) 1390 while (fromi < timecnt && attypes[fromi].type == 0) 1391 ++fromi; /* handled by default rule */ 1392 for ( ; fromi < timecnt; ++fromi) { 1393 if (toi != 0 && ((attypes[fromi].at + 1394 gmtoffs[attypes[toi - 1].type]) <= 1395 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 : 1396 attypes[toi - 2].type]))) { 1397 attypes[toi - 1].type = attypes[fromi].type; 1398 continue; 1399 } 1400 if (toi == 0 || 1401 attypes[toi - 1].type != attypes[fromi].type) 1402 attypes[toi++] = attypes[fromi]; 1403 } 1404 timecnt = toi; 1405 } 1406 /* 1407 ** Transfer. 1408 */ 1409 for (i = 0; i < timecnt; ++i) { 1410 ats[i] = attypes[i].at; 1411 types[i] = attypes[i].type; 1412 } 1413 /* 1414 ** Correct for leap seconds. 1415 */ 1416 for (i = 0; i < timecnt; ++i) { 1417 j = leapcnt; 1418 while (--j >= 0) 1419 if (ats[i] > trans[j] - corr[j]) { 1420 ats[i] = tadd(ats[i], corr[j]); 1421 break; 1422 } 1423 } 1424 /* 1425 ** Figure out 32-bit-limited starts and counts. 1426 */ 1427 timecnt32 = timecnt; 1428 timei32 = 0; 1429 leapcnt32 = leapcnt; 1430 leapi32 = 0; 1431 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1])) 1432 --timecnt32; 1433 while (timecnt32 > 0 && !is32(ats[timei32])) { 1434 --timecnt32; 1435 ++timei32; 1436 } 1437 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1])) 1438 --leapcnt32; 1439 while (leapcnt32 > 0 && !is32(trans[leapi32])) { 1440 --leapcnt32; 1441 ++leapi32; 1442 } 1443 len = strlen(directory) + 1 + strlen(name) + 1; 1444 fullname = erealloc(fullname, len); 1445 snprintf(fullname, len, "%s/%s", directory, name); 1446 /* 1447 ** Remove old file, if any, to snap links. 1448 */ 1449 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) 1450 err(1, "Can't remove %s", fullname); 1451 if ((fp = fopen(fullname, "wb")) == NULL) { 1452 if (mkdirs(fullname) != 0) 1453 exit(EXIT_FAILURE); 1454 if ((fp = fopen(fullname, "wb")) == NULL) 1455 err(1, "Can't create %s", fullname); 1456 } 1457 for (pass = 1; pass <= 2; ++pass) { 1458 int thistimei, thistimecnt; 1459 int thisleapi, thisleapcnt; 1460 int thistimelim, thisleaplim; 1461 int writetype[TZ_MAX_TIMES]; 1462 int typemap[TZ_MAX_TYPES]; 1463 int thistypecnt; 1464 char thischars[TZ_MAX_CHARS]; 1465 char thischarcnt; 1466 int indmap[TZ_MAX_CHARS]; 1467 1468 if (pass == 1) { 1469 thistimei = timei32; 1470 thistimecnt = timecnt32; 1471 thisleapi = leapi32; 1472 thisleapcnt = leapcnt32; 1473 } else { 1474 thistimei = 0; 1475 thistimecnt = timecnt; 1476 thisleapi = 0; 1477 thisleapcnt = leapcnt; 1478 } 1479 thistimelim = thistimei + thistimecnt; 1480 thisleaplim = thisleapi + thisleapcnt; 1481 for (i = 0; i < typecnt; ++i) 1482 writetype[i] = thistimecnt == timecnt; 1483 if (thistimecnt == 0) { 1484 /* 1485 ** No transition times fall in the current 1486 ** (32- or 64-bit) window. 1487 */ 1488 if (typecnt != 0) 1489 writetype[typecnt - 1] = TRUE; 1490 } else { 1491 for (i = thistimei - 1; i < thistimelim; ++i) 1492 if (i >= 0) 1493 writetype[types[i]] = TRUE; 1494 /* 1495 ** For America/Godthab and Antarctica/Palmer 1496 */ 1497 if (thistimei == 0) 1498 writetype[0] = TRUE; 1499 } 1500 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH 1501 /* 1502 ** For some pre-2011 systems: if the last-to-be-written 1503 ** standard (or daylight) type has an offset different from the 1504 ** most recently used offset, 1505 ** append an (unused) copy of the most recently used type 1506 ** (to help get global "altzone" and "timezone" variables 1507 ** set correctly). 1508 */ 1509 { 1510 int mrudst, mrustd, hidst, histd, type; 1511 1512 hidst = histd = mrudst = mrustd = -1; 1513 for (i = thistimei; i < thistimelim; ++i) 1514 if (isdsts[types[i]]) 1515 mrudst = types[i]; 1516 else 1517 mrustd = types[i]; 1518 for (i = 0; i < typecnt; ++i) 1519 if (writetype[i]) { 1520 if (isdsts[i]) 1521 hidst = i; 1522 else 1523 histd = i; 1524 } 1525 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && 1526 gmtoffs[hidst] != gmtoffs[mrudst]) { 1527 isdsts[mrudst] = -1; 1528 type = addtype(gmtoffs[mrudst], 1529 &chars[abbrinds[mrudst]], 1530 TRUE, ttisstds[mrudst], 1531 ttisgmts[mrudst]); 1532 isdsts[mrudst] = TRUE; 1533 writetype[type] = TRUE; 1534 } 1535 if (histd >= 0 && mrustd >= 0 && histd != mrustd && 1536 gmtoffs[histd] != gmtoffs[mrustd]) { 1537 isdsts[mrustd] = -1; 1538 type = addtype(gmtoffs[mrustd], 1539 &chars[abbrinds[mrustd]], 1540 FALSE, ttisstds[mrustd], 1541 ttisgmts[mrustd]); 1542 isdsts[mrustd] = FALSE; 1543 writetype[type] = TRUE; 1544 } 1545 } 1546 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ 1547 thistypecnt = 0; 1548 for (i = 0; i < typecnt; ++i) 1549 typemap[i] = writetype[i] ? thistypecnt++ : -1; 1550 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i) 1551 indmap[i] = -1; 1552 thischarcnt = 0; 1553 for (i = 0; i < typecnt; ++i) { 1554 char *thisabbr; 1555 1556 if (!writetype[i]) 1557 continue; 1558 if (indmap[abbrinds[i]] >= 0) 1559 continue; 1560 thisabbr = &chars[abbrinds[i]]; 1561 for (j = 0; j < thischarcnt; ++j) 1562 if (strcmp(&thischars[j], thisabbr) == 0) 1563 break; 1564 if (j == thischarcnt) { 1565 strlcpy(&thischars[(int) thischarcnt], 1566 thisabbr, sizeof(thischars) - thischarcnt); 1567 thischarcnt += strlen(thisabbr) + 1; 1568 } 1569 indmap[abbrinds[i]] = j; 1570 } 1571 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp) 1572 tzh = tzh0; 1573 strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); 1574 tzh.tzh_version[0] = ZIC_VERSION; 1575 convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt); 1576 convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt); 1577 convert(eitol(thisleapcnt), tzh.tzh_leapcnt); 1578 convert(eitol(thistimecnt), tzh.tzh_timecnt); 1579 convert(eitol(thistypecnt), tzh.tzh_typecnt); 1580 convert(eitol(thischarcnt), tzh.tzh_charcnt); 1581 DO(tzh_magic); 1582 DO(tzh_version); 1583 DO(tzh_reserved); 1584 DO(tzh_ttisgmtcnt); 1585 DO(tzh_ttisstdcnt); 1586 DO(tzh_leapcnt); 1587 DO(tzh_timecnt); 1588 DO(tzh_typecnt); 1589 DO(tzh_charcnt); 1590 #undef DO 1591 for (i = thistimei; i < thistimelim; ++i) 1592 if (pass == 1) 1593 puttzcode((long) ats[i], fp); 1594 else 1595 puttzcode64(ats[i], fp); 1596 for (i = thistimei; i < thistimelim; ++i) { 1597 unsigned char uc; 1598 1599 uc = typemap[types[i]]; 1600 fwrite(&uc, sizeof uc, 1, fp); 1601 } 1602 for (i = 0; i < typecnt; ++i) 1603 if (writetype[i]) { 1604 puttzcode(gmtoffs[i], fp); 1605 putc(isdsts[i], fp); 1606 putc((unsigned char)indmap[abbrinds[i]], fp); 1607 } 1608 if (thischarcnt != 0) 1609 fwrite(thischars, sizeof thischars[0], thischarcnt, fp); 1610 for (i = thisleapi; i < thisleaplim; ++i) { 1611 zic_t todo; 1612 1613 if (roll[i]) { 1614 if (timecnt == 0 || trans[i] < ats[0]) { 1615 j = 0; 1616 while (isdsts[j]) 1617 if (++j >= typecnt) { 1618 j = 0; 1619 break; 1620 } 1621 } else { 1622 j = 1; 1623 while (j < timecnt && 1624 trans[i] >= ats[j]) 1625 ++j; 1626 j = types[j - 1]; 1627 } 1628 todo = tadd(trans[i], -gmtoffs[j]); 1629 } else 1630 todo = trans[i]; 1631 if (pass == 1) 1632 puttzcode((long) todo, fp); 1633 else 1634 puttzcode64(todo, fp); 1635 puttzcode(corr[i], fp); 1636 } 1637 for (i = 0; i < typecnt; ++i) 1638 if (writetype[i]) 1639 putc(ttisstds[i], fp); 1640 for (i = 0; i < typecnt; ++i) 1641 if (writetype[i]) 1642 putc(ttisgmts[i], fp); 1643 } 1644 fprintf(fp, "\n%s\n", string); 1645 if (ferror(fp) || fclose(fp)) 1646 errx(1, "Error writing %s", fullname); 1647 } 1648 1649 static void 1650 doabbr(char *abbr, size_t size, const char *format, const char *letters, 1651 int isdst, int doquotes) 1652 { 1653 char *cp, *slashp; 1654 int len; 1655 1656 slashp = strchr(format, '/'); 1657 if (slashp == NULL) { 1658 if (letters == NULL) 1659 strlcpy(abbr, format, size); 1660 else 1661 snprintf(abbr, size, format, letters); 1662 } else if (isdst) { 1663 strlcpy(abbr, slashp + 1, size); 1664 } else { 1665 if (slashp - format + 1 < size) 1666 size = slashp - format + 1; 1667 strlcpy(abbr, format, size); 1668 } 1669 if (!doquotes) 1670 return; 1671 for (cp = abbr; *cp != '\0'; ++cp) 1672 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL && 1673 strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL) 1674 break; 1675 len = strlen(abbr); 1676 if (len > 0 && *cp == '\0') 1677 return; 1678 abbr[len + 2] = '\0'; 1679 abbr[len + 1] = '>'; 1680 for ( ; len > 0; --len) 1681 abbr[len] = abbr[len - 1]; 1682 abbr[0] = '<'; 1683 } 1684 1685 static void 1686 updateminmax(int x) 1687 { 1688 if (min_year > x) 1689 min_year = x; 1690 if (max_year < x) 1691 max_year = x; 1692 } 1693 1694 static int 1695 stringoffset(char *result, size_t size, long offset) 1696 { 1697 int hours, minutes, seconds; 1698 char *ep; 1699 1700 result[0] = '\0'; 1701 if (offset < 0) { 1702 strlcpy(result, "-", size); 1703 offset = -offset; 1704 } 1705 seconds = offset % SECSPERMIN; 1706 offset /= SECSPERMIN; 1707 minutes = offset % MINSPERHOUR; 1708 offset /= MINSPERHOUR; 1709 hours = offset; 1710 if (hours >= HOURSPERDAY) { 1711 result[0] = '\0'; 1712 return -1; 1713 } 1714 ep = end(result, size); 1715 snprintf(ep, size - (ep - result), "%d", hours); 1716 if (minutes != 0 || seconds != 0) { 1717 ep = end(result, size); 1718 snprintf(ep, size - (ep - result), ":%02d", minutes); 1719 if (seconds != 0) { 1720 ep = end(result, size); 1721 snprintf(ep, size - (ep - result), ":%02d", seconds); 1722 } 1723 } 1724 return 0; 1725 } 1726 1727 static int 1728 stringrule(char *result, size_t size, const struct rule *rp, long dstoff, long gmtoff) 1729 { 1730 long tod; 1731 char *ep; 1732 1733 ep = end(result, size); 1734 size -= ep - result; 1735 result = ep; 1736 if (rp->r_dycode == DC_DOM) { 1737 int month, total; 1738 1739 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY) 1740 return -1; 1741 total = 0; 1742 for (month = 0; month < rp->r_month; ++month) 1743 total += len_months[0][month]; 1744 snprintf(result, size, "J%d", total + rp->r_dayofmonth); 1745 } else { 1746 int week; 1747 1748 if (rp->r_dycode == DC_DOWGEQ) { 1749 if ((rp->r_dayofmonth % DAYSPERWEEK) != 1) 1750 return -1; 1751 week = 1 + rp->r_dayofmonth / DAYSPERWEEK; 1752 } else if (rp->r_dycode == DC_DOWLEQ) { 1753 if (rp->r_dayofmonth == len_months[1][rp->r_month]) 1754 week = 5; 1755 else { 1756 if ((rp->r_dayofmonth % DAYSPERWEEK) != 0) 1757 return -1; 1758 week = rp->r_dayofmonth / DAYSPERWEEK; 1759 } 1760 } else 1761 return -1; /* "cannot happen" */ 1762 snprintf(result, size, "M%d.%d.%d", 1763 rp->r_month + 1, week, rp->r_wday); 1764 } 1765 tod = rp->r_tod; 1766 if (rp->r_todisgmt) 1767 tod += gmtoff; 1768 if (rp->r_todisstd && rp->r_stdoff == 0) 1769 tod += dstoff; 1770 if (tod < 0) { 1771 result[0] = '\0'; 1772 return -1; 1773 } 1774 if (tod != 2 * SECSPERMIN * MINSPERHOUR) { 1775 strlcat(result, "/", size); 1776 ep = end(result, size); 1777 if (stringoffset(ep, size - (ep - result), tod) != 0) 1778 return -1; 1779 } 1780 return 0; 1781 } 1782 1783 static void 1784 stringzone(char *result, size_t size, const struct zone *zpfirst, int zonecount) 1785 { 1786 const struct zone *zp; 1787 struct rule *rp, *stdrp, *dstrp; 1788 int i; 1789 const char *abbrvar; 1790 char *ep; 1791 1792 result[0] = '\0'; 1793 zp = zpfirst + zonecount - 1; 1794 stdrp = dstrp = NULL; 1795 for (i = 0; i < zp->z_nrules; ++i) { 1796 rp = &zp->z_rules[i]; 1797 if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX) 1798 continue; 1799 if (rp->r_yrtype != NULL) 1800 continue; 1801 if (rp->r_stdoff == 0) { 1802 if (stdrp == NULL) 1803 stdrp = rp; 1804 else 1805 return; 1806 } else { 1807 if (dstrp == NULL) 1808 dstrp = rp; 1809 else 1810 return; 1811 } 1812 } 1813 if (stdrp == NULL && dstrp == NULL) { 1814 /* 1815 ** There are no rules running through "max". 1816 ** Let's find the latest rule. 1817 */ 1818 for (i = 0; i < zp->z_nrules; ++i) { 1819 rp = &zp->z_rules[i]; 1820 if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear || 1821 (rp->r_hiyear == stdrp->r_hiyear && 1822 rp->r_month > stdrp->r_month)) 1823 stdrp = rp; 1824 } 1825 if (stdrp != NULL && stdrp->r_stdoff != 0) 1826 return; /* We end up in DST (a POSIX no-no). */ 1827 /* 1828 ** Horrid special case: if year is 2037, 1829 ** presume this is a zone handled on a year-by-year basis; 1830 ** do not try to apply a rule to the zone. 1831 */ 1832 if (stdrp != NULL && stdrp->r_hiyear == 2037) 1833 return; 1834 } 1835 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0)) 1836 return; 1837 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; 1838 doabbr(result, size, zp->z_format, abbrvar, FALSE, TRUE); 1839 ep = end(result, size); 1840 if (stringoffset(ep, size - (ep - result), -zp->z_gmtoff) != 0) { 1841 result[0] = '\0'; 1842 return; 1843 } 1844 if (dstrp == NULL) 1845 return; 1846 ep = end(result, size); 1847 doabbr(ep, size - (ep - result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE); 1848 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) { 1849 ep = end(result, size); 1850 if (stringoffset(ep, size - (ep - result), 1851 -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) { 1852 result[0] = '\0'; 1853 return; 1854 } 1855 } 1856 strlcat(result, ",", size); 1857 if (stringrule(result, size, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { 1858 result[0] = '\0'; 1859 return; 1860 } 1861 strlcat(result, ",", size); 1862 if (stringrule(result, size, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { 1863 result[0] = '\0'; 1864 return; 1865 } 1866 } 1867 1868 static void 1869 outzone(const struct zone *zpfirst, int zonecount) 1870 { 1871 const struct zone *zp; 1872 struct rule *rp; 1873 int i, j, usestart, useuntil, type; 1874 zic_t starttime = 0, untiltime = 0; 1875 long gmtoff, stdoff, startoff; 1876 int year, startttisstd = FALSE, startttisgmt = FALSE; 1877 char *startbuf, *ab, *envvar; 1878 int max_abbr_len, max_envvar_len; 1879 int prodstic; /* all rules are min to max */ 1880 1881 max_abbr_len = 2 + max_format_len + max_abbrvar_len; 1882 max_envvar_len = 2 * max_abbr_len + 5 * 9; 1883 startbuf = emalloc(max_abbr_len + 1); 1884 ab = emalloc(max_abbr_len + 1); 1885 envvar = emalloc(max_envvar_len + 1); 1886 /* 1887 ** Now. . .finally. . .generate some useful data! 1888 */ 1889 timecnt = 0; 1890 typecnt = 0; 1891 charcnt = 0; 1892 prodstic = zonecount == 1; 1893 /* 1894 ** Thanks to Earl Chew 1895 ** for noting the need to unconditionally initialize startttisstd. 1896 */ 1897 min_year = max_year = EPOCH_YEAR; 1898 if (leapseen) { 1899 updateminmax(leapminyear); 1900 updateminmax(leapmaxyear + (leapmaxyear < INT_MAX)); 1901 } 1902 for (i = 0; i < zonecount; ++i) { 1903 zp = &zpfirst[i]; 1904 if (i < zonecount - 1) 1905 updateminmax(zp->z_untilrule.r_loyear); 1906 for (j = 0; j < zp->z_nrules; ++j) { 1907 rp = &zp->z_rules[j]; 1908 if (rp->r_lowasnum) 1909 updateminmax(rp->r_loyear); 1910 if (rp->r_hiwasnum) 1911 updateminmax(rp->r_hiyear); 1912 if (rp->r_lowasnum || rp->r_hiwasnum) 1913 prodstic = FALSE; 1914 } 1915 } 1916 /* 1917 ** Generate lots of data if a rule can't cover all future times. 1918 */ 1919 stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount); 1920 if (noise && envvar[0] == '\0') { 1921 char * wp; 1922 1923 wp = ecpyalloc("no POSIX environment variable for zone"); 1924 wp = ecatalloc(wp, " "); 1925 wp = ecatalloc(wp, zpfirst->z_name); 1926 warning(wp); 1927 free(wp); 1928 } 1929 if (envvar[0] == '\0') { 1930 if (min_year >= INT_MIN + YEARSPERREPEAT) 1931 min_year -= YEARSPERREPEAT; 1932 else 1933 min_year = INT_MIN; 1934 if (max_year <= INT_MAX - YEARSPERREPEAT) 1935 max_year += YEARSPERREPEAT; 1936 else 1937 max_year = INT_MAX; 1938 /* 1939 ** Regardless of any of the above, 1940 ** for a "proDSTic" zone which specifies that its rules 1941 ** always have and always will be in effect, 1942 ** we only need one cycle to define the zone. 1943 */ 1944 if (prodstic) { 1945 min_year = 1900; 1946 max_year = min_year + YEARSPERREPEAT; 1947 } 1948 } 1949 /* 1950 ** For the benefit of older systems, 1951 ** generate data from 1900 through 2037. 1952 */ 1953 if (min_year > 1900) 1954 min_year = 1900; 1955 if (max_year < 2037) 1956 max_year = 2037; 1957 for (i = 0; i < zonecount; ++i) { 1958 /* 1959 ** A guess that may well be corrected later. 1960 */ 1961 stdoff = 0; 1962 zp = &zpfirst[i]; 1963 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 1964 useuntil = i < (zonecount - 1); 1965 if (useuntil && zp->z_untiltime <= min_time) 1966 continue; 1967 gmtoff = zp->z_gmtoff; 1968 eat(zp->z_filename, zp->z_linenum); 1969 *startbuf = '\0'; 1970 startoff = zp->z_gmtoff; 1971 if (zp->z_nrules == 0) { 1972 stdoff = zp->z_stdoff; 1973 doabbr(startbuf, max_abbr_len + 1, zp->z_format, 1974 NULL, stdoff != 0, FALSE); 1975 type = addtype(oadd(zp->z_gmtoff, stdoff), 1976 startbuf, stdoff != 0, startttisstd, 1977 startttisgmt); 1978 if (usestart) { 1979 addtt(starttime, type); 1980 usestart = FALSE; 1981 } else if (stdoff != 0) 1982 addtt(min_time, type); 1983 } else for (year = min_year; year <= max_year; ++year) { 1984 if (useuntil && year > zp->z_untilrule.r_hiyear) 1985 break; 1986 /* 1987 ** Mark which rules to do in the current year. 1988 ** For those to do, calculate rpytime(rp, year); 1989 */ 1990 for (j = 0; j < zp->z_nrules; ++j) { 1991 rp = &zp->z_rules[j]; 1992 eats(zp->z_filename, zp->z_linenum, 1993 rp->r_filename, rp->r_linenum); 1994 rp->r_todo = year >= rp->r_loyear && 1995 year <= rp->r_hiyear && 1996 yearistype(year, rp->r_yrtype); 1997 if (rp->r_todo) 1998 rp->r_temp = rpytime(rp, year); 1999 } 2000 for ( ; ; ) { 2001 int k; 2002 zic_t jtime, ktime = 0; 2003 long offset; 2004 2005 if (useuntil) { 2006 /* 2007 ** Turn untiltime into UTC 2008 ** assuming the current gmtoff and 2009 ** stdoff values. 2010 */ 2011 untiltime = zp->z_untiltime; 2012 if (!zp->z_untilrule.r_todisgmt) 2013 untiltime = tadd(untiltime, 2014 -gmtoff); 2015 if (!zp->z_untilrule.r_todisstd) 2016 untiltime = tadd(untiltime, 2017 -stdoff); 2018 } 2019 /* 2020 ** Find the rule (of those to do, if any) 2021 ** that takes effect earliest in the year. 2022 */ 2023 k = -1; 2024 for (j = 0; j < zp->z_nrules; ++j) { 2025 rp = &zp->z_rules[j]; 2026 if (!rp->r_todo) 2027 continue; 2028 eats(zp->z_filename, zp->z_linenum, 2029 rp->r_filename, rp->r_linenum); 2030 offset = rp->r_todisgmt ? 0 : gmtoff; 2031 if (!rp->r_todisstd) 2032 offset = oadd(offset, stdoff); 2033 jtime = rp->r_temp; 2034 if (jtime == min_time || 2035 jtime == max_time) 2036 continue; 2037 jtime = tadd(jtime, -offset); 2038 if (k < 0 || jtime < ktime) { 2039 k = j; 2040 ktime = jtime; 2041 } 2042 } 2043 if (k < 0) 2044 break; /* go on to next year */ 2045 rp = &zp->z_rules[k]; 2046 rp->r_todo = FALSE; 2047 if (useuntil && ktime >= untiltime) 2048 break; 2049 stdoff = rp->r_stdoff; 2050 if (usestart && ktime == starttime) 2051 usestart = FALSE; 2052 if (usestart) { 2053 if (ktime < starttime) { 2054 startoff = oadd(zp->z_gmtoff, 2055 stdoff); 2056 doabbr(startbuf, 2057 max_abbr_len + 1, 2058 zp->z_format, 2059 rp->r_abbrvar, 2060 rp->r_stdoff != 0, 2061 FALSE); 2062 continue; 2063 } 2064 if (*startbuf == '\0' && 2065 startoff == oadd(zp->z_gmtoff, 2066 stdoff)) { 2067 doabbr(startbuf, 2068 max_abbr_len + 1, 2069 zp->z_format, 2070 rp->r_abbrvar, 2071 rp->r_stdoff != 0, 2072 FALSE); 2073 } 2074 } 2075 eats(zp->z_filename, zp->z_linenum, 2076 rp->r_filename, rp->r_linenum); 2077 doabbr(ab, max_abbr_len + 1, zp->z_format, 2078 rp->r_abbrvar, rp->r_stdoff != 0, FALSE); 2079 offset = oadd(zp->z_gmtoff, rp->r_stdoff); 2080 type = addtype(offset, ab, rp->r_stdoff != 0, 2081 rp->r_todisstd, rp->r_todisgmt); 2082 addtt(ktime, type); 2083 } 2084 } 2085 if (usestart) { 2086 if (*startbuf == '\0' && 2087 zp->z_format != NULL && 2088 strchr(zp->z_format, '%') == NULL && 2089 strchr(zp->z_format, '/') == NULL) 2090 strlcpy(startbuf, zp->z_format, max_abbr_len + 1); 2091 eat(zp->z_filename, zp->z_linenum); 2092 if (*startbuf == '\0') 2093 error("can't determine time zone abbreviation to use just after until time"); 2094 else 2095 addtt(starttime, 2096 addtype(startoff, startbuf, 2097 startoff != zp->z_gmtoff, 2098 startttisstd, startttisgmt)); 2099 } 2100 /* 2101 ** Now we may get to set starttime for the next zone line. 2102 */ 2103 if (useuntil) { 2104 startttisstd = zp->z_untilrule.r_todisstd; 2105 startttisgmt = zp->z_untilrule.r_todisgmt; 2106 starttime = zp->z_untiltime; 2107 if (!startttisstd) 2108 starttime = tadd(starttime, -stdoff); 2109 if (!startttisgmt) 2110 starttime = tadd(starttime, -gmtoff); 2111 } 2112 } 2113 writezone(zpfirst->z_name, envvar); 2114 free(startbuf); 2115 free(ab); 2116 free(envvar); 2117 } 2118 2119 static void 2120 addtt(const zic_t starttime, int type) 2121 { 2122 size_t len; 2123 2124 if (starttime <= min_time || 2125 (timecnt == 1 && attypes[0].at < min_time)) { 2126 gmtoffs[0] = gmtoffs[type]; 2127 isdsts[0] = isdsts[type]; 2128 ttisstds[0] = ttisstds[type]; 2129 ttisgmts[0] = ttisgmts[type]; 2130 if (abbrinds[type] != 0) { 2131 len = strlen(&chars[abbrinds[type]]) + 1; 2132 memmove(chars, &chars[abbrinds[type]], len); 2133 } 2134 abbrinds[0] = 0; 2135 charcnt = strlen(chars) + 1; 2136 typecnt = 1; 2137 timecnt = 0; 2138 type = 0; 2139 } 2140 if (timecnt >= TZ_MAX_TIMES) { 2141 error("too many transitions?!"); 2142 exit(EXIT_FAILURE); 2143 } 2144 attypes[timecnt].at = starttime; 2145 attypes[timecnt].type = type; 2146 ++timecnt; 2147 } 2148 2149 static int 2150 addtype(long gmtoff, const char *abbr, int isdst, int ttisstd, int ttisgmt) 2151 { 2152 int i, j; 2153 2154 if (isdst != TRUE && isdst != FALSE) { 2155 error("internal error - addtype called with bad isdst"); 2156 exit(EXIT_FAILURE); 2157 } 2158 if (ttisstd != TRUE && ttisstd != FALSE) { 2159 error("internal error - addtype called with bad ttisstd"); 2160 exit(EXIT_FAILURE); 2161 } 2162 if (ttisgmt != TRUE && ttisgmt != FALSE) { 2163 error("internal error - addtype called with bad ttisgmt"); 2164 exit(EXIT_FAILURE); 2165 } 2166 /* 2167 ** See if there's already an entry for this zone type. 2168 ** If so, just return its index. 2169 */ 2170 for (i = 0; i < typecnt; ++i) { 2171 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 2172 strcmp(abbr, &chars[abbrinds[i]]) == 0 && 2173 ttisstd == ttisstds[i] && 2174 ttisgmt == ttisgmts[i]) 2175 return i; 2176 } 2177 /* 2178 ** There isn't one; add a new one, unless there are already too 2179 ** many. 2180 */ 2181 if (typecnt >= TZ_MAX_TYPES) { 2182 error("too many local time types"); 2183 exit(EXIT_FAILURE); 2184 } 2185 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { 2186 error("UTC offset out of range"); 2187 exit(EXIT_FAILURE); 2188 } 2189 gmtoffs[i] = gmtoff; 2190 isdsts[i] = isdst; 2191 ttisstds[i] = ttisstd; 2192 ttisgmts[i] = ttisgmt; 2193 2194 for (j = 0; j < charcnt; ++j) 2195 if (strcmp(&chars[j], abbr) == 0) 2196 break; 2197 if (j == charcnt) 2198 newabbr(abbr); 2199 abbrinds[i] = j; 2200 ++typecnt; 2201 return i; 2202 } 2203 2204 static void 2205 leapadd(zic_t t, int positive, int rolling, int count) 2206 { 2207 int i, j; 2208 2209 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 2210 error("too many leap seconds"); 2211 exit(EXIT_FAILURE); 2212 } 2213 for (i = 0; i < leapcnt; ++i) 2214 if (t <= trans[i]) { 2215 if (t == trans[i]) { 2216 error("repeated leap second moment"); 2217 exit(EXIT_FAILURE); 2218 } 2219 break; 2220 } 2221 do { 2222 for (j = leapcnt; j > i; --j) { 2223 trans[j] = trans[j - 1]; 2224 corr[j] = corr[j - 1]; 2225 roll[j] = roll[j - 1]; 2226 } 2227 trans[i] = t; 2228 corr[i] = positive ? 1L : eitol(-count); 2229 roll[i] = rolling; 2230 ++leapcnt; 2231 } while (positive && --count != 0); 2232 } 2233 2234 static void 2235 adjleap(void) 2236 { 2237 int i; 2238 long last = 0; 2239 2240 /* 2241 ** propagate leap seconds forward 2242 */ 2243 for (i = 0; i < leapcnt; ++i) { 2244 trans[i] = tadd(trans[i], last); 2245 last = corr[i] += last; 2246 } 2247 } 2248 2249 static int 2250 yearistype(int year, const char *type) 2251 { 2252 static char *buf; 2253 int result; 2254 size_t len; 2255 2256 if (type == NULL || *type == '\0') 2257 return TRUE; 2258 len = 132 + strlen(yitcommand) + strlen(type); 2259 buf = erealloc(buf, len); 2260 snprintf(buf, len, "%s %d %s", yitcommand, year, type); 2261 result = system(buf); 2262 if (WIFEXITED(result)) 2263 switch (WEXITSTATUS(result)) { 2264 case 0: 2265 return TRUE; 2266 case 1: 2267 return FALSE; 2268 } 2269 error("Wild result from command execution"); 2270 errx(1, "command was '%s', result was %d", buf, result); 2271 } 2272 2273 /* this function is not strncasecmp */ 2274 static int 2275 itsabbr(const char *sabbr, const char *sword) 2276 { 2277 const unsigned char *abbr = sabbr; 2278 const unsigned char *word = sword; 2279 2280 if (tolower(*abbr) != tolower(*word)) 2281 return FALSE; 2282 while (*++abbr != '\0') 2283 do { 2284 ++word; 2285 if (*word == '\0') 2286 return FALSE; 2287 } while (tolower(*word) != tolower(*abbr)); 2288 return TRUE; 2289 } 2290 2291 static const struct lookup * 2292 byword(const char *word, const struct lookup *table) 2293 { 2294 const struct lookup *foundlp; 2295 const struct lookup *lp; 2296 2297 if (word == NULL || table == NULL) 2298 return NULL; 2299 /* 2300 ** Look for exact match. 2301 */ 2302 for (lp = table; lp->l_word != NULL; ++lp) 2303 if (strcasecmp(word, lp->l_word) == 0) 2304 return lp; 2305 /* 2306 ** Look for inexact match. 2307 */ 2308 foundlp = NULL; 2309 for (lp = table; lp->l_word != NULL; ++lp) 2310 if (itsabbr(word, lp->l_word)) { 2311 if (foundlp == NULL) 2312 foundlp = lp; 2313 else 2314 return NULL; /* multiple inexact matches */ 2315 } 2316 return foundlp; 2317 } 2318 2319 static char ** 2320 getfields(char *cp) 2321 { 2322 char *dp; 2323 char **array; 2324 int nsubs; 2325 2326 if (cp == NULL) 2327 return NULL; 2328 array = ereallocarray(NULL, strlen(cp) + 1, sizeof *array); 2329 nsubs = 0; 2330 for ( ; ; ) { 2331 while (isascii((unsigned char)*cp) && 2332 isspace((unsigned char)*cp)) 2333 ++cp; 2334 if (*cp == '\0' || *cp == '#') 2335 break; 2336 array[nsubs++] = dp = cp; 2337 do { 2338 if ((*dp = *cp++) != '"') { 2339 ++dp; 2340 } else { 2341 while ((*dp = *cp++) != '"') { 2342 if (*dp != '\0') 2343 ++dp; 2344 else { 2345 error("Odd number of quotation marks"); 2346 exit(EXIT_FAILURE); 2347 } 2348 } 2349 } 2350 } while (*cp != '\0' && *cp != '#' && 2351 (!isascii((unsigned char)*cp) || !isspace((unsigned char)*cp))); 2352 if (isascii((unsigned char)*cp) && isspace((unsigned char)*cp)) 2353 ++cp; 2354 *dp = '\0'; 2355 } 2356 array[nsubs] = NULL; 2357 return array; 2358 } 2359 2360 static long 2361 oadd(long t1, long t2) 2362 { 2363 long t = t1 + t2; 2364 2365 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 2366 error("time overflow"); 2367 exit(EXIT_FAILURE); 2368 } 2369 return t; 2370 } 2371 2372 static zic_t 2373 tadd(zic_t t1, long t2) 2374 { 2375 zic_t t; 2376 2377 if (t1 == max_time && t2 > 0) 2378 return max_time; 2379 if (t1 == min_time && t2 < 0) 2380 return min_time; 2381 t = t1 + t2; 2382 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 2383 error("time overflow"); 2384 exit(EXIT_FAILURE); 2385 } 2386 return t; 2387 } 2388 2389 /* 2390 ** Given a rule, and a year, compute the date - in seconds since January 1, 2391 ** 1970, 00:00 LOCAL time - in that year that the rule refers to. 2392 */ 2393 static zic_t 2394 rpytime(const struct rule *rp, int wantedy) 2395 { 2396 int y, m, i; 2397 long dayoff; /* with a nod to Margaret O. */ 2398 zic_t t; 2399 2400 if (wantedy == INT_MIN) 2401 return min_time; 2402 if (wantedy == INT_MAX) 2403 return max_time; 2404 dayoff = 0; 2405 m = TM_JANUARY; 2406 y = EPOCH_YEAR; 2407 while (wantedy != y) { 2408 if (wantedy > y) { 2409 i = len_years[isleap(y)]; 2410 ++y; 2411 } else { 2412 --y; 2413 i = -len_years[isleap(y)]; 2414 } 2415 dayoff = oadd(dayoff, eitol(i)); 2416 } 2417 while (m != rp->r_month) { 2418 i = len_months[isleap(y)][m]; 2419 dayoff = oadd(dayoff, eitol(i)); 2420 ++m; 2421 } 2422 i = rp->r_dayofmonth; 2423 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 2424 if (rp->r_dycode == DC_DOWLEQ) 2425 --i; 2426 else { 2427 error("use of 2/29 in non leap-year"); 2428 exit(EXIT_FAILURE); 2429 } 2430 } 2431 --i; 2432 dayoff = oadd(dayoff, eitol(i)); 2433 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 2434 long wday; 2435 2436 #define LDAYSPERWEEK ((long) DAYSPERWEEK) 2437 wday = eitol(EPOCH_WDAY); 2438 /* 2439 ** Don't trust mod of negative numbers. 2440 */ 2441 if (dayoff >= 0) 2442 wday = (wday + dayoff) % LDAYSPERWEEK; 2443 else { 2444 wday -= ((-dayoff) % LDAYSPERWEEK); 2445 if (wday < 0) 2446 wday += LDAYSPERWEEK; 2447 } 2448 while (wday != eitol(rp->r_wday)) 2449 if (rp->r_dycode == DC_DOWGEQ) { 2450 dayoff = oadd(dayoff, 1); 2451 if (++wday >= LDAYSPERWEEK) 2452 wday = 0; 2453 ++i; 2454 } else { 2455 dayoff = oadd(dayoff, -1); 2456 if (--wday < 0) 2457 wday = LDAYSPERWEEK - 1; 2458 --i; 2459 } 2460 } 2461 if (dayoff < min_time / SECSPERDAY) 2462 return min_time; 2463 if (dayoff > max_time / SECSPERDAY) 2464 return max_time; 2465 t = (zic_t) dayoff * SECSPERDAY; 2466 return tadd(t, rp->r_tod); 2467 } 2468 2469 static void 2470 newabbr(const char *string) 2471 { 2472 int i; 2473 2474 if (strcmp(string, GRANDPARENTED) != 0) { 2475 const char * cp; 2476 char * wp; 2477 2478 cp = string; 2479 wp = NULL; 2480 while (isascii((unsigned char)*cp) && 2481 (isalnum((unsigned char)*cp) || *cp == '-' || *cp == '+')) 2482 ++cp; 2483 if (noise && cp - string > 3) 2484 wp = "time zone abbreviation has more than 3 characters"; 2485 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) 2486 wp = "time zone abbreviation has too many characters"; 2487 if (*cp != '\0') 2488 wp = "time zone abbreviation differs from POSIX standard"; 2489 if (wp != NULL) { 2490 wp = ecpyalloc(wp); 2491 wp = ecatalloc(wp, " ("); 2492 wp = ecatalloc(wp, string); 2493 wp = ecatalloc(wp, ")"); 2494 warning(wp); 2495 free(wp); 2496 } 2497 } 2498 i = strlen(string) + 1; 2499 if (charcnt + i > TZ_MAX_CHARS) { 2500 error("too many, or too long, time zone abbreviations"); 2501 exit(EXIT_FAILURE); 2502 } 2503 strlcpy(&chars[charcnt], string, sizeof(chars) - charcnt); 2504 charcnt += eitol(i); 2505 } 2506 2507 static int 2508 mkdirs(char *argname) 2509 { 2510 char * name; 2511 char * cp; 2512 2513 if (argname == NULL || *argname == '\0') 2514 return 0; 2515 cp = name = ecpyalloc(argname); 2516 while ((cp = strchr(cp + 1, '/')) != 0) { 2517 *cp = '\0'; 2518 if (!itsdir(name)) { 2519 /* 2520 ** It doesn't seem to exist, so we try to create it. 2521 ** Creation may fail because of the directory being 2522 ** created by some other multiprocessor, so we get 2523 ** to do extra checking. 2524 */ 2525 if (mkdir(name, MKDIR_UMASK) != 0) { 2526 const char *e = strerror(errno); 2527 2528 if (errno != EEXIST || !itsdir(name)) { 2529 fprintf(stderr, 2530 "%s: Can't create directory %s: %s\n", 2531 __progname, name, e); 2532 free(name); 2533 return -1; 2534 } 2535 } 2536 } 2537 *cp = '/'; 2538 } 2539 free(name); 2540 return 0; 2541 } 2542 2543 static long 2544 eitol(int i) 2545 { 2546 long l = i; 2547 2548 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) 2549 errx(1, "%d did not sign extend correctly", i); 2550 return l; 2551 } 2552