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