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