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