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