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