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