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