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