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