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