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