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