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