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