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 gethms(const char * string, const char * errstring);
266 static zic_t getsave(char *, bool *);
267 static void inexpires(char **, int);
268 static void infile(int, char const *);
269 static void inleap(char ** fields, int nfields);
270 static void inlink(char ** fields, int nfields);
271 static void inrule(char ** fields, int nfields);
272 static bool inzcont(char ** fields, int nfields);
273 static bool inzone(char ** fields, int nfields);
274 static bool inzsub(char **, int, bool);
275 static bool is_alpha(char a);
276 static int itssymlink(char const *, int *);
277 static void leapadd(zic_t, int, int);
278 static char lowerit(char);
279 static void mkdirs(char const *, bool);
280 static zic_t oadd(zic_t t1, zic_t t2);
281 static zic_t omul(zic_t, zic_t);
282 static void outzone(const struct zone * zp, ptrdiff_t ntzones);
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 (The "+"s pacify gcc -Wenum-compare.) */
417 enum {
418 MAX_FIELDS = max(max(+RULE_FIELDS, +LINK_FIELDS),
419 max(+LEAP_FIELDS, +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(const char * const string,va_list args)707 verror(const char *const string, 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, string, 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(const char * const string,...)726 error(const char *const string, ...)
727 {
728 va_list args;
729 va_start(args, string);
730 verror(string, args);
731 va_end(args);
732 errors = true;
733 }
734
735 ATTRIBUTE_FORMAT((printf, 1, 2)) static void
warning(const char * const string,...)736 warning(const char *const string, ...)
737 {
738 va_list args;
739 fprintf(stderr, _("warning: "));
740 va_start(args, string);
741 verror(string, 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(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(_("\"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(_("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(_("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(_("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(_("incompatible -b options"));
1268 bloat = -1;
1269 } else if (strcmp(optarg, "fat") == 0) {
1270 if (bloat < 0)
1271 error(_("incompatible -b options"));
1272 bloat = 1;
1273 } else
1274 error(_("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(_("-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(_("-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(_("-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(_("empty file name"));
1423 else
1424 error(_(component == name
1425 ? "file name '%s' begins with '/'"
1426 : *component_end
1427 ? "file name '%s' contains '//'"
1428 : "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(_("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(_("file name '%s' component contains leading '-'"),
1442 name);
1443 if (component_len_max < component_len)
1444 warning(_("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 ? _("file name '%s' contains byte '%c'")
1473 : _("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 remove(tempname);
1673 fprintf(stderr, _("%s: rename to %s%s%s: %s\n"),
1674 progname, diagdir(name), diagslash(name), name,
1675 strerror(rename_errno));
1676 exit(EXIT_FAILURE);
1677 }
1678 free(tempname);
1679 }
1680 }
1681
1682 /* Create symlink contents suitable for symlinking TARGET to LINKNAME, as a
1683 freshly allocated string. TARGET should be a relative file name, and
1684 is relative to the global variable DIRECTORY. LINKNAME can be either
1685 relative or absolute. Return a null pointer if the symlink contents
1686 was not computed because LINKNAME is absolute but DIRECTORY is not. */
1687 static char *
relname(char const * target,char const * linkname)1688 relname(char const *target, char const *linkname)
1689 {
1690 size_t i, taillen, dir_len = 0, dotdots = 0;
1691 ptrdiff_t dotdotetcsize, linksize = INDEX_MAX;
1692 char const *f = target;
1693 char *result = NULL;
1694 if (*linkname == '/') {
1695 /* Make F absolute too. */
1696 size_t len = strlen(directory);
1697 bool needs_slash = len && directory[len - 1] != '/';
1698 size_t lenslash = len + needs_slash;
1699 size_t targetsize = strlen(target) + 1;
1700 char *cp;
1701 if (*directory != '/')
1702 return NULL;
1703 linksize = size_sum(lenslash, targetsize);
1704 f = cp = result = xmalloc(linksize);
1705 cp = mempcpy(cp, directory, len);
1706 *cp = '/';
1707 memcpy(cp + needs_slash, target, targetsize);
1708 }
1709 for (i = 0; f[i] && f[i] == linkname[i]; i++)
1710 if (f[i] == '/')
1711 dir_len = i + 1;
1712 for (; linkname[i]; i++)
1713 dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
1714 taillen = strlen(f + dir_len);
1715 dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1);
1716 if (dotdotetcsize <= linksize) {
1717 char *cp;
1718 if (!result)
1719 result = xmalloc(dotdotetcsize);
1720 cp = result;
1721 for (i = 0; i < dotdots; i++)
1722 cp = mempcpy(cp, "../", 3);
1723 memmove(cp, f + dir_len, taillen + 1);
1724 }
1725 return result;
1726 }
1727
1728 /* Return true if A and B must have the same parent dir if A and B exist.
1729 Return false if this is not necessarily true (though it might be true).
1730 Keep it simple, and do not inspect the file system. */
1731 ATTRIBUTE_PURE_114833
1732 static bool
same_parent_dirs(char const * a,char const * b)1733 same_parent_dirs(char const *a, char const *b)
1734 {
1735 for (; *a == *b; a++, b++)
1736 if (!*a)
1737 return true;
1738 return ! (strchr(a, '/') || strchr(b, '/'));
1739 }
1740
1741 static void
dolink(char const * target,char const * linkname,bool staysymlink)1742 dolink(char const *target, char const *linkname, bool staysymlink)
1743 {
1744 bool linkdirs_made = false;
1745 int link_errno;
1746 char *tempname = NULL;
1747 char const *outname = linkname;
1748 int targetissym = -2, linknameissym = -2;
1749
1750 if (strcmp(target, "-") == 0) {
1751 if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR)
1752 return;
1753 else {
1754 char const *e = strerror(errno);
1755 fprintf(stderr, _("%s: Can't remove %s%s%s: %s\n"),
1756 progname, diagdir(linkname), diagslash(linkname), linkname,
1757 e);
1758 exit(EXIT_FAILURE);
1759 }
1760 }
1761
1762 for (;; check_for_signal()) {
1763 if (linkat(AT_FDCWD, target, AT_FDCWD, outname, AT_SYMLINK_FOLLOW)
1764 == 0) {
1765 link_errno = 0;
1766 break;
1767 }
1768 link_errno = errno;
1769 /* Linux 2.6.16 and 2.6.17 mishandle AT_SYMLINK_FOLLOW. */
1770 if (link_errno == EINVAL)
1771 link_errno = ENOTSUP;
1772 #if HAVE_LINK
1773 /* If linkat is not supported, fall back on link(A, B).
1774 However, skip this if A is a relative symlink
1775 and A and B might not have the same parent directory.
1776 On some platforms link(A, B) does not follow a symlink A,
1777 and if A is relative it might misbehave elsewhere. */
1778 if (link_errno == ENOTSUP
1779 && (same_parent_dirs(target, outname)
1780 || 0 <= itssymlink(target, &targetissym))) {
1781 if (link(target, outname) == 0) {
1782 link_errno = 0;
1783 break;
1784 }
1785 link_errno = errno;
1786 }
1787 #endif
1788 if (link_errno == EXDEV || link_errno == ENOTSUP)
1789 break;
1790
1791 if (link_errno == EEXIST) {
1792 staysymlink &= !tempname;
1793 random_dirent(&outname, &tempname);
1794 if (staysymlink && itssymlink(linkname, &linknameissym))
1795 break;
1796 } else if (link_errno == ENOENT && !linkdirs_made) {
1797 mkdirs(linkname, true);
1798 linkdirs_made = true;
1799 } else {
1800 fprintf(stderr, _("%s: Can't link %s%s%s to %s%s%s: %s\n"),
1801 progname, diagdir(target), diagslash(target), target,
1802 diagdir(outname), diagslash(outname), outname,
1803 strerror(link_errno));
1804 exit(EXIT_FAILURE);
1805 }
1806 }
1807 if (link_errno != 0) {
1808 bool absolute = *target == '/';
1809 char *linkalloc = absolute ? NULL : relname(target, linkname);
1810 char const *contents = absolute ? target : linkalloc;
1811 int symlink_errno = -1;
1812
1813 if (contents) {
1814 for (;; check_for_signal()) {
1815 if (symlink(contents, outname) == 0) {
1816 symlink_errno = 0;
1817 break;
1818 }
1819 symlink_errno = errno;
1820 if (symlink_errno == EEXIST)
1821 random_dirent(&outname, &tempname);
1822 else if (symlink_errno == ENOENT && !linkdirs_made) {
1823 mkdirs(linkname, true);
1824 linkdirs_made = true;
1825 } else
1826 break;
1827 }
1828 }
1829 free(linkalloc);
1830 if (symlink_errno == 0) {
1831 if (link_errno != ENOTSUP && link_errno != EEXIST)
1832 warning(_("symbolic link used because hard link failed: %s"),
1833 strerror(link_errno));
1834 } else {
1835 FILE *fp, *tp;
1836 int c;
1837 fp = fopen(target, "rb");
1838 if (!fp) {
1839 char const *e = strerror(errno);
1840 fprintf(stderr, _("%s: Can't read %s%s%s: %s\n"),
1841 progname, diagdir(target), diagslash(target), target, e);
1842 exit(EXIT_FAILURE);
1843 }
1844 tp = open_outfile(&outname, &tempname);
1845 for (; (c = getc(fp)) != EOF; check_for_signal())
1846 putc(c, tp);
1847 close_file(tp, directory, linkname, tempname);
1848 close_file(fp, directory, target, NULL);
1849 if (link_errno != ENOTSUP)
1850 warning(_("copy used because hard link failed: %s"),
1851 strerror(link_errno));
1852 else if (symlink_errno < 0)
1853 warning(_("copy used because symbolic link not obvious"));
1854 else if (symlink_errno != ENOTSUP)
1855 warning(_("copy used because symbolic link failed: %s"),
1856 strerror(symlink_errno));
1857 }
1858 }
1859 rename_dest(tempname, linkname);
1860 }
1861
1862 /* Return 1 if NAME is an absolute symbolic link, -1 if it is relative,
1863 0 if it is not a symbolic link. If *CACHE is not -2, it is the
1864 cached result of a previous call to this function with the same NAME. */
1865 static int
itssymlink(char const * name,int * cache)1866 itssymlink(char const *name, int *cache)
1867 {
1868 if (*cache == -2) {
1869 char c = '\0';
1870 *cache = readlink(name, &c, 1) < 0 ? 0 : c == '/' ? 1 : -1;
1871 }
1872 return *cache;
1873 }
1874
1875 /*
1876 ** Associate sets of rules with zones.
1877 */
1878
1879 /*
1880 ** Sort by rule name.
1881 */
1882
1883 static int
rcomp(const void * cp1,const void * cp2)1884 rcomp(const void *cp1, const void *cp2)
1885 {
1886 struct rule const *r1 = cp1, *r2 = cp2;
1887 return strcmp(r1->r_name, r2->r_name);
1888 }
1889
1890 static void
associate(void)1891 associate(void)
1892 {
1893 register struct zone * zp;
1894 register struct rule * rp;
1895 register ptrdiff_t i, j, base, out;
1896
1897 if (1 < nrules) {
1898 qsort(rules, nrules, sizeof *rules, rcomp);
1899 for (i = 0; i < nrules - 1; ++i) {
1900 if (strcmp(rules[i].r_name,
1901 rules[i + 1].r_name) != 0)
1902 continue;
1903 if (rules[i].r_filenum == rules[i + 1].r_filenum)
1904 continue;
1905 eat(rules[i].r_filenum, rules[i].r_linenum);
1906 warning(_("same rule name in multiple files"));
1907 eat(rules[i + 1].r_filenum, rules[i + 1].r_linenum);
1908 warning(_("same rule name in multiple files"));
1909 for (j = i + 2; j < nrules; ++j) {
1910 if (strcmp(rules[i].r_name,
1911 rules[j].r_name) != 0)
1912 break;
1913 if (rules[i].r_filenum == rules[j].r_filenum)
1914 continue;
1915 if (rules[i + 1].r_filenum
1916 == rules[j].r_filenum)
1917 continue;
1918 break;
1919 }
1920 i = j - 1;
1921 }
1922 }
1923 for (i = 0; i < nzones; ++i) {
1924 zp = &zones[i];
1925 zp->z_rules = NULL;
1926 zp->z_nrules = 0;
1927 }
1928 for (base = 0; base < nrules; base = out) {
1929 rp = &rules[base];
1930 for (out = base + 1; out < nrules; ++out)
1931 if (strcmp(rp->r_name, rules[out].r_name) != 0)
1932 break;
1933 for (i = 0; i < nzones; ++i) {
1934 zp = &zones[i];
1935 if (strcmp(zp->z_rule, rp->r_name) != 0)
1936 continue;
1937 zp->z_rules = rp;
1938 zp->z_nrules = out - base;
1939 }
1940 }
1941 for (i = 0; i < nzones; ++i) {
1942 zp = &zones[i];
1943 if (zp->z_nrules == 0) {
1944 /*
1945 ** Maybe we have a local standard time offset.
1946 */
1947 eat(zp->z_filenum, zp->z_linenum);
1948 zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
1949 /*
1950 ** Note, though, that if there's no rule,
1951 ** a '%s' in the format is a bad thing.
1952 */
1953 if (zp->z_format_specifier == 's')
1954 error("%s", _("%s in ruleless zone"));
1955 }
1956 }
1957 if (errors)
1958 exit(EXIT_FAILURE);
1959 }
1960
1961 /* Read a text line from FP into BUF, which is of size BUFSIZE.
1962 Terminate it with a NUL byte instead of a newline.
1963 Return true if successful, false if EOF.
1964 On error, report the error and exit. */
1965 static bool
inputline(FILE * fp,char * buf,ptrdiff_t bufsize)1966 inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
1967 {
1968 ptrdiff_t linelen = 0, ch;
1969 for (; (ch = getc(fp)) != '\n'; check_for_signal()) {
1970 if (ch < 0) {
1971 if (ferror(fp)) {
1972 error(_("input error"));
1973 exit(EXIT_FAILURE);
1974 }
1975 if (linelen == 0)
1976 return false;
1977 error(_("unterminated line"));
1978 exit(EXIT_FAILURE);
1979 }
1980 if (!ch) {
1981 error(_("NUL input byte"));
1982 exit(EXIT_FAILURE);
1983 }
1984 buf[linelen++] = ch;
1985 if (linelen == bufsize) {
1986 error(_("line too long"));
1987 exit(EXIT_FAILURE);
1988 }
1989 }
1990 buf[linelen] = '\0';
1991 return true;
1992 }
1993
1994 static void
infile(int fnum,char const * name)1995 infile(int fnum, char const *name)
1996 {
1997 register FILE * fp;
1998 register const struct lookup * lp;
1999 register bool wantcont;
2000 register lineno num;
2001
2002 if (strcmp(name, "-") == 0) {
2003 fp = stdin;
2004 } else if ((fp = fopen(name, "r")) == NULL) {
2005 const char *e = strerror(errno);
2006
2007 fprintf(stderr, _("%s: Can't open %s: %s\n"),
2008 progname, name, e);
2009 exit(EXIT_FAILURE);
2010 }
2011 wantcont = false;
2012 for (num = 1; ; ++num) {
2013 enum { bufsize_bound
2014 = (min(INT_MAX, INDEX_MAX) / FORMAT_LEN_GROWTH_BOUND) };
2015 char buf[min(_POSIX2_LINE_MAX, bufsize_bound)];
2016 int nfields;
2017 char *fields[MAX_FIELDS];
2018 eat(fnum, num);
2019 if (!inputline(fp, buf, sizeof buf))
2020 break;
2021 nfields = getfields(buf, fields,
2022 sizeof fields / sizeof *fields);
2023 if (nfields == 0) {
2024 /* nothing to do */
2025 } else if (wantcont) {
2026 wantcont = inzcont(fields, nfields);
2027 } else {
2028 struct lookup const *line_codes
2029 = fnum < 0 ? leap_line_codes : zi_line_codes;
2030 lp = byword(fields[0], line_codes);
2031 if (lp == NULL)
2032 error(_("input line of unknown type"));
2033 else switch (lp->l_value) {
2034 case LC_RULE:
2035 inrule(fields, nfields);
2036 wantcont = false;
2037 break;
2038 case LC_ZONE:
2039 wantcont = inzone(fields, nfields);
2040 break;
2041 case LC_LINK:
2042 inlink(fields, nfields);
2043 wantcont = false;
2044 break;
2045 case LC_LEAP:
2046 inleap(fields, nfields);
2047 wantcont = false;
2048 break;
2049 case LC_EXPIRES:
2050 inexpires(fields, nfields);
2051 wantcont = false;
2052 break;
2053 default: unreachable();
2054 }
2055 }
2056 check_for_signal();
2057 }
2058 close_file(fp, NULL, filename(fnum), NULL);
2059 if (wantcont)
2060 error(_("expected continuation line not found"));
2061 }
2062
2063 /*
2064 ** Convert a string of one of the forms
2065 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
2066 ** into a number of seconds.
2067 ** A null string maps to zero.
2068 ** Call error with errstring and return zero on errors.
2069 */
2070
2071 static zic_t
gethms(char const * string,char const * errstring)2072 gethms(char const *string, char const *errstring)
2073 {
2074 zic_t hh;
2075 int sign, mm = 0, ss = 0;
2076 char hhx, mmx, ssx, xr = '0', xs;
2077 int tenths = 0;
2078 bool ok = true;
2079
2080 if (string == NULL || *string == '\0')
2081 return 0;
2082 if (*string == '-') {
2083 sign = -1;
2084 ++string;
2085 } else sign = 1;
2086 switch (sscanf(string,
2087 "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
2088 &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) {
2089 default: ok = false; break;
2090 case 8:
2091 ok = is_digit(xr);
2092 ATTRIBUTE_FALLTHROUGH;
2093 case 7:
2094 ok &= ssx == '.';
2095 if (ok && noise)
2096 warning(_("fractional seconds rejected by"
2097 " pre-2018 versions of zic"));
2098 ATTRIBUTE_FALLTHROUGH;
2099 case 5: ok &= mmx == ':'; ATTRIBUTE_FALLTHROUGH;
2100 case 3: ok &= hhx == ':'; ATTRIBUTE_FALLTHROUGH;
2101 case 1: break;
2102 }
2103 if (!ok) {
2104 error("%s", errstring);
2105 return 0;
2106 }
2107 if (hh < 0 ||
2108 mm < 0 || mm >= MINSPERHOUR ||
2109 ss < 0 || ss > SECSPERMIN) {
2110 error("%s", errstring);
2111 return 0;
2112 }
2113 ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */
2114 if (noise && (hh > HOURSPERDAY ||
2115 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
2116 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
2117 return oadd(omul(hh, sign * SECSPERHOUR),
2118 sign * (mm * SECSPERMIN + ss));
2119 }
2120
2121 static zic_t
getsave(char * field,bool * isdst)2122 getsave(char *field, bool *isdst)
2123 {
2124 int dst = -1;
2125 zic_t save;
2126 ptrdiff_t fieldlen = strlen(field);
2127 if (fieldlen != 0) {
2128 char *ep = field + fieldlen - 1;
2129 switch (*ep) {
2130 case 'd': dst = 1; *ep = '\0'; break;
2131 case 's': dst = 0; *ep = '\0'; break;
2132 }
2133 }
2134 save = gethms(field, _("invalid saved time"));
2135 *isdst = dst < 0 ? save != 0 : dst;
2136 return save;
2137 }
2138
2139 static void
inrule(char ** fields,int nfields)2140 inrule(char **fields, int nfields)
2141 {
2142 struct rule r;
2143
2144 if (nfields != RULE_FIELDS) {
2145 error(_("wrong number of fields on Rule line"));
2146 return;
2147 }
2148 switch (*fields[RF_NAME]) {
2149 case '\0':
2150 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2151 case '+': case '-':
2152 case '0': case '1': case '2': case '3': case '4':
2153 case '5': case '6': case '7': case '8': case '9':
2154 error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
2155 return;
2156 }
2157 r.r_filenum = filenum;
2158 r.r_linenum = linenum;
2159 r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
2160 if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR],
2161 fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
2162 fields[RF_TOD]))
2163 return;
2164 r.r_name = xstrdup(fields[RF_NAME]);
2165 r.r_abbrvar = xstrdup(fields[RF_ABBRVAR]);
2166 if (max_abbrvar_len < strlen(r.r_abbrvar))
2167 max_abbrvar_len = strlen(r.r_abbrvar);
2168 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
2169 rules[nrules++] = r;
2170 }
2171
2172 static bool
inzone(char ** fields,int nfields)2173 inzone(char **fields, int nfields)
2174 {
2175 register ptrdiff_t i;
2176
2177 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
2178 error(_("wrong number of fields on Zone line"));
2179 return false;
2180 }
2181 if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) {
2182 error(_("\"Zone %s\" line and -l option are mutually exclusive"),
2183 tzdefault);
2184 return false;
2185 }
2186 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
2187 error(_("\"Zone %s\" line and -p option are mutually exclusive"),
2188 TZDEFRULES);
2189 return false;
2190 }
2191 for (i = 0; i < nzones; ++i)
2192 if (zones[i].z_name != NULL &&
2193 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
2194 error(_("duplicate zone name %s"
2195 " (file \"%s\", line %"PRIdMAX")"),
2196 fields[ZF_NAME],
2197 filename(zones[i].z_filenum),
2198 zones[i].z_linenum);
2199 return false;
2200 }
2201 return inzsub(fields, nfields, false);
2202 }
2203
2204 static bool
inzcont(char ** fields,int nfields)2205 inzcont(char **fields, int nfields)
2206 {
2207 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
2208 error(_("wrong number of fields on Zone continuation line"));
2209 return false;
2210 }
2211 return inzsub(fields, nfields, true);
2212 }
2213
2214 static bool
inzsub(char ** fields,int nfields,bool iscont)2215 inzsub(char **fields, int nfields, bool iscont)
2216 {
2217 register char * cp;
2218 char * cp1;
2219 struct zone z;
2220 int format_len;
2221 register int i_stdoff, i_rule, i_format;
2222 register int i_untilyear, i_untilmonth;
2223 register int i_untilday, i_untiltime;
2224 register bool hasuntil;
2225
2226 if (iscont) {
2227 i_stdoff = ZFC_STDOFF;
2228 i_rule = ZFC_RULE;
2229 i_format = ZFC_FORMAT;
2230 i_untilyear = ZFC_TILYEAR;
2231 i_untilmonth = ZFC_TILMONTH;
2232 i_untilday = ZFC_TILDAY;
2233 i_untiltime = ZFC_TILTIME;
2234 } else if (!namecheck(fields[ZF_NAME]))
2235 return false;
2236 else {
2237 i_stdoff = ZF_STDOFF;
2238 i_rule = ZF_RULE;
2239 i_format = ZF_FORMAT;
2240 i_untilyear = ZF_TILYEAR;
2241 i_untilmonth = ZF_TILMONTH;
2242 i_untilday = ZF_TILDAY;
2243 i_untiltime = ZF_TILTIME;
2244 }
2245 z.z_filenum = filenum;
2246 z.z_linenum = linenum;
2247 z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
2248 cp = strchr(fields[i_format], '%');
2249 if (cp) {
2250 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
2251 || strchr(fields[i_format], '/')) {
2252 error(_("invalid abbreviation format"));
2253 return false;
2254 }
2255 }
2256 z.z_format_specifier = cp ? *cp : '\0';
2257 format_len = strlen(fields[i_format]);
2258 if (max_format_len < format_len)
2259 max_format_len = format_len;
2260 hasuntil = nfields > i_untilyear;
2261 if (hasuntil) {
2262 z.z_untilrule.r_filenum = filenum;
2263 z.z_untilrule.r_linenum = linenum;
2264 if (!rulesub(
2265 &z.z_untilrule,
2266 fields[i_untilyear],
2267 "only",
2268 "",
2269 (nfields > i_untilmonth) ?
2270 fields[i_untilmonth] : "Jan",
2271 (nfields > i_untilday) ? fields[i_untilday] : "1",
2272 (nfields > i_untiltime) ? fields[i_untiltime] : "0"))
2273 return false;
2274 z.z_untiltime = rpytime(&z.z_untilrule,
2275 z.z_untilrule.r_loyear);
2276 if (iscont && nzones > 0 &&
2277 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
2278 error(_("Zone continuation line end time is"
2279 " not after end time of previous line"));
2280 return false;
2281 }
2282 }
2283 z.z_name = iscont ? NULL : xstrdup(fields[ZF_NAME]);
2284 z.z_rule = xstrdup(fields[i_rule]);
2285 z.z_format = cp1 = xstrdup(fields[i_format]);
2286 if (z.z_format_specifier == 'z') {
2287 cp1[cp - fields[i_format]] = 's';
2288 if (noise)
2289 warning(_("format '%s' not handled by pre-2015 versions of zic"),
2290 fields[i_format]);
2291 }
2292 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
2293 zones[nzones++] = z;
2294 /*
2295 ** If there was an UNTIL field on this line,
2296 ** there's more information about the zone on the next line.
2297 */
2298 return hasuntil;
2299 }
2300
2301 static zic_t
getleapdatetime(char ** fields,bool expire_line)2302 getleapdatetime(char **fields, bool expire_line)
2303 {
2304 register const char * cp;
2305 register const struct lookup * lp;
2306 register zic_t i, j;
2307 zic_t year;
2308 int month, day;
2309 zic_t dayoff, tod;
2310 zic_t t;
2311 char xs;
2312
2313 dayoff = 0;
2314 cp = fields[LP_YEAR];
2315 if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
2316 /*
2317 ** Leapin' Lizards!
2318 */
2319 error(_("invalid leaping year"));
2320 return -1;
2321 }
2322 if (!expire_line) {
2323 if (!leapseen || leapmaxyear < year)
2324 leapmaxyear = year;
2325 if (!leapseen || leapminyear > year)
2326 leapminyear = year;
2327 leapseen = true;
2328 }
2329 j = EPOCH_YEAR;
2330 while (j != year) {
2331 if (year > j) {
2332 i = len_years[isleap(j)];
2333 ++j;
2334 } else {
2335 --j;
2336 i = -len_years[isleap(j)];
2337 }
2338 dayoff = oadd(dayoff, i);
2339 }
2340 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
2341 error(_("invalid month name"));
2342 return -1;
2343 }
2344 month = lp->l_value;
2345 j = TM_JANUARY;
2346 while (j != month) {
2347 i = len_months[isleap(year)][j];
2348 dayoff = oadd(dayoff, i);
2349 ++j;
2350 }
2351 cp = fields[LP_DAY];
2352 if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
2353 day <= 0 || day > len_months[isleap(year)][month]) {
2354 error(_("invalid day of month"));
2355 return -1;
2356 }
2357 dayoff = oadd(dayoff, day - 1);
2358 t = omul(dayoff, SECSPERDAY);
2359 tod = gethms(fields[LP_TIME], _("invalid time of day"));
2360 t = tadd(t, tod);
2361 if (t < 0)
2362 error(_("leap second precedes Epoch"));
2363 return t;
2364 }
2365
2366 static void
inleap(char ** fields,int nfields)2367 inleap(char **fields, int nfields)
2368 {
2369 if (nfields != LEAP_FIELDS)
2370 error(_("wrong number of fields on Leap line"));
2371 else {
2372 zic_t t = getleapdatetime(fields, false);
2373 if (0 <= t) {
2374 struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
2375 if (!lp)
2376 error(_("invalid Rolling/Stationary field on Leap line"));
2377 else {
2378 int correction = 0;
2379 if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */
2380 correction = -1;
2381 else if (strcmp(fields[LP_CORR], "+") == 0)
2382 correction = 1;
2383 else
2384 error(_("invalid CORRECTION field on Leap line"));
2385 if (correction)
2386 leapadd(t, correction, lp->l_value);
2387 }
2388 }
2389 }
2390 }
2391
2392 static void
inexpires(char ** fields,int nfields)2393 inexpires(char **fields, int nfields)
2394 {
2395 if (nfields != EXPIRES_FIELDS)
2396 error(_("wrong number of fields on Expires line"));
2397 else if (0 <= leapexpires)
2398 error(_("multiple Expires lines"));
2399 else
2400 leapexpires = getleapdatetime(fields, true);
2401 }
2402
2403 static void
inlink(char ** fields,int nfields)2404 inlink(char **fields, int nfields)
2405 {
2406 struct link l;
2407
2408 if (nfields != LINK_FIELDS) {
2409 error(_("wrong number of fields on Link line"));
2410 return;
2411 }
2412 if (*fields[LF_TARGET] == '\0') {
2413 error(_("blank TARGET field on Link line"));
2414 return;
2415 }
2416 if (! namecheck(fields[LF_LINKNAME]))
2417 return;
2418 l.l_filenum = filenum;
2419 l.l_linenum = linenum;
2420 l.l_target = xstrdup(fields[LF_TARGET]);
2421 l.l_linkname = xstrdup(fields[LF_LINKNAME]);
2422 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
2423 links[nlinks++] = l;
2424 }
2425
2426 static bool
rulesub(struct rule * rp,const char * loyearp,const char * hiyearp,const char * typep,const char * monthp,const char * dayp,const char * timep)2427 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
2428 const char *typep, const char *monthp, const char *dayp,
2429 const char *timep)
2430 {
2431 register const struct lookup * lp;
2432 register const char * cp;
2433 register char * dp;
2434 register char * ep;
2435 char xs;
2436
2437 if ((lp = byword(monthp, mon_names)) == NULL) {
2438 error(_("invalid month name"));
2439 return false;
2440 }
2441 rp->r_month = lp->l_value;
2442 rp->r_todisstd = false;
2443 rp->r_todisut = false;
2444 dp = xstrdup(timep);
2445 if (*dp != '\0') {
2446 ep = dp + strlen(dp) - 1;
2447 switch (lowerit(*ep)) {
2448 case 's': /* Standard */
2449 rp->r_todisstd = true;
2450 rp->r_todisut = false;
2451 *ep = '\0';
2452 break;
2453 case 'w': /* Wall */
2454 rp->r_todisstd = false;
2455 rp->r_todisut = false;
2456 *ep = '\0';
2457 break;
2458 case 'g': /* Greenwich */
2459 case 'u': /* Universal */
2460 case 'z': /* Zulu */
2461 rp->r_todisstd = true;
2462 rp->r_todisut = true;
2463 *ep = '\0';
2464 break;
2465 }
2466 }
2467 rp->r_tod = gethms(dp, _("invalid time of day"));
2468 free(dp);
2469 /*
2470 ** Year work.
2471 */
2472 cp = loyearp;
2473 lp = byword(cp, begin_years);
2474 if (lp) switch (lp->l_value) {
2475 case YR_MINIMUM:
2476 warning(_("FROM year \"%s\" is obsolete;"
2477 " treated as %d"),
2478 cp, YEAR_32BIT_MIN - 1);
2479 rp->r_loyear = YEAR_32BIT_MIN - 1;
2480 break;
2481 default: unreachable();
2482 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
2483 error(_("invalid starting year"));
2484 return false;
2485 }
2486 cp = hiyearp;
2487 lp = byword(cp, end_years);
2488 rp->r_hiwasnum = lp == NULL;
2489 if (!rp->r_hiwasnum) switch (lp->l_value) {
2490 case YR_MAXIMUM:
2491 rp->r_hiyear = ZIC_MAX;
2492 break;
2493 case YR_ONLY:
2494 rp->r_hiyear = rp->r_loyear;
2495 break;
2496 default: unreachable();
2497 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
2498 error(_("invalid ending year"));
2499 return false;
2500 }
2501 if (rp->r_loyear > rp->r_hiyear) {
2502 error(_("starting year greater than ending year"));
2503 return false;
2504 }
2505 if (*typep != '\0') {
2506 error(_("year type \"%s\" is unsupported; use \"-\" instead"),
2507 typep);
2508 return false;
2509 }
2510 /*
2511 ** Day work.
2512 ** Accept things such as:
2513 ** 1
2514 ** lastSunday
2515 ** last-Sunday (undocumented; warn about this)
2516 ** Sun<=20
2517 ** Sun>=7
2518 */
2519 dp = xstrdup(dayp);
2520 if ((lp = byword(dp, lasts)) != NULL) {
2521 rp->r_dycode = DC_DOWLEQ;
2522 rp->r_wday = lp->l_value;
2523 rp->r_dayofmonth = len_months[1][rp->r_month];
2524 } else {
2525 ep = strchr(dp, '<');
2526 if (ep)
2527 rp->r_dycode = DC_DOWLEQ;
2528 else {
2529 ep = strchr(dp, '>');
2530 if (ep)
2531 rp->r_dycode = DC_DOWGEQ;
2532 else {
2533 ep = dp;
2534 rp->r_dycode = DC_DOM;
2535 }
2536 }
2537 if (rp->r_dycode != DC_DOM) {
2538 *ep++ = 0;
2539 if (*ep++ != '=') {
2540 error(_("invalid day of month"));
2541 free(dp);
2542 return false;
2543 }
2544 if ((lp = byword(dp, wday_names)) == NULL) {
2545 error(_("invalid weekday name"));
2546 free(dp);
2547 return false;
2548 }
2549 rp->r_wday = lp->l_value;
2550 }
2551 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
2552 rp->r_dayofmonth <= 0 ||
2553 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
2554 error(_("invalid day of month"));
2555 free(dp);
2556 return false;
2557 }
2558 }
2559 free(dp);
2560 return true;
2561 }
2562
2563 static void
convert(uint_fast32_t val,char * buf)2564 convert(uint_fast32_t val, char *buf)
2565 {
2566 register int i;
2567 register int shift;
2568 unsigned char *const b = (unsigned char *) buf;
2569
2570 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
2571 b[i] = (val >> shift) & 0xff;
2572 }
2573
2574 static void
convert64(uint_fast64_t val,char * buf)2575 convert64(uint_fast64_t val, char *buf)
2576 {
2577 register int i;
2578 register int shift;
2579 unsigned char *const b = (unsigned char *) buf;
2580
2581 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
2582 b[i] = (val >> shift) & 0xff;
2583 }
2584
2585 static void
puttzcode(zic_t val,FILE * fp)2586 puttzcode(zic_t val, FILE *fp)
2587 {
2588 char buf[4];
2589
2590 convert(val, buf);
2591 fwrite(buf, sizeof buf, 1, fp);
2592 }
2593
2594 static void
puttzcodepass(zic_t val,FILE * fp,int pass)2595 puttzcodepass(zic_t val, FILE *fp, int pass)
2596 {
2597 if (pass == 1)
2598 puttzcode(val, fp);
2599 else {
2600 char buf[8];
2601
2602 convert64(val, buf);
2603 fwrite(buf, sizeof buf, 1, fp);
2604 }
2605 }
2606
2607 static int
atcomp(const void * avp,const void * bvp)2608 atcomp(const void *avp, const void *bvp)
2609 {
2610 struct attype const *ap = avp, *bp = bvp;
2611 zic_t a = ap->at, b = bp->at;
2612 return a < b ? -1 : a > b;
2613 }
2614
2615 struct timerange {
2616 int defaulttype;
2617 ptrdiff_t base, count;
2618 ptrdiff_t leapbase, leapcount;
2619 bool leapexpiry;
2620 };
2621
2622 static struct timerange
limitrange(struct timerange r,zic_t lo,zic_t hi,zic_t const * ats,unsigned char const * types)2623 limitrange(struct timerange r, zic_t lo, zic_t hi,
2624 zic_t const *ats, unsigned char const *types)
2625 {
2626 /* Omit ordinary transitions < LO. */
2627 while (0 < r.count && ats[r.base] < lo) {
2628 r.defaulttype = types[r.base];
2629 r.count--;
2630 r.base++;
2631 }
2632
2633 /* Omit as many initial leap seconds as possible, such that the
2634 first leap second in the truncated list is <= LO, and is a
2635 positive leap second if and only if it has a positive correction.
2636 This supports common TZif readers that assume that the first leap
2637 second is positive if and only if its correction is positive. */
2638 while (1 < r.leapcount && leap[r.leapbase + 1].trans <= lo) {
2639 r.leapcount--;
2640 r.leapbase++;
2641 }
2642 while (0 < r.leapbase
2643 && ((leap[r.leapbase - 1].corr < leap[r.leapbase].corr)
2644 != (0 < leap[r.leapbase].corr))) {
2645 r.leapcount++;
2646 r.leapbase--;
2647 }
2648
2649
2650 /* Omit ordinary and leap second transitions greater than HI + 1. */
2651 if (hi < max_time) {
2652 while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
2653 r.count--;
2654 while (0 < r.leapcount && hi + 1 < leap[r.leapbase + r.leapcount - 1].trans)
2655 r.leapcount--;
2656 }
2657
2658 /* Determine whether to append an expiration to the leap second table. */
2659 r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi;
2660
2661 return r;
2662 }
2663
2664 static void
writezone(const char * const name,const char * const string,char version,int defaulttype)2665 writezone(const char *const name, const char *const string, char version,
2666 int defaulttype)
2667 {
2668 register FILE * fp;
2669 register ptrdiff_t i, j;
2670 register int pass;
2671 char *tempname = NULL;
2672 char const *outname = name;
2673
2674 /* Allocate the ATS and TYPES arrays via a single malloc,
2675 as this is a bit faster. Do not malloc(0) if !timecnt,
2676 as that might return NULL even on success. */
2677 zic_t *ats = xmalloc(align_to(size_product(timecnt + !timecnt,
2678 sizeof *ats + 1),
2679 alignof(zic_t)));
2680 void *typesptr = ats + timecnt;
2681 unsigned char *types = typesptr;
2682 struct timerange rangeall = {0}, range32, range64;
2683
2684 /*
2685 ** Sort.
2686 */
2687 if (timecnt > 1)
2688 qsort(attypes, timecnt, sizeof *attypes, atcomp);
2689 /*
2690 ** Optimize and skip unwanted transitions.
2691 */
2692 {
2693 ptrdiff_t fromi, toi;
2694
2695 toi = 0;
2696 fromi = 0;
2697 for ( ; fromi < timecnt; ++fromi) {
2698 if (toi != 0) {
2699 /* Skip the previous transition if it is unwanted
2700 because its local time is not earlier.
2701 The UT offset additions can't overflow because
2702 of how the times were calculated. */
2703 unsigned char type_2 =
2704 toi == 1 ? 0 : attypes[toi - 2].type;
2705 if ((attypes[fromi].at
2706 + utoffs[attypes[toi - 1].type])
2707 <= attypes[toi - 1].at + utoffs[type_2]) {
2708 if (attypes[fromi].type == type_2)
2709 toi--;
2710 else
2711 attypes[toi - 1].type =
2712 attypes[fromi].type;
2713 continue;
2714 }
2715 }
2716
2717 /* Use a transition if it is the first one,
2718 or if it cannot be merged for other reasons,
2719 or if it transitions to different timekeeping. */
2720 if (toi == 0
2721 || attypes[fromi].dontmerge
2722 || (utoffs[attypes[toi - 1].type]
2723 != utoffs[attypes[fromi].type])
2724 || (isdsts[attypes[toi - 1].type]
2725 != isdsts[attypes[fromi].type])
2726 || (desigidx[attypes[toi - 1].type]
2727 != desigidx[attypes[fromi].type]))
2728 attypes[toi++] = attypes[fromi];
2729 }
2730 timecnt = toi;
2731 }
2732
2733 if (noise) {
2734 if (1200 < timecnt) {
2735 if (TZ_MAX_TIMES < timecnt)
2736 warning(_("reference clients mishandle"
2737 " more than %d transition times"),
2738 TZ_MAX_TIMES);
2739 else
2740 warning(_("pre-2014 clients may mishandle"
2741 " more than 1200 transition times"));
2742 }
2743 if (TZ_MAX_LEAPS < leapcnt)
2744 warning(_("reference clients mishandle more than %d leap seconds"),
2745 TZ_MAX_LEAPS);
2746 }
2747 /*
2748 ** Transfer.
2749 */
2750 for (i = 0; i < timecnt; ++i) {
2751 ats[i] = attypes[i].at;
2752 types[i] = attypes[i].type;
2753 }
2754
2755 /*
2756 ** Correct for leap seconds.
2757 */
2758 for (i = 0; i < timecnt; ++i) {
2759 j = leapcnt;
2760 while (--j >= 0)
2761 if (leap[j].trans - leap[j].corr < ats[i]) {
2762 ats[i] = tadd(ats[i], leap[j].corr);
2763 break;
2764 }
2765 }
2766
2767 rangeall.defaulttype = defaulttype;
2768 rangeall.count = timecnt;
2769 rangeall.leapcount = leapcnt;
2770 range64 = limitrange(rangeall, lo_time,
2771 max(hi_time,
2772 redundant_time - (ZIC_MIN < redundant_time)),
2773 ats, types);
2774 range32 = limitrange(range64, ZIC32_MIN, ZIC32_MAX, ats, types);
2775
2776 /* TZif version 4 is needed if a no-op transition is appended to
2777 indicate the expiration of the leap second table, or if the first
2778 leap second transition is not to a +1 or -1 correction. */
2779 for (pass = 1; pass <= 2; pass++) {
2780 struct timerange const *r = pass == 1 ? &range32 : &range64;
2781 if (pass == 1 && !want_bloat())
2782 continue;
2783 if (r->leapexpiry) {
2784 if (noise)
2785 warning(_("%s: pre-2021b clients may mishandle"
2786 " leap second expiry"),
2787 name);
2788 version = '4';
2789 }
2790 if (0 < r->leapcount
2791 && leap[r->leapbase].corr != 1 && leap[r->leapbase].corr != -1) {
2792 if (noise)
2793 warning(_("%s: pre-2021b clients may mishandle"
2794 " leap second table truncation"),
2795 name);
2796 version = '4';
2797 }
2798 if (version == '4')
2799 break;
2800 }
2801
2802 fp = open_outfile(&outname, &tempname);
2803
2804 for (pass = 1; pass <= 2; ++pass) {
2805 register ptrdiff_t thistimei, thistimecnt, thistimelim;
2806 register ptrdiff_t thisleapi, thisleapcnt, thisleaplim;
2807 struct tzhead tzh;
2808 int pretranstype = -1, thisdefaulttype;
2809 bool locut, hicut, thisleapexpiry;
2810 zic_t lo, thismin, thismax;
2811 int old0;
2812 char omittype[TZ_MAX_TYPES];
2813 int typemap[TZ_MAX_TYPES];
2814 int thistypecnt, stdcnt, utcnt;
2815 char thischars[TZ_MAX_CHARS];
2816 int thischarcnt;
2817 bool toomanytimes;
2818 int indmap[TZ_MAX_CHARS];
2819
2820 if (pass == 1) {
2821 thisdefaulttype = range32.defaulttype;
2822 thistimei = range32.base;
2823 thistimecnt = range32.count;
2824 toomanytimes = thistimecnt >> 31 >> 1 != 0;
2825 thisleapi = range32.leapbase;
2826 thisleapcnt = range32.leapcount;
2827 thisleapexpiry = range32.leapexpiry;
2828 thismin = ZIC32_MIN;
2829 thismax = ZIC32_MAX;
2830 } else {
2831 thisdefaulttype = range64.defaulttype;
2832 thistimei = range64.base;
2833 thistimecnt = range64.count;
2834 toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
2835 thisleapi = range64.leapbase;
2836 thisleapcnt = range64.leapcount;
2837 thisleapexpiry = range64.leapexpiry;
2838 thismin = min_time;
2839 thismax = max_time;
2840 }
2841 if (toomanytimes)
2842 error(_("too many transition times"));
2843
2844 locut = thismin < lo_time && lo_time <= thismax;
2845 hicut = thismin <= hi_time && hi_time < thismax;
2846 thistimelim = thistimei + thistimecnt;
2847 memset(omittype, true, typecnt);
2848
2849 /* Determine whether to output a transition before the first
2850 transition in range. This is needed when the output is
2851 truncated at the start, and is also useful when catering to
2852 buggy 32-bit clients that do not use time type 0 for
2853 timestamps before the first transition. */
2854 if ((locut || (pass == 1 && thistimei))
2855 && ! (thistimecnt && ats[thistimei] == lo_time)) {
2856 pretranstype = thisdefaulttype;
2857 omittype[pretranstype] = false;
2858 }
2859
2860 /* Arguably the default time type in the 32-bit data
2861 should be range32.defaulttype, which is suited for
2862 timestamps just before ZIC32_MIN. However, zic
2863 traditionally used the time type of the indefinite
2864 past instead. Internet RFC 8532 says readers should
2865 ignore 32-bit data, so this discrepancy matters only
2866 to obsolete readers where the traditional type might
2867 be more appropriate even if it's "wrong". So, use
2868 the historical zic value, unless -r specifies a low
2869 cutoff that excludes some 32-bit timestamps. */
2870 if (pass == 1 && lo_time <= thismin)
2871 thisdefaulttype = range64.defaulttype;
2872
2873 if (locut)
2874 thisdefaulttype = unspecifiedtype;
2875 omittype[thisdefaulttype] = false;
2876 for (i = thistimei; i < thistimelim; i++)
2877 omittype[types[i]] = false;
2878 if (hicut)
2879 omittype[unspecifiedtype] = false;
2880
2881 /* Reorder types to make THISDEFAULTTYPE type 0.
2882 Use TYPEMAP to swap OLD0 and THISDEFAULTTYPE so that
2883 THISDEFAULTTYPE appears as type 0 in the output instead
2884 of OLD0. TYPEMAP also omits unused types. */
2885 old0 = strlen(omittype);
2886
2887 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
2888 /*
2889 ** For some pre-2011 systems: if the last-to-be-written
2890 ** standard (or daylight) type has an offset different from the
2891 ** most recently used offset,
2892 ** append an (unused) copy of the most recently used type
2893 ** (to help get global "altzone" and "timezone" variables
2894 ** set correctly).
2895 */
2896 if (want_bloat()) {
2897 register int mrudst, mrustd, hidst, histd, type;
2898
2899 hidst = histd = mrudst = mrustd = -1;
2900 if (0 <= pretranstype) {
2901 if (isdsts[pretranstype])
2902 mrudst = pretranstype;
2903 else
2904 mrustd = pretranstype;
2905 }
2906 for (i = thistimei; i < thistimelim; i++)
2907 if (isdsts[types[i]])
2908 mrudst = types[i];
2909 else mrustd = types[i];
2910 for (i = old0; i < typecnt; i++) {
2911 int h = (i == old0 ? thisdefaulttype
2912 : i == thisdefaulttype ? old0 : i);
2913 if (!omittype[h]) {
2914 if (isdsts[h])
2915 hidst = i;
2916 else
2917 histd = i;
2918 }
2919 }
2920 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
2921 utoffs[hidst] != utoffs[mrudst]) {
2922 isdsts[mrudst] = -1;
2923 type = addtype(utoffs[mrudst],
2924 &chars[desigidx[mrudst]],
2925 true,
2926 ttisstds[mrudst],
2927 ttisuts[mrudst]);
2928 isdsts[mrudst] = 1;
2929 omittype[type] = false;
2930 }
2931 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
2932 utoffs[histd] != utoffs[mrustd]) {
2933 isdsts[mrustd] = -1;
2934 type = addtype(utoffs[mrustd],
2935 &chars[desigidx[mrustd]],
2936 false,
2937 ttisstds[mrustd],
2938 ttisuts[mrustd]);
2939 isdsts[mrustd] = 0;
2940 omittype[type] = false;
2941 }
2942 }
2943 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
2944 thistypecnt = 0;
2945 for (i = old0; i < typecnt; i++)
2946 if (!omittype[i])
2947 typemap[i == old0 ? thisdefaulttype
2948 : i == thisdefaulttype ? old0 : i]
2949 = thistypecnt++;
2950
2951 thischarcnt = stdcnt = utcnt = 0;
2952 for (i = old0; i < typecnt; i++) {
2953 if (omittype[i])
2954 continue;
2955 if (ttisstds[i])
2956 stdcnt = thistypecnt;
2957 if (ttisuts[i])
2958 utcnt = thistypecnt;
2959 addabbr(thischars, &thischarcnt, &chars[desigidx[i]]);
2960 }
2961
2962 /* Now that all abbrevs have been added to THISCHARS,
2963 it is safe to set INDMAP without worrying about
2964 whether the abbrevs might move later. */
2965 for (i = 0; i < TZ_MAX_CHARS; i++)
2966 indmap[i] = -1;
2967 for (i = old0; i < typecnt; i++)
2968 if (!omittype[i] && indmap[desigidx[i]] < 0)
2969 indmap[desigidx[i]] = addabbr(thischars, &thischarcnt,
2970 &chars[desigidx[i]]);
2971
2972 if (pass == 1 && !want_bloat()) {
2973 hicut = thisleapexpiry = false;
2974 pretranstype = -1;
2975 thistimecnt = thisleapcnt = 0;
2976 thistypecnt = thischarcnt = 1;
2977 }
2978 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
2979 memset(&tzh, 0, sizeof tzh);
2980 memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
2981 tzh.tzh_version[0] = version;
2982 convert(utcnt, tzh.tzh_ttisutcnt);
2983 convert(stdcnt, tzh.tzh_ttisstdcnt);
2984 convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt);
2985 convert((0 <= pretranstype) + thistimecnt + hicut,
2986 tzh.tzh_timecnt);
2987 convert(thistypecnt, tzh.tzh_typecnt);
2988 convert(thischarcnt, tzh.tzh_charcnt);
2989 DO(tzh_magic);
2990 DO(tzh_version);
2991 DO(tzh_reserved);
2992 DO(tzh_ttisutcnt);
2993 DO(tzh_ttisstdcnt);
2994 DO(tzh_leapcnt);
2995 DO(tzh_timecnt);
2996 DO(tzh_typecnt);
2997 DO(tzh_charcnt);
2998 #undef DO
2999 if (pass == 1 && !want_bloat()) {
3000 /* Output a minimal data block with just one time type. */
3001 puttzcode(0, fp); /* utoff */
3002 putc(0, fp); /* dst */
3003 putc(0, fp); /* index of abbreviation */
3004 putc(0, fp); /* empty-string abbreviation */
3005 continue;
3006 }
3007
3008 if (pass == 2 && noise && 50 < thischarcnt)
3009 warning(_("%s: pre-2026 reference clients mishandle"
3010 " more than 50 bytes of abbreviations"),
3011 name);
3012
3013 /* Output a LO_TIME transition if needed; see limitrange.
3014 But do not go below the minimum representable value
3015 for this pass. */
3016 lo = pass == 1 && lo_time < ZIC32_MIN ? ZIC32_MIN : lo_time;
3017
3018 if (0 <= pretranstype)
3019 puttzcodepass(lo, fp, pass);
3020 for (i = thistimei; i < thistimelim; ++i) {
3021 puttzcodepass(ats[i], fp, pass);
3022 }
3023 if (hicut)
3024 puttzcodepass(hi_time + 1, fp, pass);
3025 if (0 <= pretranstype)
3026 putc(typemap[pretranstype], fp);
3027 for (i = thistimei; i < thistimelim; i++)
3028 putc(typemap[types[i]], fp);
3029 if (hicut)
3030 putc(typemap[unspecifiedtype], fp);
3031
3032 for (i = old0; i < typecnt; i++) {
3033 int h = (i == old0 ? thisdefaulttype
3034 : i == thisdefaulttype ? old0 : i);
3035 if (!omittype[h]) {
3036 puttzcode(utoffs[h], fp);
3037 putc(isdsts[h], fp);
3038 putc(indmap[desigidx[h]], fp);
3039 }
3040 }
3041 if (thischarcnt != 0)
3042 fwrite(thischars, sizeof thischars[0],
3043 thischarcnt, fp);
3044 thisleaplim = thisleapi + thisleapcnt;
3045 for (i = thisleapi; i < thisleaplim; ++i) {
3046 register zic_t todo;
3047
3048 if (leap[i].roll) {
3049 if (timecnt == 0 || leap[i].trans < ats[0]) {
3050 j = 0;
3051 while (isdsts[j])
3052 if (++j >= typecnt) {
3053 j = 0;
3054 break;
3055 }
3056 } else {
3057 j = 1;
3058 while (j < timecnt &&
3059 ats[j] <= leap[i].trans)
3060 ++j;
3061 j = types[j - 1];
3062 }
3063 todo = tadd(leap[i].trans, -utoffs[j]);
3064 } else todo = leap[i].trans;
3065 puttzcodepass(todo, fp, pass);
3066 puttzcode(leap[i].corr, fp);
3067 }
3068 if (thisleapexpiry) {
3069 /* Append a no-op leap correction indicating when the leap
3070 second table expires. Although this does not conform to
3071 Internet RFC 9636, most clients seem to accept this and
3072 the plan is to amend the RFC to allow this in version 4
3073 TZif files. */
3074 puttzcodepass(leapexpires, fp, pass);
3075 puttzcode(thisleaplim ? leap[thisleaplim - 1].corr : 0, fp);
3076 }
3077 if (stdcnt != 0)
3078 for (i = old0; i < typecnt; i++)
3079 if (!omittype[i])
3080 putc(ttisstds[i], fp);
3081 if (utcnt != 0)
3082 for (i = old0; i < typecnt; i++)
3083 if (!omittype[i])
3084 putc(ttisuts[i], fp);
3085 }
3086 fprintf(fp, "\n%s\n", string);
3087 close_file(fp, directory, name, tempname);
3088 rename_dest(tempname, name);
3089 free(ats);
3090 }
3091
3092 static char const *
abbroffset(char * buf,zic_t offset)3093 abbroffset(char *buf, zic_t offset)
3094 {
3095 char sign = '+';
3096 int seconds, minutes;
3097
3098 if (offset < 0) {
3099 offset = -offset;
3100 sign = '-';
3101 }
3102
3103 seconds = offset % SECSPERMIN;
3104 offset /= SECSPERMIN;
3105 minutes = offset % MINSPERHOUR;
3106 offset /= MINSPERHOUR;
3107 if (100 <= offset) {
3108 error(_("%%z UT offset magnitude exceeds 99:59:59"));
3109 return "%z";
3110 } else {
3111 char *p = buf;
3112 *p++ = sign;
3113 *p++ = '0' + offset / 10;
3114 *p++ = '0' + offset % 10;
3115 if (minutes | seconds) {
3116 *p++ = '0' + minutes / 10;
3117 *p++ = '0' + minutes % 10;
3118 if (seconds) {
3119 *p++ = '0' + seconds / 10;
3120 *p++ = '0' + seconds % 10;
3121 }
3122 }
3123 *p = '\0';
3124 return buf;
3125 }
3126 }
3127
3128 static char const disable_percent_s[] = "";
3129
3130 static ptrdiff_t
doabbr(char * abbr,struct zone const * zp,char const * letters,bool isdst,zic_t save,bool doquotes)3131 doabbr(char *abbr, struct zone const *zp, char const *letters,
3132 bool isdst, zic_t save, bool doquotes)
3133 {
3134 register char * cp;
3135 ptrdiff_t len;
3136 char const *format = zp->z_format;
3137 char const *slashp = strchr(format, '/');
3138
3139 if (slashp == NULL) {
3140 char letterbuf[PERCENT_Z_LEN_BOUND + 1];
3141 if (zp->z_format_specifier == 'z')
3142 letters = abbroffset(letterbuf, zp->z_stdoff + save);
3143 else if (!letters)
3144 letters = "%s";
3145 else if (letters == disable_percent_s)
3146 return 0;
3147 sprintf(abbr, format, letters);
3148 } else if (isdst)
3149 strcpy(abbr, slashp + 1);
3150 else {
3151 char *abbrend = mempcpy(abbr, format, slashp - format);
3152 *abbrend = '\0';
3153 }
3154 len = strlen(abbr);
3155 if (!doquotes)
3156 return len;
3157 for (cp = abbr; is_alpha(*cp); cp++)
3158 continue;
3159 if (len > 0 && *cp == '\0')
3160 return len;
3161 abbr[len + 2] = '\0';
3162 abbr[len + 1] = '>';
3163 memmove(abbr + 1, abbr, len);
3164 abbr[0] = '<';
3165 return len + 2;
3166 }
3167
3168 static void
updateminmax(const zic_t x)3169 updateminmax(const zic_t x)
3170 {
3171 if (min_year > x)
3172 min_year = x;
3173 if (max_year < x)
3174 max_year = x;
3175 }
3176
3177 static int
stringoffset(char * result,zic_t offset)3178 stringoffset(char *result, zic_t offset)
3179 {
3180 register int hours;
3181 register int minutes;
3182 register int seconds;
3183 bool negative = offset < 0;
3184 int len = negative;
3185
3186 if (negative) {
3187 offset = -offset;
3188 result[0] = '-';
3189 }
3190 seconds = offset % SECSPERMIN;
3191 offset /= SECSPERMIN;
3192 minutes = offset % MINSPERHOUR;
3193 offset /= MINSPERHOUR;
3194 if (offset >= HOURSPERDAY * DAYSPERWEEK) {
3195 result[0] = '\0';
3196 return 0;
3197 }
3198 hours = offset;
3199 len += sprintf(result + len, "%d", hours);
3200 if (minutes != 0 || seconds != 0) {
3201 len += sprintf(result + len, ":%02d", minutes);
3202 if (seconds != 0)
3203 len += sprintf(result + len, ":%02d", seconds);
3204 }
3205 return len;
3206 }
3207
3208 static int
stringrule(char * result,struct rule * const rp,zic_t save,zic_t stdoff)3209 stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff)
3210 {
3211 register zic_t tod = rp->r_tod;
3212 register int compat = 0;
3213
3214 if (rp->r_dycode == DC_DOM) {
3215 register int month, total;
3216
3217 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
3218 return -1;
3219 total = 0;
3220 for (month = 0; month < rp->r_month; ++month)
3221 total += len_months[0][month];
3222 /* Omit the "J" in Jan and Feb, as that's shorter. */
3223 if (rp->r_month <= 1)
3224 result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
3225 else
3226 result += sprintf(result, "J%d", total + rp->r_dayofmonth);
3227 } else {
3228 register int week;
3229 register int wday = rp->r_wday;
3230 register int wdayoff;
3231
3232 if (rp->r_dycode == DC_DOWGEQ) {
3233 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
3234 if (wdayoff)
3235 compat = 2013;
3236 wday -= wdayoff;
3237 tod += wdayoff * SECSPERDAY;
3238 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
3239 } else if (rp->r_dycode == DC_DOWLEQ) {
3240 if (rp->r_dayofmonth == len_months[1][rp->r_month])
3241 week = 5;
3242 else {
3243 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
3244 if (wdayoff)
3245 compat = 2013;
3246 wday -= wdayoff;
3247 tod += wdayoff * SECSPERDAY;
3248 week = rp->r_dayofmonth / DAYSPERWEEK;
3249 }
3250 } else return -1; /* "cannot happen" */
3251 if (wday < 0)
3252 wday += DAYSPERWEEK;
3253 result += sprintf(result, "M%d.%d.%d",
3254 rp->r_month + 1, week, wday);
3255 }
3256 if (rp->r_todisut)
3257 tod += stdoff;
3258 if (rp->r_todisstd && !rp->r_isdst)
3259 tod += save;
3260 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
3261 *result++ = '/';
3262 if (! stringoffset(result, tod))
3263 return -1;
3264 if (tod < 0) {
3265 if (compat < 2013)
3266 compat = 2013;
3267 } else if (SECSPERDAY <= tod) {
3268 if (compat < 1994)
3269 compat = 1994;
3270 }
3271 }
3272 return compat;
3273 }
3274
3275 static int
rule_cmp(struct rule const * a,struct rule const * b)3276 rule_cmp(struct rule const *a, struct rule const *b)
3277 {
3278 if (!a)
3279 return -!!b;
3280 if (!b)
3281 return 1;
3282 if (a->r_hiyear != b->r_hiyear)
3283 return a->r_hiyear < b->r_hiyear ? -1 : 1;
3284 if (a->r_hiyear == ZIC_MAX)
3285 return 0;
3286 if (a->r_month - b->r_month != 0)
3287 return a->r_month - b->r_month;
3288 return a->r_dayofmonth - b->r_dayofmonth;
3289 }
3290
3291 /* Store into RESULT a proleptic TZ string that represent the future
3292 predictions for the zone ZPFIRST with ZONECOUNT entries. Return a
3293 compatibility indicator (a TZDB release year) if successful, a
3294 negative integer if no such TZ string exists. */
3295 static int
stringzone(char * result,struct zone const * zpfirst,ptrdiff_t zonecount)3296 stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
3297 {
3298 register const struct zone * zp;
3299 register struct rule * rp;
3300 register struct rule * stdrp;
3301 register struct rule * dstrp;
3302 register ptrdiff_t i;
3303 register int compat = 0;
3304 register int c;
3305 int offsetlen;
3306 struct rule stdr, dstr;
3307 ptrdiff_t len;
3308 int dstcmp;
3309 struct rule *lastrp[2] = { NULL, NULL };
3310 struct zone zstr[2];
3311 struct zone const *stdzp;
3312 struct zone const *dstzp;
3313
3314 result[0] = '\0';
3315
3316 /* Internet RFC 9636 section 6.1 says to use an empty TZ string if
3317 future timestamps are truncated. */
3318 if (hi_time < max_time)
3319 return -1;
3320
3321 zp = zpfirst + zonecount - 1;
3322 for (i = 0; i < zp->z_nrules; ++i) {
3323 struct rule **last;
3324 int cmp;
3325 rp = &zp->z_rules[i];
3326 last = &lastrp[rp->r_isdst];
3327 cmp = rule_cmp(*last, rp);
3328 if (cmp < 0)
3329 *last = rp;
3330 else if (cmp == 0)
3331 return -1;
3332 }
3333 stdrp = lastrp[false];
3334 dstrp = lastrp[true];
3335 dstcmp = zp->z_nrules ? rule_cmp(dstrp, stdrp) : zp->z_isdst ? 1 : -1;
3336 stdzp = dstzp = zp;
3337
3338 if (dstcmp < 0) {
3339 /* Standard time all year. */
3340 dstrp = NULL;
3341 } else if (0 < dstcmp) {
3342 /* DST all year. Use an abbreviation like
3343 "XXX3EDT4,0/0,J365/23" for EDT (-04) all year. */
3344 zic_t save = dstrp ? dstrp->r_save : zp->z_save;
3345 if (0 <= save)
3346 {
3347 /* Positive DST, the typical case for all-year DST.
3348 Fake a timezone with negative DST. */
3349 stdzp = &zstr[0];
3350 dstzp = &zstr[1];
3351 zstr[0].z_stdoff = zp->z_stdoff + 2 * save;
3352 zstr[0].z_format = "XXX"; /* Any 3 letters will do. */
3353 zstr[0].z_format_specifier = 0;
3354 zstr[1].z_stdoff = zstr[0].z_stdoff;
3355 zstr[1].z_format = zp->z_format;
3356 zstr[1].z_format_specifier = zp->z_format_specifier;
3357 }
3358 dstr.r_month = TM_JANUARY;
3359 dstr.r_dycode = DC_DOM;
3360 dstr.r_dayofmonth = 1;
3361 dstr.r_tod = 0;
3362 dstr.r_todisstd = dstr.r_todisut = false;
3363 dstr.r_isdst = true;
3364 dstr.r_save = save < 0 ? save : -save;
3365 dstr.r_abbrvar = dstrp ? dstrp->r_abbrvar : NULL;
3366 stdr.r_month = TM_DECEMBER;
3367 stdr.r_dycode = DC_DOM;
3368 stdr.r_dayofmonth = 31;
3369 stdr.r_tod = SECSPERDAY + dstr.r_save;
3370 stdr.r_todisstd = stdr.r_todisut = false;
3371 stdr.r_isdst = false;
3372 stdr.r_save = 0;
3373 stdr.r_abbrvar = save < 0 && stdrp ? stdrp->r_abbrvar : NULL;
3374 dstrp = &dstr;
3375 stdrp = &stdr;
3376 }
3377 len = doabbr(result, stdzp, stdrp ? stdrp->r_abbrvar : NULL,
3378 false, 0, true);
3379 offsetlen = stringoffset(result + len, - stdzp->z_stdoff);
3380 if (! offsetlen) {
3381 result[0] = '\0';
3382 return -1;
3383 }
3384 len += offsetlen;
3385 if (dstrp == NULL)
3386 return compat;
3387 len += doabbr(result + len, dstzp, dstrp->r_abbrvar,
3388 dstrp->r_isdst, dstrp->r_save, true);
3389 if (dstrp->r_save != SECSPERMIN * MINSPERHOUR) {
3390 offsetlen = stringoffset(result + len,
3391 - (dstzp->z_stdoff + dstrp->r_save));
3392 if (! offsetlen) {
3393 result[0] = '\0';
3394 return -1;
3395 }
3396 len += offsetlen;
3397 }
3398 result[len++] = ',';
3399 c = stringrule(result + len, dstrp, dstrp->r_save, stdzp->z_stdoff);
3400 if (c < 0) {
3401 result[0] = '\0';
3402 return -1;
3403 }
3404 if (compat < c)
3405 compat = c;
3406 len += strlen(result + len);
3407 result[len++] = ',';
3408 c = stringrule(result + len, stdrp, dstrp->r_save, stdzp->z_stdoff);
3409 if (c < 0) {
3410 result[0] = '\0';
3411 return -1;
3412 }
3413 if (compat < c)
3414 compat = c;
3415 return compat;
3416 }
3417
3418 static void
outzone(const struct zone * zpfirst,ptrdiff_t zonecount)3419 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
3420 {
3421 register ptrdiff_t i, j;
3422 register zic_t starttime, untiltime;
3423 register bool startttisstd;
3424 register bool startttisut;
3425 register char * startbuf;
3426 register char * ab;
3427 register char * envvar;
3428 register int max_abbr_len;
3429 register int max_envvar_len;
3430 register int compat;
3431 register bool do_extend;
3432 register char version;
3433 zic_t nonTZlimtime = ZIC_MIN;
3434 int nonTZlimtype = -1;
3435 zic_t max_year0;
3436 int defaulttype = -1;
3437 int max_stringoffset_len = sizeof "-167:59:59" - 1;
3438 int max_comma_stringrule_len = (sizeof ",M12.5.6/" - 1
3439 + max_stringoffset_len);
3440
3441 check_for_signal();
3442
3443 /* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND. */
3444 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
3445 max_envvar_len = 2 * (max_abbr_len + max_stringoffset_len
3446 + max_comma_stringrule_len);
3447
3448 startbuf = xmalloc(max_abbr_len + 1);
3449 ab = xmalloc(max_abbr_len + 1);
3450 envvar = xmalloc(max_envvar_len + 1);
3451 INITIALIZE(untiltime);
3452 INITIALIZE(starttime);
3453 /*
3454 ** Now. . .finally. . .generate some useful data!
3455 */
3456 timecnt = 0;
3457 typecnt = 0;
3458 charcnt = 0;
3459 /*
3460 ** Thanks to Earl Chew
3461 ** for noting the need to unconditionally initialize startttisstd.
3462 */
3463 startttisstd = false;
3464 startttisut = false;
3465 min_year = max_year = EPOCH_YEAR;
3466 if (leapseen) {
3467 updateminmax(leapminyear);
3468 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
3469 }
3470 for (i = 0; i < zonecount; ++i) {
3471 struct zone const *zp = &zpfirst[i];
3472 if (i < zonecount - 1)
3473 updateminmax(zp->z_untilrule.r_loyear);
3474 for (j = 0; j < zp->z_nrules; ++j) {
3475 struct rule *rp = &zp->z_rules[j];
3476 updateminmax(rp->r_loyear);
3477 if (rp->r_hiwasnum)
3478 updateminmax(rp->r_hiyear);
3479 }
3480 }
3481 /*
3482 ** Generate lots of data if a rule can't cover all future times.
3483 */
3484 compat = stringzone(envvar, zpfirst, zonecount);
3485 version = compat < 2013 ? '2' : '3';
3486 do_extend = compat < 0;
3487 if (noise) {
3488 if (!*envvar)
3489 warning("%s %s",
3490 _("no proleptic TZ string for zone"),
3491 zpfirst->z_name);
3492 else if (compat != 0) {
3493 /* Circa-COMPAT clients, and earlier clients, might
3494 not work for this zone when given dates before
3495 1970 or after 2038. */
3496 warning(_("%s: pre-%d clients may mishandle"
3497 " distant timestamps"),
3498 zpfirst->z_name, compat);
3499 }
3500 }
3501 if (do_extend) {
3502 if (min_year >= ZIC_MIN + years_of_observations)
3503 min_year -= years_of_observations;
3504 else min_year = ZIC_MIN;
3505 if (max_year <= ZIC_MAX - years_of_observations)
3506 max_year += years_of_observations;
3507 else max_year = ZIC_MAX;
3508 }
3509 max_year = max(max_year, (redundant_time / (SECSPERDAY * DAYSPERNYEAR)
3510 + EPOCH_YEAR + 1));
3511 max_year0 = max_year;
3512 if (want_bloat()) {
3513 /* For the benefit of older systems,
3514 generate data from 1900 through 2038. */
3515 if (min_year > YEAR_32BIT_MIN - 1)
3516 min_year = YEAR_32BIT_MIN - 1;
3517 if (max_year < YEAR_32BIT_MAX)
3518 max_year = YEAR_32BIT_MAX;
3519 }
3520
3521 if (min_time < lo_time || hi_time < max_time)
3522 unspecifiedtype = addtype(0, "-00", false, false, false);
3523
3524 for (i = 0; i < zonecount; ++i) {
3525 /*
3526 ** A guess that may well be corrected later.
3527 */
3528 zic_t save = 0;
3529 struct zone const *zp = &zpfirst[i];
3530 bool usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
3531 bool useuntil = i < (zonecount - 1);
3532 zic_t stdoff = zp->z_stdoff;
3533 zic_t startoff = stdoff;
3534 if (useuntil && zp->z_untiltime <= min_time)
3535 continue;
3536 eat(zp->z_filenum, zp->z_linenum);
3537 *startbuf = '\0';
3538 if (zp->z_nrules == 0) {
3539 int type;
3540 save = zp->z_save;
3541 doabbr(startbuf, zp, NULL, zp->z_isdst, save, false);
3542 type = addtype(oadd(zp->z_stdoff, save),
3543 startbuf, zp->z_isdst, startttisstd,
3544 startttisut);
3545 if (usestart) {
3546 addtt(starttime, type);
3547 if (nonTZlimtime < starttime) {
3548 nonTZlimtime = starttime;
3549 nonTZlimtype = type;
3550 }
3551 usestart = false;
3552 } else
3553 defaulttype = type;
3554 } else {
3555 zic_t year;
3556 for (year = min_year; year <= max_year; ++year) {
3557 if (useuntil && year > zp->z_untilrule.r_hiyear)
3558 break;
3559 /*
3560 ** Mark which rules to do in the current year.
3561 ** For those to do, calculate rpytime(rp, year);
3562 ** The former TYPE field was also considered here.
3563 */
3564 for (j = 0; j < zp->z_nrules; ++j) {
3565 zic_t one = 1;
3566 zic_t y2038_boundary = one << 31;
3567 struct rule *rp = &zp->z_rules[j];
3568 eats(zp->z_filenum, zp->z_linenum,
3569 rp->r_filenum, rp->r_linenum);
3570 rp->r_todo = year >= rp->r_loyear &&
3571 year <= rp->r_hiyear;
3572 if (rp->r_todo) {
3573 rp->r_temp = rpytime(rp, year);
3574 rp->r_todo
3575 = (rp->r_temp < y2038_boundary
3576 || year <= max_year0);
3577 }
3578 }
3579 for ( ; ; ) {
3580 register ptrdiff_t k;
3581 register zic_t jtime, ktime;
3582 register zic_t offset;
3583 struct rule *rp;
3584 int type;
3585
3586 INITIALIZE(ktime);
3587 if (useuntil) {
3588 /*
3589 ** Turn untiltime into UT
3590 ** assuming the current stdoff and
3591 ** save values.
3592 */
3593 untiltime = zp->z_untiltime;
3594 if (!zp->z_untilrule.r_todisut)
3595 untiltime = tadd(untiltime,
3596 -stdoff);
3597 if (!zp->z_untilrule.r_todisstd)
3598 untiltime = tadd(untiltime,
3599 -save);
3600 }
3601 /*
3602 ** Find the rule (of those to do, if any)
3603 ** that takes effect earliest in the year.
3604 */
3605 k = -1;
3606 for (j = 0; j < zp->z_nrules; ++j) {
3607 struct rule *r = &zp->z_rules[j];
3608 if (!r->r_todo)
3609 continue;
3610 eats(zp->z_filenum, zp->z_linenum,
3611 r->r_filenum, r->r_linenum);
3612 offset = r->r_todisut ? 0 : stdoff;
3613 if (!r->r_todisstd)
3614 offset = oadd(offset, save);
3615 jtime = r->r_temp;
3616 jtime = tadd(jtime, -offset);
3617 if (k < 0 || jtime < ktime) {
3618 k = j;
3619 ktime = jtime;
3620 } else if (jtime == ktime) {
3621 char const *dup_rules_msg =
3622 _("two rules for same instant");
3623 eats(zp->z_filenum, zp->z_linenum,
3624 r->r_filenum, r->r_linenum);
3625 warning("%s", dup_rules_msg);
3626 r = &zp->z_rules[k];
3627 eats(zp->z_filenum, zp->z_linenum,
3628 r->r_filenum, r->r_linenum);
3629 error("%s", dup_rules_msg);
3630 }
3631 }
3632 if (k < 0)
3633 break; /* go on to next year */
3634 rp = &zp->z_rules[k];
3635 rp->r_todo = false;
3636 if (useuntil && ktime >= untiltime) {
3637 if (!*startbuf
3638 && (oadd(zp->z_stdoff, rp->r_save)
3639 == startoff))
3640 doabbr(startbuf, zp, rp->r_abbrvar,
3641 rp->r_isdst, rp->r_save,
3642 false);
3643 break;
3644 }
3645 save = rp->r_save;
3646 if (usestart && ktime == starttime)
3647 usestart = false;
3648 if (usestart) {
3649 if (ktime < starttime) {
3650 startoff = oadd(zp->z_stdoff,
3651 save);
3652 doabbr(startbuf, zp,
3653 rp->r_abbrvar,
3654 rp->r_isdst,
3655 rp->r_save,
3656 false);
3657 continue;
3658 }
3659 if (*startbuf == '\0'
3660 && startoff == oadd(zp->z_stdoff,
3661 save)) {
3662 doabbr(startbuf,
3663 zp,
3664 rp->r_abbrvar,
3665 rp->r_isdst,
3666 rp->r_save,
3667 false);
3668 }
3669 }
3670 eats(zp->z_filenum, zp->z_linenum,
3671 rp->r_filenum, rp->r_linenum);
3672 doabbr(ab, zp, rp->r_abbrvar,
3673 rp->r_isdst, rp->r_save, false);
3674 offset = oadd(zp->z_stdoff, rp->r_save);
3675 type = addtype(offset, ab, rp->r_isdst,
3676 rp->r_todisstd, rp->r_todisut);
3677 if (defaulttype < 0 && !rp->r_isdst)
3678 defaulttype = type;
3679 addtt(ktime, type);
3680 if (nonTZlimtime < ktime
3681 && (useuntil || rp->r_hiyear != ZIC_MAX)) {
3682 nonTZlimtime = ktime;
3683 nonTZlimtype = type;
3684 }
3685 }
3686 }
3687 }
3688 if (usestart) {
3689 bool isdst = startoff != zp->z_stdoff;
3690 if (*startbuf == '\0' && zp->z_format)
3691 doabbr(startbuf, zp, disable_percent_s,
3692 isdst, save, false);
3693 eat(zp->z_filenum, zp->z_linenum);
3694 if (*startbuf == '\0')
3695 error(_("can't determine time zone abbreviation"
3696 " to use just after until time"));
3697 else {
3698 int type = addtype(startoff, startbuf, isdst,
3699 startttisstd, startttisut);
3700 if (defaulttype < 0 && !isdst)
3701 defaulttype = type;
3702 addtt(starttime, type);
3703 }
3704 }
3705 /*
3706 ** Now we may get to set starttime for the next zone line.
3707 */
3708 if (useuntil) {
3709 startttisstd = zp->z_untilrule.r_todisstd;
3710 startttisut = zp->z_untilrule.r_todisut;
3711 starttime = zp->z_untiltime;
3712 if (!startttisstd)
3713 starttime = tadd(starttime, -save);
3714 if (!startttisut)
3715 starttime = tadd(starttime, -stdoff);
3716 }
3717 }
3718 if (defaulttype < 0)
3719 defaulttype = 0;
3720 if (!do_extend && !want_bloat()) {
3721 /* Keep trailing transitions that are no greater than this. */
3722 zic_t keep_at_max;
3723
3724 /* The earliest transition into a time governed by the TZ string. */
3725 zic_t TZstarttime = ZIC_MAX;
3726 for (i = 0; i < timecnt; i++) {
3727 zic_t at = attypes[i].at;
3728 if (nonTZlimtime < at && at < TZstarttime)
3729 TZstarttime = at;
3730 }
3731 if (TZstarttime == ZIC_MAX)
3732 TZstarttime = nonTZlimtime;
3733
3734 /* Omit trailing transitions deducible from the TZ string,
3735 and not needed for -r or -R. */
3736 keep_at_max = max(TZstarttime, redundant_time);
3737 for (i = j = 0; i < timecnt; i++)
3738 if (attypes[i].at <= keep_at_max) {
3739 attypes[j].at = attypes[i].at;
3740 attypes[j].dontmerge = (attypes[i].at == TZstarttime
3741 && (nonTZlimtype != attypes[i].type
3742 || strchr(envvar, ',')));
3743 attypes[j].type = attypes[i].type;
3744 j++;
3745 }
3746 timecnt = j;
3747 }
3748 if (do_extend) {
3749 /*
3750 ** If we're extending the explicitly listed observations for
3751 ** 400 years because we can't fill the proleptic TZ field,
3752 ** check whether we actually ended up explicitly listing
3753 ** observations through that period. If there aren't any
3754 ** near the end of the 400-year period, add a redundant
3755 ** one at the end of the final year, to make it clear
3756 ** that we are claiming to have definite knowledge of
3757 ** the lack of transitions up to that point.
3758 */
3759 struct rule xr;
3760 struct attype *lastat;
3761 xr.r_month = TM_JANUARY;
3762 xr.r_dycode = DC_DOM;
3763 xr.r_dayofmonth = 1;
3764 xr.r_tod = 0;
3765 for (lastat = attypes, i = 1; i < timecnt; i++)
3766 if (attypes[i].at > lastat->at)
3767 lastat = &attypes[i];
3768 if (!lastat || lastat->at < rpytime(&xr, max_year - 1)) {
3769 addtt(rpytime(&xr, max_year + 1),
3770 lastat ? lastat->type : defaulttype);
3771 attypes[timecnt - 1].dontmerge = true;
3772 }
3773 }
3774 writezone(zpfirst->z_name, envvar, version, defaulttype);
3775 free(startbuf);
3776 free(ab);
3777 free(envvar);
3778 }
3779
3780 static void
addtt(zic_t starttime,int type)3781 addtt(zic_t starttime, int type)
3782 {
3783 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
3784 attypes[timecnt].at = starttime;
3785 attypes[timecnt].dontmerge = false;
3786 attypes[timecnt].type = type;
3787 ++timecnt;
3788 }
3789
3790 static int
addtype(zic_t utoff,char const * abbr,bool isdst,bool ttisstd,bool ttisut)3791 addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
3792 {
3793 register int i, j;
3794 int charcnt0;
3795
3796 /* RFC 9636 section 3.2 specifies this range for utoff. */
3797 if (! (-TWO_31_MINUS_1 <= utoff && utoff <= TWO_31_MINUS_1)) {
3798 error(_("UT offset out of range"));
3799 exit(EXIT_FAILURE);
3800 }
3801 if (!want_bloat())
3802 ttisstd = ttisut = false;
3803
3804 checkabbr(abbr);
3805
3806 charcnt0 = charcnt;
3807 j = addabbr(chars, &charcnt, abbr);
3808 if (charcnt0 < charcnt) {
3809 /* If an abbreviation was inserted, increment indexes no
3810 earlier than the insert by the size of the insertion,
3811 so that they continue to point to the same contents. */
3812 for (i = 0; i < typecnt; i++)
3813 if (j <= desigidx[i])
3814 desigidx[i] += charcnt - charcnt0;
3815 } else {
3816 /* If there's already an entry, return its index. */
3817 for (i = 0; i < typecnt; i++)
3818 if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
3819 && ttisstd == ttisstds[i] && ttisut == ttisuts[i])
3820 return i;
3821 }
3822 /*
3823 ** There isn't one; add a new one, unless there are already too
3824 ** many.
3825 */
3826 if (typecnt >= TZ_MAX_TYPES) {
3827 error(_("too many local time types"));
3828 exit(EXIT_FAILURE);
3829 }
3830 i = typecnt++;
3831 utoffs[i] = utoff;
3832 isdsts[i] = isdst;
3833 ttisstds[i] = ttisstd;
3834 ttisuts[i] = ttisut;
3835 desigidx[i] = j;
3836 return i;
3837 }
3838
3839 static void
leapadd(zic_t t,int correction,int rolling)3840 leapadd(zic_t t, int correction, int rolling)
3841 {
3842 register ptrdiff_t i;
3843
3844 if (rolling && (lo_time != min_time || hi_time != max_time)) {
3845 error(_("Rolling leap seconds not supported with -r"));
3846 exit(EXIT_FAILURE);
3847 }
3848 leap = growalloc(leap, sizeof *leap, leapcnt, &leap_alloc);
3849 for (i = 0; i < leapcnt; ++i)
3850 if (t <= leap[i].trans)
3851 break;
3852 memmove(&leap[i + 1], &leap[i], (leapcnt - i) * sizeof *leap);
3853 leap[i].trans = t;
3854 leap[i].corr = correction;
3855 leap[i].roll = rolling;
3856 ++leapcnt;
3857 }
3858
3859 static void
adjleap(void)3860 adjleap(void)
3861 {
3862 register ptrdiff_t i;
3863 register zic_t last = 0;
3864 register zic_t prevtrans = 0;
3865
3866 /*
3867 ** propagate leap seconds forward
3868 */
3869 for (i = 0; i < leapcnt; ++i) {
3870 if (leap[i].trans - prevtrans < 28 * SECSPERDAY) {
3871 error(_("Leap seconds too close together"));
3872 exit(EXIT_FAILURE);
3873 }
3874 prevtrans = leap[i].trans;
3875 leap[i].trans = tadd(prevtrans, last);
3876 last = leap[i].corr += last;
3877 }
3878
3879 if (0 <= leapexpires) {
3880 leapexpires = oadd(leapexpires, last);
3881 if (! (leapcnt == 0 || (leap[leapcnt - 1].trans < leapexpires))) {
3882 error(_("last Leap time does not precede Expires time"));
3883 exit(EXIT_FAILURE);
3884 }
3885 }
3886 }
3887
3888 /* Is A a space character in the C locale? */
3889 static bool
is_space(char a)3890 is_space(char a)
3891 {
3892 switch (a) {
3893 default:
3894 return false;
3895 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
3896 return true;
3897 }
3898 }
3899
3900 /* Is A an alphabetic character in the C locale? */
3901 static bool
is_alpha(char a)3902 is_alpha(char a)
3903 {
3904 switch (a) {
3905 default:
3906 return false;
3907 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
3908 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
3909 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
3910 case 'V': case 'W': case 'X': case 'Y': case 'Z':
3911 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
3912 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
3913 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
3914 case 'v': case 'w': case 'x': case 'y': case 'z':
3915 return true;
3916 }
3917 }
3918
3919 /* If A is an uppercase character in the C locale, return its lowercase
3920 counterpart. Otherwise, return A. */
3921 static char
lowerit(char a)3922 lowerit(char a)
3923 {
3924 switch (a) {
3925 default: return a;
3926 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
3927 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
3928 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
3929 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
3930 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
3931 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
3932 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
3933 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
3934 case 'Y': return 'y'; case 'Z': return 'z';
3935 }
3936 }
3937
3938 /* case-insensitive equality */
3939 ATTRIBUTE_PURE_114833
3940 static bool
ciequal(register const char * ap,register const char * bp)3941 ciequal(register const char *ap, register const char *bp)
3942 {
3943 while (lowerit(*ap) == lowerit(*bp++))
3944 if (*ap++ == '\0')
3945 return true;
3946 return false;
3947 }
3948
3949 ATTRIBUTE_PURE_114833
3950 static bool
itsabbr(register const char * abbr,register const char * word)3951 itsabbr(register const char *abbr, register const char *word)
3952 {
3953 if (lowerit(*abbr) != lowerit(*word))
3954 return false;
3955 ++word;
3956 while (*++abbr != '\0')
3957 do {
3958 if (*word == '\0')
3959 return false;
3960 } while (lowerit(*word++) != lowerit(*abbr));
3961 return true;
3962 }
3963
3964 /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
3965
3966 ATTRIBUTE_PURE_114833
3967 static bool
ciprefix(char const * abbr,char const * word)3968 ciprefix(char const *abbr, char const *word)
3969 {
3970 do
3971 if (!*abbr)
3972 return true;
3973 while (lowerit(*abbr++) == lowerit(*word++));
3974
3975 return false;
3976 }
3977
3978 static const struct lookup *
byword(const char * word,const struct lookup * table)3979 byword(const char *word, const struct lookup *table)
3980 {
3981 register const struct lookup * foundlp;
3982 register const struct lookup * lp;
3983
3984 if (word == NULL || table == NULL)
3985 return NULL;
3986
3987 /* If TABLE is LASTS and the word starts with "last" followed
3988 by a non-'-', skip the "last" and look in WDAY_NAMES instead.
3989 Warn about any usage of the undocumented prefix "last-". */
3990 if (table == lasts && ciprefix("last", word) && word[4]) {
3991 if (word[4] == '-')
3992 warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
3993 word, word + 5);
3994 else {
3995 word += 4;
3996 table = wday_names;
3997 }
3998 }
3999
4000 /*
4001 ** Look for exact match.
4002 */
4003 for (lp = table; lp->l_word != NULL; ++lp)
4004 if (ciequal(word, lp->l_word))
4005 return lp;
4006 /*
4007 ** Look for inexact match.
4008 */
4009 foundlp = NULL;
4010 for (lp = table; lp->l_word != NULL; ++lp)
4011 if (ciprefix(word, lp->l_word)) {
4012 if (foundlp == NULL)
4013 foundlp = lp;
4014 else return NULL; /* multiple inexact matches */
4015 }
4016
4017 if (foundlp && noise) {
4018 /* Warn about any backward-compatibility issue with pre-2017c zic. */
4019 bool pre_2017c_match = false;
4020 for (lp = table; lp->l_word; lp++)
4021 if (itsabbr(word, lp->l_word)) {
4022 if (pre_2017c_match) {
4023 warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
4024 break;
4025 }
4026 pre_2017c_match = true;
4027 }
4028 }
4029
4030 return foundlp;
4031 }
4032
4033 static int
getfields(char * cp,char ** array,int arrayelts)4034 getfields(char *cp, char **array, int arrayelts)
4035 {
4036 register char * dp;
4037 register int nsubs;
4038
4039 nsubs = 0;
4040 for ( ; ; ) {
4041 char *dstart;
4042 while (is_space(*cp))
4043 ++cp;
4044 if (*cp == '\0' || *cp == '#')
4045 break;
4046 dstart = dp = cp;
4047 do {
4048 if ((*dp = *cp++) != '"')
4049 ++dp;
4050 else while ((*dp = *cp++) != '"')
4051 if (*dp != '\0')
4052 ++dp;
4053 else {
4054 error(_("Odd number of quotation marks"));
4055 exit(EXIT_FAILURE);
4056 }
4057 } while (*cp && *cp != '#' && !is_space(*cp));
4058 if (is_space(*cp))
4059 ++cp;
4060 *dp = '\0';
4061 if (nsubs == arrayelts) {
4062 error(_("Too many input fields"));
4063 exit(EXIT_FAILURE);
4064 }
4065 array[nsubs++] = dstart + (*dstart == '-' && dp == dstart + 1);
4066 }
4067 return nsubs;
4068 }
4069
4070 ATTRIBUTE_NORETURN static void
time_overflow(void)4071 time_overflow(void)
4072 {
4073 error(_("time overflow"));
4074 exit(EXIT_FAILURE);
4075 }
4076
4077 /* Return T1 + T2, but diagnose any overflow and exit. */
4078 ATTRIBUTE_PURE_114833_HACK
4079 static zic_t
oadd(zic_t t1,zic_t t2)4080 oadd(zic_t t1, zic_t t2)
4081 {
4082 #ifdef ckd_add
4083 zic_t sum;
4084 if (!ckd_add(&sum, t1, t2))
4085 return sum;
4086 #else
4087 if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1)
4088 return t1 + t2;
4089 #endif
4090 time_overflow();
4091 }
4092
4093 /* Return T1 + T2, but diagnose any overflow and exit.
4094 This is like oadd, except the result must fit in min_time..max_time range,
4095 which on oddball machines can be a smaller range than ZIC_MIN..ZIC_MAX. */
4096 ATTRIBUTE_PURE_114833_HACK
4097 static zic_t
tadd(zic_t t1,zic_t t2)4098 tadd(zic_t t1, zic_t t2)
4099 {
4100 zic_t sum = oadd(t1, t2);
4101 if (min_time <= sum && sum <= max_time)
4102 return sum;
4103 time_overflow();
4104 }
4105
4106 /* Return T1 * T2, but diagnose any overflow and exit. */
4107 ATTRIBUTE_PURE_114833_HACK
4108 static zic_t
omul(zic_t t1,zic_t t2)4109 omul(zic_t t1, zic_t t2)
4110 {
4111 #ifdef ckd_mul
4112 zic_t product;
4113 if (!ckd_mul(&product, t1, t2))
4114 return product;
4115 #else
4116 if (t2 < 0
4117 ? ZIC_MAX / t2 <= t1 && (t2 == -1 || t1 <= ZIC_MIN / t2)
4118 : t2 == 0 || (ZIC_MIN / t2 <= t1 && t1 <= ZIC_MAX / t2))
4119 return t1 * t2;
4120 #endif
4121 time_overflow();
4122 }
4123
4124 /*
4125 ** Given a rule, and a year, compute the date (in seconds since January 1,
4126 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
4127 ** Do not count leap seconds. On error, diagnose and exit.
4128 */
4129
4130 static zic_t
rpytime(const struct rule * rp,zic_t wantedy)4131 rpytime(const struct rule *rp, zic_t wantedy)
4132 {
4133 register int m, i;
4134 register zic_t dayoff; /* with a nod to Margaret O. */
4135 register zic_t t, y;
4136 int yrem;
4137
4138 m = TM_JANUARY;
4139 y = EPOCH_YEAR;
4140
4141 /* dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT,
4142 sans overflow. */
4143 yrem = wantedy % YEARSPERREPEAT - y % YEARSPERREPEAT;
4144 dayoff = ((wantedy / YEARSPERREPEAT - y / YEARSPERREPEAT
4145 + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0))
4146 * DAYSPERREPEAT);
4147 /* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow. */
4148 wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT;
4149
4150 while (wantedy != y) {
4151 i = len_years[isleap(y)];
4152 dayoff = oadd(dayoff, i);
4153 y++;
4154 }
4155 while (m != rp->r_month) {
4156 i = len_months[isleap(y)][m];
4157 dayoff = oadd(dayoff, i);
4158 ++m;
4159 }
4160 i = rp->r_dayofmonth;
4161 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
4162 if (rp->r_dycode == DC_DOWLEQ)
4163 --i;
4164 else {
4165 error(_("use of 2/29 in non leap-year"));
4166 exit(EXIT_FAILURE);
4167 }
4168 }
4169 --i;
4170 dayoff = oadd(dayoff, i);
4171 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
4172 /*
4173 ** Don't trust mod of negative numbers.
4174 */
4175 zic_t wday = ((EPOCH_WDAY + dayoff % DAYSPERWEEK + DAYSPERWEEK)
4176 % DAYSPERWEEK);
4177 while (wday != rp->r_wday)
4178 if (rp->r_dycode == DC_DOWGEQ) {
4179 dayoff = oadd(dayoff, 1);
4180 if (++wday >= DAYSPERWEEK)
4181 wday = 0;
4182 ++i;
4183 } else {
4184 dayoff = oadd(dayoff, -1);
4185 if (--wday < 0)
4186 wday = DAYSPERWEEK - 1;
4187 --i;
4188 }
4189 if (i < 0 || i >= len_months[isleap(y)][m]) {
4190 if (noise)
4191 warning(_("rule goes past start/end of month; \
4192 will not work with pre-2004 versions of zic"));
4193 }
4194 }
4195 t = omul(dayoff, SECSPERDAY);
4196 return tadd(t, rp->r_tod);
4197 }
4198
4199 static void
checkabbr(char const * string)4200 checkabbr(char const *string)
4201 {
4202 if (strcmp(string, GRANDPARENTED) != 0) {
4203 register const char * cp;
4204 const char * mp;
4205
4206 cp = string;
4207 mp = NULL;
4208 while (is_alpha(*cp) || is_digit(*cp)
4209 || *cp == '-' || *cp == '+')
4210 ++cp;
4211 if (noise && cp - string < 3)
4212 mp = _("time zone abbreviation has fewer than 3 characters");
4213 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
4214 mp = _("time zone abbreviation has too many characters");
4215 if (*cp != '\0')
4216 mp = _("time zone abbreviation differs from POSIX standard");
4217 if (mp != NULL)
4218 warning("%s (%s)", mp, string);
4219 }
4220 }
4221
4222 /* Put into CHS, which currently contains *PNCHS bytes containing
4223 NUL-terminated abbreviations none of which are suffixes of another,
4224 the abbreviation ABBR including its trailing NUL.
4225 If ABBR does not already appear in CHS,
4226 possibly as a suffix of an existing abbreviation,
4227 add ABBR to CHS, remove from CHS any abbreviation
4228 that is a suffix of ABBR, and increment *PNCHS accordingly.
4229 Return the index of ABBR after any modifications to CHS are made.
4230
4231 If all abbreviations have already been added, this function
4232 lets the caller look up the index of an existing abbreviation. */
4233 static int
addabbr(char chs[TZ_MAX_CHARS],int * pnchs,char const * abbr)4234 addabbr(char chs[TZ_MAX_CHARS], int *pnchs, char const *abbr)
4235 {
4236 int nchs = *pnchs;
4237 int alen = strlen(abbr), nchs_incr = alen + 1;
4238 int i;
4239 for (i = 0; i < nchs; ) {
4240 int clen = strlen(&chs[i]);
4241 if (alen <= clen) {
4242 /* If ABBR is a suffix of an abbreviation in CHS,
4243 return the index of ABBR in CHS. */
4244 int isuff = i + (clen - alen);
4245 if (memcmp(&chs[isuff], abbr, alen) == 0)
4246 return isuff;
4247 } else if (memcmp(&chs[i], &abbr[alen - clen], clen) == 0) {
4248 /* An abbreviation in CHS is a substring of ABBR.
4249 Replace it with ABBR, instead of the more-common
4250 actions of appending ABBR or doing nothing. */
4251 nchs_incr = alen - clen;
4252 break;
4253 }
4254 i += clen + 1;
4255 }
4256 if (TZ_MAX_CHARS < nchs + nchs_incr) {
4257 error(_("too many, or too long, time zone abbreviations"));
4258 exit(EXIT_FAILURE);
4259 }
4260 memmove(&chs[i + nchs_incr], &chs[i], nchs - i);
4261 memcpy(&chs[i], abbr, nchs_incr);
4262 *pnchs = nchs + nchs_incr;
4263 return i;
4264 }
4265
4266 /* Ensure that the directories of ARGNAME exist, by making any missing
4267 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
4268 do it for ARGNAME too. Exit with failure if there is trouble.
4269 Do not consider an existing file to be trouble. */
4270 static void
mkdirs(char const * argname,bool ancestors)4271 mkdirs(char const *argname, bool ancestors)
4272 {
4273 /* If -D was specified, do not create directories.
4274 If a file operation's parent directory is missing,
4275 the operation will fail and be diagnosed. */
4276 if (!skip_mkdir) {
4277
4278 char *name = xstrdup(argname);
4279 char *cp = name;
4280
4281 /* On MS-Windows systems, do not worry about drive letters or
4282 backslashes, as this should suffice in practice. Time zone
4283 names do not use drive letters and backslashes. If the -d
4284 option of zic does not name an already-existing directory,
4285 it can use slashes to separate the already-existing
4286 ancestor prefix from the to-be-created subdirectories. */
4287
4288 /* Do not mkdir a root directory, as it must exist. */
4289 while (*cp == '/')
4290 cp++;
4291
4292 while (cp && ((cp = strchr(cp, '/')) || !ancestors)) {
4293 if (cp)
4294 *cp = '\0';
4295 /*
4296 ** Try to create it. It's OK if creation fails because
4297 ** the directory already exists, perhaps because some
4298 ** other process just created it. For simplicity do
4299 ** not check first whether it already exists, as that
4300 ** is checked anyway if the mkdir fails.
4301 */
4302 if (mkdir(name, MKDIR_PERMS) < 0) {
4303 /* Do not report an error if err == EEXIST, because
4304 some other process might have made the directory
4305 in the meantime. Likewise for ENOSYS, because
4306 Solaris 10 mkdir fails with ENOSYS if the
4307 directory is an automounted mount point.
4308 Likewise for EACCES, since mkdir can fail
4309 with EACCES merely because the parent directory
4310 is unwritable. Likewise for most other error
4311 numbers. */
4312 int err = errno;
4313 if (err == ELOOP || err == ENAMETOOLONG
4314 || err == ENOENT || err == ENOTDIR) {
4315 error(_("%s: Can't create directory %s: %s"),
4316 progname, name, strerror(err));
4317 exit(EXIT_FAILURE);
4318 }
4319 }
4320 if (cp)
4321 *cp++ = '/';
4322 }
4323 free(name);
4324 }
4325 }
4326