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