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