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