1 /* $NetBSD: zic.c,v 1.77 2020/10/09 18:38:48 christos Exp $ */ 2 /* 3 ** This file is in the public domain, so clarified as of 4 ** 2006-07-17 by Arthur David Olson. 5 */ 6 /* Compile .zi time zone data into TZif binary files. */ 7 8 #if HAVE_NBTOOL_CONFIG_H 9 #include "nbtool_config.h" 10 #endif 11 12 #include <sys/cdefs.h> 13 #ifndef lint 14 __RCSID("$NetBSD: zic.c,v 1.77 2020/10/09 18:38:48 christos Exp $"); 15 #endif /* !defined lint */ 16 17 #include "private.h" 18 #include "tzfile.h" 19 20 #include <fcntl.h> 21 #include <locale.h> 22 #include <stdarg.h> 23 #include <stddef.h> 24 #include <stdio.h> 25 #include <unistd.h> 26 #include <util.h> 27 28 #define ZIC_VERSION_PRE_2013 '2' 29 #define ZIC_VERSION '3' 30 31 typedef int_fast64_t zic_t; 32 #define ZIC_MIN INT_FAST64_MIN 33 #define ZIC_MAX INT_FAST64_MAX 34 #define PRIdZIC PRIdFAST64 35 #define SCNdZIC SCNdFAST64 36 37 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN 38 #define ZIC_MAX_ABBR_LEN_WO_WARN 6 39 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ 40 41 #ifdef HAVE_DIRECT_H 42 # include <direct.h> 43 # include <io.h> 44 # undef mkdir 45 # define mkdir(name, mode) _mkdir(name) 46 #endif 47 48 #if HAVE_SYS_STAT_H 49 #include <sys/stat.h> 50 #endif 51 #ifdef S_IRUSR 52 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 53 #else 54 #define MKDIR_UMASK 0755 55 #endif 56 /* Port to native MS-Windows and to ancient UNIX. */ 57 #if !defined S_ISDIR && defined S_IFDIR && defined S_IFMT 58 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 59 #endif 60 61 #if HAVE_SYS_WAIT_H 62 #include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */ 63 #endif /* HAVE_SYS_WAIT_H */ 64 65 #ifndef WIFEXITED 66 #define WIFEXITED(status) (((status) & 0xff) == 0) 67 #endif /* !defined WIFEXITED */ 68 #ifndef WEXITSTATUS 69 #define WEXITSTATUS(status) (((status) >> 8) & 0xff) 70 #endif /* !defined WEXITSTATUS */ 71 72 /* The maximum ptrdiff_t value, for pre-C99 platforms. */ 73 #ifndef PTRDIFF_MAX 74 static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t)); 75 #endif 76 77 /* The minimum alignment of a type, for pre-C11 platforms. */ 78 #if __STDC_VERSION__ < 201112 79 # define _Alignof(type) offsetof(struct { char a; type b; }, b) 80 #endif 81 82 /* The type for line numbers. Use PRIdMAX to format them; formerly 83 there was also "#define PRIdLINENO PRIdMAX" and formats used 84 PRIdLINENO, but xgettext cannot grok that. */ 85 typedef intmax_t lineno; 86 87 struct rule { 88 const char * r_filename; 89 lineno r_linenum; 90 const char * r_name; 91 92 zic_t r_loyear; /* for example, 1986 */ 93 zic_t r_hiyear; /* for example, 1986 */ 94 bool r_lowasnum; 95 bool r_hiwasnum; 96 97 int r_month; /* 0..11 */ 98 99 int r_dycode; /* see below */ 100 int r_dayofmonth; 101 int r_wday; 102 103 zic_t r_tod; /* time from midnight */ 104 bool r_todisstd; /* is r_tod standard time? */ 105 bool r_todisut; /* is r_tod UT? */ 106 bool r_isdst; /* is this daylight saving time? */ 107 zic_t r_save; /* offset from standard time */ 108 const char * r_abbrvar; /* variable part of abbreviation */ 109 110 bool r_todo; /* a rule to do (used in outzone) */ 111 zic_t r_temp; /* used in outzone */ 112 }; 113 114 /* 115 ** r_dycode r_dayofmonth r_wday 116 */ 117 118 #define DC_DOM 0 /* 1..31 */ /* unused */ 119 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 120 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 121 122 struct zone { 123 const char * z_filename; 124 lineno z_linenum; 125 126 const char * z_name; 127 zic_t z_stdoff; 128 char * z_rule; 129 const char * z_format; 130 char z_format_specifier; 131 132 bool z_isdst; 133 zic_t z_save; 134 135 struct rule * z_rules; 136 ptrdiff_t z_nrules; 137 138 struct rule z_untilrule; 139 zic_t z_untiltime; 140 }; 141 142 #if !HAVE_POSIX_DECLS 143 extern int getopt(int argc, char * const argv[], 144 const char * options); 145 extern int link(const char * target, const char * linkname); 146 extern char * optarg; 147 extern int optind; 148 #endif 149 150 #if ! HAVE_LINK 151 # define link(target, linkname) (errno = ENOTSUP, -1) 152 #endif 153 #if ! HAVE_SYMLINK 154 # define readlink(file, buf, size) (errno = ENOTSUP, -1) 155 # define symlink(target, linkname) (errno = ENOTSUP, -1) 156 # define S_ISLNK(m) 0 157 #endif 158 #ifndef AT_SYMLINK_FOLLOW 159 # define linkat(targetdir, target, linknamedir, linkname, flag) \ 160 (itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname)) 161 #endif 162 163 static void addtt(zic_t starttime, int type); 164 static int addtype(zic_t, char const *, bool, bool, bool); 165 static void leapadd(zic_t, int, int); 166 static void adjleap(void); 167 static void associate(void); 168 static void dolink(const char *, const char *, bool); 169 static char ** getfields(char * buf); 170 static zic_t gethms(const char * string, const char * errstring); 171 static zic_t getsave(char *, bool *); 172 static void inexpires(char **, int); 173 static void infile(const char * filename); 174 static void inleap(char ** fields, int nfields); 175 static void inlink(char ** fields, int nfields); 176 static void inrule(char ** fields, int nfields); 177 static bool inzcont(char ** fields, int nfields); 178 static bool inzone(char ** fields, int nfields); 179 static bool inzsub(char **, int, bool); 180 static bool itsdir(char const *); 181 static bool itssymlink(char const *); 182 static bool is_alpha(char a); 183 static char lowerit(char); 184 static void mkdirs(char const *, bool); 185 static void newabbr(const char * abbr); 186 static zic_t oadd(zic_t t1, zic_t t2); 187 static void outzone(const struct zone * zp, ptrdiff_t ntzones); 188 static zic_t rpytime(const struct rule * rp, zic_t wantedy); 189 static void rulesub(struct rule * rp, 190 const char * loyearp, const char * hiyearp, 191 const char * typep, const char * monthp, 192 const char * dayp, const char * timep); 193 static zic_t tadd(zic_t t1, zic_t t2); 194 195 /* Bound on length of what %z can expand to. */ 196 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 }; 197 198 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles 199 TZif files whose POSIX-TZ-style strings contain '<'; see 200 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This 201 workaround will no longer be needed when Qt 5.6.1 and earlier are 202 obsolete, say in the year 2021. */ 203 #ifndef WORK_AROUND_QTBUG_53071 204 enum { WORK_AROUND_QTBUG_53071 = true }; 205 #endif 206 207 static int charcnt; 208 static bool errors; 209 static bool warnings; 210 static const char * filename; 211 static int leapcnt; 212 static bool leapseen; 213 static zic_t leapminyear; 214 static zic_t leapmaxyear; 215 static lineno linenum; 216 static size_t max_abbrvar_len = PERCENT_Z_LEN_BOUND; 217 static size_t max_format_len; 218 static zic_t max_year; 219 static zic_t min_year; 220 static bool noise; 221 static const char * rfilename; 222 static lineno rlinenum; 223 static const char * progname; 224 static ptrdiff_t timecnt; 225 static ptrdiff_t timecnt_alloc; 226 static int typecnt; 227 228 /* 229 ** Line codes. 230 */ 231 232 #define LC_RULE 0 233 #define LC_ZONE 1 234 #define LC_LINK 2 235 #define LC_LEAP 3 236 #define LC_EXPIRES 4 237 238 /* 239 ** Which fields are which on a Zone line. 240 */ 241 242 #define ZF_NAME 1 243 #define ZF_STDOFF 2 244 #define ZF_RULE 3 245 #define ZF_FORMAT 4 246 #define ZF_TILYEAR 5 247 #define ZF_TILMONTH 6 248 #define ZF_TILDAY 7 249 #define ZF_TILTIME 8 250 #define ZONE_MINFIELDS 5 251 #define ZONE_MAXFIELDS 9 252 253 /* 254 ** Which fields are which on a Zone continuation line. 255 */ 256 257 #define ZFC_STDOFF 0 258 #define ZFC_RULE 1 259 #define ZFC_FORMAT 2 260 #define ZFC_TILYEAR 3 261 #define ZFC_TILMONTH 4 262 #define ZFC_TILDAY 5 263 #define ZFC_TILTIME 6 264 #define ZONEC_MINFIELDS 3 265 #define ZONEC_MAXFIELDS 7 266 267 /* 268 ** Which files are which on a Rule line. 269 */ 270 271 #define RF_NAME 1 272 #define RF_LOYEAR 2 273 #define RF_HIYEAR 3 274 #define RF_COMMAND 4 275 #define RF_MONTH 5 276 #define RF_DAY 6 277 #define RF_TOD 7 278 #define RF_SAVE 8 279 #define RF_ABBRVAR 9 280 #define RULE_FIELDS 10 281 282 /* 283 ** Which fields are which on a Link line. 284 */ 285 286 #define LF_TARGET 1 287 #define LF_LINKNAME 2 288 #define LINK_FIELDS 3 289 290 /* 291 ** Which fields are which on a Leap line. 292 */ 293 294 #define LP_YEAR 1 295 #define LP_MONTH 2 296 #define LP_DAY 3 297 #define LP_TIME 4 298 #define LP_CORR 5 299 #define LP_ROLL 6 300 #define LEAP_FIELDS 7 301 302 /* Expires lines are like Leap lines, except without CORR and ROLL fields. */ 303 #define EXPIRES_FIELDS 5 304 305 /* 306 ** Year synonyms. 307 */ 308 309 #define YR_MINIMUM 0 310 #define YR_MAXIMUM 1 311 #define YR_ONLY 2 312 313 static struct rule * rules; 314 static ptrdiff_t nrules; /* number of rules */ 315 static ptrdiff_t nrules_alloc; 316 317 static struct zone * zones; 318 static ptrdiff_t nzones; /* number of zones */ 319 static ptrdiff_t nzones_alloc; 320 321 struct link { 322 const char * l_filename; 323 lineno l_linenum; 324 const char * l_target; 325 const char * l_linkname; 326 }; 327 328 static struct link * links; 329 static ptrdiff_t nlinks; 330 static ptrdiff_t nlinks_alloc; 331 332 struct lookup { 333 const char * l_word; 334 const int l_value; 335 }; 336 337 static struct lookup const * byword(const char * string, 338 const struct lookup * lp); 339 340 static struct lookup const zi_line_codes[] = { 341 { "Rule", LC_RULE }, 342 { "Zone", LC_ZONE }, 343 { "Link", LC_LINK }, 344 { NULL, 0 } 345 }; 346 static struct lookup const leap_line_codes[] = { 347 { "Leap", LC_LEAP }, 348 { "Expires", LC_EXPIRES }, 349 { NULL, 0} 350 }; 351 352 static struct lookup const mon_names[] = { 353 { "January", TM_JANUARY }, 354 { "February", TM_FEBRUARY }, 355 { "March", TM_MARCH }, 356 { "April", TM_APRIL }, 357 { "May", TM_MAY }, 358 { "June", TM_JUNE }, 359 { "July", TM_JULY }, 360 { "August", TM_AUGUST }, 361 { "September", TM_SEPTEMBER }, 362 { "October", TM_OCTOBER }, 363 { "November", TM_NOVEMBER }, 364 { "December", TM_DECEMBER }, 365 { NULL, 0 } 366 }; 367 368 static struct lookup const wday_names[] = { 369 { "Sunday", TM_SUNDAY }, 370 { "Monday", TM_MONDAY }, 371 { "Tuesday", TM_TUESDAY }, 372 { "Wednesday", TM_WEDNESDAY }, 373 { "Thursday", TM_THURSDAY }, 374 { "Friday", TM_FRIDAY }, 375 { "Saturday", TM_SATURDAY }, 376 { NULL, 0 } 377 }; 378 379 static struct lookup const lasts[] = { 380 { "last-Sunday", TM_SUNDAY }, 381 { "last-Monday", TM_MONDAY }, 382 { "last-Tuesday", TM_TUESDAY }, 383 { "last-Wednesday", TM_WEDNESDAY }, 384 { "last-Thursday", TM_THURSDAY }, 385 { "last-Friday", TM_FRIDAY }, 386 { "last-Saturday", TM_SATURDAY }, 387 { NULL, 0 } 388 }; 389 390 static struct lookup const begin_years[] = { 391 { "minimum", YR_MINIMUM }, 392 { "maximum", YR_MAXIMUM }, 393 { NULL, 0 } 394 }; 395 396 static struct lookup const end_years[] = { 397 { "minimum", YR_MINIMUM }, 398 { "maximum", YR_MAXIMUM }, 399 { "only", YR_ONLY }, 400 { NULL, 0 } 401 }; 402 403 static struct lookup const leap_types[] = { 404 { "Rolling", true }, 405 { "Stationary", false }, 406 { NULL, 0 } 407 }; 408 409 static const int len_months[2][MONSPERYEAR] = { 410 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 411 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 412 }; 413 414 static const int len_years[2] = { 415 DAYSPERNYEAR, DAYSPERLYEAR 416 }; 417 418 static struct attype { 419 zic_t at; 420 bool dontmerge; 421 unsigned char type; 422 } * attypes; 423 static zic_t utoffs[TZ_MAX_TYPES]; 424 static char isdsts[TZ_MAX_TYPES]; 425 static unsigned char desigidx[TZ_MAX_TYPES]; 426 static bool ttisstds[TZ_MAX_TYPES]; 427 static bool ttisuts[TZ_MAX_TYPES]; 428 static char chars[TZ_MAX_CHARS]; 429 static zic_t trans[TZ_MAX_LEAPS]; 430 static zic_t corr[TZ_MAX_LEAPS]; 431 static char roll[TZ_MAX_LEAPS]; 432 433 /* 434 ** Memory allocation. 435 */ 436 437 static _Noreturn void 438 memory_exhausted(const char *msg) 439 { 440 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg); 441 exit(EXIT_FAILURE); 442 } 443 444 static ATTRIBUTE_PURE size_t 445 size_product(size_t nitems, size_t itemsize) 446 { 447 if (SIZE_MAX / itemsize < nitems) 448 memory_exhausted(_("size overflow")); 449 return nitems * itemsize; 450 } 451 452 static ATTRIBUTE_PURE size_t 453 align_to(size_t size, size_t alignment) 454 { 455 size_t aligned_size = size + alignment - 1; 456 aligned_size -= aligned_size % alignment; 457 if (aligned_size < size) 458 memory_exhausted(_("alignment overflow")); 459 return aligned_size; 460 } 461 462 #if !HAVE_STRDUP 463 static char * 464 strdup(char const *str) 465 { 466 char *result = malloc(strlen(str) + 1); 467 return result ? strcpy(result, str) : result; 468 } 469 #endif 470 471 static void * 472 memcheck(void *ptr) 473 { 474 if (ptr == NULL) 475 memory_exhausted(strerror(errno)); 476 return ptr; 477 } 478 479 static void * ATTRIBUTE_MALLOC 480 zic_malloc(size_t size) 481 { 482 return memcheck(malloc(size)); 483 } 484 485 static void * 486 zic_realloc(void *ptr, size_t size) 487 { 488 return memcheck(realloc(ptr, size)); 489 } 490 491 static char * ATTRIBUTE_MALLOC 492 ecpyalloc(char const *str) 493 { 494 return memcheck(strdup(str)); 495 } 496 497 static void * 498 growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc) 499 { 500 if (nitems < *nitems_alloc) 501 return ptr; 502 else { 503 ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071; 504 ptrdiff_t amax = (ptrdiff_t)((size_t)nitems_max < SIZE_MAX ? 505 (size_t)nitems_max : SIZE_MAX); 506 if ((amax - 1) / 3 * 2 < *nitems_alloc) 507 memory_exhausted(_("integer overflow")); 508 *nitems_alloc += (*nitems_alloc >> 1) + 1; 509 return zic_realloc(ptr, size_product(*nitems_alloc, itemsize)); 510 } 511 } 512 513 /* 514 ** Error handling. 515 */ 516 517 static void 518 eats(char const *name, lineno num, char const *rname, lineno rnum) 519 { 520 filename = name; 521 linenum = num; 522 rfilename = rname; 523 rlinenum = rnum; 524 } 525 526 static void 527 eat(char const *name, lineno num) 528 { 529 eats(name, num, NULL, -1); 530 } 531 532 static void ATTRIBUTE_FORMAT((printf, 1, 0)) 533 verror(const char *const string, va_list args) 534 { 535 /* 536 ** Match the format of "cc" to allow sh users to 537 ** zic ... 2>&1 | error -t "*" -v 538 ** on BSD systems. 539 */ 540 if (filename) 541 fprintf(stderr, _("\"%s\", line %"PRIdMAX": "), filename, linenum); 542 vfprintf(stderr, string, args); 543 if (rfilename != NULL) 544 fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"), 545 rfilename, rlinenum); 546 fprintf(stderr, "\n"); 547 } 548 549 static void ATTRIBUTE_FORMAT((printf, 1, 2)) 550 error(const char *const string, ...) 551 { 552 va_list args; 553 va_start(args, string); 554 verror(string, args); 555 va_end(args); 556 errors = true; 557 } 558 559 static void ATTRIBUTE_FORMAT((printf, 1, 2)) 560 warning(const char *const string, ...) 561 { 562 va_list args; 563 fprintf(stderr, _("warning: ")); 564 va_start(args, string); 565 verror(string, args); 566 va_end(args); 567 warnings = true; 568 } 569 570 static void 571 close_file(FILE *stream, char const *dir, char const *name) 572 { 573 char const *e = (ferror(stream) ? _("I/O error") 574 : fclose(stream) != 0 ? strerror(errno) : NULL); 575 if (e) { 576 fprintf(stderr, "%s: %s%s%s%s%s\n", progname, 577 dir ? dir : "", dir ? "/" : "", 578 name ? name : "", name ? ": " : "", 579 e); 580 exit(EXIT_FAILURE); 581 } 582 } 583 584 static _Noreturn void 585 usage(FILE *stream, int status) 586 { 587 fprintf(stream, 588 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n" 589 "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]" 590 " [ -L leapseconds ] \\\n" 591 "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -t localtime-link ] \\\n" 592 "\t[ filename ... ]\n\n" 593 "Report bugs to %s.\n"), 594 progname, progname, REPORT_BUGS_TO); 595 if (status == EXIT_SUCCESS) 596 close_file(stream, NULL, NULL); 597 exit(status); 598 } 599 600 /* Change the working directory to DIR, possibly creating DIR and its 601 ancestors. After this is done, all files are accessed with names 602 relative to DIR. */ 603 static void 604 change_directory (char const *dir) 605 { 606 if (chdir(dir) != 0) { 607 int chdir_errno = errno; 608 if (chdir_errno == ENOENT) { 609 mkdirs(dir, false); 610 chdir_errno = chdir(dir) == 0 ? 0 : errno; 611 } 612 if (chdir_errno != 0) { 613 fprintf(stderr, _("%s: Can't chdir to %s: %s\n"), 614 progname, dir, strerror(chdir_errno)); 615 exit(EXIT_FAILURE); 616 } 617 } 618 } 619 620 #define TIME_T_BITS_IN_FILE 64 621 622 /* The minimum and maximum values representable in a TZif file. */ 623 static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE); 624 static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE); 625 626 /* The minimum, and one less than the maximum, values specified by 627 the -r option. These default to MIN_TIME and MAX_TIME. */ 628 static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE); 629 static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE); 630 631 /* The time specified by an Expires line, or negative if no such line. */ 632 static zic_t leapexpires = -1; 633 634 /* The time specified by an #expires comment, or negative if no such line. */ 635 static zic_t comment_leapexpires = -1; 636 637 /* Set the time range of the output to TIMERANGE. 638 Return true if successful. */ 639 static bool 640 timerange_option(char *timerange) 641 { 642 intmax_t lo = min_time, hi = max_time; 643 char *lo_end = timerange, *hi_end; 644 if (*timerange == '@') { 645 errno = 0; 646 lo = strtoimax (timerange + 1, &lo_end, 10); 647 if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE)) 648 return false; 649 } 650 hi_end = lo_end; 651 if (lo_end[0] == '/' && lo_end[1] == '@') { 652 errno = 0; 653 hi = strtoimax (lo_end + 2, &hi_end, 10); 654 if (hi_end == lo_end + 2 || hi == INTMAX_MIN) 655 return false; 656 hi -= ! (hi == INTMAX_MAX && errno == ERANGE); 657 } 658 if (*hi_end || hi < lo || max_time < lo || hi < min_time) 659 return false; 660 lo_time = lo < min_time ? min_time : lo; 661 hi_time = max_time < hi ? max_time : hi; 662 return true; 663 } 664 665 static const char * psxrules; 666 static const char * lcltime; 667 static const char * directory; 668 static const char * leapsec; 669 static const char * tzdefault; 670 671 /* -1 if the TZif output file should be slim, 0 if default, 1 if the 672 output should be fat for backward compatibility. The default is slim. */ 673 static int bloat; 674 675 static bool 676 want_bloat(void) 677 { 678 return 0 <= bloat; 679 } 680 681 #ifndef ZIC_BLOAT_DEFAULT 682 # define ZIC_BLOAT_DEFAULT "slim" 683 #endif 684 685 int 686 main(int argc, char **argv) 687 { 688 int c, k; 689 ptrdiff_t i, j; 690 bool timerange_given = false; 691 692 #ifdef S_IWGRP 693 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 694 #endif 695 #if HAVE_GETTEXT 696 setlocale(LC_MESSAGES, ""); 697 #ifdef TZ_DOMAINDIR 698 bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 699 #endif /* defined TEXTDOMAINDIR */ 700 textdomain(TZ_DOMAIN); 701 #endif /* HAVE_GETTEXT */ 702 progname = argv[0]; 703 if (TYPE_BIT(zic_t) < 64) { 704 fprintf(stderr, "%s: %s\n", progname, 705 _("wild compilation-time specification of zic_t")); 706 return EXIT_FAILURE; 707 } 708 for (k = 1; k < argc; k++) 709 if (strcmp(argv[k], "--version") == 0) { 710 printf("zic %s%s\n", PKGVERSION, TZVERSION); 711 close_file(stdout, NULL, NULL); 712 return EXIT_SUCCESS; 713 } else if (strcmp(argv[k], "--help") == 0) { 714 usage(stdout, EXIT_SUCCESS); 715 } 716 while ((c = getopt(argc, argv, "b:d:l:L:p:r:st:vy:")) != EOF && c != -1) 717 switch (c) { 718 default: 719 usage(stderr, EXIT_FAILURE); 720 case 'b': 721 if (strcmp(optarg, "slim") == 0) { 722 if (0 < bloat) 723 error(_("incompatible -b options")); 724 bloat = -1; 725 } else if (strcmp(optarg, "fat") == 0) { 726 if (bloat < 0) 727 error(_("incompatible -b options")); 728 bloat = 1; 729 } else 730 error(_("invalid option: -b '%s'"), optarg); 731 break; 732 case 'd': 733 if (directory == NULL) 734 directory = optarg; 735 else { 736 fprintf(stderr, 737 _("%s: More than one -d option specified\n"), 738 progname); 739 return EXIT_FAILURE; 740 } 741 break; 742 case 'l': 743 if (lcltime == NULL) 744 lcltime = optarg; 745 else { 746 fprintf(stderr, 747 _("%s: More than one -l option specified\n"), 748 progname); 749 return EXIT_FAILURE; 750 } 751 break; 752 case 'p': 753 if (psxrules == NULL) 754 psxrules = optarg; 755 else { 756 fprintf(stderr, 757 _("%s: More than one -p option specified\n"), 758 progname); 759 return EXIT_FAILURE; 760 } 761 break; 762 case 't': 763 if (tzdefault != NULL) { 764 fprintf(stderr, 765 _("%s: More than one -t option" 766 " specified\n"), 767 progname); 768 return EXIT_FAILURE; 769 } 770 tzdefault = optarg; 771 break; 772 case 'y': 773 warning(_("-y ignored")); 774 break; 775 case 'L': 776 if (leapsec == NULL) 777 leapsec = optarg; 778 else { 779 fprintf(stderr, 780 _("%s: More than one -L option specified\n"), 781 progname); 782 return EXIT_FAILURE; 783 } 784 break; 785 case 'v': 786 noise = true; 787 break; 788 case 'r': 789 if (timerange_given) { 790 fprintf(stderr, 791 _("%s: More than one -r option specified\n"), 792 progname); 793 return EXIT_FAILURE; 794 } 795 if (! timerange_option(optarg)) { 796 fprintf(stderr, 797 _("%s: invalid time range: %s\n"), 798 progname, optarg); 799 return EXIT_FAILURE; 800 } 801 timerange_given = true; 802 break; 803 case 's': 804 warning(_("-s ignored")); 805 break; 806 } 807 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 808 usage(stderr, EXIT_FAILURE); /* usage message by request */ 809 if (bloat == 0) 810 bloat = strcmp(ZIC_BLOAT_DEFAULT, "slim") == 0 ? -1 : 1; 811 if (directory == NULL) 812 directory = TZDIR; 813 if (tzdefault == NULL) 814 tzdefault = TZDEFAULT; 815 816 if (optind < argc && leapsec != NULL) { 817 infile(leapsec); 818 adjleap(); 819 } 820 821 for (k = optind; k < argc; k++) 822 infile(argv[k]); 823 if (errors) 824 return EXIT_FAILURE; 825 associate(); 826 change_directory(directory); 827 for (i = 0; i < nzones; i = j) { 828 /* 829 ** Find the next non-continuation zone entry. 830 */ 831 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 832 continue; 833 outzone(&zones[i], j - i); 834 } 835 /* 836 ** Make links. 837 */ 838 for (i = 0; i < nlinks; ++i) { 839 eat(links[i].l_filename, links[i].l_linenum); 840 dolink(links[i].l_target, links[i].l_linkname, false); 841 if (noise) 842 for (j = 0; j < nlinks; ++j) 843 if (strcmp(links[i].l_linkname, 844 links[j].l_target) == 0) 845 warning(_("link to link")); 846 } 847 if (lcltime != NULL) { 848 eat(_("command line"), 1); 849 dolink(lcltime, tzdefault, true); 850 } 851 if (psxrules != NULL) { 852 eat(_("command line"), 1); 853 dolink(psxrules, TZDEFRULES, true); 854 } 855 if (warnings && (ferror(stderr) || fclose(stderr) != 0)) 856 return EXIT_FAILURE; 857 return errors ? EXIT_FAILURE : EXIT_SUCCESS; 858 } 859 860 static bool 861 componentcheck(char const *name, char const *component, 862 char const *component_end) 863 { 864 enum { component_len_max = 14 }; 865 ptrdiff_t component_len = component_end - component; 866 if (component_len == 0) { 867 if (!*name) 868 error (_("empty file name")); 869 else 870 error (_(component == name 871 ? "file name '%s' begins with '/'" 872 : *component_end 873 ? "file name '%s' contains '//'" 874 : "file name '%s' ends with '/'"), 875 name); 876 return false; 877 } 878 if (0 < component_len && component_len <= 2 879 && component[0] == '.' && component_end[-1] == '.') { 880 int len = component_len; 881 error(_("file name '%s' contains '%.*s' component"), 882 name, len, component); 883 return false; 884 } 885 if (noise) { 886 if (0 < component_len && component[0] == '-') 887 warning(_("file name '%s' component contains leading '-'"), 888 name); 889 if (component_len_max < component_len) 890 warning(_("file name '%s' contains overlength component" 891 " '%.*s...'"), 892 name, component_len_max, component); 893 } 894 return true; 895 } 896 897 static bool 898 namecheck(const char *name) 899 { 900 char const *cp; 901 902 /* Benign characters in a portable file name. */ 903 static char const benign[] = 904 "-/_" 905 "abcdefghijklmnopqrstuvwxyz" 906 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 907 908 /* Non-control chars in the POSIX portable character set, 909 excluding the benign characters. */ 910 static char const printable_and_not_benign[] = 911 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~"; 912 913 char const *component = name; 914 for (cp = name; *cp; cp++) { 915 unsigned char c = *cp; 916 if (noise && !strchr(benign, c)) { 917 warning((strchr(printable_and_not_benign, c) 918 ? _("file name '%s' contains byte '%c'") 919 : _("file name '%s' contains byte '\\%o'")), 920 name, c); 921 } 922 if (c == '/') { 923 if (!componentcheck(name, component, cp)) 924 return false; 925 component = cp + 1; 926 } 927 } 928 return componentcheck(name, component, cp); 929 } 930 931 /* Create symlink contents suitable for symlinking FROM to TO, as a 932 freshly allocated string. FROM should be a relative file name, and 933 is relative to the global variable DIRECTORY. TO can be either 934 relative or absolute. */ 935 static char * 936 relname(char const *target, char const *linkname) 937 { 938 size_t i, taillen, dotdotetcsize; 939 size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX; 940 char const *f = target; 941 char *result = NULL; 942 if (*linkname == '/') { 943 /* Make F absolute too. */ 944 size_t len = strlen(directory); 945 bool needslash = len && directory[len - 1] != '/'; 946 linksize = len + needslash + strlen(target) + 1; 947 f = result = emalloc(linksize); 948 strcpy(result, directory); 949 result[len] = '/'; 950 strcpy(result + len + needslash, target); 951 } 952 for (i = 0; f[i] && f[i] == linkname[i]; i++) 953 if (f[i] == '/') 954 dir_len = i + 1; 955 for (; linkname[i]; i++) 956 dotdots += linkname[i] == '/' && linkname[i - 1] != '/'; 957 taillen = strlen(f + dir_len); 958 dotdotetcsize = 3 * dotdots + taillen + 1; 959 if (dotdotetcsize <= linksize) { 960 if (!result) 961 result = emalloc(dotdotetcsize); 962 for (i = 0; i < dotdots; i++) 963 memcpy(result + 3 * i, "../", 3); 964 memmove(result + 3 * dotdots, f + dir_len, taillen + 1); 965 } 966 return result; 967 } 968 969 /* Hard link FROM to TO, following any symbolic links. 970 Return 0 if successful, an error number otherwise. */ 971 static int 972 hardlinkerr(char const *target, char const *linkname) 973 { 974 int r = linkat(AT_FDCWD, target, AT_FDCWD, linkname, AT_SYMLINK_FOLLOW); 975 return r == 0 ? 0 : errno; 976 } 977 978 static void 979 dolink(char const *target, char const *linkname, bool staysymlink) 980 { 981 bool remove_only = strcmp(target, "-") == 0; 982 bool linkdirs_made = false; 983 int link_errno; 984 985 /* 986 ** We get to be careful here since 987 ** there's a fair chance of root running us. 988 */ 989 if (!remove_only && itsdir(target)) { 990 fprintf(stderr, _("%s: linking target %s/%s failed: %s\n"), 991 progname, directory, target, strerror(EPERM)); 992 exit(EXIT_FAILURE); 993 } 994 if (staysymlink) 995 staysymlink = itssymlink(linkname); 996 if (remove(linkname) == 0) 997 linkdirs_made = true; 998 else if (errno != ENOENT) { 999 char const *e = strerror(errno); 1000 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), 1001 progname, directory, linkname, e); 1002 exit(EXIT_FAILURE); 1003 } 1004 if (remove_only) 1005 return; 1006 link_errno = staysymlink ? ENOTSUP : hardlinkerr(target, linkname); 1007 if (link_errno == ENOENT && !linkdirs_made) { 1008 mkdirs(linkname, true); 1009 linkdirs_made = true; 1010 link_errno = hardlinkerr(target, linkname); 1011 } 1012 if (link_errno != 0) { 1013 bool absolute = *target == '/'; 1014 char *linkalloc = absolute ? NULL : relname(target, linkname); 1015 char const *contents = absolute ? target : linkalloc; 1016 int symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno; 1017 if (!linkdirs_made 1018 && (symlink_errno == ENOENT || symlink_errno == ENOTSUP)) { 1019 mkdirs(linkname, true); 1020 if (symlink_errno == ENOENT) 1021 symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno; 1022 } 1023 free(linkalloc); 1024 if (symlink_errno == 0) { 1025 if (link_errno != ENOTSUP) 1026 warning(_("symbolic link used because hard link failed: %s"), 1027 strerror(link_errno)); 1028 } else { 1029 FILE *fp, *tp; 1030 int c; 1031 fp = fopen(target, "rb"); 1032 if (!fp) { 1033 char const *e = strerror(errno); 1034 fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), 1035 progname, directory, target, e); 1036 exit(EXIT_FAILURE); 1037 } 1038 tp = fopen(linkname, "wb"); 1039 if (!tp) { 1040 char const *e = strerror(errno); 1041 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), 1042 progname, directory, linkname, e); 1043 exit(EXIT_FAILURE); 1044 } 1045 while ((c = getc(fp)) != EOF) 1046 putc(c, tp); 1047 close_file(fp, directory, target); 1048 close_file(tp, directory, linkname); 1049 if (link_errno != ENOTSUP) 1050 warning(_("copy used because hard link failed: %s"), 1051 strerror(link_errno)); 1052 else if (symlink_errno != ENOTSUP) 1053 warning(_("copy used because symbolic link failed: %s"), 1054 strerror(symlink_errno)); 1055 } 1056 } 1057 } 1058 1059 /* Return true if NAME is a directory. */ 1060 static bool 1061 itsdir(char const *name) 1062 { 1063 struct stat st; 1064 int res = stat(name, &st); 1065 #ifdef S_ISDIR 1066 if (res == 0) 1067 return S_ISDIR(st.st_mode) != 0; 1068 #endif 1069 if (res == 0 || errno == EOVERFLOW) { 1070 size_t n = strlen(name); 1071 char *nameslashdot = emalloc(n + 3); 1072 bool dir; 1073 memcpy(nameslashdot, name, n); 1074 strcpy(&nameslashdot[n], &"/."[! (n && name[n - 1] != '/')]); 1075 dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW; 1076 free(nameslashdot); 1077 return dir; 1078 } 1079 return false; 1080 } 1081 1082 /* Return true if NAME is a symbolic link. */ 1083 static bool 1084 itssymlink(char const *name) 1085 { 1086 char c; 1087 return 0 <= readlink(name, &c, 1); 1088 } 1089 1090 /* 1091 ** Associate sets of rules with zones. 1092 */ 1093 1094 /* 1095 ** Sort by rule name. 1096 */ 1097 1098 static int 1099 rcomp(const void *cp1, const void *cp2) 1100 { 1101 return strcmp(((const struct rule *) cp1)->r_name, 1102 ((const struct rule *) cp2)->r_name); 1103 } 1104 1105 static void 1106 associate(void) 1107 { 1108 struct zone * zp; 1109 struct rule * rp; 1110 ptrdiff_t i, j, base, out; 1111 1112 if (nrules != 0) { 1113 qsort(rules, (size_t)nrules, sizeof *rules, rcomp); 1114 for (i = 0; i < nrules - 1; ++i) { 1115 if (strcmp(rules[i].r_name, 1116 rules[i + 1].r_name) != 0) 1117 continue; 1118 if (strcmp(rules[i].r_filename, 1119 rules[i + 1].r_filename) == 0) 1120 continue; 1121 eat(rules[i].r_filename, rules[i].r_linenum); 1122 warning(_("same rule name in multiple files")); 1123 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); 1124 warning(_("same rule name in multiple files")); 1125 for (j = i + 2; j < nrules; ++j) { 1126 if (strcmp(rules[i].r_name, 1127 rules[j].r_name) != 0) 1128 break; 1129 if (strcmp(rules[i].r_filename, 1130 rules[j].r_filename) == 0) 1131 continue; 1132 if (strcmp(rules[i + 1].r_filename, 1133 rules[j].r_filename) == 0) 1134 continue; 1135 break; 1136 } 1137 i = j - 1; 1138 } 1139 } 1140 for (i = 0; i < nzones; ++i) { 1141 zp = &zones[i]; 1142 zp->z_rules = NULL; 1143 zp->z_nrules = 0; 1144 } 1145 for (base = 0; base < nrules; base = out) { 1146 rp = &rules[base]; 1147 for (out = base + 1; out < nrules; ++out) 1148 if (strcmp(rp->r_name, rules[out].r_name) != 0) 1149 break; 1150 for (i = 0; i < nzones; ++i) { 1151 zp = &zones[i]; 1152 if (strcmp(zp->z_rule, rp->r_name) != 0) 1153 continue; 1154 zp->z_rules = rp; 1155 zp->z_nrules = out - base; 1156 } 1157 } 1158 for (i = 0; i < nzones; ++i) { 1159 zp = &zones[i]; 1160 if (zp->z_nrules == 0) { 1161 /* 1162 ** Maybe we have a local standard time offset. 1163 */ 1164 eat(zp->z_filename, zp->z_linenum); 1165 zp->z_save = getsave(zp->z_rule, &zp->z_isdst); 1166 /* 1167 ** Note, though, that if there's no rule, 1168 ** a '%s' in the format is a bad thing. 1169 */ 1170 if (zp->z_format_specifier == 's') 1171 error("%s", _("%s in ruleless zone")); 1172 } 1173 } 1174 if (errors) 1175 exit(EXIT_FAILURE); 1176 } 1177 1178 static void 1179 infile(const char *name) 1180 { 1181 FILE * fp; 1182 char ** fields; 1183 char * cp; 1184 const struct lookup * lp; 1185 int nfields; 1186 bool wantcont; 1187 lineno num; 1188 char buf[BUFSIZ]; 1189 1190 if (strcmp(name, "-") == 0) { 1191 name = _("standard input"); 1192 fp = stdin; 1193 } else if ((fp = fopen(name, "r")) == NULL) { 1194 const char *e = strerror(errno); 1195 1196 fprintf(stderr, _("%s: Can't open %s: %s\n"), 1197 progname, name, e); 1198 exit(EXIT_FAILURE); 1199 } 1200 wantcont = false; 1201 for (num = 1; ; ++num) { 1202 eat(name, num); 1203 if (fgets(buf, (int) sizeof buf, fp) != buf) 1204 break; 1205 cp = strchr(buf, '\n'); 1206 if (cp == NULL) { 1207 error(_("line too long")); 1208 exit(EXIT_FAILURE); 1209 } 1210 *cp = '\0'; 1211 fields = getfields(buf); 1212 nfields = 0; 1213 while (fields[nfields] != NULL) { 1214 static char nada; 1215 1216 if (strcmp(fields[nfields], "-") == 0) 1217 fields[nfields] = &nada; 1218 ++nfields; 1219 } 1220 if (nfields == 0) { 1221 if (name == leapsec && *buf == '#') 1222 sscanf(buf, "#expires %"SCNdZIC, &comment_leapexpires); 1223 } else if (wantcont) { 1224 wantcont = inzcont(fields, nfields); 1225 } else { 1226 struct lookup const *line_codes 1227 = name == leapsec ? leap_line_codes : zi_line_codes; 1228 lp = byword(fields[0], line_codes); 1229 if (lp == NULL) 1230 error(_("input line of unknown type")); 1231 else switch (lp->l_value) { 1232 case LC_RULE: 1233 inrule(fields, nfields); 1234 wantcont = false; 1235 break; 1236 case LC_ZONE: 1237 wantcont = inzone(fields, nfields); 1238 break; 1239 case LC_LINK: 1240 inlink(fields, nfields); 1241 wantcont = false; 1242 break; 1243 case LC_LEAP: 1244 inleap(fields, nfields); 1245 wantcont = false; 1246 break; 1247 case LC_EXPIRES: 1248 inexpires(fields, nfields); 1249 wantcont = false; 1250 break; 1251 default: /* "cannot happen" */ 1252 fprintf(stderr, 1253 _("%s: panic: Invalid l_value %d\n"), 1254 progname, lp->l_value); 1255 exit(EXIT_FAILURE); 1256 } 1257 } 1258 free(fields); 1259 } 1260 close_file(fp, NULL, filename); 1261 if (wantcont) 1262 error(_("expected continuation line not found")); 1263 } 1264 1265 /* 1266 ** Convert a string of one of the forms 1267 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 1268 ** into a number of seconds. 1269 ** A null string maps to zero. 1270 ** Call error with errstring and return zero on errors. 1271 */ 1272 1273 static zic_t 1274 gethms(char const *string, char const *errstring) 1275 { 1276 zic_t hh; 1277 int sign, mm = 0, ss = 0; 1278 char hhx, mmx, ssx, xr = '0', xs; 1279 int tenths = 0; 1280 bool ok = true; 1281 1282 if (string == NULL || *string == '\0') 1283 return 0; 1284 if (*string == '-') { 1285 sign = -1; 1286 ++string; 1287 } else sign = 1; 1288 switch (sscanf(string, 1289 "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c", 1290 &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) { 1291 default: ok = false; break; 1292 case 8: 1293 ok = '0' <= xr && xr <= '9'; 1294 /* fallthrough */ 1295 case 7: 1296 ok &= ssx == '.'; 1297 if (ok && noise) 1298 warning(_("fractional seconds rejected by" 1299 " pre-2018 versions of zic")); 1300 /* fallthrough */ 1301 case 5: ok &= mmx == ':'; /* fallthrough */ 1302 case 3: ok &= hhx == ':'; /* fallthrough */ 1303 case 1: break; 1304 } 1305 if (!ok) { 1306 error("%s", errstring); 1307 return 0; 1308 } 1309 if (hh < 0 || 1310 mm < 0 || mm >= MINSPERHOUR || 1311 ss < 0 || ss > SECSPERMIN) { 1312 error("%s", errstring); 1313 return 0; 1314 } 1315 if (ZIC_MAX / SECSPERHOUR < hh) { 1316 error(_("time overflow")); 1317 return 0; 1318 } 1319 ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */ 1320 if (noise && (hh > HOURSPERDAY || 1321 (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) 1322 warning(_("values over 24 hours not handled by pre-2007 versions of zic")); 1323 return oadd(sign * hh * SECSPERHOUR, 1324 sign * (mm * SECSPERMIN + ss)); 1325 } 1326 1327 static zic_t 1328 getsave(char *field, bool *isdst) 1329 { 1330 int dst = -1; 1331 zic_t save; 1332 size_t fieldlen = strlen(field); 1333 if (fieldlen != 0) { 1334 char *ep = field + fieldlen - 1; 1335 switch (*ep) { 1336 case 'd': dst = 1; *ep = '\0'; break; 1337 case 's': dst = 0; *ep = '\0'; break; 1338 } 1339 } 1340 save = gethms(field, _("invalid saved time")); 1341 *isdst = dst < 0 ? save != 0 : dst; 1342 return save; 1343 } 1344 1345 static void 1346 inrule(char **fields, int nfields) 1347 { 1348 static struct rule r; 1349 1350 if (nfields != RULE_FIELDS) { 1351 error(_("wrong number of fields on Rule line")); 1352 return; 1353 } 1354 switch (*fields[RF_NAME]) { 1355 case '\0': 1356 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': 1357 case '+': case '-': 1358 case '0': case '1': case '2': case '3': case '4': 1359 case '5': case '6': case '7': case '8': case '9': 1360 error(_("Invalid rule name \"%s\""), fields[RF_NAME]); 1361 return; 1362 } 1363 r.r_filename = filename; 1364 r.r_linenum = linenum; 1365 r.r_save = getsave(fields[RF_SAVE], &r.r_isdst); 1366 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 1367 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 1368 r.r_name = ecpyalloc(fields[RF_NAME]); 1369 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 1370 if (max_abbrvar_len < strlen(r.r_abbrvar)) 1371 max_abbrvar_len = strlen(r.r_abbrvar); 1372 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); 1373 rules[nrules++] = r; 1374 } 1375 1376 static bool 1377 inzone(char **fields, int nfields) 1378 { 1379 ptrdiff_t i; 1380 1381 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 1382 error(_("wrong number of fields on Zone line")); 1383 return false; 1384 } 1385 if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) { 1386 error( 1387 _("\"Zone %s\" line and -l option are mutually exclusive"), 1388 tzdefault); 1389 return false; 1390 } 1391 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 1392 error( 1393 _("\"Zone %s\" line and -p option are mutually exclusive"), 1394 TZDEFRULES); 1395 return false; 1396 } 1397 for (i = 0; i < nzones; ++i) 1398 if (zones[i].z_name != NULL && 1399 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 1400 error(_("duplicate zone name %s" 1401 " (file \"%s\", line %"PRIdMAX")"), 1402 fields[ZF_NAME], 1403 zones[i].z_filename, 1404 zones[i].z_linenum); 1405 return false; 1406 } 1407 return inzsub(fields, nfields, false); 1408 } 1409 1410 static bool 1411 inzcont(char **fields, int nfields) 1412 { 1413 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 1414 error(_("wrong number of fields on Zone continuation line")); 1415 return false; 1416 } 1417 return inzsub(fields, nfields, true); 1418 } 1419 1420 static bool 1421 inzsub(char **fields, int nfields, bool iscont) 1422 { 1423 char * cp; 1424 char * cp1; 1425 static struct zone z; 1426 int i_stdoff, i_rule, i_format; 1427 int i_untilyear, i_untilmonth; 1428 int i_untilday, i_untiltime; 1429 bool hasuntil; 1430 1431 if (iscont) { 1432 i_stdoff = ZFC_STDOFF; 1433 i_rule = ZFC_RULE; 1434 i_format = ZFC_FORMAT; 1435 i_untilyear = ZFC_TILYEAR; 1436 i_untilmonth = ZFC_TILMONTH; 1437 i_untilday = ZFC_TILDAY; 1438 i_untiltime = ZFC_TILTIME; 1439 z.z_name = NULL; 1440 } else if (!namecheck(fields[ZF_NAME])) 1441 return false; 1442 else { 1443 i_stdoff = ZF_STDOFF; 1444 i_rule = ZF_RULE; 1445 i_format = ZF_FORMAT; 1446 i_untilyear = ZF_TILYEAR; 1447 i_untilmonth = ZF_TILMONTH; 1448 i_untilday = ZF_TILDAY; 1449 i_untiltime = ZF_TILTIME; 1450 z.z_name = ecpyalloc(fields[ZF_NAME]); 1451 } 1452 z.z_filename = filename; 1453 z.z_linenum = linenum; 1454 z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset")); 1455 if ((cp = strchr(fields[i_format], '%')) != 0) { 1456 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') 1457 || strchr(fields[i_format], '/')) { 1458 error(_("invalid abbreviation format")); 1459 return false; 1460 } 1461 } 1462 z.z_rule = ecpyalloc(fields[i_rule]); 1463 z.z_format = cp1 = ecpyalloc(fields[i_format]); 1464 z.z_format_specifier = cp ? *cp : '\0'; 1465 if (z.z_format_specifier == 'z') { 1466 if (noise) 1467 warning(_("format '%s' not handled by pre-2015 versions of zic"), 1468 z.z_format); 1469 cp1[cp - fields[i_format]] = 's'; 1470 } 1471 if (max_format_len < strlen(z.z_format)) 1472 max_format_len = strlen(z.z_format); 1473 hasuntil = nfields > i_untilyear; 1474 if (hasuntil) { 1475 z.z_untilrule.r_filename = filename; 1476 z.z_untilrule.r_linenum = linenum; 1477 rulesub(&z.z_untilrule, 1478 fields[i_untilyear], 1479 "only", 1480 "", 1481 (nfields > i_untilmonth) ? 1482 fields[i_untilmonth] : "Jan", 1483 (nfields > i_untilday) ? fields[i_untilday] : "1", 1484 (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 1485 z.z_untiltime = rpytime(&z.z_untilrule, 1486 z.z_untilrule.r_loyear); 1487 if (iscont && nzones > 0 && 1488 z.z_untiltime > min_time && 1489 z.z_untiltime < max_time && 1490 zones[nzones - 1].z_untiltime > min_time && 1491 zones[nzones - 1].z_untiltime < max_time && 1492 zones[nzones - 1].z_untiltime >= z.z_untiltime) { 1493 error(_( 1494 "Zone continuation line end time is not after end time of previous line" 1495 )); 1496 return false; 1497 } 1498 } 1499 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc); 1500 zones[nzones++] = z; 1501 /* 1502 ** If there was an UNTIL field on this line, 1503 ** there's more information about the zone on the next line. 1504 */ 1505 return hasuntil; 1506 } 1507 1508 static zic_t 1509 getleapdatetime(char **fields, int nfields, bool expire_line) 1510 { 1511 const char * cp; 1512 const struct lookup * lp; 1513 zic_t i, j; 1514 zic_t year; 1515 int month, day; 1516 zic_t dayoff, tod; 1517 zic_t t; 1518 char xs; 1519 1520 dayoff = 0; 1521 cp = fields[LP_YEAR]; 1522 if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) { 1523 /* 1524 ** Leapin' Lizards! 1525 */ 1526 error(_("invalid leaping year")); 1527 return -1; 1528 } 1529 if (!expire_line) { 1530 if (!leapseen || leapmaxyear < year) 1531 leapmaxyear = year; 1532 if (!leapseen || leapminyear > year) 1533 leapminyear = year; 1534 leapseen = true; 1535 } 1536 j = EPOCH_YEAR; 1537 while (j != year) { 1538 if (year > j) { 1539 i = len_years[isleap(j)]; 1540 ++j; 1541 } else { 1542 --j; 1543 i = -len_years[isleap(j)]; 1544 } 1545 dayoff = oadd(dayoff, i); 1546 } 1547 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1548 error(_("invalid month name")); 1549 return -1; 1550 } 1551 month = lp->l_value; 1552 j = TM_JANUARY; 1553 while (j != month) { 1554 i = len_months[isleap(year)][j]; 1555 dayoff = oadd(dayoff, i); 1556 ++j; 1557 } 1558 cp = fields[LP_DAY]; 1559 if (sscanf(cp, "%d%c", &day, &xs) != 1 || 1560 day <= 0 || day > len_months[isleap(year)][month]) { 1561 error(_("invalid day of month")); 1562 return -1; 1563 } 1564 dayoff = oadd(dayoff, day - 1); 1565 if (dayoff < min_time / SECSPERDAY) { 1566 error(_("time too small")); 1567 return -1; 1568 } 1569 if (dayoff > max_time / SECSPERDAY) { 1570 error(_("time too large")); 1571 return -1; 1572 } 1573 t = dayoff * SECSPERDAY; 1574 tod = gethms(fields[LP_TIME], _("invalid time of day")); 1575 t = tadd(t, tod); 1576 if (t < 0) 1577 error(_("leap second precedes Epoch")); 1578 return t; 1579 } 1580 1581 static void 1582 inleap(char **fields, int nfields) 1583 { 1584 if (nfields != LEAP_FIELDS) 1585 error(_("wrong number of fields on Leap line")); 1586 else { 1587 zic_t t = getleapdatetime(fields, nfields, false); 1588 if (0 <= t) { 1589 struct lookup const *lp = byword(fields[LP_ROLL], leap_types); 1590 if (!lp) 1591 error(_("invalid Rolling/Stationary field on Leap line")); 1592 else { 1593 int correction = 0; 1594 if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */ 1595 correction = -1; 1596 else if (strcmp(fields[LP_CORR], "+") == 0) 1597 correction = 1; 1598 else 1599 error(_("invalid CORRECTION field on Leap line")); 1600 if (correction) 1601 leapadd(t, correction, lp->l_value); 1602 } 1603 } 1604 } 1605 } 1606 1607 static void 1608 inexpires(char **fields, int nfields) 1609 { 1610 if (nfields != EXPIRES_FIELDS) 1611 error(_("wrong number of fields on Expires line")); 1612 else if (0 <= leapexpires) 1613 error(_("multiple Expires lines")); 1614 else 1615 leapexpires = getleapdatetime(fields, nfields, true); 1616 } 1617 1618 static void 1619 inlink(char **fields, int nfields) 1620 { 1621 struct link l; 1622 1623 if (nfields != LINK_FIELDS) { 1624 error(_("wrong number of fields on Link line")); 1625 return; 1626 } 1627 if (*fields[LF_TARGET] == '\0') { 1628 error(_("blank TARGET field on Link line")); 1629 return; 1630 } 1631 if (! namecheck(fields[LF_LINKNAME])) 1632 return; 1633 l.l_filename = filename; 1634 l.l_linenum = linenum; 1635 l.l_target = ecpyalloc(fields[LF_TARGET]); 1636 l.l_linkname = ecpyalloc(fields[LF_LINKNAME]); 1637 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); 1638 links[nlinks++] = l; 1639 } 1640 1641 static void 1642 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, 1643 const char *typep, const char *monthp, const char *dayp, 1644 const char *timep) 1645 { 1646 const struct lookup * lp; 1647 const char * cp; 1648 char * dp; 1649 char * ep; 1650 char xs; 1651 1652 if ((lp = byword(monthp, mon_names)) == NULL) { 1653 error(_("invalid month name")); 1654 return; 1655 } 1656 rp->r_month = lp->l_value; 1657 rp->r_todisstd = false; 1658 rp->r_todisut = false; 1659 dp = ecpyalloc(timep); 1660 if (*dp != '\0') { 1661 ep = dp + strlen(dp) - 1; 1662 switch (lowerit(*ep)) { 1663 case 's': /* Standard */ 1664 rp->r_todisstd = true; 1665 rp->r_todisut = false; 1666 *ep = '\0'; 1667 break; 1668 case 'w': /* Wall */ 1669 rp->r_todisstd = false; 1670 rp->r_todisut = false; 1671 *ep = '\0'; 1672 break; 1673 case 'g': /* Greenwich */ 1674 case 'u': /* Universal */ 1675 case 'z': /* Zulu */ 1676 rp->r_todisstd = true; 1677 rp->r_todisut = true; 1678 *ep = '\0'; 1679 break; 1680 } 1681 } 1682 rp->r_tod = gethms(dp, _("invalid time of day")); 1683 free(dp); 1684 /* 1685 ** Year work. 1686 */ 1687 cp = loyearp; 1688 lp = byword(cp, begin_years); 1689 rp->r_lowasnum = lp == NULL; 1690 if (!rp->r_lowasnum) switch (lp->l_value) { 1691 case YR_MINIMUM: 1692 rp->r_loyear = ZIC_MIN; 1693 break; 1694 case YR_MAXIMUM: 1695 rp->r_loyear = ZIC_MAX; 1696 break; 1697 default: /* "cannot happen" */ 1698 fprintf(stderr, 1699 _("%s: panic: Invalid l_value %d\n"), 1700 progname, lp->l_value); 1701 exit(EXIT_FAILURE); 1702 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) { 1703 error(_("invalid starting year")); 1704 return; 1705 } 1706 cp = hiyearp; 1707 lp = byword(cp, end_years); 1708 rp->r_hiwasnum = lp == NULL; 1709 if (!rp->r_hiwasnum) switch (lp->l_value) { 1710 case YR_MINIMUM: 1711 rp->r_hiyear = ZIC_MIN; 1712 break; 1713 case YR_MAXIMUM: 1714 rp->r_hiyear = ZIC_MAX; 1715 break; 1716 case YR_ONLY: 1717 rp->r_hiyear = rp->r_loyear; 1718 break; 1719 default: /* "cannot happen" */ 1720 fprintf(stderr, 1721 _("%s: panic: Invalid l_value %d\n"), 1722 progname, lp->l_value); 1723 exit(EXIT_FAILURE); 1724 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) { 1725 error(_("invalid ending year")); 1726 return; 1727 } 1728 if (rp->r_loyear > rp->r_hiyear) { 1729 error(_("starting year greater than ending year")); 1730 return; 1731 } 1732 if (*typep != '\0') { 1733 error(_("year type \"%s\" is unsupported; use \"-\" instead"), 1734 typep); 1735 return; 1736 } 1737 /* 1738 ** Day work. 1739 ** Accept things such as: 1740 ** 1 1741 ** lastSunday 1742 ** last-Sunday (undocumented; warn about this) 1743 ** Sun<=20 1744 ** Sun>=7 1745 */ 1746 dp = ecpyalloc(dayp); 1747 if ((lp = byword(dp, lasts)) != NULL) { 1748 rp->r_dycode = DC_DOWLEQ; 1749 rp->r_wday = lp->l_value; 1750 rp->r_dayofmonth = len_months[1][rp->r_month]; 1751 } else { 1752 if ((ep = strchr(dp, '<')) != 0) 1753 rp->r_dycode = DC_DOWLEQ; 1754 else if ((ep = strchr(dp, '>')) != 0) 1755 rp->r_dycode = DC_DOWGEQ; 1756 else { 1757 ep = dp; 1758 rp->r_dycode = DC_DOM; 1759 } 1760 if (rp->r_dycode != DC_DOM) { 1761 *ep++ = 0; 1762 if (*ep++ != '=') { 1763 error(_("invalid day of month")); 1764 free(dp); 1765 return; 1766 } 1767 if ((lp = byword(dp, wday_names)) == NULL) { 1768 error(_("invalid weekday name")); 1769 free(dp); 1770 return; 1771 } 1772 rp->r_wday = lp->l_value; 1773 } 1774 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 || 1775 rp->r_dayofmonth <= 0 || 1776 (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1777 error(_("invalid day of month")); 1778 free(dp); 1779 return; 1780 } 1781 } 1782 free(dp); 1783 } 1784 1785 static void 1786 convert(const int_fast32_t val, char *const buf) 1787 { 1788 int i; 1789 int shift; 1790 unsigned char *const b = (unsigned char *) buf; 1791 1792 for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1793 b[i] = val >> shift; 1794 } 1795 1796 static void 1797 convert64(const zic_t val, char *const buf) 1798 { 1799 int i; 1800 int shift; 1801 unsigned char *const b = (unsigned char *) buf; 1802 1803 for (i = 0, shift = 56; i < 8; ++i, shift -= 8) 1804 b[i] = val >> shift; 1805 } 1806 1807 static void 1808 puttzcode(const int_fast32_t val, FILE *const fp) 1809 { 1810 char buf[4]; 1811 1812 convert(val, buf); 1813 fwrite(buf, sizeof buf, (size_t) 1, fp); 1814 } 1815 1816 static void 1817 puttzcodepass(zic_t val, FILE *fp, int pass) 1818 { 1819 if (pass == 1) 1820 puttzcode(val, fp); 1821 else { 1822 char buf[8]; 1823 1824 convert64(val, buf); 1825 fwrite(buf, sizeof buf, (size_t) 1, fp); 1826 } 1827 } 1828 1829 static int 1830 atcomp(const void *avp, const void *bvp) 1831 { 1832 const zic_t a = ((const struct attype *) avp)->at; 1833 const zic_t b = ((const struct attype *) bvp)->at; 1834 1835 return (a < b) ? -1 : (a > b); 1836 } 1837 1838 struct timerange { 1839 int defaulttype; 1840 ptrdiff_t base, count; 1841 int leapbase, leapcount; 1842 }; 1843 1844 static struct timerange 1845 limitrange(struct timerange r, zic_t lo, zic_t hi, 1846 zic_t const *ats, unsigned char const *types) 1847 { 1848 while (0 < r.count && ats[r.base] < lo) { 1849 r.defaulttype = types[r.base]; 1850 r.count--; 1851 r.base++; 1852 } 1853 while (0 < r.leapcount && trans[r.leapbase] < lo) { 1854 r.leapcount--; 1855 r.leapbase++; 1856 } 1857 1858 if (hi < ZIC_MAX) { 1859 while (0 < r.count && hi + 1 < ats[r.base + r.count - 1]) 1860 r.count--; 1861 while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1]) 1862 r.leapcount--; 1863 } 1864 1865 return r; 1866 } 1867 1868 static void 1869 writezone(const char *const name, const char *const string, char version, 1870 int defaulttype) 1871 { 1872 FILE * fp; 1873 ptrdiff_t i, j; 1874 int pass; 1875 static const struct tzhead tzh0; 1876 static struct tzhead tzh; 1877 bool dir_checked = false; 1878 zic_t one = 1; 1879 zic_t y2038_boundary = one << 31; 1880 ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071; 1881 1882 /* Allocate the ATS and TYPES arrays via a single malloc, 1883 as this is a bit faster. */ 1884 zic_t *ats = zic_malloc(align_to(size_product(nats, sizeof *ats + 1), 1885 _Alignof(zic_t))); 1886 void *typesptr = ats + nats; 1887 unsigned char *types = typesptr; 1888 struct timerange rangeall, range32, range64; 1889 1890 /* 1891 ** Sort. 1892 */ 1893 if (timecnt > 1) 1894 qsort(attypes, (size_t) timecnt, sizeof *attypes, atcomp); 1895 /* 1896 ** Optimize. 1897 */ 1898 { 1899 ptrdiff_t fromi, toi; 1900 1901 toi = 0; 1902 fromi = 0; 1903 for ( ; fromi < timecnt; ++fromi) { 1904 if (toi != 0 1905 && ((attypes[fromi].at 1906 + utoffs[attypes[toi - 1].type]) 1907 <= (attypes[toi - 1].at 1908 + utoffs[toi == 1 ? 0 1909 : attypes[toi - 2].type]))) { 1910 attypes[toi - 1].type = 1911 attypes[fromi].type; 1912 continue; 1913 } 1914 if (toi == 0 1915 || attypes[fromi].dontmerge 1916 || (utoffs[attypes[toi - 1].type] 1917 != utoffs[attypes[fromi].type]) 1918 || (isdsts[attypes[toi - 1].type] 1919 != isdsts[attypes[fromi].type]) 1920 || (desigidx[attypes[toi - 1].type] 1921 != desigidx[attypes[fromi].type])) 1922 attypes[toi++] = attypes[fromi]; 1923 } 1924 timecnt = toi; 1925 } 1926 1927 if (noise && timecnt > 1200) { 1928 if (timecnt > TZ_MAX_TIMES) 1929 warning(_("reference clients mishandle" 1930 " more than %d transition times"), 1931 TZ_MAX_TIMES); 1932 else 1933 warning(_("pre-2014 clients may mishandle" 1934 " more than 1200 transition times")); 1935 } 1936 /* 1937 ** Transfer. 1938 */ 1939 for (i = 0; i < timecnt; ++i) { 1940 ats[i] = attypes[i].at; 1941 types[i] = attypes[i].type; 1942 } 1943 1944 /* 1945 ** Correct for leap seconds. 1946 */ 1947 for (i = 0; i < timecnt; ++i) { 1948 j = leapcnt; 1949 while (--j >= 0) 1950 if (ats[i] > trans[j] - corr[j]) { 1951 ats[i] = tadd(ats[i], corr[j]); 1952 break; 1953 } 1954 } 1955 1956 /* Work around QTBUG-53071 for timestamps less than y2038_boundary - 1, 1957 by inserting a no-op transition at time y2038_boundary - 1. 1958 This works only for timestamps before the boundary, which 1959 should be good enough in practice as QTBUG-53071 should be 1960 long-dead by 2038. Do this after correcting for leap 1961 seconds, as the idea is to insert a transition just before 1962 32-bit time_t rolls around, and this occurs at a slightly 1963 different moment if transitions are leap-second corrected. */ 1964 if (WORK_AROUND_QTBUG_53071 && timecnt != 0 && want_bloat() 1965 && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) { 1966 ats[timecnt] = y2038_boundary - 1; 1967 types[timecnt] = types[timecnt - 1]; 1968 timecnt++; 1969 } 1970 1971 rangeall.defaulttype = defaulttype; 1972 rangeall.base = rangeall.leapbase = 0; 1973 rangeall.count = timecnt; 1974 rangeall.leapcount = leapcnt; 1975 range64 = limitrange(rangeall, lo_time, hi_time, ats, types); 1976 range32 = limitrange(range64, INT32_MIN, INT32_MAX, ats, types); 1977 1978 /* 1979 ** Remove old file, if any, to snap links. 1980 */ 1981 if (remove(name) == 0) 1982 dir_checked = true; 1983 else if (errno != ENOENT) { 1984 const char *e = strerror(errno); 1985 1986 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), 1987 progname, directory, name, e); 1988 exit(EXIT_FAILURE); 1989 } 1990 fp = fopen(name, "wb"); 1991 if (!fp) { 1992 int fopen_errno = errno; 1993 if (fopen_errno == ENOENT && !dir_checked) { 1994 mkdirs(name, true); 1995 fp = fopen(name, "wb"); 1996 fopen_errno = errno; 1997 } 1998 if (!fp) { 1999 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), 2000 progname, directory, name, strerror(fopen_errno)); 2001 exit(EXIT_FAILURE); 2002 } 2003 } 2004 for (pass = 1; pass <= 2; ++pass) { 2005 ptrdiff_t thistimei, thistimecnt, thistimelim; 2006 int thisleapi, thisleapcnt, thisleaplim; 2007 int currenttype, thisdefaulttype; 2008 bool locut, hicut; 2009 zic_t lo; 2010 int old0; 2011 char omittype[TZ_MAX_TYPES]; 2012 int typemap[TZ_MAX_TYPES]; 2013 int thistypecnt, stdcnt, utcnt; 2014 char thischars[TZ_MAX_CHARS]; 2015 int thischarcnt; 2016 bool toomanytimes; 2017 int indmap[TZ_MAX_CHARS]; 2018 2019 if (pass == 1) { 2020 /* Arguably the default time type in the 32-bit data 2021 should be range32.defaulttype, which is suited for 2022 timestamps just before INT32_MIN. However, zic 2023 traditionally used the time type of the indefinite 2024 past instead. Internet RFC 8532 says readers should 2025 ignore 32-bit data, so this discrepancy matters only 2026 to obsolete readers where the traditional type might 2027 be more appropriate even if it's "wrong". So, use 2028 the historical zic value, unless -r specifies a low 2029 cutoff that excludes some 32-bit timestamps. */ 2030 thisdefaulttype = (lo_time <= INT32_MIN 2031 ? range64.defaulttype 2032 : range32.defaulttype); 2033 2034 thistimei = range32.base; 2035 thistimecnt = range32.count; 2036 toomanytimes = thistimecnt >> 31 >> 1 != 0; 2037 thisleapi = range32.leapbase; 2038 thisleapcnt = range32.leapcount; 2039 locut = INT32_MIN < lo_time; 2040 hicut = hi_time < INT32_MAX; 2041 } else { 2042 thisdefaulttype = range64.defaulttype; 2043 thistimei = range64.base; 2044 thistimecnt = range64.count; 2045 toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0; 2046 thisleapi = range64.leapbase; 2047 thisleapcnt = range64.leapcount; 2048 locut = min_time < lo_time; 2049 hicut = hi_time < max_time; 2050 } 2051 if (toomanytimes) 2052 error(_("too many transition times")); 2053 2054 /* Keep the last too-low transition if no transition is 2055 exactly at LO. The kept transition will be output as 2056 a LO "transition"; see "Output a LO_TIME transition" 2057 below. This is needed when the output is truncated at 2058 the start, and is also useful when catering to buggy 2059 32-bit clients that do not use time type 0 for 2060 timestamps before the first transition. */ 2061 if (0 < thistimei && ats[thistimei] != lo_time) { 2062 thistimei--; 2063 thistimecnt++; 2064 locut = false; 2065 } 2066 2067 thistimelim = thistimei + thistimecnt; 2068 thisleaplim = thisleapi + thisleapcnt; 2069 if (thistimecnt != 0) { 2070 if (ats[thistimei] == lo_time) 2071 locut = false; 2072 if (hi_time < ZIC_MAX && ats[thistimelim - 1] == hi_time + 1) 2073 hicut = false; 2074 } 2075 memset(omittype, true, typecnt); 2076 omittype[thisdefaulttype] = false; 2077 for (i = thistimei; i < thistimelim; i++) 2078 omittype[types[i]] = false; 2079 2080 /* Reorder types to make THISDEFAULTTYPE type 0. 2081 Use TYPEMAP to swap OLD0 and THISDEFAULTTYPE so that 2082 THISDEFAULTTYPE appears as type 0 in the output instead 2083 of OLD0. TYPEMAP also omits unused types. */ 2084 old0 = strlen(omittype); 2085 2086 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH 2087 /* 2088 ** For some pre-2011 systems: if the last-to-be-written 2089 ** standard (or daylight) type has an offset different from the 2090 ** most recently used offset, 2091 ** append an (unused) copy of the most recently used type 2092 ** (to help get global "altzone" and "timezone" variables 2093 ** set correctly). 2094 */ 2095 if (want_bloat()) { 2096 int mrudst, mrustd, hidst, histd, type; 2097 2098 hidst = histd = mrudst = mrustd = -1; 2099 for (i = thistimei; i < thistimelim; ++i) 2100 if (isdsts[types[i]]) 2101 mrudst = types[i]; 2102 else mrustd = types[i]; 2103 for (i = old0; i < typecnt; i++) { 2104 int h = (i == old0 ? thisdefaulttype 2105 : i == thisdefaulttype ? old0 : i); 2106 if (!omittype[h]) { 2107 if (isdsts[h]) 2108 hidst = i; 2109 else 2110 histd = i; 2111 } 2112 } 2113 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && 2114 utoffs[hidst] != utoffs[mrudst]) { 2115 isdsts[mrudst] = -1; 2116 type = addtype(utoffs[mrudst], 2117 &chars[desigidx[mrudst]], 2118 true, 2119 ttisstds[mrudst], 2120 ttisuts[mrudst]); 2121 isdsts[mrudst] = 1; 2122 omittype[type] = false; 2123 } 2124 if (histd >= 0 && mrustd >= 0 && histd != mrustd && 2125 utoffs[histd] != utoffs[mrustd]) { 2126 isdsts[mrustd] = -1; 2127 type = addtype(utoffs[mrustd], 2128 &chars[desigidx[mrustd]], 2129 false, 2130 ttisstds[mrustd], 2131 ttisuts[mrustd]); 2132 isdsts[mrustd] = 0; 2133 omittype[type] = false; 2134 } 2135 } 2136 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ 2137 thistypecnt = 0; 2138 for (i = old0; i < typecnt; i++) 2139 if (!omittype[i]) 2140 typemap[i == old0 ? thisdefaulttype 2141 : i == thisdefaulttype ? old0 : i] 2142 = thistypecnt++; 2143 2144 for (i = 0; i < (int)(sizeof indmap / sizeof indmap[0]); ++i) 2145 indmap[i] = -1; 2146 thischarcnt = stdcnt = utcnt = 0; 2147 for (i = old0; i < typecnt; i++) { 2148 char * thisabbr; 2149 2150 if (omittype[i]) 2151 continue; 2152 if (ttisstds[i]) 2153 stdcnt = thistypecnt; 2154 if (ttisuts[i]) 2155 utcnt = thistypecnt; 2156 if (indmap[desigidx[i]] >= 0) 2157 continue; 2158 thisabbr = &chars[desigidx[i]]; 2159 for (j = 0; j < thischarcnt; ++j) 2160 if (strcmp(&thischars[j], thisabbr) == 0) 2161 break; 2162 if (j == thischarcnt) { 2163 strcpy(&thischars[thischarcnt], thisabbr); 2164 thischarcnt += strlen(thisabbr) + 1; 2165 } 2166 indmap[desigidx[i]] = j; 2167 } 2168 if (pass == 1 && !want_bloat()) { 2169 utcnt = stdcnt = thisleapcnt = 0; 2170 thistimecnt = - (locut + hicut); 2171 thistypecnt = thischarcnt = 1; 2172 thistimelim = thistimei; 2173 } 2174 #define DO(field) fwrite(tzh.field, sizeof tzh.field, (size_t) 1, fp) 2175 tzh = tzh0; 2176 memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); 2177 tzh.tzh_version[0] = version; 2178 convert(utcnt, tzh.tzh_ttisutcnt); 2179 convert(stdcnt, tzh.tzh_ttisstdcnt); 2180 convert(thisleapcnt, tzh.tzh_leapcnt); 2181 convert(locut + thistimecnt + hicut, tzh.tzh_timecnt); 2182 convert(thistypecnt, tzh.tzh_typecnt); 2183 convert(thischarcnt, tzh.tzh_charcnt); 2184 DO(tzh_magic); 2185 DO(tzh_version); 2186 DO(tzh_reserved); 2187 DO(tzh_ttisutcnt); 2188 DO(tzh_ttisstdcnt); 2189 DO(tzh_leapcnt); 2190 DO(tzh_timecnt); 2191 DO(tzh_typecnt); 2192 DO(tzh_charcnt); 2193 #undef DO 2194 if (pass == 1 && !want_bloat()) { 2195 /* Output a minimal data block with just one time type. */ 2196 puttzcode(0, fp); /* utoff */ 2197 putc(0, fp); /* dst */ 2198 putc(0, fp); /* index of abbreviation */ 2199 putc(0, fp); /* empty-string abbreviation */ 2200 continue; 2201 } 2202 2203 /* Output a LO_TIME transition if needed; see limitrange. 2204 But do not go below the minimum representable value 2205 for this pass. */ 2206 lo = pass == 1 && lo_time < INT32_MIN ? INT32_MIN : lo_time; 2207 2208 if (locut) 2209 puttzcodepass(lo, fp, pass); 2210 for (i = thistimei; i < thistimelim; ++i) { 2211 zic_t at = ats[i] < lo ? lo : ats[i]; 2212 puttzcodepass(at, fp, pass); 2213 } 2214 if (hicut) 2215 puttzcodepass(hi_time + 1, fp, pass); 2216 currenttype = 0; 2217 if (locut) 2218 putc(currenttype, fp); 2219 for (i = thistimei; i < thistimelim; ++i) { 2220 currenttype = typemap[types[i]]; 2221 putc(currenttype, fp); 2222 } 2223 if (hicut) 2224 putc(currenttype, fp); 2225 2226 for (i = old0; i < typecnt; i++) { 2227 int h = (i == old0 ? thisdefaulttype 2228 : i == thisdefaulttype ? old0 : i); 2229 if (!omittype[h]) { 2230 puttzcode(utoffs[h], fp); 2231 putc(isdsts[h], fp); 2232 putc(indmap[desigidx[h]], fp); 2233 } 2234 } 2235 if (thischarcnt != 0) 2236 fwrite(thischars, sizeof thischars[0], 2237 (size_t) thischarcnt, fp); 2238 for (i = thisleapi; i < thisleaplim; ++i) { 2239 zic_t todo; 2240 2241 if (roll[i]) { 2242 if (timecnt == 0 || trans[i] < ats[0]) { 2243 j = 0; 2244 while (isdsts[j]) 2245 if (++j >= typecnt) { 2246 j = 0; 2247 break; 2248 } 2249 } else { 2250 j = 1; 2251 while (j < timecnt && 2252 trans[i] >= ats[j]) 2253 ++j; 2254 j = types[j - 1]; 2255 } 2256 todo = tadd(trans[i], -utoffs[j]); 2257 } else todo = trans[i]; 2258 puttzcodepass(todo, fp, pass); 2259 puttzcode(corr[i], fp); 2260 } 2261 if (stdcnt != 0) 2262 for (i = old0; i < typecnt; i++) 2263 if (!omittype[i]) 2264 putc(ttisstds[i], fp); 2265 if (utcnt != 0) 2266 for (i = old0; i < typecnt; i++) 2267 if (!omittype[i]) 2268 putc(ttisuts[i], fp); 2269 } 2270 fprintf(fp, "\n%s\n", string); 2271 close_file(fp, directory, name); 2272 free(ats); 2273 } 2274 2275 static char const * 2276 abbroffset(char *buf, zic_t offset) 2277 { 2278 char sign = '+'; 2279 int seconds, minutes; 2280 2281 if (offset < 0) { 2282 offset = -offset; 2283 sign = '-'; 2284 } 2285 2286 seconds = offset % SECSPERMIN; 2287 offset /= SECSPERMIN; 2288 minutes = offset % MINSPERHOUR; 2289 offset /= MINSPERHOUR; 2290 if (100 <= offset) { 2291 error(_("%%z UT offset magnitude exceeds 99:59:59")); 2292 return "%z"; 2293 } else { 2294 char *p = buf; 2295 *p++ = sign; 2296 *p++ = '0' + offset / 10; 2297 *p++ = '0' + offset % 10; 2298 if (minutes | seconds) { 2299 *p++ = '0' + minutes / 10; 2300 *p++ = '0' + minutes % 10; 2301 if (seconds) { 2302 *p++ = '0' + seconds / 10; 2303 *p++ = '0' + seconds % 10; 2304 } 2305 } 2306 *p = '\0'; 2307 return buf; 2308 } 2309 } 2310 2311 static size_t 2312 doabbr(char *abbr, int abbrlen, struct zone const *zp, const char *letters, 2313 bool isdst, zic_t save, bool doquotes) 2314 { 2315 char * cp; 2316 char * slashp; 2317 size_t len; 2318 char const *format = zp->z_format; 2319 2320 slashp = strchr(format, '/'); 2321 if (slashp == NULL) { 2322 char letterbuf[PERCENT_Z_LEN_BOUND + 1]; 2323 if (zp->z_format_specifier == 'z') 2324 letters = abbroffset(letterbuf, zp->z_stdoff + save); 2325 else if (!letters) 2326 letters = "%s"; 2327 snprintf(abbr, abbrlen, format, letters); 2328 } else if (isdst) { 2329 strlcpy(abbr, slashp + 1, abbrlen); 2330 } else { 2331 memcpy(abbr, format, slashp - format); 2332 abbr[slashp - format] = '\0'; 2333 } 2334 len = strlen(abbr); 2335 if (!doquotes) 2336 return len; 2337 for (cp = abbr; is_alpha(*cp); cp++) 2338 continue; 2339 if (len > 0 && *cp == '\0') 2340 return len; 2341 abbr[len + 2] = '\0'; 2342 abbr[len + 1] = '>'; 2343 memmove(abbr + 1, abbr, len); 2344 abbr[0] = '<'; 2345 return len + 2; 2346 } 2347 2348 static void 2349 updateminmax(const zic_t x) 2350 { 2351 if (min_year > x) 2352 min_year = x; 2353 if (max_year < x) 2354 max_year = x; 2355 } 2356 2357 static int 2358 stringoffset(char *result, zic_t offset) 2359 { 2360 int hours; 2361 int minutes; 2362 int seconds; 2363 bool negative = offset < 0; 2364 int len = negative; 2365 2366 if (negative) { 2367 offset = -offset; 2368 result[0] = '-'; 2369 } 2370 seconds = offset % SECSPERMIN; 2371 offset /= SECSPERMIN; 2372 minutes = offset % MINSPERHOUR; 2373 offset /= MINSPERHOUR; 2374 hours = offset; 2375 if (hours >= HOURSPERDAY * DAYSPERWEEK) { 2376 result[0] = '\0'; 2377 return 0; 2378 } 2379 len += sprintf(result + len, "%d", hours); 2380 if (minutes != 0 || seconds != 0) { 2381 len += sprintf(result + len, ":%02d", minutes); 2382 if (seconds != 0) 2383 len += sprintf(result + len, ":%02d", seconds); 2384 } 2385 return len; 2386 } 2387 2388 static int 2389 stringrule(char *result, struct rule *const rp, zic_t save, const zic_t stdoff) 2390 { 2391 zic_t tod = rp->r_tod; 2392 int compat = 0; 2393 2394 if (rp->r_dycode == DC_DOM) { 2395 int month, total; 2396 2397 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY) 2398 return -1; 2399 total = 0; 2400 for (month = 0; month < rp->r_month; ++month) 2401 total += len_months[0][month]; 2402 /* Omit the "J" in Jan and Feb, as that's shorter. */ 2403 if (rp->r_month <= 1) 2404 result += sprintf(result, "%d", total + rp->r_dayofmonth - 1); 2405 else 2406 result += sprintf(result, "J%d", total + rp->r_dayofmonth); 2407 } else { 2408 int week; 2409 int wday = rp->r_wday; 2410 int wdayoff; 2411 2412 if (rp->r_dycode == DC_DOWGEQ) { 2413 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK; 2414 if (wdayoff) 2415 compat = 2013; 2416 wday -= wdayoff; 2417 tod += wdayoff * SECSPERDAY; 2418 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK; 2419 } else if (rp->r_dycode == DC_DOWLEQ) { 2420 if (rp->r_dayofmonth == len_months[1][rp->r_month]) 2421 week = 5; 2422 else { 2423 wdayoff = rp->r_dayofmonth % DAYSPERWEEK; 2424 if (wdayoff) 2425 compat = 2013; 2426 wday -= wdayoff; 2427 tod += wdayoff * SECSPERDAY; 2428 week = rp->r_dayofmonth / DAYSPERWEEK; 2429 } 2430 } else return -1; /* "cannot happen" */ 2431 if (wday < 0) 2432 wday += DAYSPERWEEK; 2433 result += sprintf(result, "M%d.%d.%d", 2434 rp->r_month + 1, week, wday); 2435 } 2436 if (rp->r_todisut) 2437 tod += stdoff; 2438 if (rp->r_todisstd && !rp->r_isdst) 2439 tod += save; 2440 if (tod != 2 * SECSPERMIN * MINSPERHOUR) { 2441 *result++ = '/'; 2442 if (! stringoffset(result, tod)) 2443 return -1; 2444 if (tod < 0) { 2445 if (compat < 2013) 2446 compat = 2013; 2447 } else if (SECSPERDAY <= tod) { 2448 if (compat < 1994) 2449 compat = 1994; 2450 } 2451 } 2452 return compat; 2453 } 2454 2455 static int 2456 rule_cmp(struct rule const *a, struct rule const *b) 2457 { 2458 if (!a) 2459 return -!!b; 2460 if (!b) 2461 return 1; 2462 if (a->r_hiyear != b->r_hiyear) 2463 return a->r_hiyear < b->r_hiyear ? -1 : 1; 2464 if (a->r_month - b->r_month != 0) 2465 return a->r_month - b->r_month; 2466 return a->r_dayofmonth - b->r_dayofmonth; 2467 } 2468 2469 static int 2470 stringzone(char *result, int resultlen, const struct zone *const zpfirst, 2471 const int zonecount) 2472 { 2473 const struct zone * zp; 2474 struct rule * rp; 2475 struct rule * stdrp; 2476 struct rule * dstrp; 2477 ptrdiff_t i; 2478 const char * abbrvar; 2479 int compat = 0; 2480 int c; 2481 size_t len; 2482 int offsetlen; 2483 struct rule stdr, dstr; 2484 2485 result[0] = '\0'; 2486 2487 /* Internet RFC 8536 section 5.1 says to use an empty TZ string if 2488 future timestamps are truncated. */ 2489 if (hi_time < max_time) 2490 return -1; 2491 2492 zp = zpfirst + zonecount - 1; 2493 stdrp = dstrp = NULL; 2494 for (i = 0; i < zp->z_nrules; ++i) { 2495 rp = &zp->z_rules[i]; 2496 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX) 2497 continue; 2498 if (!rp->r_isdst) { 2499 if (stdrp == NULL) 2500 stdrp = rp; 2501 else return -1; 2502 } else { 2503 if (dstrp == NULL) 2504 dstrp = rp; 2505 else return -1; 2506 } 2507 } 2508 if (stdrp == NULL && dstrp == NULL) { 2509 /* 2510 ** There are no rules running through "max". 2511 ** Find the latest std rule in stdabbrrp 2512 ** and latest rule of any type in stdrp. 2513 */ 2514 struct rule *stdabbrrp = NULL; 2515 for (i = 0; i < zp->z_nrules; ++i) { 2516 rp = &zp->z_rules[i]; 2517 if (!rp->r_isdst && rule_cmp(stdabbrrp, rp) < 0) 2518 stdabbrrp = rp; 2519 if (rule_cmp(stdrp, rp) < 0) 2520 stdrp = rp; 2521 } 2522 if (stdrp != NULL && stdrp->r_isdst) { 2523 /* Perpetual DST. */ 2524 dstr.r_month = TM_JANUARY; 2525 dstr.r_dycode = DC_DOM; 2526 dstr.r_dayofmonth = 1; 2527 dstr.r_tod = 0; 2528 dstr.r_todisstd = dstr.r_todisut = false; 2529 dstr.r_isdst = stdrp->r_isdst; 2530 dstr.r_save = stdrp->r_save; 2531 dstr.r_abbrvar = stdrp->r_abbrvar; 2532 stdr.r_month = TM_DECEMBER; 2533 stdr.r_dycode = DC_DOM; 2534 stdr.r_dayofmonth = 31; 2535 stdr.r_tod = SECSPERDAY + stdrp->r_save; 2536 stdr.r_todisstd = stdr.r_todisut = false; 2537 stdr.r_isdst = false; 2538 stdr.r_save = 0; 2539 stdr.r_abbrvar 2540 = (stdabbrrp ? stdabbrrp->r_abbrvar : ""); 2541 dstrp = &dstr; 2542 stdrp = &stdr; 2543 } 2544 } 2545 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_isdst)) 2546 return -1; 2547 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; 2548 len = doabbr(result, resultlen, zp, abbrvar, false, 0, true); 2549 offsetlen = stringoffset(result + len, -zp->z_stdoff); 2550 if (! offsetlen) { 2551 result[0] = '\0'; 2552 return -1; 2553 } 2554 len += offsetlen; 2555 if (dstrp == NULL) 2556 return compat; 2557 len += doabbr(result + len, resultlen - len, zp, dstrp->r_abbrvar, 2558 dstrp->r_isdst, dstrp->r_save, true); 2559 if (dstrp->r_save != SECSPERMIN * MINSPERHOUR) { 2560 offsetlen = stringoffset(result + len, 2561 - (zp->z_stdoff + dstrp->r_save)); 2562 if (! offsetlen) { 2563 result[0] = '\0'; 2564 return -1; 2565 } 2566 len += offsetlen; 2567 } 2568 result[len++] = ','; 2569 c = stringrule(result + len, dstrp, dstrp->r_save, zp->z_stdoff); 2570 if (c < 0) { 2571 result[0] = '\0'; 2572 return -1; 2573 } 2574 if (compat < c) 2575 compat = c; 2576 len += strlen(result + len); 2577 result[len++] = ','; 2578 c = stringrule(result + len, stdrp, dstrp->r_save, zp->z_stdoff); 2579 if (c < 0) { 2580 result[0] = '\0'; 2581 return -1; 2582 } 2583 if (compat < c) 2584 compat = c; 2585 return compat; 2586 } 2587 2588 static void 2589 outzone(const struct zone *zpfirst, ptrdiff_t zonecount) 2590 { 2591 const struct zone * zp; 2592 struct rule * rp; 2593 ptrdiff_t i, j; 2594 bool usestart, useuntil; 2595 zic_t starttime, untiltime; 2596 zic_t stdoff; 2597 zic_t save; 2598 zic_t year; 2599 zic_t startoff; 2600 bool startttisstd; 2601 bool startttisut; 2602 int type; 2603 char * startbuf; 2604 char * ab; 2605 char * envvar; 2606 size_t max_abbr_len; 2607 size_t max_envvar_len; 2608 bool prodstic; /* all rules are min to max */ 2609 int compat; 2610 bool do_extend; 2611 char version; 2612 ptrdiff_t lastatmax = -1; 2613 zic_t one = 1; 2614 zic_t y2038_boundary = one << 31; 2615 zic_t max_year0; 2616 int defaulttype = -1; 2617 2618 max_abbr_len = 2 + max_format_len + max_abbrvar_len; 2619 max_envvar_len = 2 * max_abbr_len + 5 * 9; 2620 startbuf = zic_malloc(max_abbr_len + 1); 2621 ab = zic_malloc(max_abbr_len + 1); 2622 envvar = zic_malloc(max_envvar_len + 1); 2623 INITIALIZE(untiltime); 2624 INITIALIZE(starttime); 2625 /* 2626 ** Now. . .finally. . .generate some useful data! 2627 */ 2628 timecnt = 0; 2629 typecnt = 0; 2630 charcnt = 0; 2631 prodstic = zonecount == 1; 2632 /* 2633 ** Thanks to Earl Chew 2634 ** for noting the need to unconditionally initialize startttisstd. 2635 */ 2636 startttisstd = false; 2637 startttisut = false; 2638 min_year = max_year = EPOCH_YEAR; 2639 if (leapseen) { 2640 updateminmax(leapminyear); 2641 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX)); 2642 } 2643 for (i = 0; i < zonecount; ++i) { 2644 zp = &zpfirst[i]; 2645 if (i < zonecount - 1) 2646 updateminmax(zp->z_untilrule.r_loyear); 2647 for (j = 0; j < zp->z_nrules; ++j) { 2648 rp = &zp->z_rules[j]; 2649 if (rp->r_lowasnum) 2650 updateminmax(rp->r_loyear); 2651 if (rp->r_hiwasnum) 2652 updateminmax(rp->r_hiyear); 2653 if (rp->r_lowasnum || rp->r_hiwasnum) 2654 prodstic = false; 2655 } 2656 } 2657 /* 2658 ** Generate lots of data if a rule can't cover all future times. 2659 */ 2660 compat = stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount); 2661 version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION; 2662 do_extend = compat < 0; 2663 if (noise) { 2664 if (!*envvar) 2665 warning("%s %s", 2666 _("no POSIX environment variable for zone"), 2667 zpfirst->z_name); 2668 else if (compat != 0) { 2669 /* Circa-COMPAT clients, and earlier clients, might 2670 not work for this zone when given dates before 2671 1970 or after 2038. */ 2672 warning(_("%s: pre-%d clients may mishandle" 2673 " distant timestamps"), 2674 zpfirst->z_name, compat); 2675 } 2676 } 2677 if (do_extend) { 2678 /* 2679 ** Search through a couple of extra years past the obvious 2680 ** 400, to avoid edge cases. For example, suppose a non-POSIX 2681 ** rule applies from 2012 onwards and has transitions in March 2682 ** and September, plus some one-off transitions in November 2683 ** 2013. If zic looked only at the last 400 years, it would 2684 ** set max_year=2413, with the intent that the 400 years 2014 2685 ** through 2413 will be repeated. The last transition listed 2686 ** in the tzfile would be in 2413-09, less than 400 years 2687 ** after the last one-off transition in 2013-11. Two years 2688 ** might be overkill, but with the kind of edge cases 2689 ** available we're not sure that one year would suffice. 2690 */ 2691 enum { years_of_observations = YEARSPERREPEAT + 2 }; 2692 2693 if (min_year >= ZIC_MIN + years_of_observations) 2694 min_year -= years_of_observations; 2695 else min_year = ZIC_MIN; 2696 if (max_year <= ZIC_MAX - years_of_observations) 2697 max_year += years_of_observations; 2698 else max_year = ZIC_MAX; 2699 /* 2700 ** Regardless of any of the above, 2701 ** for a "proDSTic" zone which specifies that its rules 2702 ** always have and always will be in effect, 2703 ** we only need one cycle to define the zone. 2704 */ 2705 if (prodstic) { 2706 min_year = 1900; 2707 max_year = min_year + years_of_observations; 2708 } 2709 } 2710 max_year0 = max_year; 2711 if (want_bloat()) { 2712 /* For the benefit of older systems, 2713 generate data from 1900 through 2038. */ 2714 if (min_year > 1900) 2715 min_year = 1900; 2716 if (max_year < 2038) 2717 max_year = 2038; 2718 } 2719 2720 for (i = 0; i < zonecount; ++i) { 2721 struct rule *prevrp = NULL; 2722 /* 2723 ** A guess that may well be corrected later. 2724 */ 2725 save = 0; 2726 zp = &zpfirst[i]; 2727 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 2728 useuntil = i < (zonecount - 1); 2729 if (useuntil && zp->z_untiltime <= min_time) 2730 continue; 2731 stdoff = zp->z_stdoff; 2732 eat(zp->z_filename, zp->z_linenum); 2733 *startbuf = '\0'; 2734 startoff = zp->z_stdoff; 2735 if (zp->z_nrules == 0) { 2736 save = zp->z_save; 2737 doabbr(startbuf, max_abbr_len + 1, 2738 zp, NULL, zp->z_isdst, save, false); 2739 type = addtype(oadd(zp->z_stdoff, save), 2740 startbuf, zp->z_isdst, startttisstd, 2741 startttisut); 2742 if (usestart) { 2743 addtt(starttime, type); 2744 usestart = false; 2745 } else 2746 defaulttype = type; 2747 } else for (year = min_year; year <= max_year; ++year) { 2748 if (useuntil && year > zp->z_untilrule.r_hiyear) 2749 break; 2750 /* 2751 ** Mark which rules to do in the current year. 2752 ** For those to do, calculate rpytime(rp, year); 2753 ** The former TYPE field was also considered here. 2754 */ 2755 for (j = 0; j < zp->z_nrules; ++j) { 2756 rp = &zp->z_rules[j]; 2757 eats(zp->z_filename, zp->z_linenum, 2758 rp->r_filename, rp->r_linenum); 2759 rp->r_todo = year >= rp->r_loyear && 2760 year <= rp->r_hiyear; 2761 if (rp->r_todo) { 2762 rp->r_temp = rpytime(rp, year); 2763 rp->r_todo 2764 = (rp->r_temp < y2038_boundary 2765 || year <= max_year0); 2766 } 2767 } 2768 for ( ; ; ) { 2769 ptrdiff_t k; 2770 zic_t jtime, ktime; 2771 zic_t offset; 2772 2773 INITIALIZE(ktime); 2774 if (useuntil) { 2775 /* 2776 ** Turn untiltime into UT 2777 ** assuming the current stdoff and 2778 ** save values. 2779 */ 2780 untiltime = zp->z_untiltime; 2781 if (!zp->z_untilrule.r_todisut) 2782 untiltime = tadd(untiltime, 2783 -stdoff); 2784 if (!zp->z_untilrule.r_todisstd) 2785 untiltime = tadd(untiltime, 2786 -save); 2787 } 2788 /* 2789 ** Find the rule (of those to do, if any) 2790 ** that takes effect earliest in the year. 2791 */ 2792 k = -1; 2793 for (j = 0; j < zp->z_nrules; ++j) { 2794 rp = &zp->z_rules[j]; 2795 if (!rp->r_todo) 2796 continue; 2797 eats(zp->z_filename, zp->z_linenum, 2798 rp->r_filename, rp->r_linenum); 2799 offset = rp->r_todisut ? 0 : stdoff; 2800 if (!rp->r_todisstd) 2801 offset = oadd(offset, save); 2802 jtime = rp->r_temp; 2803 if (jtime == min_time || 2804 jtime == max_time) 2805 continue; 2806 jtime = tadd(jtime, -offset); 2807 if (k < 0 || jtime < ktime) { 2808 k = j; 2809 ktime = jtime; 2810 } else if (jtime == ktime) { 2811 char const *dup_rules_msg = 2812 _("two rules for same instant"); 2813 eats(zp->z_filename, zp->z_linenum, 2814 rp->r_filename, rp->r_linenum); 2815 warning("%s", dup_rules_msg); 2816 rp = &zp->z_rules[k]; 2817 eats(zp->z_filename, zp->z_linenum, 2818 rp->r_filename, rp->r_linenum); 2819 error("%s", dup_rules_msg); 2820 } 2821 } 2822 if (k < 0) 2823 break; /* go on to next year */ 2824 rp = &zp->z_rules[k]; 2825 rp->r_todo = false; 2826 if (useuntil && ktime >= untiltime) 2827 break; 2828 save = rp->r_save; 2829 if (usestart && ktime == starttime) 2830 usestart = false; 2831 if (usestart) { 2832 if (ktime < starttime) { 2833 startoff = oadd(zp->z_stdoff, 2834 save); 2835 doabbr(startbuf, 2836 max_abbr_len + 1, 2837 zp, 2838 rp->r_abbrvar, 2839 rp->r_isdst, 2840 rp->r_save, 2841 false); 2842 continue; 2843 } 2844 if (*startbuf == '\0' 2845 && startoff == oadd(zp->z_stdoff, 2846 save)) { 2847 doabbr(startbuf, 2848 max_abbr_len + 1, 2849 zp, 2850 rp->r_abbrvar, 2851 rp->r_isdst, 2852 rp->r_save, 2853 false); 2854 } 2855 } 2856 eats(zp->z_filename, zp->z_linenum, 2857 rp->r_filename, rp->r_linenum); 2858 doabbr(ab, max_abbr_len + 1, zp, rp->r_abbrvar, 2859 rp->r_isdst, rp->r_save, false); 2860 offset = oadd(zp->z_stdoff, rp->r_save); 2861 if (!want_bloat() && !useuntil && !do_extend 2862 && prevrp 2863 && rp->r_hiyear == ZIC_MAX 2864 && prevrp->r_hiyear == ZIC_MAX) 2865 break; 2866 type = addtype(offset, ab, rp->r_isdst, 2867 rp->r_todisstd, rp->r_todisut); 2868 if (defaulttype < 0 && !rp->r_isdst) 2869 defaulttype = type; 2870 if (rp->r_hiyear == ZIC_MAX 2871 && ! (0 <= lastatmax 2872 && ktime < attypes[lastatmax].at)) 2873 lastatmax = timecnt; 2874 addtt(ktime, type); 2875 prevrp = rp; 2876 } 2877 } 2878 if (usestart) { 2879 if (*startbuf == '\0' && 2880 zp->z_format != NULL && 2881 strchr(zp->z_format, '%') == NULL && 2882 strchr(zp->z_format, '/') == NULL) 2883 strncpy(startbuf, zp->z_format, 2884 max_abbr_len + 1 - 1); 2885 eat(zp->z_filename, zp->z_linenum); 2886 if (*startbuf == '\0') 2887 error(_("can't determine time zone abbreviation to use just after until time")); 2888 else { 2889 bool isdst = startoff != zp->z_stdoff; 2890 type = addtype(startoff, startbuf, isdst, 2891 startttisstd, startttisut); 2892 if (defaulttype < 0 && !isdst) 2893 defaulttype = type; 2894 addtt(starttime, type); 2895 } 2896 } 2897 /* 2898 ** Now we may get to set starttime for the next zone line. 2899 */ 2900 if (useuntil) { 2901 startttisstd = zp->z_untilrule.r_todisstd; 2902 startttisut = zp->z_untilrule.r_todisut; 2903 starttime = zp->z_untiltime; 2904 if (!startttisstd) 2905 starttime = tadd(starttime, -save); 2906 if (!startttisut) 2907 starttime = tadd(starttime, -stdoff); 2908 } 2909 } 2910 if (defaulttype < 0) 2911 defaulttype = 0; 2912 if (0 <= lastatmax) 2913 attypes[lastatmax].dontmerge = true; 2914 if (do_extend) { 2915 /* 2916 ** If we're extending the explicitly listed observations 2917 ** for 400 years because we can't fill the POSIX-TZ field, 2918 ** check whether we actually ended up explicitly listing 2919 ** observations through that period. If there aren't any 2920 ** near the end of the 400-year period, add a redundant 2921 ** one at the end of the final year, to make it clear 2922 ** that we are claiming to have definite knowledge of 2923 ** the lack of transitions up to that point. 2924 */ 2925 struct rule xr; 2926 struct attype *lastat; 2927 memset(&xr, 0, sizeof(xr)); 2928 xr.r_month = TM_JANUARY; 2929 xr.r_dycode = DC_DOM; 2930 xr.r_dayofmonth = 1; 2931 xr.r_tod = 0; 2932 for (lastat = attypes, i = 1; i < timecnt; i++) 2933 if (attypes[i].at > lastat->at) 2934 lastat = &attypes[i]; 2935 if (!lastat || lastat->at < rpytime(&xr, max_year - 1)) { 2936 addtt(rpytime(&xr, max_year + 1), 2937 lastat ? lastat->type : defaulttype); 2938 attypes[timecnt - 1].dontmerge = true; 2939 } 2940 } 2941 writezone(zpfirst->z_name, envvar, version, defaulttype); 2942 free(startbuf); 2943 free(ab); 2944 free(envvar); 2945 } 2946 2947 static void 2948 addtt(zic_t starttime, int type) 2949 { 2950 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc); 2951 attypes[timecnt].at = starttime; 2952 attypes[timecnt].dontmerge = false; 2953 attypes[timecnt].type = type; 2954 ++timecnt; 2955 } 2956 2957 static int 2958 addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut) 2959 { 2960 int i, j; 2961 2962 if (! (-1L - 2147483647L <= utoff && utoff <= 2147483647L)) { 2963 error(_("UT offset out of range")); 2964 exit(EXIT_FAILURE); 2965 } 2966 if (!want_bloat()) 2967 ttisstd = ttisut = false; 2968 2969 for (j = 0; j < charcnt; ++j) 2970 if (strcmp(&chars[j], abbr) == 0) 2971 break; 2972 if (j == charcnt) 2973 newabbr(abbr); 2974 else { 2975 /* If there's already an entry, return its index. */ 2976 for (i = 0; i < typecnt; i++) 2977 if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i] 2978 && ttisstd == ttisstds[i] && ttisut == ttisuts[i]) 2979 return i; 2980 } 2981 /* 2982 ** There isn't one; add a new one, unless there are already too 2983 ** many. 2984 */ 2985 if (typecnt >= TZ_MAX_TYPES) { 2986 error(_("too many local time types")); 2987 exit(EXIT_FAILURE); 2988 } 2989 i = typecnt++; 2990 utoffs[i] = utoff; 2991 isdsts[i] = isdst; 2992 ttisstds[i] = ttisstd; 2993 ttisuts[i] = ttisut; 2994 desigidx[i] = j; 2995 return i; 2996 } 2997 2998 static void 2999 leapadd(zic_t t, int correction, int rolling) 3000 { 3001 int i; 3002 3003 if (TZ_MAX_LEAPS <= leapcnt) { 3004 error(_("too many leap seconds")); 3005 exit(EXIT_FAILURE); 3006 } 3007 for (i = 0; i < leapcnt; ++i) 3008 if (t <= trans[i]) 3009 break; 3010 memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans); 3011 memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr); 3012 memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll); 3013 trans[i] = t; 3014 corr[i] = correction; 3015 roll[i] = rolling; 3016 ++leapcnt; 3017 } 3018 3019 static void 3020 adjleap(void) 3021 { 3022 int i; 3023 zic_t last = 0; 3024 zic_t prevtrans = 0; 3025 3026 /* 3027 ** propagate leap seconds forward 3028 */ 3029 for (i = 0; i < leapcnt; ++i) { 3030 if (trans[i] - prevtrans < 28 * SECSPERDAY) { 3031 error(_("Leap seconds too close together")); 3032 exit(EXIT_FAILURE); 3033 } 3034 prevtrans = trans[i]; 3035 trans[i] = tadd(trans[i], last); 3036 last = corr[i] += last; 3037 } 3038 3039 if (leapexpires < 0) { 3040 leapexpires = comment_leapexpires; 3041 if (0 <= leapexpires) 3042 warning(_("\"#expires\" is obsolescent; use \"Expires\"")); 3043 } 3044 3045 if (0 <= leapexpires) { 3046 leapexpires = oadd(leapexpires, last); 3047 if (! (leapcnt == 0 || (trans[leapcnt - 1] < leapexpires))) { 3048 error(_("last Leap time does not precede Expires time")); 3049 exit(EXIT_FAILURE); 3050 } 3051 if (leapexpires <= hi_time) 3052 hi_time = leapexpires - 1; 3053 } 3054 } 3055 3056 /* Is A a space character in the C locale? */ 3057 static bool 3058 is_space(char a) 3059 { 3060 switch (a) { 3061 default: 3062 return false; 3063 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': 3064 return true; 3065 } 3066 } 3067 3068 /* Is A an alphabetic character in the C locale? */ 3069 static bool 3070 is_alpha(char a) 3071 { 3072 switch (a) { 3073 default: 3074 return false; 3075 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 3076 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': 3077 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': 3078 case 'V': case 'W': case 'X': case 'Y': case 'Z': 3079 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': 3080 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': 3081 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': 3082 case 'v': case 'w': case 'x': case 'y': case 'z': 3083 return true; 3084 } 3085 } 3086 3087 /* If A is an uppercase character in the C locale, return its lowercase 3088 counterpart. Otherwise, return A. */ 3089 static char 3090 lowerit(char a) 3091 { 3092 switch (a) { 3093 default: return a; 3094 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c'; 3095 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f'; 3096 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i'; 3097 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l'; 3098 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o'; 3099 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r'; 3100 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u'; 3101 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x'; 3102 case 'Y': return 'y'; case 'Z': return 'z'; 3103 } 3104 } 3105 3106 /* case-insensitive equality */ 3107 static ATTRIBUTE_PURE bool 3108 ciequal(const char *ap, const char *bp) 3109 { 3110 while (lowerit(*ap) == lowerit(*bp++)) 3111 if (*ap++ == '\0') 3112 return true; 3113 return false; 3114 } 3115 3116 static ATTRIBUTE_PURE bool 3117 itsabbr(const char *abbr, const char *word) 3118 { 3119 if (lowerit(*abbr) != lowerit(*word)) 3120 return false; 3121 ++word; 3122 while (*++abbr != '\0') 3123 do { 3124 if (*word == '\0') 3125 return false; 3126 } while (lowerit(*word++) != lowerit(*abbr)); 3127 return true; 3128 } 3129 3130 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */ 3131 3132 static ATTRIBUTE_PURE bool 3133 ciprefix(char const *abbr, char const *word) 3134 { 3135 do 3136 if (!*abbr) 3137 return true; 3138 while (lowerit(*abbr++) == lowerit(*word++)); 3139 3140 return false; 3141 } 3142 3143 static const struct lookup * 3144 byword(const char *word, const struct lookup *table) 3145 { 3146 const struct lookup * foundlp; 3147 const struct lookup * lp; 3148 3149 if (word == NULL || table == NULL) 3150 return NULL; 3151 3152 /* If TABLE is LASTS and the word starts with "last" followed 3153 by a non-'-', skip the "last" and look in WDAY_NAMES instead. 3154 Warn about any usage of the undocumented prefix "last-". */ 3155 if (table == lasts && ciprefix("last", word) && word[4]) { 3156 if (word[4] == '-') 3157 warning(_("\"%s\" is undocumented; use \"last%s\" instead"), 3158 word, word + 5); 3159 else { 3160 word += 4; 3161 table = wday_names; 3162 } 3163 } 3164 3165 /* 3166 ** Look for exact match. 3167 */ 3168 for (lp = table; lp->l_word != NULL; ++lp) 3169 if (ciequal(word, lp->l_word)) 3170 return lp; 3171 /* 3172 ** Look for inexact match. 3173 */ 3174 foundlp = NULL; 3175 for (lp = table; lp->l_word != NULL; ++lp) 3176 if (ciprefix(word, lp->l_word)) { 3177 if (foundlp == NULL) 3178 foundlp = lp; 3179 else return NULL; /* multiple inexact matches */ 3180 } 3181 3182 if (foundlp && noise) { 3183 /* Warn about any backward-compatibility issue with pre-2017c zic. */ 3184 bool pre_2017c_match = false; 3185 for (lp = table; lp->l_word; lp++) 3186 if (itsabbr(word, lp->l_word)) { 3187 if (pre_2017c_match) { 3188 warning(_("\"%s\" is ambiguous in pre-2017c zic"), word); 3189 break; 3190 } 3191 pre_2017c_match = true; 3192 } 3193 } 3194 3195 return foundlp; 3196 } 3197 3198 static char ** 3199 getfields(char *cp) 3200 { 3201 char * dp; 3202 char ** array; 3203 int nsubs; 3204 3205 if (cp == NULL) 3206 return NULL; 3207 array = zic_malloc(size_product(strlen(cp) + 1, sizeof *array)); 3208 nsubs = 0; 3209 for ( ; ; ) { 3210 while (is_space(*cp)) 3211 ++cp; 3212 if (*cp == '\0' || *cp == '#') 3213 break; 3214 array[nsubs++] = dp = cp; 3215 do { 3216 if ((*dp = *cp++) != '"') 3217 ++dp; 3218 else while ((*dp = *cp++) != '"') 3219 if (*dp != '\0') 3220 ++dp; 3221 else { 3222 error(_("Odd number of quotation marks")); 3223 exit(EXIT_FAILURE); 3224 } 3225 } while (*cp && *cp != '#' && !is_space(*cp)); 3226 if (is_space(*cp)) 3227 ++cp; 3228 *dp = '\0'; 3229 } 3230 array[nsubs] = NULL; 3231 return array; 3232 } 3233 3234 static _Noreturn void 3235 time_overflow(void) 3236 { 3237 error(_("time overflow")); 3238 exit(EXIT_FAILURE); 3239 } 3240 3241 static ATTRIBUTE_PURE zic_t 3242 oadd(zic_t t1, zic_t t2) 3243 { 3244 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) 3245 time_overflow(); 3246 return t1 + t2; 3247 } 3248 3249 static ATTRIBUTE_PURE zic_t 3250 tadd(zic_t t1, zic_t t2) 3251 { 3252 if (t1 < 0) { 3253 if (t2 < min_time - t1) { 3254 if (t1 != min_time) 3255 time_overflow(); 3256 return min_time; 3257 } 3258 } else { 3259 if (max_time - t1 < t2) { 3260 if (t1 != max_time) 3261 time_overflow(); 3262 return max_time; 3263 } 3264 } 3265 return t1 + t2; 3266 } 3267 3268 /* 3269 ** Given a rule, and a year, compute the date (in seconds since January 1, 3270 ** 1970, 00:00 LOCAL time) in that year that the rule refers to. 3271 */ 3272 3273 static zic_t 3274 rpytime(const struct rule *rp, zic_t wantedy) 3275 { 3276 int m, i; 3277 zic_t dayoff; /* with a nod to Margaret O. */ 3278 zic_t t, y; 3279 3280 if (wantedy == ZIC_MIN) 3281 return min_time; 3282 if (wantedy == ZIC_MAX) 3283 return max_time; 3284 dayoff = 0; 3285 m = TM_JANUARY; 3286 y = EPOCH_YEAR; 3287 if (y < wantedy) { 3288 wantedy -= y; 3289 dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY); 3290 wantedy %= YEARSPERREPEAT; 3291 wantedy += y; 3292 } else if (wantedy < 0) { 3293 dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY); 3294 wantedy %= YEARSPERREPEAT; 3295 } 3296 while (wantedy != y) { 3297 if (wantedy > y) { 3298 i = len_years[isleap(y)]; 3299 ++y; 3300 } else { 3301 --y; 3302 i = -len_years[isleap(y)]; 3303 } 3304 dayoff = oadd(dayoff, i); 3305 } 3306 while (m != rp->r_month) { 3307 i = len_months[isleap(y)][m]; 3308 dayoff = oadd(dayoff, i); 3309 ++m; 3310 } 3311 i = rp->r_dayofmonth; 3312 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 3313 if (rp->r_dycode == DC_DOWLEQ) 3314 --i; 3315 else { 3316 error(_("use of 2/29 in non leap-year")); 3317 exit(EXIT_FAILURE); 3318 } 3319 } 3320 --i; 3321 dayoff = oadd(dayoff, i); 3322 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 3323 zic_t wday; 3324 3325 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK) 3326 wday = EPOCH_WDAY; 3327 /* 3328 ** Don't trust mod of negative numbers. 3329 */ 3330 if (dayoff >= 0) 3331 wday = (wday + dayoff) % LDAYSPERWEEK; 3332 else { 3333 wday -= ((-dayoff) % LDAYSPERWEEK); 3334 if (wday < 0) 3335 wday += LDAYSPERWEEK; 3336 } 3337 while (wday != rp->r_wday) 3338 if (rp->r_dycode == DC_DOWGEQ) { 3339 dayoff = oadd(dayoff, (zic_t) 1); 3340 if (++wday >= LDAYSPERWEEK) 3341 wday = 0; 3342 ++i; 3343 } else { 3344 dayoff = oadd(dayoff, (zic_t) -1); 3345 if (--wday < 0) 3346 wday = LDAYSPERWEEK - 1; 3347 --i; 3348 } 3349 if (i < 0 || i >= len_months[isleap(y)][m]) { 3350 if (noise) 3351 warning(_("rule goes past start/end of month; \ 3352 will not work with pre-2004 versions of zic")); 3353 } 3354 } 3355 if (dayoff < min_time / SECSPERDAY) 3356 return min_time; 3357 if (dayoff > max_time / SECSPERDAY) 3358 return max_time; 3359 t = (zic_t) dayoff * SECSPERDAY; 3360 return tadd(t, rp->r_tod); 3361 } 3362 3363 static void 3364 newabbr(const char *string) 3365 { 3366 int i; 3367 3368 if (strcmp(string, GRANDPARENTED) != 0) { 3369 const char * cp; 3370 const char * mp; 3371 3372 cp = string; 3373 mp = NULL; 3374 while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9') 3375 || *cp == '-' || *cp == '+') 3376 ++cp; 3377 if (noise && cp - string < 3) 3378 mp = _("time zone abbreviation has fewer than 3 characters"); 3379 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) 3380 mp = _("time zone abbreviation has too many characters"); 3381 if (*cp != '\0') 3382 mp = _("time zone abbreviation differs from POSIX standard"); 3383 if (mp != NULL) 3384 warning("%s (%s)", mp, string); 3385 } 3386 i = strlen(string) + 1; 3387 if (charcnt + i > TZ_MAX_CHARS) { 3388 error(_("too many, or too long, time zone abbreviations")); 3389 exit(EXIT_FAILURE); 3390 } 3391 strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1); 3392 charcnt += i; 3393 } 3394 3395 /* Ensure that the directories of ARGNAME exist, by making any missing 3396 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise, 3397 do it for ARGNAME too. Exit with failure if there is trouble. 3398 Do not consider an existing non-directory to be trouble. */ 3399 static void 3400 mkdirs(char const *argname, bool ancestors) 3401 { 3402 char * name; 3403 char * cp; 3404 3405 cp = name = ecpyalloc(argname); 3406 3407 /* On MS-Windows systems, do not worry about drive letters or 3408 backslashes, as this should suffice in practice. Time zone 3409 names do not use drive letters and backslashes. If the -d 3410 option of zic does not name an already-existing directory, 3411 it can use slashes to separate the already-existing 3412 ancestor prefix from the to-be-created subdirectories. */ 3413 3414 /* Do not mkdir a root directory, as it must exist. */ 3415 while (*cp == '/') 3416 cp++; 3417 3418 while (cp && ((cp = strchr(cp, '/')) || !ancestors)) { 3419 if (cp) 3420 *cp = '\0'; 3421 /* 3422 ** Try to create it. It's OK if creation fails because 3423 ** the directory already exists, perhaps because some 3424 ** other process just created it. For simplicity do 3425 ** not check first whether it already exists, as that 3426 ** is checked anyway if the mkdir fails. 3427 */ 3428 if (mkdir(name, MKDIR_UMASK) != 0) { 3429 /* For speed, skip itsdir if errno == EEXIST. Since 3430 mkdirs is called only after open fails with ENOENT 3431 on a subfile, EEXIST implies itsdir here. */ 3432 int err = errno; 3433 if (err != EEXIST && !itsdir(name)) { 3434 error(_("%s: Can't create directory %s: %s"), 3435 progname, name, strerror(err)); 3436 exit(EXIT_FAILURE); 3437 } 3438 } 3439 if (cp) 3440 *cp++ = '/'; 3441 } 3442 free(name); 3443 } 3444