xref: /openbsd/usr.sbin/zic/zic.c (revision 6a4024dc)
1 /*	$OpenBSD: zic.c,v 1.27 2024/09/18 17:05:50 millert Exp $	*/
2 /*
3 ** This file is in the public domain, so clarified as of
4 ** 2006-07-17 by Arthur David Olson.
5 */
6 
7 #include <sys/types.h>
8 #include <sys/wait.h>
9 #include <sys/stat.h>
10 #include <ctype.h>
11 #include <err.h>
12 #include <errno.h>
13 #include <limits.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdint.h>
18 #include <unistd.h>
19 #include <time.h>
20 
21 #include "tzfile.h"
22 
23 #define TRUE	1
24 #define FALSE	0
25 
26 #define TYPE_SIGNED(type) (((type) -1) < 0)
27 
28 #define YEARSPERREPEAT	400	/* years before a Gregorian repeat */
29 
30 #define GRANDPARENTED   "Local time zone must be set--see zic manual page"
31 
32 #define	ZIC_VERSION	'2'
33 
34 typedef int_fast64_t	zic_t;
35 
36 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
37 #define ZIC_MAX_ABBR_LEN_WO_WARN	6
38 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
39 
40 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
41 
42 #define OFFSET_STRLEN_MAXIMUM	(7 + INT_STRLEN_MAXIMUM(long))
43 #define RULE_STRLEN_MAXIMUM	8	/* "Mdd.dd.d" */
44 
45 #define end(cp, n)	(memchr((cp), '\0', (n)))
46 
47 struct rule {
48 	const char	*r_filename;
49 	int		r_linenum;
50 	const char	*r_name;
51 
52 	int		r_loyear;	/* for example, 1986 */
53 	int		r_hiyear;	/* for example, 1986 */
54 	int		r_lowasnum;
55 	int		r_hiwasnum;
56 
57 	int		r_month;	/* 0..11 */
58 
59 	int		r_dycode;	/* see below */
60 	int		r_dayofmonth;
61 	int		r_wday;
62 
63 	long		r_tod;		/* time from midnight */
64 	int		r_todisstd;	/* above is standard time if TRUE */
65 					/* or wall clock time if FALSE */
66 	int		r_todisgmt;	/* above is GMT if TRUE */
67 					/* or local time if FALSE */
68 	long		r_stdoff;	/* offset from standard time */
69 	const char	*r_abbrvar;	/* variable part of abbreviation */
70 
71 	int		r_todo;		/* a rule to do (used in outzone) */
72 	zic_t		r_temp;		/* used in outzone */
73 };
74 
75 /*
76 **	r_dycode		r_dayofmonth	r_wday
77 */
78 
79 #define DC_DOM		0	/* 1..31 */	/* unused */
80 #define DC_DOWGEQ	1	/* 1..31 */	/* 0..6 (Sun..Sat) */
81 #define DC_DOWLEQ	2	/* 1..31 */	/* 0..6 (Sun..Sat) */
82 
83 struct zone {
84 	const char	*z_filename;
85 	int		z_linenum;
86 
87 	const char	*z_name;
88 	long		z_gmtoff;
89 	const char	*z_rule;
90 	const char	*z_format;
91 	char		z_format_specifier;
92 
93 	long		z_stdoff;
94 
95 	struct rule	*z_rules;
96 	int		z_nrules;
97 
98 	struct rule	z_untilrule;
99 	zic_t		z_untiltime;
100 };
101 
102 static void	addtt(zic_t starttime, int type);
103 static int	addtype(long gmtoff, const char *abbr, int isdst,
104 	    int ttisstd, int ttisgmt);
105 static void	leapadd(zic_t t, int positive, int rolling, int count);
106 static void	adjleap(void);
107 static void	associate(void);
108 static void	convert(long val, char *buf);
109 static void	convert64(zic_t val, char *buf);
110 static void	dolink(const char *fromfield, const char *tofield);
111 static void	doabbr(char *abbr, size_t size, struct zone const *zp,
112 	    const char *letters, int isdst, int doquotes);
113 static void	eat(const char *name, int num);
114 static void	eats(const char *name, int num, const char *rname, int rnum);
115 static long	eitol(int i);
116 static void	error(const char *message);
117 static char	**getfields(char *buf);
118 static long	gethms(const char *string, const char *errstrng, int signable);
119 static void	infile(const char *filename);
120 static void	inleap(char **fields, int nfields);
121 static void	inlink(char **fields, int nfields);
122 static void	inrule(char **fields, int nfields);
123 static int	inzcont(char **fields, int nfields);
124 static int	inzone(char **fields, int nfields);
125 static int	inzsub(char **fields, int nfields, int iscont);
126 static int	is32(zic_t x);
127 static int	itsabbr(const char *abbr, const char *word);
128 static int	itsdir(const char *name);
129 static int	mkdirs(char *filename);
130 static void	newabbr(const char *abbr);
131 static long	oadd(long t1, long t2);
132 static void	outzone(const struct zone *zp, int ntzones);
133 static void	puttzcode(long code, FILE *fp);
134 static void	puttzcode64(zic_t code, FILE *fp);
135 static int	rcomp(const void *leftp, const void *rightp);
136 static zic_t	rpytime(const struct rule *rp, int wantedy);
137 static void	rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
138 	    const char *typep, const char *monthp,
139 	    const char *dayp, const char *timep);
140 static int	stringoffset(char *result, size_t size, long offset);
141 static int	stringrule(char *result, size_t size, const struct rule *rp,
142 	    long dstoff, long gmtoff);
143 static void	stringzone(char *result, size_t size,
144 	    const struct zone *zp, int ntzones);
145 static void	setboundaries(void);
146 static zic_t	tadd(zic_t t1, long t2);
147 static void	usage(void);
148 static void	writezone(const char *name, const char *string);
149 
150 extern char	*__progname;
151 
152 /* Bound on length of what %z can expand to.  */
153 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
154 
155 static int		charcnt;
156 static int		errors;
157 static const char	*filename;
158 static int		leapcnt;
159 static int		leapseen;
160 static int		leapminyear;
161 static int		leapmaxyear;
162 static int		linenum;
163 static int		max_abbrvar_len = PERCENT_Z_LEN_BOUND;
164 static int		max_format_len;
165 static zic_t		max_time;
166 static int		max_year;
167 static zic_t		min_time;
168 static int		min_year;
169 static int		noise;
170 static const char	*rfilename;
171 static int		rlinenum;
172 static int		timecnt;
173 static int		typecnt;
174 
175 /*
176 ** Line codes.
177 */
178 
179 #define LC_RULE		0
180 #define LC_ZONE		1
181 #define LC_LINK		2
182 #define LC_LEAP		3
183 
184 /*
185 ** Which fields are which on a Zone line.
186 */
187 
188 #define ZF_NAME		1
189 #define ZF_GMTOFF	2
190 #define ZF_RULE		3
191 #define ZF_FORMAT	4
192 #define ZF_TILYEAR	5
193 #define ZF_TILMONTH	6
194 #define ZF_TILDAY	7
195 #define ZF_TILTIME	8
196 #define ZONE_MINFIELDS	5
197 #define ZONE_MAXFIELDS	9
198 
199 /*
200 ** Which fields are which on a Zone continuation line.
201 */
202 
203 #define ZFC_GMTOFF	0
204 #define ZFC_RULE	1
205 #define ZFC_FORMAT	2
206 #define ZFC_TILYEAR	3
207 #define ZFC_TILMONTH	4
208 #define ZFC_TILDAY	5
209 #define ZFC_TILTIME	6
210 #define ZONEC_MINFIELDS	3
211 #define ZONEC_MAXFIELDS	7
212 
213 /*
214 ** Which files are which on a Rule line.
215 */
216 
217 #define RF_NAME		1
218 #define RF_LOYEAR	2
219 #define RF_HIYEAR	3
220 #define RF_COMMAND	4
221 #define RF_MONTH	5
222 #define RF_DAY		6
223 #define RF_TOD		7
224 #define RF_STDOFF	8
225 #define RF_ABBRVAR	9
226 #define RULE_FIELDS	10
227 
228 /*
229 ** Which fields are which on a Link line.
230 */
231 
232 #define LF_FROM		1
233 #define LF_TO		2
234 #define LINK_FIELDS	3
235 
236 /*
237 ** Which fields are which on a Leap line.
238 */
239 
240 #define LP_YEAR		1
241 #define LP_MONTH	2
242 #define LP_DAY		3
243 #define LP_TIME		4
244 #define LP_CORR		5
245 #define LP_ROLL		6
246 #define LEAP_FIELDS	7
247 
248 /*
249 ** Year synonyms.
250 */
251 
252 #define YR_MINIMUM	0
253 #define YR_MAXIMUM	1
254 #define YR_ONLY		2
255 
256 static struct rule	*rules;
257 static int		nrules;	/* number of rules */
258 
259 static struct zone	*zones;
260 static int		nzones;	/* number of zones */
261 
262 struct link {
263 	const char	*l_filename;
264 	int		l_linenum;
265 	const char	*l_from;
266 	const char	*l_to;
267 };
268 
269 static struct link	*links;
270 static int		nlinks;
271 
272 struct lookup {
273 	const char	*l_word;
274 	const int	l_value;
275 };
276 
277 static struct lookup const	*byword(const char *string, const struct lookup *lp);
278 
279 static struct lookup const	line_codes[] = {
280 	{ "Rule",	LC_RULE },
281 	{ "Zone",	LC_ZONE },
282 	{ "Link",	LC_LINK },
283 	{ "Leap",	LC_LEAP },
284 	{ NULL,		0}
285 };
286 
287 static struct lookup const	mon_names[] = {
288 	{ "January",	TM_JANUARY },
289 	{ "February",	TM_FEBRUARY },
290 	{ "March",	TM_MARCH },
291 	{ "April",	TM_APRIL },
292 	{ "May",	TM_MAY },
293 	{ "June",	TM_JUNE },
294 	{ "July",	TM_JULY },
295 	{ "August",	TM_AUGUST },
296 	{ "September",	TM_SEPTEMBER },
297 	{ "October",	TM_OCTOBER },
298 	{ "November",	TM_NOVEMBER },
299 	{ "December",	TM_DECEMBER },
300 	{ NULL,		0 }
301 };
302 
303 static struct lookup const	wday_names[] = {
304 	{ "Sunday",	TM_SUNDAY },
305 	{ "Monday",	TM_MONDAY },
306 	{ "Tuesday",	TM_TUESDAY },
307 	{ "Wednesday",	TM_WEDNESDAY },
308 	{ "Thursday",	TM_THURSDAY },
309 	{ "Friday",	TM_FRIDAY },
310 	{ "Saturday",	TM_SATURDAY },
311 	{ NULL,		0 }
312 };
313 
314 static struct lookup const	lasts[] = {
315 	{ "last-Sunday",	TM_SUNDAY },
316 	{ "last-Monday",	TM_MONDAY },
317 	{ "last-Tuesday",	TM_TUESDAY },
318 	{ "last-Wednesday",	TM_WEDNESDAY },
319 	{ "last-Thursday",	TM_THURSDAY },
320 	{ "last-Friday",	TM_FRIDAY },
321 	{ "last-Saturday",	TM_SATURDAY },
322 	{ NULL,			0 }
323 };
324 
325 static struct lookup const	begin_years[] = {
326 	{ "minimum",	YR_MINIMUM },
327 	{ "maximum",	YR_MAXIMUM },
328 	{ NULL,		0 }
329 };
330 
331 static struct lookup const	end_years[] = {
332 	{ "minimum",	YR_MINIMUM },
333 	{ "maximum",	YR_MAXIMUM },
334 	{ "only",	YR_ONLY },
335 	{ NULL,		0 }
336 };
337 
338 static struct lookup const	leap_types[] = {
339 	{ "Rolling",	TRUE },
340 	{ "Stationary",	FALSE },
341 	{ NULL,		0 }
342 };
343 
344 static const int	len_months[2][MONSPERYEAR] = {
345 	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
346 	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
347 };
348 
349 static const int	len_years[2] = {
350 	DAYSPERNYEAR, DAYSPERLYEAR
351 };
352 
353 static struct attype {
354 	zic_t		at;
355 	unsigned char	type;
356 }			attypes[TZ_MAX_TIMES];
357 
358 static long		gmtoffs[TZ_MAX_TYPES];
359 static char		isdsts[TZ_MAX_TYPES];
360 static unsigned char	abbrinds[TZ_MAX_TYPES];
361 static char		ttisstds[TZ_MAX_TYPES];
362 static char		ttisgmts[TZ_MAX_TYPES];
363 static char		chars[TZ_MAX_CHARS];
364 static zic_t		trans[TZ_MAX_LEAPS];
365 static long		corr[TZ_MAX_LEAPS];
366 static char		roll[TZ_MAX_LEAPS];
367 
368 /*
369 ** Memory allocation.
370 */
371 
372 static void *
memcheck(void * ptr)373 memcheck(void *ptr)
374 {
375 	if (ptr == NULL)
376 		err(1, "Memory exhausted");
377 	return ptr;
378 }
379 
380 static char *
ecatalloc(char * start,const char * tail)381 ecatalloc(char *start, const char *tail)
382 {
383 	size_t len;
384 	char *str;
385 
386 	len = strlen(start) + strlen(tail) + 1;
387 	str = memcheck(realloc(start, len));
388 	strlcat(str, tail, len);
389 	return str;
390 }
391 
392 #define emalloc(size)		memcheck(malloc(size))
393 #define ereallocarray(ptr, nmemb, size)		memcheck(reallocarray(ptr, nmemb, size))
394 #define erealloc(ptr, size)	memcheck(realloc((ptr), (size)))
395 #define ecpyalloc(ptr)		memcheck(strdup(ptr))
396 
397 /*
398 ** Error handling.
399 */
400 
401 static void
eats(const char * name,int num,const char * rname,int rnum)402 eats(const char *name, int num, const char *rname, int rnum)
403 {
404 	filename = name;
405 	linenum = num;
406 	rfilename = rname;
407 	rlinenum = rnum;
408 }
409 
410 static void
eat(const char * name,int num)411 eat(const char *name, int num)
412 {
413 	eats(name, num, NULL, -1);
414 }
415 
416 static void
error(const char * string)417 error(const char *string)
418 {
419 	/*
420 	** Match the format of "cc" to allow sh users to
421 	**	zic ... 2>&1 | error -t "*" -v
422 	** on BSD systems.
423 	*/
424 	fprintf(stderr, "\"%s\", line %d: %s",
425 		filename, linenum, string);
426 	if (rfilename != NULL)
427 		fprintf(stderr, " (rule from \"%s\", line %d)",
428 			rfilename, rlinenum);
429 	fprintf(stderr, "\n");
430 	++errors;
431 }
432 
433 static void
warning(const char * string)434 warning(const char *string)
435 {
436 	char	*cp;
437 
438 	cp = ecpyalloc("warning: ");
439 	cp = ecatalloc(cp, string);
440 	error(cp);
441 	free(cp);
442 	--errors;
443 }
444 
445 
446 static const char *
scheck(const char * string,const char * format)447 scheck(const char *string, const char *format)
448 {
449 	const char	*fp, *result;
450 	char		*fbuf, *tp, dummy;
451 	int		c;
452 
453 	result = "";
454 	if (string == NULL || format == NULL)
455 		return result;
456 	fbuf = reallocarray(NULL, strlen(format) + 2, 2);
457 	if (fbuf == NULL)
458 		return result;
459 	fp = format;
460 	tp = fbuf;
461 	while ((*tp++ = c = *fp++) != '\0') {
462 		if (c != '%')
463 			continue;
464 		if (*fp == '%') {
465 			*tp++ = *fp++;
466 			continue;
467 		}
468 		*tp++ = '*';
469 		if (*fp == '*')
470 			++fp;
471 		while (isdigit((unsigned char)*fp))
472 			*tp++ = *fp++;
473 		if (*fp == 'l' || *fp == 'h')
474 			*tp++ = *fp++;
475 		else if (*fp == '[')
476 			do {
477 				*tp++ = *fp++;
478 			} while (*fp != '\0' && *fp != ']');
479 		if ((*tp++ = *fp++) == '\0')
480 			break;
481 	}
482 	*(tp - 1) = '%';
483 	*tp++ = 'c';
484 	*tp = '\0';
485 	if (sscanf(string, fbuf, &dummy) != 1)
486 		result = format;
487 	free(fbuf);
488 	return result;
489 }
490 
491 static void
usage(void)492 usage(void)
493 {
494 	fprintf(stderr,
495 	    "usage: %s [-v] [-d directory] [-L leapsecondfilename] [-l timezone]\n"
496 	    "\t\t[-p timezone] [filename ...]\n",
497 		__progname);
498 	exit(EXIT_FAILURE);
499 }
500 
501 static const char	*psxrules;
502 static const char	*lcltime;
503 static const char	*directory;
504 static const char	*leapsec;
505 
506 int
main(int argc,char ** argv)507 main(int argc, char **argv)
508 {
509 	int	i, j, c;
510 
511 	if (pledge("stdio rpath wpath cpath proc exec", NULL) == -1)
512 		err(1, "pledge");
513 
514 	umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
515 	while ((c = getopt(argc, argv, "d:l:p:L:vy:")) != -1)
516 		switch (c) {
517 			default:
518 				usage();
519 			case 'd':
520 				if (directory == NULL)
521 					directory = optarg;
522 				else
523 					errx(1, "More than one -d option specified");
524 				break;
525 			case 'l':
526 				if (lcltime == NULL)
527 					lcltime = optarg;
528 				else
529 					errx(1, "More than one -l option specified");
530 				break;
531 			case 'p':
532 				if (psxrules == NULL)
533 					psxrules = optarg;
534 				else
535 					errx(1, "More than one -p option specified");
536 				break;
537 			case 'y':
538 				warning("ignoring obsolescent option -y");
539 				break;
540 			case 'L':
541 				if (leapsec == NULL)
542 					leapsec = optarg;
543 				else
544 					errx(1, "More than one -L option specified");
545 				break;
546 			case 'v':
547 				noise = TRUE;
548 				break;
549 		}
550 	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
551 		usage();	/* usage message by request */
552 	if (directory == NULL)
553 		directory = TZDIR;
554 
555 	setboundaries();
556 
557 	if (optind < argc && leapsec != NULL) {
558 		infile(leapsec);
559 		adjleap();
560 	}
561 
562 	for (i = optind; i < argc; ++i)
563 		infile(argv[i]);
564 	if (errors)
565 		exit(EXIT_FAILURE);
566 	associate();
567 	for (i = 0; i < nzones; i = j) {
568 		/*
569 		** Find the next non-continuation zone entry.
570 		*/
571 		for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
572 			continue;
573 		outzone(&zones[i], j - i);
574 	}
575 	/*
576 	** Make links.
577 	*/
578 	for (i = 0; i < nlinks; ++i) {
579 		eat(links[i].l_filename, links[i].l_linenum);
580 		dolink(links[i].l_from, links[i].l_to);
581 		if (noise)
582 			for (j = 0; j < nlinks; ++j)
583 				if (strcmp(links[i].l_to,
584 					links[j].l_from) == 0)
585 						warning("link to link");
586 	}
587 	if (lcltime != NULL) {
588 		eat("command line", 1);
589 		dolink(lcltime, TZDEFAULT);
590 	}
591 	if (psxrules != NULL) {
592 		eat("command line", 1);
593 		dolink(psxrules, TZDEFRULES);
594 	}
595 	return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
596 }
597 
598 static void
dolink(const char * fromfield,const char * tofield)599 dolink(const char *fromfield, const char *tofield)
600 {
601 	char	*fromname, *toname;
602 
603 	if (fromfield[0] == '/')
604 		fromname = ecpyalloc(fromfield);
605 	else {
606 		fromname = ecpyalloc(directory);
607 		fromname = ecatalloc(fromname, "/");
608 		fromname = ecatalloc(fromname, fromfield);
609 	}
610 	if (tofield[0] == '/')
611 		toname = ecpyalloc(tofield);
612 	else {
613 		toname = ecpyalloc(directory);
614 		toname = ecatalloc(toname, "/");
615 		toname = ecatalloc(toname, tofield);
616 	}
617 	/*
618 	** We get to be careful here since
619 	** there's a fair chance of root running us.
620 	*/
621 	if (!itsdir(toname))
622 		remove(toname);
623 	if (link(fromname, toname) != 0) {
624 		int	result;
625 
626 		if (mkdirs(toname) != 0)
627 			exit(EXIT_FAILURE);
628 
629 		result = link(fromname, toname);
630 		if (result != 0 && errno == EXDEV)
631 			result = symlink(fromname, toname);
632 		if (result != 0)
633 			err(1, "Can't link from %s to %s", fromname, toname);
634 	}
635 	free(fromname);
636 	free(toname);
637 }
638 
639 #define TIME_T_BITS_IN_FILE	64
640 
641 static void
setboundaries(void)642 setboundaries(void)
643 {
644 	int	i;
645 
646 	min_time = -1;
647 	for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
648 		min_time *= 2;
649 	max_time = -(min_time + 1);
650 }
651 
652 static int
itsdir(const char * name)653 itsdir(const char *name)
654 {
655 	char	*myname;
656 	int	accres;
657 
658 	myname = ecpyalloc(name);
659 	myname = ecatalloc(myname, "/.");
660 	accres = access(myname, F_OK);
661 	free(myname);
662 	return accres == 0;
663 }
664 
665 /*
666 ** Associate sets of rules with zones.
667 */
668 
669 /*
670 ** Sort by rule name.
671 */
672 
673 static int
rcomp(const void * cp1,const void * cp2)674 rcomp(const void *cp1, const void *cp2)
675 {
676 	return strcmp(((const struct rule *) cp1)->r_name,
677 		((const struct rule *) cp2)->r_name);
678 }
679 
680 static void
associate(void)681 associate(void)
682 {
683 	struct zone	*zp;
684 	struct rule	*rp;
685 	int		base, out, i, j;
686 
687 	if (nrules != 0) {
688 		qsort(rules, nrules, sizeof *rules, rcomp);
689 		for (i = 0; i < nrules - 1; ++i) {
690 			if (strcmp(rules[i].r_name,
691 				rules[i + 1].r_name) != 0)
692 					continue;
693 			if (strcmp(rules[i].r_filename,
694 				rules[i + 1].r_filename) == 0)
695 					continue;
696 			eat(rules[i].r_filename, rules[i].r_linenum);
697 			warning("same rule name in multiple files");
698 			eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
699 			warning("same rule name in multiple files");
700 			for (j = i + 2; j < nrules; ++j) {
701 				if (strcmp(rules[i].r_name,
702 					rules[j].r_name) != 0)
703 						break;
704 				if (strcmp(rules[i].r_filename,
705 					rules[j].r_filename) == 0)
706 						continue;
707 				if (strcmp(rules[i + 1].r_filename,
708 					rules[j].r_filename) == 0)
709 						continue;
710 				break;
711 			}
712 			i = j - 1;
713 		}
714 	}
715 	for (i = 0; i < nzones; ++i) {
716 		zp = &zones[i];
717 		zp->z_rules = NULL;
718 		zp->z_nrules = 0;
719 	}
720 	for (base = 0; base < nrules; base = out) {
721 		rp = &rules[base];
722 		for (out = base + 1; out < nrules; ++out)
723 			if (strcmp(rp->r_name, rules[out].r_name) != 0)
724 				break;
725 		for (i = 0; i < nzones; ++i) {
726 			zp = &zones[i];
727 			if (strcmp(zp->z_rule, rp->r_name) != 0)
728 				continue;
729 			zp->z_rules = rp;
730 			zp->z_nrules = out - base;
731 		}
732 	}
733 	for (i = 0; i < nzones; ++i) {
734 		zp = &zones[i];
735 		if (zp->z_nrules == 0) {
736 			/*
737 			** Maybe we have a local standard time offset.
738 			*/
739 			eat(zp->z_filename, zp->z_linenum);
740 			zp->z_stdoff = gethms(zp->z_rule, "unruly zone",
741 				TRUE);
742 			/*
743 			** Note, though, that if there's no rule,
744 			** a '%s' in the format is a bad thing.
745 			*/
746 			if (zp->z_format_specifier == 's')
747 				error("%s in ruleless zone");
748 		}
749 	}
750 	if (errors)
751 		exit(EXIT_FAILURE);
752 }
753 
754 static void
infile(const char * name)755 infile(const char *name)
756 {
757 	FILE			*fp;
758 	char			**fields, *cp;
759 	const struct lookup	*lp;
760 	int			nfields, wantcont, num;
761 	char			buf[BUFSIZ];
762 
763 	if (strcmp(name, "-") == 0) {
764 		name = "standard input";
765 		fp = stdin;
766 	} else if ((fp = fopen(name, "r")) == NULL)
767 		err(1, "Can't open %s", name);
768 	wantcont = FALSE;
769 	for (num = 1; ; ++num) {
770 		eat(name, num);
771 		if (fgets(buf, sizeof buf, fp) != buf)
772 			break;
773 		cp = strchr(buf, '\n');
774 		if (cp == NULL) {
775 			error("line too long");
776 			exit(EXIT_FAILURE);
777 		}
778 		*cp = '\0';
779 		fields = getfields(buf);
780 		nfields = 0;
781 		while (fields[nfields] != NULL) {
782 			static char	nada;
783 
784 			if (strcmp(fields[nfields], "-") == 0)
785 				fields[nfields] = &nada;
786 			++nfields;
787 		}
788 		if (nfields == 0) {
789 			/* nothing to do */
790 		} else if (wantcont) {
791 			wantcont = inzcont(fields, nfields);
792 		} else {
793 			lp = byword(fields[0], line_codes);
794 			if (lp == NULL)
795 				error("input line of unknown type");
796 			else switch ((int) (lp->l_value)) {
797 				case LC_RULE:
798 					inrule(fields, nfields);
799 					wantcont = FALSE;
800 					break;
801 				case LC_ZONE:
802 					wantcont = inzone(fields, nfields);
803 					break;
804 				case LC_LINK:
805 					inlink(fields, nfields);
806 					wantcont = FALSE;
807 					break;
808 				case LC_LEAP:
809 					if (name != leapsec)
810 						fprintf(stderr,
811 						    "%s: Leap line in non leap seconds file %s\n",
812 							__progname, name);
813 						/* no exit? */
814 					else
815 						inleap(fields, nfields);
816 					wantcont = FALSE;
817 					break;
818 				default:	/* "cannot happen" */
819 					errx(1, "panic: Invalid l_value %d", lp->l_value);
820 			}
821 		}
822 		free(fields);
823 	}
824 	if (ferror(fp))
825 		errx(1, "Error reading %s", filename);
826 	if (fp != stdin && fclose(fp))
827 		err(1, "Error closing %s", filename);
828 	if (wantcont)
829 		error("expected continuation line not found");
830 }
831 
832 /*
833 ** Convert a string of one of the forms
834 **	h	-h	hh:mm	-hh:mm	hh:mm:ss	-hh:mm:ss
835 ** into a number of seconds.
836 ** A null string maps to zero.
837 ** Call error with errstring and return zero on errors.
838 */
839 
840 static long
gethms(const char * string,const char * errstring,int signable)841 gethms(const char *string, const char *errstring, int signable)
842 {
843 	long	hh;
844 	int	mm, ss, sign;
845 
846 	if (string == NULL || *string == '\0')
847 		return 0;
848 	if (!signable)
849 		sign = 1;
850 	else if (*string == '-') {
851 		sign = -1;
852 		++string;
853 	} else
854 		sign = 1;
855 	if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
856 		mm = ss = 0;
857 	else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
858 		ss = 0;
859 	else if (sscanf(string, scheck(string, "%ld:%d:%d"),
860 	    &hh, &mm, &ss) != 3) {
861 		error(errstring);
862 		return 0;
863 	}
864 	if (hh < 0 ||
865 	    mm < 0 || mm >= MINSPERHOUR ||
866 	    ss < 0 || ss > SECSPERMIN) {
867 		error(errstring);
868 		return 0;
869 	}
870 	if (LONG_MAX / SECSPERHOUR < hh) {
871 		error("time overflow");
872 		return 0;
873 	}
874 	return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
875 	    eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
876 }
877 
878 static void
inrule(char ** fields,int nfields)879 inrule(char **fields, int nfields)
880 {
881 	static struct rule	r;
882 
883 	if (nfields != RULE_FIELDS) {
884 		error("wrong number of fields on Rule line");
885 		return;
886 	}
887 	if (*fields[RF_NAME] == '\0') {
888 		error("nameless rule");
889 		return;
890 	}
891 	r.r_filename = filename;
892 	r.r_linenum = linenum;
893 	r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
894 	rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
895 		fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
896 	r.r_name = ecpyalloc(fields[RF_NAME]);
897 	r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
898 	if (max_abbrvar_len < strlen(r.r_abbrvar))
899 		max_abbrvar_len = strlen(r.r_abbrvar);
900 	rules = ereallocarray(rules, nrules + 1, sizeof *rules);
901 	rules[nrules++] = r;
902 }
903 
904 static int
inzone(char ** fields,int nfields)905 inzone(char **fields, int nfields)
906 {
907 	int	i;
908 	static char	*buf;
909 	size_t		len;
910 
911 	if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
912 		error("wrong number of fields on Zone line");
913 		return FALSE;
914 	}
915 	if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
916 		len = 132 + strlen(TZDEFAULT);
917 		buf = erealloc(buf, len);
918 		snprintf(buf, len,
919 		    "\"Zone %s\" line and -l option are mutually exclusive",
920 		    TZDEFAULT);
921 		error(buf);
922 		return FALSE;
923 	}
924 	if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
925 		len = 132 + strlen(TZDEFRULES);
926 		buf = erealloc(buf, len);
927 		snprintf(buf, len,
928 		    "\"Zone %s\" line and -p option are mutually exclusive",
929 		    TZDEFRULES);
930 		error(buf);
931 		return FALSE;
932 	}
933 	for (i = 0; i < nzones; ++i)
934 		if (zones[i].z_name != NULL &&
935 		    strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
936 			len = 132 + strlen(fields[ZF_NAME]) +
937 			    strlen(zones[i].z_filename);
938 			buf = erealloc(buf, len);
939 			snprintf(buf, len,
940 			    "duplicate zone name %s (file \"%s\", line %d)",
941 			    fields[ZF_NAME],
942 			    zones[i].z_filename,
943 			    zones[i].z_linenum);
944 			error(buf);
945 			return FALSE;
946 		}
947 	return inzsub(fields, nfields, FALSE);
948 }
949 
950 static int
inzcont(char ** fields,int nfields)951 inzcont(char **fields, int nfields)
952 {
953 	if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
954 		error("wrong number of fields on Zone continuation line");
955 		return FALSE;
956 	}
957 	return inzsub(fields, nfields, TRUE);
958 }
959 
960 static int
inzsub(char ** fields,int nfields,int iscont)961 inzsub(char **fields, int nfields, int iscont)
962 {
963 	char		*cp;
964 	char		*cp1;
965 	static struct zone	z;
966 	int		i_gmtoff, i_rule, i_format;
967 	int		i_untilyear, i_untilmonth;
968 	int		i_untilday, i_untiltime;
969 	int		hasuntil;
970 
971 	if (iscont) {
972 		i_gmtoff = ZFC_GMTOFF;
973 		i_rule = ZFC_RULE;
974 		i_format = ZFC_FORMAT;
975 		i_untilyear = ZFC_TILYEAR;
976 		i_untilmonth = ZFC_TILMONTH;
977 		i_untilday = ZFC_TILDAY;
978 		i_untiltime = ZFC_TILTIME;
979 		z.z_name = NULL;
980 	} else {
981 		i_gmtoff = ZF_GMTOFF;
982 		i_rule = ZF_RULE;
983 		i_format = ZF_FORMAT;
984 		i_untilyear = ZF_TILYEAR;
985 		i_untilmonth = ZF_TILMONTH;
986 		i_untilday = ZF_TILDAY;
987 		i_untiltime = ZF_TILTIME;
988 		z.z_name = ecpyalloc(fields[ZF_NAME]);
989 	}
990 	z.z_filename = filename;
991 	z.z_linenum = linenum;
992 	z.z_gmtoff = gethms(fields[i_gmtoff], "invalid UTC offset", TRUE);
993 	if ((cp = strchr(fields[i_format], '%')) != 0) {
994 		if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
995 		    || strchr(fields[i_format], '/')) {
996 			error("invalid abbreviation format");
997 			return FALSE;
998 		}
999 	}
1000 	z.z_rule = ecpyalloc(fields[i_rule]);
1001 	z.z_format = cp1 = ecpyalloc(fields[i_format]);
1002 	z.z_format_specifier = cp ? *cp : '\0';
1003 	if (z.z_format_specifier == 'z') {
1004 		if (noise) {
1005 			warning("format '%%z' not handled by pre-2015 versions "
1006 			    "of zic");
1007 		}
1008 		cp1[cp - fields[i_format]] = 's';
1009 	}
1010 	if (max_format_len < strlen(z.z_format))
1011 		max_format_len = strlen(z.z_format);
1012 	hasuntil = nfields > i_untilyear;
1013 	if (hasuntil) {
1014 		z.z_untilrule.r_filename = filename;
1015 		z.z_untilrule.r_linenum = linenum;
1016 		rulesub(&z.z_untilrule,
1017 			fields[i_untilyear],
1018 			"only",
1019 			"",
1020 			(nfields > i_untilmonth) ?
1021 			fields[i_untilmonth] : "Jan",
1022 			(nfields > i_untilday) ? fields[i_untilday] : "1",
1023 			(nfields > i_untiltime) ? fields[i_untiltime] : "0");
1024 		z.z_untiltime = rpytime(&z.z_untilrule,
1025 			z.z_untilrule.r_loyear);
1026 		if (iscont && nzones > 0 &&
1027 		    z.z_untiltime > min_time &&
1028 		    z.z_untiltime < max_time &&
1029 		    zones[nzones - 1].z_untiltime > min_time &&
1030 		    zones[nzones - 1].z_untiltime < max_time &&
1031 		    zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1032 			error("Zone continuation line end time is not after end time of previous line");
1033 			return FALSE;
1034 		}
1035 	}
1036 	zones = ereallocarray(zones, nzones + 1, sizeof *zones);
1037 	zones[nzones++] = z;
1038 	/*
1039 	** If there was an UNTIL field on this line,
1040 	** there's more information about the zone on the next line.
1041 	*/
1042 	return hasuntil;
1043 }
1044 
1045 static void
inleap(char ** fields,int nfields)1046 inleap(char **fields, int nfields)
1047 {
1048 	const char		*cp;
1049 	const struct lookup	*lp;
1050 	int			i, j;
1051 	int			year, month, day;
1052 	long			dayoff, tod;
1053 	zic_t			t;
1054 
1055 	if (nfields != LEAP_FIELDS) {
1056 		error("wrong number of fields on Leap line");
1057 		return;
1058 	}
1059 	dayoff = 0;
1060 	cp = fields[LP_YEAR];
1061 	if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1062 		/*
1063 		** Leapin' Lizards!
1064 		*/
1065 		error("invalid leaping year");
1066 		return;
1067 	}
1068 	if (!leapseen || leapmaxyear < year)
1069 		leapmaxyear = year;
1070 	if (!leapseen || leapminyear > year)
1071 		leapminyear = year;
1072 	leapseen = TRUE;
1073 	j = EPOCH_YEAR;
1074 	while (j != year) {
1075 		if (year > j) {
1076 			i = len_years[isleap(j)];
1077 			++j;
1078 		} else {
1079 			--j;
1080 			i = -len_years[isleap(j)];
1081 		}
1082 		dayoff = oadd(dayoff, eitol(i));
1083 	}
1084 	if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1085 		error("invalid month name");
1086 		return;
1087 	}
1088 	month = lp->l_value;
1089 	j = TM_JANUARY;
1090 	while (j != month) {
1091 		i = len_months[isleap(year)][j];
1092 		dayoff = oadd(dayoff, eitol(i));
1093 		++j;
1094 	}
1095 	cp = fields[LP_DAY];
1096 	if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1097 	    day <= 0 || day > len_months[isleap(year)][month]) {
1098 		error("invalid day of month");
1099 		return;
1100 	}
1101 	dayoff = oadd(dayoff, eitol(day - 1));
1102 	if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1103 		error("time before zero");
1104 		return;
1105 	}
1106 	if (dayoff < min_time / SECSPERDAY) {
1107 		error("time too small");
1108 		return;
1109 	}
1110 	if (dayoff > max_time / SECSPERDAY) {
1111 		error("time too large");
1112 		return;
1113 	}
1114 	t = (zic_t) dayoff * SECSPERDAY;
1115 	tod = gethms(fields[LP_TIME], "invalid time of day", FALSE);
1116 	cp = fields[LP_CORR];
1117 	{
1118 		int	positive;
1119 		int		count;
1120 
1121 		if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1122 			positive = FALSE;
1123 			count = 1;
1124 		} else if (strcmp(cp, "--") == 0) {
1125 			positive = FALSE;
1126 			count = 2;
1127 		} else if (strcmp(cp, "+") == 0) {
1128 			positive = TRUE;
1129 			count = 1;
1130 		} else if (strcmp(cp, "++") == 0) {
1131 			positive = TRUE;
1132 			count = 2;
1133 		} else {
1134 			error("illegal CORRECTION field on Leap line");
1135 			return;
1136 		}
1137 		if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1138 			error("illegal Rolling/Stationary field on Leap line");
1139 			return;
1140 		}
1141 		leapadd(tadd(t, tod), positive, lp->l_value, count);
1142 	}
1143 }
1144 
1145 static void
inlink(char ** fields,int nfields)1146 inlink(char **fields, int nfields)
1147 {
1148 	struct link	l;
1149 
1150 	if (nfields != LINK_FIELDS) {
1151 		error("wrong number of fields on Link line");
1152 		return;
1153 	}
1154 	if (*fields[LF_FROM] == '\0') {
1155 		error("blank FROM field on Link line");
1156 		return;
1157 	}
1158 	if (*fields[LF_TO] == '\0') {
1159 		error("blank TO field on Link line");
1160 		return;
1161 	}
1162 	l.l_filename = filename;
1163 	l.l_linenum = linenum;
1164 	l.l_from = ecpyalloc(fields[LF_FROM]);
1165 	l.l_to = ecpyalloc(fields[LF_TO]);
1166 	links = ereallocarray(links, nlinks + 1, sizeof *links);
1167 	links[nlinks++] = l;
1168 }
1169 
1170 static void
rulesub(struct rule * const rp,const char * const loyearp,const char * const hiyearp,const char * const typep,const char * const monthp,const char * const dayp,const char * const timep)1171 rulesub(struct rule * const rp, const char * const loyearp,
1172     const char * const hiyearp, const char * const typep,
1173     const char * const monthp, const char * const dayp,
1174     const char * const timep)
1175 {
1176 	const struct lookup	*lp;
1177 	const char		*cp;
1178 	char			*dp, *ep;
1179 
1180 	if ((lp = byword(monthp, mon_names)) == NULL) {
1181 		error("invalid month name");
1182 		return;
1183 	}
1184 	rp->r_month = lp->l_value;
1185 	rp->r_todisstd = FALSE;
1186 	rp->r_todisgmt = FALSE;
1187 	dp = ecpyalloc(timep);
1188 	if (*dp != '\0') {
1189 		ep = dp + strlen(dp) - 1;
1190 		switch (tolower((unsigned char)*ep)) {
1191 		case 's':	/* Standard */
1192 			rp->r_todisstd = TRUE;
1193 			rp->r_todisgmt = FALSE;
1194 			*ep = '\0';
1195 			break;
1196 		case 'w':	/* Wall */
1197 			rp->r_todisstd = FALSE;
1198 			rp->r_todisgmt = FALSE;
1199 			*ep = '\0';
1200 			break;
1201 		case 'g':	/* Greenwich */
1202 		case 'u':	/* Universal */
1203 		case 'z':	/* Zulu */
1204 			rp->r_todisstd = TRUE;
1205 			rp->r_todisgmt = TRUE;
1206 			*ep = '\0';
1207 			break;
1208 		}
1209 	}
1210 	rp->r_tod = gethms(dp, "invalid time of day", FALSE);
1211 	free(dp);
1212 	/*
1213 	** Year work.
1214 	*/
1215 	cp = loyearp;
1216 	lp = byword(cp, begin_years);
1217 	rp->r_lowasnum = lp == NULL;
1218 	if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1219 		case YR_MINIMUM:
1220 			rp->r_loyear = INT_MIN;
1221 			break;
1222 		case YR_MAXIMUM:
1223 			rp->r_loyear = INT_MAX;
1224 			break;
1225 		default:	/* "cannot happen" */
1226 			errx(1, "panic: Invalid l_value %d", lp->l_value);
1227 	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1228 		error("invalid starting year");
1229 		return;
1230 	}
1231 	cp = hiyearp;
1232 	lp = byword(cp, end_years);
1233 	rp->r_hiwasnum = lp == NULL;
1234 	if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1235 		case YR_MINIMUM:
1236 			rp->r_hiyear = INT_MIN;
1237 			break;
1238 		case YR_MAXIMUM:
1239 			rp->r_hiyear = INT_MAX;
1240 			break;
1241 		case YR_ONLY:
1242 			rp->r_hiyear = rp->r_loyear;
1243 			break;
1244 		default:	/* "cannot happen" */
1245 			errx(1, "panic: Invalid l_value %d", lp->l_value);
1246 	} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1247 		error("invalid ending year");
1248 		return;
1249 	}
1250 	if (rp->r_loyear > rp->r_hiyear) {
1251 		error("starting year greater than ending year");
1252 		return;
1253 	}
1254 	if (*typep != '\0') {
1255 		if (rp->r_loyear == rp->r_hiyear) {
1256 			error("typed single year");
1257 			return;
1258 		}
1259 		warning("year type is obsolete; use \"-\" instead");
1260 	}
1261 	/*
1262 	** Day work.
1263 	** Accept things such as:
1264 	**	1
1265 	**	last-Sunday
1266 	**	Sun<=20
1267 	**	Sun>=7
1268 	*/
1269 	dp = ecpyalloc(dayp);
1270 	if ((lp = byword(dp, lasts)) != NULL) {
1271 		rp->r_dycode = DC_DOWLEQ;
1272 		rp->r_wday = lp->l_value;
1273 		rp->r_dayofmonth = len_months[1][rp->r_month];
1274 	} else {
1275 		if ((ep = strchr(dp, '<')) != 0)
1276 			rp->r_dycode = DC_DOWLEQ;
1277 		else if ((ep = strchr(dp, '>')) != 0)
1278 			rp->r_dycode = DC_DOWGEQ;
1279 		else {
1280 			ep = dp;
1281 			rp->r_dycode = DC_DOM;
1282 		}
1283 		if (rp->r_dycode != DC_DOM) {
1284 			*ep++ = 0;
1285 			if (*ep++ != '=') {
1286 				error("invalid day of month");
1287 				free(dp);
1288 				return;
1289 			}
1290 			if ((lp = byword(dp, wday_names)) == NULL) {
1291 				error("invalid weekday name");
1292 				free(dp);
1293 				return;
1294 			}
1295 			rp->r_wday = lp->l_value;
1296 		}
1297 		if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1298 		    rp->r_dayofmonth <= 0 ||
1299 		    (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1300 			error("invalid day of month");
1301 			free(dp);
1302 			return;
1303 		}
1304 	}
1305 	free(dp);
1306 }
1307 
1308 static void
convert(long val,char * buf)1309 convert(long val, char *buf)
1310 {
1311 	int	i;
1312 	int	shift;
1313 
1314 	for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1315 		buf[i] = val >> shift;
1316 }
1317 
1318 static void
convert64(zic_t val,char * buf)1319 convert64(zic_t val, char *buf)
1320 {
1321 	int	i;
1322 	int	shift;
1323 
1324 	for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1325 		buf[i] = val >> shift;
1326 }
1327 
1328 static void
puttzcode(long val,FILE * fp)1329 puttzcode(long val, FILE *fp)
1330 {
1331 	char	buf[4];
1332 
1333 	convert(val, buf);
1334 	fwrite(buf, sizeof buf, 1, fp);
1335 }
1336 
1337 static void
puttzcode64(zic_t val,FILE * fp)1338 puttzcode64(zic_t val, FILE *fp)
1339 {
1340 	char	buf[8];
1341 
1342 	convert64(val, buf);
1343 	fwrite(buf, sizeof buf, 1, fp);
1344 }
1345 
1346 static int
atcomp(const void * avp,const void * bvp)1347 atcomp(const void *avp, const void *bvp)
1348 {
1349 	const zic_t	a = ((const struct attype *) avp)->at;
1350 	const zic_t	b = ((const struct attype *) bvp)->at;
1351 
1352 	return (a < b) ? -1 : (a > b);
1353 }
1354 
1355 static int
is32(zic_t x)1356 is32(zic_t x)
1357 {
1358 	return INT32_MIN <= x && x <= INT32_MAX;
1359 }
1360 
1361 static void
writezone(const char * name,const char * string)1362 writezone(const char *name, const char *string)
1363 {
1364 	FILE			*fp;
1365 	int			i, j;
1366 	int			leapcnt32, leapi32;
1367 	int			timecnt32, timei32;
1368 	int			pass;
1369 	static char		*fullname;
1370 	static const struct tzhead	tzh0;
1371 	static struct tzhead	tzh;
1372 	zic_t			ats[TZ_MAX_TIMES];
1373 	unsigned char		types[TZ_MAX_TIMES];
1374 	size_t			len;
1375 
1376 	/*
1377 	** Sort.
1378 	*/
1379 	if (timecnt > 1)
1380 		qsort(attypes, timecnt, sizeof *attypes, atcomp);
1381 	/*
1382 	** Optimize.
1383 	*/
1384 	{
1385 		int	fromi;
1386 		int	toi;
1387 
1388 		toi = 0;
1389 		fromi = 0;
1390 		while (fromi < timecnt && attypes[fromi].at < min_time)
1391 			++fromi;
1392 		if (isdsts[0] == 0)
1393 			while (fromi < timecnt && attypes[fromi].type == 0)
1394 				++fromi;	/* handled by default rule */
1395 		for ( ; fromi < timecnt; ++fromi) {
1396 			if (toi != 0 && ((attypes[fromi].at +
1397 			    gmtoffs[attypes[toi - 1].type]) <=
1398 			    (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 :
1399 			    attypes[toi - 2].type]))) {
1400 				attypes[toi - 1].type = attypes[fromi].type;
1401 				continue;
1402 			}
1403 			if (toi == 0 ||
1404 			    attypes[toi - 1].type != attypes[fromi].type)
1405 				attypes[toi++] = attypes[fromi];
1406 		}
1407 		timecnt = toi;
1408 	}
1409 	/*
1410 	** Transfer.
1411 	*/
1412 	for (i = 0; i < timecnt; ++i) {
1413 		ats[i] = attypes[i].at;
1414 		types[i] = attypes[i].type;
1415 	}
1416 	/*
1417 	** Correct for leap seconds.
1418 	*/
1419 	for (i = 0; i < timecnt; ++i) {
1420 		j = leapcnt;
1421 		while (--j >= 0)
1422 			if (ats[i] > trans[j] - corr[j]) {
1423 				ats[i] = tadd(ats[i], corr[j]);
1424 				break;
1425 			}
1426 	}
1427 	/*
1428 	** Figure out 32-bit-limited starts and counts.
1429 	*/
1430 	timecnt32 = timecnt;
1431 	timei32 = 0;
1432 	leapcnt32 = leapcnt;
1433 	leapi32 = 0;
1434 	while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1435 		--timecnt32;
1436 	while (timecnt32 > 0 && !is32(ats[timei32])) {
1437 		--timecnt32;
1438 		++timei32;
1439 	}
1440 	while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1441 		--leapcnt32;
1442 	while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1443 		--leapcnt32;
1444 		++leapi32;
1445 	}
1446 	len = strlen(directory) + 1 + strlen(name) + 1;
1447 	fullname = erealloc(fullname, len);
1448 	snprintf(fullname, len, "%s/%s", directory, name);
1449 	/*
1450 	** Remove old file, if any, to snap links.
1451 	*/
1452 	if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT)
1453 		err(1, "Can't remove %s", fullname);
1454 	if ((fp = fopen(fullname, "wb")) == NULL) {
1455 		if (mkdirs(fullname) != 0)
1456 			exit(EXIT_FAILURE);
1457 		if ((fp = fopen(fullname, "wb")) == NULL)
1458 			err(1, "Can't create %s", fullname);
1459 	}
1460 	for (pass = 1; pass <= 2; ++pass) {
1461 		int	thistimei, thistimecnt;
1462 		int	thisleapi, thisleapcnt;
1463 		int	thistimelim, thisleaplim;
1464 		int	writetype[TZ_MAX_TIMES];
1465 		int	typemap[TZ_MAX_TYPES];
1466 		int	thistypecnt;
1467 		char	thischars[TZ_MAX_CHARS];
1468 		char	thischarcnt;
1469 		int	indmap[TZ_MAX_CHARS];
1470 
1471 		if (pass == 1) {
1472 			thistimei = timei32;
1473 			thistimecnt = timecnt32;
1474 			thisleapi = leapi32;
1475 			thisleapcnt = leapcnt32;
1476 		} else {
1477 			thistimei = 0;
1478 			thistimecnt = timecnt;
1479 			thisleapi = 0;
1480 			thisleapcnt = leapcnt;
1481 		}
1482 		thistimelim = thistimei + thistimecnt;
1483 		thisleaplim = thisleapi + thisleapcnt;
1484 		for (i = 0; i < typecnt; ++i)
1485 			writetype[i] = thistimecnt == timecnt;
1486 		if (thistimecnt == 0) {
1487 			/*
1488 			** No transition times fall in the current
1489 			** (32- or 64-bit) window.
1490 			*/
1491 			if (typecnt != 0)
1492 				writetype[typecnt - 1] = TRUE;
1493 		} else {
1494 			for (i = thistimei - 1; i < thistimelim; ++i)
1495 				if (i >= 0)
1496 					writetype[types[i]] = TRUE;
1497 			/*
1498 			** For America/Godthab and Antarctica/Palmer
1499 			*/
1500 			if (thistimei == 0)
1501 				writetype[0] = TRUE;
1502 		}
1503 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1504 		/*
1505 		** For some pre-2011 systems: if the last-to-be-written
1506 		** standard (or daylight) type has an offset different from the
1507 		** most recently used offset,
1508 		** append an (unused) copy of the most recently used type
1509 		** (to help get global "altzone" and "timezone" variables
1510 		** set correctly).
1511 		*/
1512 		{
1513 			int	mrudst, mrustd, hidst, histd, type;
1514 
1515 			hidst = histd = mrudst = mrustd = -1;
1516 			for (i = thistimei; i < thistimelim; ++i)
1517 				if (isdsts[types[i]])
1518 					mrudst = types[i];
1519 				else
1520 					mrustd = types[i];
1521 			for (i = 0; i < typecnt; ++i)
1522 				if (writetype[i]) {
1523 					if (isdsts[i])
1524 						hidst = i;
1525 					else
1526 						histd = i;
1527 				}
1528 			if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1529 			    gmtoffs[hidst] != gmtoffs[mrudst]) {
1530 				isdsts[mrudst] = -1;
1531 				type = addtype(gmtoffs[mrudst],
1532 				    &chars[abbrinds[mrudst]],
1533 				    TRUE, ttisstds[mrudst],
1534 				    ttisgmts[mrudst]);
1535 				isdsts[mrudst] = TRUE;
1536 				writetype[type] = TRUE;
1537 			}
1538 			if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1539 			    gmtoffs[histd] != gmtoffs[mrustd]) {
1540 				isdsts[mrustd] = -1;
1541 				type = addtype(gmtoffs[mrustd],
1542 				    &chars[abbrinds[mrustd]],
1543 				    FALSE, ttisstds[mrustd],
1544 				    ttisgmts[mrustd]);
1545 				isdsts[mrustd] = FALSE;
1546 				writetype[type] = TRUE;
1547 			}
1548 		}
1549 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1550 		thistypecnt = 0;
1551 		for (i = 0; i < typecnt; ++i)
1552 			typemap[i] = writetype[i] ?  thistypecnt++ : -1;
1553 		for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1554 			indmap[i] = -1;
1555 		thischarcnt = 0;
1556 		for (i = 0; i < typecnt; ++i) {
1557 			char	*thisabbr;
1558 
1559 			if (!writetype[i])
1560 				continue;
1561 			if (indmap[abbrinds[i]] >= 0)
1562 				continue;
1563 			thisabbr = &chars[abbrinds[i]];
1564 			for (j = 0; j < thischarcnt; ++j)
1565 				if (strcmp(&thischars[j], thisabbr) == 0)
1566 					break;
1567 			if (j == thischarcnt) {
1568 				strlcpy(&thischars[(int) thischarcnt],
1569 				    thisabbr, sizeof(thischars) - thischarcnt);
1570 				thischarcnt += strlen(thisabbr) + 1;
1571 			}
1572 			indmap[abbrinds[i]] = j;
1573 		}
1574 #define DO(field)	fwrite(tzh.field, sizeof tzh.field, 1, fp)
1575 		tzh = tzh0;
1576 		strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1577 		tzh.tzh_version[0] = ZIC_VERSION;
1578 		convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
1579 		convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
1580 		convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
1581 		convert(eitol(thistimecnt), tzh.tzh_timecnt);
1582 		convert(eitol(thistypecnt), tzh.tzh_typecnt);
1583 		convert(eitol(thischarcnt), tzh.tzh_charcnt);
1584 		DO(tzh_magic);
1585 		DO(tzh_version);
1586 		DO(tzh_reserved);
1587 		DO(tzh_ttisgmtcnt);
1588 		DO(tzh_ttisstdcnt);
1589 		DO(tzh_leapcnt);
1590 		DO(tzh_timecnt);
1591 		DO(tzh_typecnt);
1592 		DO(tzh_charcnt);
1593 #undef DO
1594 		for (i = thistimei; i < thistimelim; ++i)
1595 			if (pass == 1)
1596 				puttzcode((long) ats[i], fp);
1597 			else
1598 				puttzcode64(ats[i], fp);
1599 		for (i = thistimei; i < thistimelim; ++i) {
1600 			unsigned char	uc;
1601 
1602 			uc = typemap[types[i]];
1603 			fwrite(&uc, sizeof uc, 1, fp);
1604 		}
1605 		for (i = 0; i < typecnt; ++i)
1606 			if (writetype[i]) {
1607 				puttzcode(gmtoffs[i], fp);
1608 				putc(isdsts[i], fp);
1609 				putc((unsigned char)indmap[abbrinds[i]], fp);
1610 			}
1611 		if (thischarcnt != 0)
1612 			fwrite(thischars, sizeof thischars[0], thischarcnt, fp);
1613 		for (i = thisleapi; i < thisleaplim; ++i) {
1614 			zic_t	todo;
1615 
1616 			if (roll[i]) {
1617 				if (timecnt == 0 || trans[i] < ats[0]) {
1618 					j = 0;
1619 					while (isdsts[j])
1620 						if (++j >= typecnt) {
1621 							j = 0;
1622 							break;
1623 						}
1624 				} else {
1625 					j = 1;
1626 					while (j < timecnt &&
1627 					    trans[i] >= ats[j])
1628 						++j;
1629 					j = types[j - 1];
1630 				}
1631 				todo = tadd(trans[i], -gmtoffs[j]);
1632 			} else
1633 				todo = trans[i];
1634 			if (pass == 1)
1635 				puttzcode((long) todo, fp);
1636 			else
1637 				puttzcode64(todo, fp);
1638 			puttzcode(corr[i], fp);
1639 		}
1640 		for (i = 0; i < typecnt; ++i)
1641 			if (writetype[i])
1642 				putc(ttisstds[i], fp);
1643 		for (i = 0; i < typecnt; ++i)
1644 			if (writetype[i])
1645 				putc(ttisgmts[i], fp);
1646 	}
1647 	fprintf(fp, "\n%s\n", string);
1648 	if (ferror(fp) || fclose(fp))
1649 		errx(1, "Error writing %s", fullname);
1650 }
1651 
1652 static char const *
abbroffset(char * buf,zic_t offset)1653 abbroffset(char *buf, zic_t offset)
1654 {
1655 	char sign = '+';
1656 	int seconds, minutes;
1657 
1658 	if (offset < 0) {
1659 		offset = -offset;
1660 		sign = '-';
1661 	}
1662 
1663 	seconds = offset % SECSPERMIN;
1664 	offset /= SECSPERMIN;
1665 	minutes = offset % MINSPERHOUR;
1666 	offset /= MINSPERHOUR;
1667 	if (100 <= offset) {
1668 		error("%%z UTC offset magnitude exceeds 99:59:59");
1669 		return "%z";
1670 	} else {
1671 		char *p = buf;
1672 		*p++ = sign;
1673 		*p++ = '0' + offset / 10;
1674 		*p++ = '0' + offset % 10;
1675 		if (minutes | seconds) {
1676 			*p++ = '0' + minutes / 10;
1677 			*p++ = '0' + minutes % 10;
1678 			if (seconds) {
1679 				*p++ = '0' + seconds / 10;
1680 				*p++ = '0' + seconds % 10;
1681 			}
1682 		}
1683 		*p = '\0';
1684 		return buf;
1685 	}
1686 }
1687 
1688 static void
doabbr(char * abbr,size_t size,struct zone const * zp,const char * letters,int isdst,int doquotes)1689 doabbr(char *abbr, size_t size, struct zone const *zp, const char *letters,
1690     int isdst, int doquotes)
1691 {
1692 	char	*cp, *slashp;
1693 	size_t	len;
1694 	char const *format = zp->z_format;
1695 
1696 	slashp = strchr(format, '/');
1697 	if (slashp == NULL) {
1698 		char letterbuf[PERCENT_Z_LEN_BOUND + 1];
1699 		if (zp->z_format_specifier == 'z')
1700 			letters = abbroffset(letterbuf, -zp->z_gmtoff);
1701 		else if (letters == NULL)
1702 			letters = "%s";
1703 		snprintf(abbr, size, format, letters);
1704 	} else if (isdst) {
1705 		strlcpy(abbr, slashp + 1, size);
1706 	} else {
1707 		if (slashp - format + 1 < size)
1708 			size = slashp - format + 1;
1709 		strlcpy(abbr, format, size);
1710 	}
1711 	if (!doquotes)
1712 		return;
1713 	for (cp = abbr; *cp != '\0'; ++cp)
1714 		if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
1715 			strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
1716 				break;
1717 	len = strlen(abbr);
1718 	if (len > 0 && *cp == '\0')
1719 		return;
1720 	abbr[len + 2] = '\0';
1721 	abbr[len + 1] = '>';
1722 	for ( ; len > 0; --len)
1723 		abbr[len] = abbr[len - 1];
1724 	abbr[0] = '<';
1725 }
1726 
1727 static void
updateminmax(int x)1728 updateminmax(int x)
1729 {
1730 	if (min_year > x)
1731 		min_year = x;
1732 	if (max_year < x)
1733 		max_year = x;
1734 }
1735 
1736 static int
stringoffset(char * result,size_t size,long offset)1737 stringoffset(char *result, size_t size, long offset)
1738 {
1739 	int	hours, minutes, seconds;
1740 	char	*ep;
1741 
1742 	result[0] = '\0';
1743 	if (offset < 0) {
1744 		strlcpy(result, "-", size);
1745 		offset = -offset;
1746 	}
1747 	seconds = offset % SECSPERMIN;
1748 	offset /= SECSPERMIN;
1749 	minutes = offset % MINSPERHOUR;
1750 	offset /= MINSPERHOUR;
1751 	hours = offset;
1752 	if (hours >= HOURSPERDAY) {
1753 		result[0] = '\0';
1754 		return -1;
1755 	}
1756 	ep = end(result, size);
1757 	snprintf(ep, size - (ep - result), "%d", hours);
1758 	if (minutes != 0 || seconds != 0) {
1759 		ep = end(result, size);
1760 		snprintf(ep, size - (ep - result), ":%02d", minutes);
1761 		if (seconds != 0) {
1762 			ep = end(result, size);
1763 			snprintf(ep, size - (ep - result), ":%02d", seconds);
1764 		}
1765 	}
1766 	return 0;
1767 }
1768 
1769 static int
stringrule(char * result,size_t size,const struct rule * rp,long dstoff,long gmtoff)1770 stringrule(char *result, size_t size, const struct rule *rp, long dstoff, long gmtoff)
1771 {
1772 	long	tod;
1773 	char	*ep;
1774 
1775 	ep = end(result, size);
1776 	size -= ep - result;
1777 	result = ep;
1778 	if (rp->r_dycode == DC_DOM) {
1779 		int	month, total;
1780 
1781 		if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
1782 			return -1;
1783 		total = 0;
1784 		for (month = 0; month < rp->r_month; ++month)
1785 			total += len_months[0][month];
1786 		snprintf(result, size, "J%d", total + rp->r_dayofmonth);
1787 	} else {
1788 		int	week;
1789 
1790 		if (rp->r_dycode == DC_DOWGEQ) {
1791 			if ((rp->r_dayofmonth % DAYSPERWEEK) != 1)
1792 				return -1;
1793 			week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
1794 		} else if (rp->r_dycode == DC_DOWLEQ) {
1795 			if (rp->r_dayofmonth == len_months[1][rp->r_month])
1796 				week = 5;
1797 			else {
1798 				if ((rp->r_dayofmonth % DAYSPERWEEK) != 0)
1799 					return -1;
1800 				week = rp->r_dayofmonth / DAYSPERWEEK;
1801 			}
1802 		} else
1803 			return -1;	/* "cannot happen" */
1804 		snprintf(result, size, "M%d.%d.%d",
1805 			rp->r_month + 1, week, rp->r_wday);
1806 	}
1807 	tod = rp->r_tod;
1808 	if (rp->r_todisgmt)
1809 		tod += gmtoff;
1810 	if (rp->r_todisstd && rp->r_stdoff == 0)
1811 		tod += dstoff;
1812 	if (tod < 0) {
1813 		result[0] = '\0';
1814 		return -1;
1815 	}
1816 	if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
1817 		strlcat(result, "/", size);
1818 		ep = end(result, size);
1819 		if (stringoffset(ep, size - (ep - result), tod) != 0)
1820 			return -1;
1821 	}
1822 	return 0;
1823 }
1824 
1825 static void
stringzone(char * result,size_t size,const struct zone * zpfirst,int zonecount)1826 stringzone(char *result, size_t size, const struct zone *zpfirst, int zonecount)
1827 {
1828 	const struct zone	*zp;
1829 	struct rule		*rp, *stdrp, *dstrp;
1830 	int			i;
1831 	const char		*abbrvar;
1832 	char			*ep;
1833 
1834 	result[0] = '\0';
1835 	zp = zpfirst + zonecount - 1;
1836 	stdrp = dstrp = NULL;
1837 	for (i = 0; i < zp->z_nrules; ++i) {
1838 		rp = &zp->z_rules[i];
1839 		if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
1840 			continue;
1841 		if (rp->r_stdoff == 0) {
1842 			if (stdrp == NULL)
1843 				stdrp = rp;
1844 			else
1845 				return;
1846 		} else {
1847 			if (dstrp == NULL)
1848 				dstrp = rp;
1849 			else
1850 				return;
1851 		}
1852 	}
1853 	if (stdrp == NULL && dstrp == NULL) {
1854 		/*
1855 		** There are no rules running through "max".
1856 		** Let's find the latest rule.
1857 		*/
1858 		for (i = 0; i < zp->z_nrules; ++i) {
1859 			rp = &zp->z_rules[i];
1860 			if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
1861 				(rp->r_hiyear == stdrp->r_hiyear &&
1862 				rp->r_month > stdrp->r_month))
1863 					stdrp = rp;
1864 		}
1865 		if (stdrp != NULL && stdrp->r_stdoff != 0)
1866 			return;	/* We end up in DST (a POSIX no-no). */
1867 		/*
1868 		** Horrid special case: if year is 2037,
1869 		** presume this is a zone handled on a year-by-year basis;
1870 		** do not try to apply a rule to the zone.
1871 		*/
1872 		if (stdrp != NULL && stdrp->r_hiyear == 2037)
1873 			return;
1874 	}
1875 	if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
1876 		return;
1877 	abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
1878 	doabbr(result, size, zp, abbrvar, FALSE, TRUE);
1879 	ep = end(result, size);
1880 	if (stringoffset(ep, size - (ep - result), -zp->z_gmtoff) != 0) {
1881 		result[0] = '\0';
1882 		return;
1883 	}
1884 	if (dstrp == NULL)
1885 		return;
1886 	ep = end(result, size);
1887 	doabbr(ep, size - (ep - result), zp, dstrp->r_abbrvar, TRUE, TRUE);
1888 	if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
1889 		ep = end(result, size);
1890 		if (stringoffset(ep, size - (ep - result),
1891 			-(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
1892 				result[0] = '\0';
1893 				return;
1894 		}
1895 	}
1896 	strlcat(result, ",", size);
1897 	if (stringrule(result, size, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
1898 		result[0] = '\0';
1899 		return;
1900 	}
1901 	strlcat(result, ",", size);
1902 	if (stringrule(result, size, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
1903 		result[0] = '\0';
1904 		return;
1905 	}
1906 }
1907 
1908 static void
outzone(const struct zone * zpfirst,int zonecount)1909 outzone(const struct zone *zpfirst, int zonecount)
1910 {
1911 	const struct zone	*zp;
1912 	struct rule		*rp;
1913 	int			i, j, usestart, useuntil, type;
1914 	zic_t			starttime = 0, untiltime = 0;
1915 	long			gmtoff, stdoff, startoff;
1916 	int			year, startttisstd = FALSE, startttisgmt = FALSE;
1917 	char			*startbuf, *ab, *envvar;
1918 	int			max_abbr_len, max_envvar_len;
1919 	int			prodstic; /* all rules are min to max */
1920 
1921 	max_abbr_len = 2 + max_format_len + max_abbrvar_len;
1922 	max_envvar_len = 2 * max_abbr_len + 5 * 9;
1923 	startbuf = emalloc(max_abbr_len + 1);
1924 	ab = emalloc(max_abbr_len + 1);
1925 	envvar = emalloc(max_envvar_len + 1);
1926 	/*
1927 	** Now. . .finally. . .generate some useful data!
1928 	*/
1929 	timecnt = 0;
1930 	typecnt = 0;
1931 	charcnt = 0;
1932 	prodstic = zonecount == 1;
1933 	/*
1934 	** Thanks to Earl Chew
1935 	** for noting the need to unconditionally initialize startttisstd.
1936 	*/
1937 	min_year = max_year = EPOCH_YEAR;
1938 	if (leapseen) {
1939 		updateminmax(leapminyear);
1940 		updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
1941 	}
1942 	for (i = 0; i < zonecount; ++i) {
1943 		zp = &zpfirst[i];
1944 		if (i < zonecount - 1)
1945 			updateminmax(zp->z_untilrule.r_loyear);
1946 		for (j = 0; j < zp->z_nrules; ++j) {
1947 			rp = &zp->z_rules[j];
1948 			if (rp->r_lowasnum)
1949 				updateminmax(rp->r_loyear);
1950 			if (rp->r_hiwasnum)
1951 				updateminmax(rp->r_hiyear);
1952 			if (rp->r_lowasnum || rp->r_hiwasnum)
1953 				prodstic = FALSE;
1954 		}
1955 	}
1956 	/*
1957 	** Generate lots of data if a rule can't cover all future times.
1958 	*/
1959 	stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount);
1960 	if (noise && envvar[0] == '\0') {
1961 		char *	wp;
1962 
1963 		wp = ecpyalloc("no POSIX environment variable for zone");
1964 		wp = ecatalloc(wp, " ");
1965 		wp = ecatalloc(wp, zpfirst->z_name);
1966 		warning(wp);
1967 		free(wp);
1968 	}
1969 	if (envvar[0] == '\0') {
1970 		if (min_year >= INT_MIN + YEARSPERREPEAT)
1971 			min_year -= YEARSPERREPEAT;
1972 		else
1973 			min_year = INT_MIN;
1974 		if (max_year <= INT_MAX - YEARSPERREPEAT)
1975 			max_year += YEARSPERREPEAT;
1976 		else
1977 			max_year = INT_MAX;
1978 		/*
1979 		** Regardless of any of the above,
1980 		** for a "proDSTic" zone which specifies that its rules
1981 		** always have and always will be in effect,
1982 		** we only need one cycle to define the zone.
1983 		*/
1984 		if (prodstic) {
1985 			min_year = 1900;
1986 			max_year = min_year + YEARSPERREPEAT;
1987 		}
1988 	}
1989 	/*
1990 	** For the benefit of older systems,
1991 	** generate data from 1900 through 2037.
1992 	*/
1993 	if (min_year > 1900)
1994 		min_year = 1900;
1995 	if (max_year < 2037)
1996 		max_year = 2037;
1997 	for (i = 0; i < zonecount; ++i) {
1998 		/*
1999 		** A guess that may well be corrected later.
2000 		*/
2001 		stdoff = 0;
2002 		zp = &zpfirst[i];
2003 		usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2004 		useuntil = i < (zonecount - 1);
2005 		if (useuntil && zp->z_untiltime <= min_time)
2006 			continue;
2007 		gmtoff = zp->z_gmtoff;
2008 		eat(zp->z_filename, zp->z_linenum);
2009 		*startbuf = '\0';
2010 		startoff = zp->z_gmtoff;
2011 		if (zp->z_nrules == 0) {
2012 			stdoff = zp->z_stdoff;
2013 			doabbr(startbuf, max_abbr_len + 1, zp, NULL,
2014 			    stdoff != 0, FALSE);
2015 			type = addtype(oadd(zp->z_gmtoff, stdoff),
2016 				startbuf, stdoff != 0, startttisstd,
2017 				startttisgmt);
2018 			if (usestart) {
2019 				addtt(starttime, type);
2020 				usestart = FALSE;
2021 			} else if (stdoff != 0)
2022 				addtt(min_time, type);
2023 		} else for (year = min_year; year <= max_year; ++year) {
2024 			if (useuntil && year > zp->z_untilrule.r_hiyear)
2025 				break;
2026 			/*
2027 			** Mark which rules to do in the current year.
2028 			** For those to do, calculate rpytime(rp, year);
2029 			*/
2030 			for (j = 0; j < zp->z_nrules; ++j) {
2031 				rp = &zp->z_rules[j];
2032 				eats(zp->z_filename, zp->z_linenum,
2033 					rp->r_filename, rp->r_linenum);
2034 				rp->r_todo = year >= rp->r_loyear &&
2035 				    year <= rp->r_hiyear;
2036 				if (rp->r_todo)
2037 					rp->r_temp = rpytime(rp, year);
2038 			}
2039 			for ( ; ; ) {
2040 				int	k;
2041 				zic_t	jtime, ktime = 0;
2042 				long	offset;
2043 
2044 				if (useuntil) {
2045 					/*
2046 					** Turn untiltime into UTC
2047 					** assuming the current gmtoff and
2048 					** stdoff values.
2049 					*/
2050 					untiltime = zp->z_untiltime;
2051 					if (!zp->z_untilrule.r_todisgmt)
2052 						untiltime = tadd(untiltime,
2053 							-gmtoff);
2054 					if (!zp->z_untilrule.r_todisstd)
2055 						untiltime = tadd(untiltime,
2056 							-stdoff);
2057 				}
2058 				/*
2059 				** Find the rule (of those to do, if any)
2060 				** that takes effect earliest in the year.
2061 				*/
2062 				k = -1;
2063 				for (j = 0; j < zp->z_nrules; ++j) {
2064 					rp = &zp->z_rules[j];
2065 					if (!rp->r_todo)
2066 						continue;
2067 					eats(zp->z_filename, zp->z_linenum,
2068 						rp->r_filename, rp->r_linenum);
2069 					offset = rp->r_todisgmt ? 0 : gmtoff;
2070 					if (!rp->r_todisstd)
2071 						offset = oadd(offset, stdoff);
2072 					jtime = rp->r_temp;
2073 					if (jtime == min_time ||
2074 						jtime == max_time)
2075 							continue;
2076 					jtime = tadd(jtime, -offset);
2077 					if (k < 0 || jtime < ktime) {
2078 						k = j;
2079 						ktime = jtime;
2080 					}
2081 				}
2082 				if (k < 0)
2083 					break;	/* go on to next year */
2084 				rp = &zp->z_rules[k];
2085 				rp->r_todo = FALSE;
2086 				if (useuntil && ktime >= untiltime)
2087 					break;
2088 				stdoff = rp->r_stdoff;
2089 				if (usestart && ktime == starttime)
2090 					usestart = FALSE;
2091 				if (usestart) {
2092 					if (ktime < starttime) {
2093 						startoff = oadd(zp->z_gmtoff,
2094 						    stdoff);
2095 						doabbr(startbuf,
2096 						    max_abbr_len + 1,
2097 						    zp,
2098 						    rp->r_abbrvar,
2099 						    rp->r_stdoff != 0,
2100 						    FALSE);
2101 						continue;
2102 					}
2103 					if (*startbuf == '\0' &&
2104 					    startoff == oadd(zp->z_gmtoff,
2105 					    stdoff)) {
2106 						doabbr(startbuf,
2107 						    max_abbr_len + 1,
2108 						    zp,
2109 						    rp->r_abbrvar,
2110 						    rp->r_stdoff != 0,
2111 						    FALSE);
2112 					}
2113 				}
2114 				eats(zp->z_filename, zp->z_linenum,
2115 				    rp->r_filename, rp->r_linenum);
2116 				doabbr(ab, max_abbr_len + 1, zp,
2117 				    rp->r_abbrvar, rp->r_stdoff != 0, FALSE);
2118 				offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2119 				type = addtype(offset, ab, rp->r_stdoff != 0,
2120 				    rp->r_todisstd, rp->r_todisgmt);
2121 				addtt(ktime, type);
2122 			}
2123 		}
2124 		if (usestart) {
2125 			if (*startbuf == '\0' &&
2126 			    zp->z_format != NULL &&
2127 			    strchr(zp->z_format, '%') == NULL &&
2128 			    strchr(zp->z_format, '/') == NULL)
2129 				strlcpy(startbuf, zp->z_format, max_abbr_len + 1);
2130 			eat(zp->z_filename, zp->z_linenum);
2131 			if (*startbuf == '\0')
2132 				error("can't determine time zone abbreviation to use just after until time");
2133 			else
2134 				addtt(starttime,
2135 				    addtype(startoff, startbuf,
2136 				    startoff != zp->z_gmtoff,
2137 				    startttisstd, startttisgmt));
2138 		}
2139 		/*
2140 		** Now we may get to set starttime for the next zone line.
2141 		*/
2142 		if (useuntil) {
2143 			startttisstd = zp->z_untilrule.r_todisstd;
2144 			startttisgmt = zp->z_untilrule.r_todisgmt;
2145 			starttime = zp->z_untiltime;
2146 			if (!startttisstd)
2147 				starttime = tadd(starttime, -stdoff);
2148 			if (!startttisgmt)
2149 				starttime = tadd(starttime, -gmtoff);
2150 		}
2151 	}
2152 	writezone(zpfirst->z_name, envvar);
2153 	free(startbuf);
2154 	free(ab);
2155 	free(envvar);
2156 }
2157 
2158 static void
addtt(const zic_t starttime,int type)2159 addtt(const zic_t starttime, int type)
2160 {
2161 	size_t len;
2162 
2163 	if (starttime <= min_time ||
2164 	    (timecnt == 1 && attypes[0].at < min_time)) {
2165 		gmtoffs[0] = gmtoffs[type];
2166 		isdsts[0] = isdsts[type];
2167 		ttisstds[0] = ttisstds[type];
2168 		ttisgmts[0] = ttisgmts[type];
2169 		if (abbrinds[type] != 0) {
2170 			len = strlen(&chars[abbrinds[type]]) + 1;
2171 			memmove(chars, &chars[abbrinds[type]], len);
2172 		}
2173 		abbrinds[0] = 0;
2174 		charcnt = strlen(chars) + 1;
2175 		typecnt = 1;
2176 		timecnt = 0;
2177 		type = 0;
2178 	}
2179 	if (timecnt >= TZ_MAX_TIMES) {
2180 		error("too many transitions?!");
2181 		exit(EXIT_FAILURE);
2182 	}
2183 	attypes[timecnt].at = starttime;
2184 	attypes[timecnt].type = type;
2185 	++timecnt;
2186 }
2187 
2188 static int
addtype(long gmtoff,const char * abbr,int isdst,int ttisstd,int ttisgmt)2189 addtype(long gmtoff, const char *abbr, int isdst, int ttisstd, int ttisgmt)
2190 {
2191 	int	i, j;
2192 
2193 	if (isdst != TRUE && isdst != FALSE) {
2194 		error("internal error - addtype called with bad isdst");
2195 		exit(EXIT_FAILURE);
2196 	}
2197 	if (ttisstd != TRUE && ttisstd != FALSE) {
2198 		error("internal error - addtype called with bad ttisstd");
2199 		exit(EXIT_FAILURE);
2200 	}
2201 	if (ttisgmt != TRUE && ttisgmt != FALSE) {
2202 		error("internal error - addtype called with bad ttisgmt");
2203 		exit(EXIT_FAILURE);
2204 	}
2205 	/*
2206 	** See if there's already an entry for this zone type.
2207 	** If so, just return its index.
2208 	*/
2209 	for (i = 0; i < typecnt; ++i) {
2210 		if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2211 		    strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2212 		    ttisstd == ttisstds[i] &&
2213 		    ttisgmt == ttisgmts[i])
2214 			return i;
2215 	}
2216 	/*
2217 	** There isn't one; add a new one, unless there are already too
2218 	** many.
2219 	*/
2220 	if (typecnt >= TZ_MAX_TYPES) {
2221 		error("too many local time types");
2222 		exit(EXIT_FAILURE);
2223 	}
2224 	if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2225 		error("UTC offset out of range");
2226 		exit(EXIT_FAILURE);
2227 	}
2228 	gmtoffs[i] = gmtoff;
2229 	isdsts[i] = isdst;
2230 	ttisstds[i] = ttisstd;
2231 	ttisgmts[i] = ttisgmt;
2232 
2233 	for (j = 0; j < charcnt; ++j)
2234 		if (strcmp(&chars[j], abbr) == 0)
2235 			break;
2236 	if (j == charcnt)
2237 		newabbr(abbr);
2238 	abbrinds[i] = j;
2239 	++typecnt;
2240 	return i;
2241 }
2242 
2243 static void
leapadd(zic_t t,int positive,int rolling,int count)2244 leapadd(zic_t t, int positive, int rolling, int count)
2245 {
2246 	int	i, j;
2247 
2248 	if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2249 		error("too many leap seconds");
2250 		exit(EXIT_FAILURE);
2251 	}
2252 	for (i = 0; i < leapcnt; ++i)
2253 		if (t <= trans[i]) {
2254 			if (t == trans[i]) {
2255 				error("repeated leap second moment");
2256 				exit(EXIT_FAILURE);
2257 			}
2258 			break;
2259 		}
2260 	do {
2261 		for (j = leapcnt; j > i; --j) {
2262 			trans[j] = trans[j - 1];
2263 			corr[j] = corr[j - 1];
2264 			roll[j] = roll[j - 1];
2265 		}
2266 		trans[i] = t;
2267 		corr[i] = positive ? 1L : eitol(-count);
2268 		roll[i] = rolling;
2269 		++leapcnt;
2270 	} while (positive && --count != 0);
2271 }
2272 
2273 static void
adjleap(void)2274 adjleap(void)
2275 {
2276 	int	i;
2277 	long	last = 0;
2278 
2279 	/*
2280 	** propagate leap seconds forward
2281 	*/
2282 	for (i = 0; i < leapcnt; ++i) {
2283 		trans[i] = tadd(trans[i], last);
2284 		last = corr[i] += last;
2285 	}
2286 }
2287 
2288 /* this function is not strncasecmp */
2289 static int
itsabbr(const char * sabbr,const char * sword)2290 itsabbr(const char *sabbr, const char *sword)
2291 {
2292 	const unsigned char *abbr = sabbr;
2293 	const unsigned char *word = sword;
2294 
2295 	if (tolower(*abbr) != tolower(*word))
2296 		return FALSE;
2297 	while (*++abbr != '\0')
2298 		do {
2299 			++word;
2300 			if (*word == '\0')
2301 				return FALSE;
2302 		} while (tolower(*word) != tolower(*abbr));
2303 	return TRUE;
2304 }
2305 
2306 static const struct lookup *
byword(const char * word,const struct lookup * table)2307 byword(const char *word, const struct lookup *table)
2308 {
2309 	const struct lookup	*foundlp;
2310 	const struct lookup	*lp;
2311 
2312 	if (word == NULL || table == NULL)
2313 		return NULL;
2314 	/*
2315 	** Look for exact match.
2316 	*/
2317 	for (lp = table; lp->l_word != NULL; ++lp)
2318 		if (strcasecmp(word, lp->l_word) == 0)
2319 			return lp;
2320 	/*
2321 	** Look for inexact match.
2322 	*/
2323 	foundlp = NULL;
2324 	for (lp = table; lp->l_word != NULL; ++lp)
2325 		if (itsabbr(word, lp->l_word)) {
2326 			if (foundlp == NULL)
2327 				foundlp = lp;
2328 			else
2329 				return NULL;	/* multiple inexact matches */
2330 		}
2331 	return foundlp;
2332 }
2333 
2334 static char **
getfields(char * cp)2335 getfields(char *cp)
2336 {
2337 	char		*dp;
2338 	char		**array;
2339 	int		nsubs;
2340 
2341 	if (cp == NULL)
2342 		return NULL;
2343 	array = ereallocarray(NULL, strlen(cp) + 1, sizeof *array);
2344 	nsubs = 0;
2345 	for ( ; ; ) {
2346 		while (isascii((unsigned char)*cp) &&
2347 		    isspace((unsigned char)*cp))
2348 			++cp;
2349 		if (*cp == '\0' || *cp == '#')
2350 			break;
2351 		array[nsubs++] = dp = cp;
2352 		do {
2353 			if ((*dp = *cp++) != '"') {
2354 				++dp;
2355 			} else {
2356 				while ((*dp = *cp++) != '"') {
2357 					if (*dp != '\0')
2358 						++dp;
2359 					else {
2360 						error("Odd number of quotation marks");
2361 						exit(EXIT_FAILURE);
2362 					}
2363 				}
2364 			}
2365 		} while (*cp != '\0' && *cp != '#' &&
2366 		    (!isascii((unsigned char)*cp) || !isspace((unsigned char)*cp)));
2367 		if (isascii((unsigned char)*cp) && isspace((unsigned char)*cp))
2368 			++cp;
2369 		*dp = '\0';
2370 	}
2371 	array[nsubs] = NULL;
2372 	return array;
2373 }
2374 
2375 static long
oadd(long t1,long t2)2376 oadd(long t1, long t2)
2377 {
2378 	long	t = t1 + t2;
2379 
2380 	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2381 		error("time overflow");
2382 		exit(EXIT_FAILURE);
2383 	}
2384 	return t;
2385 }
2386 
2387 static zic_t
tadd(zic_t t1,long t2)2388 tadd(zic_t t1, long t2)
2389 {
2390 	zic_t	t;
2391 
2392 	if (t1 == max_time && t2 > 0)
2393 		return max_time;
2394 	if (t1 == min_time && t2 < 0)
2395 		return min_time;
2396 	t = t1 + t2;
2397 	if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2398 		error("time overflow");
2399 		exit(EXIT_FAILURE);
2400 	}
2401 	return t;
2402 }
2403 
2404 /*
2405 ** Given a rule, and a year, compute the date - in seconds since January 1,
2406 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2407 */
2408 static zic_t
rpytime(const struct rule * rp,int wantedy)2409 rpytime(const struct rule *rp, int wantedy)
2410 {
2411 	int	y, m, i;
2412 	long	dayoff;			/* with a nod to Margaret O. */
2413 	zic_t	t;
2414 
2415 	if (wantedy == INT_MIN)
2416 		return min_time;
2417 	if (wantedy == INT_MAX)
2418 		return max_time;
2419 	dayoff = 0;
2420 	m = TM_JANUARY;
2421 	y = EPOCH_YEAR;
2422 	while (wantedy != y) {
2423 		if (wantedy > y) {
2424 			i = len_years[isleap(y)];
2425 			++y;
2426 		} else {
2427 			--y;
2428 			i = -len_years[isleap(y)];
2429 		}
2430 		dayoff = oadd(dayoff, eitol(i));
2431 	}
2432 	while (m != rp->r_month) {
2433 		i = len_months[isleap(y)][m];
2434 		dayoff = oadd(dayoff, eitol(i));
2435 		++m;
2436 	}
2437 	i = rp->r_dayofmonth;
2438 	if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2439 		if (rp->r_dycode == DC_DOWLEQ)
2440 			--i;
2441 		else {
2442 			error("use of 2/29 in non leap-year");
2443 			exit(EXIT_FAILURE);
2444 		}
2445 	}
2446 	--i;
2447 	dayoff = oadd(dayoff, eitol(i));
2448 	if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2449 		long	wday;
2450 
2451 #define LDAYSPERWEEK	((long) DAYSPERWEEK)
2452 		wday = eitol(EPOCH_WDAY);
2453 		/*
2454 		** Don't trust mod of negative numbers.
2455 		*/
2456 		if (dayoff >= 0)
2457 			wday = (wday + dayoff) % LDAYSPERWEEK;
2458 		else {
2459 			wday -= ((-dayoff) % LDAYSPERWEEK);
2460 			if (wday < 0)
2461 				wday += LDAYSPERWEEK;
2462 		}
2463 		while (wday != eitol(rp->r_wday))
2464 			if (rp->r_dycode == DC_DOWGEQ) {
2465 				dayoff = oadd(dayoff, 1);
2466 				if (++wday >= LDAYSPERWEEK)
2467 					wday = 0;
2468 				++i;
2469 			} else {
2470 				dayoff = oadd(dayoff, -1);
2471 				if (--wday < 0)
2472 					wday = LDAYSPERWEEK - 1;
2473 				--i;
2474 			}
2475 	}
2476 	if (dayoff < min_time / SECSPERDAY)
2477 		return min_time;
2478 	if (dayoff > max_time / SECSPERDAY)
2479 		return max_time;
2480 	t = (zic_t) dayoff * SECSPERDAY;
2481 	return tadd(t, rp->r_tod);
2482 }
2483 
2484 static void
newabbr(const char * string)2485 newabbr(const char *string)
2486 {
2487 	int	i;
2488 
2489 	if (strcmp(string, GRANDPARENTED) != 0) {
2490 		const char *	cp;
2491 		char *		wp;
2492 
2493 		cp = string;
2494 		wp = NULL;
2495 		while (isascii((unsigned char)*cp) &&
2496 		    (isalnum((unsigned char)*cp) || *cp == '-' || *cp == '+'))
2497 			++cp;
2498 		if (noise && cp - string > 3)
2499 			wp = "time zone abbreviation has more than 3 characters";
2500 		if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2501 			wp = "time zone abbreviation has too many characters";
2502 		if (*cp != '\0')
2503 			wp = "time zone abbreviation differs from POSIX standard";
2504 		if (wp != NULL) {
2505 			wp = ecpyalloc(wp);
2506 			wp = ecatalloc(wp, " (");
2507 			wp = ecatalloc(wp, string);
2508 			wp = ecatalloc(wp, ")");
2509 			warning(wp);
2510 			free(wp);
2511 		}
2512 	}
2513 	i = strlen(string) + 1;
2514 	if (charcnt + i > TZ_MAX_CHARS) {
2515 		error("too many, or too long, time zone abbreviations");
2516 		exit(EXIT_FAILURE);
2517 	}
2518 	strlcpy(&chars[charcnt], string, sizeof(chars) - charcnt);
2519 	charcnt += eitol(i);
2520 }
2521 
2522 static int
mkdirs(char * argname)2523 mkdirs(char *argname)
2524 {
2525 	char *	name;
2526 	char *	cp;
2527 
2528 	if (argname == NULL || *argname == '\0')
2529 		return 0;
2530 	cp = name = ecpyalloc(argname);
2531 	while ((cp = strchr(cp + 1, '/')) != 0) {
2532 		*cp = '\0';
2533 		if (!itsdir(name)) {
2534 			/*
2535 			** It doesn't seem to exist, so we try to create it.
2536 			** Creation may fail because of the directory being
2537 			** created by some other multiprocessor, so we get
2538 			** to do extra checking.
2539 			*/
2540 			if (mkdir(name, MKDIR_UMASK) != 0) {
2541 				const char *e = strerror(errno);
2542 
2543 				if (errno != EEXIST || !itsdir(name)) {
2544 					fprintf(stderr,
2545 					    "%s: Can't create directory %s: %s\n",
2546 					    __progname, name, e);
2547 					free(name);
2548 					return -1;
2549 				}
2550 			}
2551 		}
2552 		*cp = '/';
2553 	}
2554 	free(name);
2555 	return 0;
2556 }
2557 
2558 static long
eitol(int i)2559 eitol(int i)
2560 {
2561 	long	l = i;
2562 
2563 	if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0))
2564 		errx(1, "%d did not sign extend correctly", i);
2565 	return l;
2566 }
2567