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