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