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