xref: /src/contrib/tzcode/zic.c (revision ff2c98b30b57b9763e2a6575f729bab676e6c025)
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