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