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