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