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