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