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