PostgreSQL Source Code git master
Loading...
Searching...
No Matches
zic.c File Reference
#include "postgres_fe.h"
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <sys/stat.h>
#include <time.h>
#include "pg_getopt.h"
#include "private.h"
#include "tzfile.h"
Include dependency graph for zic.c:

Go to the source code of this file.

Data Structures

struct  rule
 
struct  zone
 
struct  link
 
struct  lookup
 
struct  attype
 
struct  timerange
 

Macros

#define O_BINARY   0 /* MS-Windows */
 
#define SCNdZIC   SCNdFAST64
 
#define ZIC_MAX_ABBR_LEN_WO_WARN   6
 
#define ALL_PERMS   (S_IRWXU | S_IRWXG | S_IRWXO)
 
#define TROUBLE_PERMS   (S_IWGRP | S_IWOTH)
 
#define MKDIR_PERMS   (ALL_PERMS & ~TROUBLE_PERMS)
 
#define CREAT_PERMS   (MKDIR_PERMS & ~(S_IXUSR | S_IXGRP | S_IXOTH))
 
#define GID_T_MAX   MAXVAL(gid_t, TYPE_BIT(gid_t))
 
#define UID_T_MAX   MAXVAL(uid_t, TYPE_BIT(uid_t))
 
#define alignof(type)   offsetof(struct { char a; type b; }, b)
 
#define TZDEFRULES   "posixrules"
 
#define _POSIX2_LINE_MAX   2048
 
#define linkat(targetdir, target, linknamedir, linkname, flag)    (errno = ENOTSUP, -1)
 
#define MODE_T_MAX   MAXVAL(mode_t, TYPE_BIT(mode_t))
 
#define HAVE_SETMODE   0
 
#define ZIC_BLOAT_DEFAULT   "slim"
 
#define DO(field)   fwrite(tzh.field, sizeof tzh.field, 1, fp)
 

Typedefs

typedef int_fast64_t zic_t
 
typedef intmax_t lineno_t
 

Enumerations

enum  { YEAR_32BIT_MIN = 1901 , YEAR_32BIT_MAX = 2038 }
 
enum  { FORMAT_LEN_GROWTH_BOUND = 5 }
 
enum  { DC_DOM , DC_DOWGEQ , DC_DOWLEQ }
 
enum  { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 }
 
enum  {
  LC_RULE , LC_ZONE , LC_LINK , LC_LEAP ,
  LC_EXPIRES
}
 
enum  {
  ZF_NAME = 1 , ZF_STDOFF , ZF_RULE , ZF_FORMAT ,
  ZF_TILYEAR , ZF_TILMONTH , ZF_TILDAY , ZF_TILTIME ,
  ZONE_MAXFIELDS , ZONE_MINFIELDS = ZF_TILYEAR
}
 
enum  {
  ZFC_STDOFF , ZFC_RULE , ZFC_FORMAT , ZFC_TILYEAR ,
  ZFC_TILMONTH , ZFC_TILDAY , ZFC_TILTIME , ZONEC_MAXFIELDS ,
  ZONEC_MINFIELDS = ZFC_TILYEAR
}
 
enum  {
  RF_NAME = 1 , RF_LOYEAR , RF_HIYEAR , RF_COMMAND ,
  RF_MONTH , RF_DAY , RF_TOD , RF_SAVE ,
  RF_ABBRVAR , RULE_FIELDS
}
 
enum  { LF_TARGET = 1 , LF_LINKNAME , LINK_FIELDS }
 
enum  {
  LP_YEAR = 1 , LP_MONTH , LP_DAY , LP_TIME ,
  LP_CORR , LP_ROLL , LEAP_FIELDS , EXPIRES_FIELDS = LP_TIME + 1
}
 
enum  { MAX_FIELDS }
 
enum  { YR_MINIMUM , YR_MAXIMUM , YR_ONLY }
 
enum  { LEAPSEC_FILENUM = -2 , COMMAND_LINE_FILENUM = -1 }
 
enum  { TIME_T_BITS_IN_FILE = 64 }
 

Functions

static void verror (const char *const string, va_list args) pg_attribute_printf(1
 
static void static void error (const char *const string,...) pg_attribute_printf(1
 
static void static void static void warning (const char *const string,...) pg_attribute_printf(1
 
static void static void static void static int addabbr (char chs[TZ_MAX_CHARS], int *pnchs, char const *abbr)
 
static void addtt (zic_t starttime, int type)
 
static int addtype (zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
 
static void adjleap (void)
 
static void associate (void)
 
static void checkabbr (char const *string)
 
static void check_for_signal (void)
 
static void dolink (char const *target, char const *linkname, bool staysymlink)
 
static int getfields (char *cp, char **array, int arrayelts)
 
static zic_t gethms (const char *string, const char *errstring)
 
static zic_t getsave (char *field, bool *isdst)
 
static void inexpires (char **fields, int nfields)
 
static void infile (int fnum, char const *name)
 
static void inleap (char **fields, int nfields)
 
static void inlink (char **fields, int nfields)
 
static void inrule (char **fields, int nfields)
 
static bool inzcont (char **fields, int nfields)
 
static bool inzone (char **fields, int nfields)
 
static bool inzsub (char **fields, int nfields, bool iscont)
 
static bool is_alpha (char a)
 
static int itssymlink (char const *name, int *cache)
 
static void leapadd (zic_t t, int correction, int rolling)
 
static char lowerit (char a)
 
static void mkdirs (char const *argname, bool ancestors)
 
static zic_t oadd (zic_t t1, zic_t t2)
 
static zic_t omul (zic_t t1, zic_t t2)
 
static void outzone (const struct zone *zpfirst, ptrdiff_t zonecount)
 
static zic_t rpytime (const struct rule *rp, zic_t wantedy)
 
static bool rulesub (struct rule *rp, const char *loyearp, const char *hiyearp, const char *typep, const char *monthp, const char *dayp, const char *timep)
 
static zic_t tadd (zic_t t1, zic_t t2)
 
static bool is_digit (char c)
 
static struct lookup constbyword (const char *word, const struct lookup *table)
 
static ATTRIBUTE_NORETURN void memory_exhausted (const char *msg)
 
static ATTRIBUTE_NORETURN void size_overflow (void)
 
static ATTRIBUTE_PURE_114833_HACK ptrdiff_t size_sum (size_t a, size_t b)
 
static ATTRIBUTE_PURE_114833_HACK ptrdiff_t size_product (ptrdiff_t nitems, ptrdiff_t itemsize)
 
static ATTRIBUTE_PURE_114833_HACK ptrdiff_t align_to (ptrdiff_t size, ptrdiff_t alignment)
 
static voidmemcheck (void *ptr)
 
static voidxmalloc (size_t size)
 
static voidxrealloc (void *ptr, size_t size)
 
static charxstrdup (char const *str)
 
static ptrdiff_t grow_nitems_alloc (ptrdiff_t *nitems_alloc, ptrdiff_t itemsize)
 
static voidgrowalloc (void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
 
static char constfilename (int i)
 
static void eats (int fnum, lineno_t num, int rfnum, lineno_t rnum)
 
static void eat (int fnum, lineno_t num)
 
static unsigned long arg2num (char const *arg, int base, unsigned long maxval, char const *msgid)
 
static mode_t mode_option (char const *arg)
 
static int chmetadata (FILE *stream)
 
static void close_file (FILE *stream, char const *dir, char const *name, char const *tempname)
 
static ATTRIBUTE_NORETURN void duplicate_options (char const *opt)
 
static ATTRIBUTE_NORETURN void usage (FILE *stream, int status)
 
static void group_option (char const *arg)
 
static void owner_option (char const *arg)
 
static void use_safe_temp_permissions (void)
 
static void change_directory (char const *dir)
 
static int qsort_linkcmp (void const *a, void const *b)
 
static int bsearch_linkcmp (void const *key, void const *b)
 
static void make_links (void)
 
static void signal_handler (int sig)
 
static void catch_signals (void)
 
static bool timerange_option (char *timerange)
 
static bool redundant_time_option (char *opt)
 
static bool want_bloat (void)
 
int main (int argc, char **argv)
 
static bool componentcheck (char const *name, char const *component, char const *component_end)
 
static bool namecheck (const char *name)
 
static uint_fast64_t get_rand_u64 (void)
 
static void random_dirent (char const **name, char **namealloc)
 
static char constdiagdir (char const *filename)
 
static char constdiagslash (char const *filename)
 
static FILEopen_outfile (char const **outname, char **tempname)
 
static void rename_dest (char *tempname, char const *name)
 
static charrelname (char const *target, char const *linkname)
 
static ATTRIBUTE_PURE_114833 bool same_parent_dirs (char const *a, char const *b)
 
static int rcomp (const void *cp1, const void *cp2)
 
static bool inputline (FILE *fp, char *buf, ptrdiff_t bufsize)
 
static zic_t getleapdatetime (char **fields, bool expire_line)
 
static void convert (uint_fast32_t val, char *buf)
 
static void convert64 (uint_fast64_t val, char *buf)
 
static void puttzcode (zic_t val, FILE *fp)
 
static void puttzcodepass (zic_t val, FILE *fp, int pass)
 
static int atcomp (const void *avp, const void *bvp)
 
static struct timerange limitrange (struct timerange r, zic_t lo, zic_t hi, zic_t const *ats, unsigned char const *types)
 
static void writezone (const char *const name, const char *const string, char version, int defaulttype)
 
static char constabbroffset (char *buf, zic_t offset)
 
static ptrdiff_t doabbr (char *abbr, struct zone const *zp, char const *letters, bool isdst, zic_t save, bool doquotes)
 
static void updateminmax (const zic_t x)
 
static int stringoffset (char *result, zic_t offset)
 
static int stringrule (char *result, struct rule *const rp, zic_t save, zic_t stdoff)
 
static int rule_cmp (struct rule const *a, struct rule const *b)
 
static int stringzone (char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
 
static bool is_space (char a)
 
static ATTRIBUTE_PURE_114833 bool ciequal (const char *ap, const char *bp)
 
static ATTRIBUTE_PURE_114833 bool itsabbr (const char *abbr, const char *word)
 
static ATTRIBUTE_PURE_114833 bool ciprefix (char const *abbr, char const *word)
 
static ATTRIBUTE_NORETURN void time_overflow (void)
 

Variables

static zic_t const ZIC_MIN = INT_FAST64_MIN
 
static zic_t const ZIC_MAX = INT_FAST64_MAX
 
static zic_t const ZIC32_MIN = -1 - (zic_t) TWO_31_MINUS_1
 
static zic_t const ZIC32_MAX = TWO_31_MINUS_1
 
static mode_t creat_perms = CREAT_PERMS
 
static gid_t const no_gid = -1
 
static uid_t const no_uid = -1
 
static gid_t output_group = -1
 
static uid_t output_owner = -1
 
static int charcnt
 
static bool errors
 
static bool warnings
 
static int filenum
 
static ptrdiff_t leapcnt
 
static ptrdiff_t leap_alloc
 
static bool leapseen
 
static zic_t leapminyear
 
static zic_t leapmaxyear
 
static lineno_t linenum
 
static int max_abbrvar_len = PERCENT_Z_LEN_BOUND
 
static int max_format_len
 
static zic_t max_year
 
static zic_t min_year
 
static bool noise
 
static bool print_abbrevs
 
static zic_t print_cutoff
 
static bool skip_mkdir
 
static int rfilenum
 
static lineno_t rlinenum
 
static const charprogname
 
static char constleapsec
 
static char *constmain_argv
 
static ptrdiff_t timecnt
 
static ptrdiff_t timecnt_alloc
 
static int typecnt
 
static int unspecifiedtype
 
static struct rulerules
 
static ptrdiff_t nrules
 
static ptrdiff_t nrules_alloc
 
static struct zonezones
 
static ptrdiff_t nzones
 
static ptrdiff_t nzones_alloc
 
static struct linklinks
 
static ptrdiff_t nlinks
 
static ptrdiff_t nlinks_alloc
 
static struct lookup const zi_line_codes []
 
static struct lookup const leap_line_codes []
 
static struct lookup const mon_names []
 
static struct lookup const wday_names []
 
static struct lookup const lasts []
 
static struct lookup const begin_years []
 
static struct lookup const end_years []
 
static struct lookup const leap_types []
 
static const int len_months [2][MONSPERYEAR]
 
static const int len_years [2]
 
static struct attypeattypes
 
static zic_t utoffs [TZ_MAX_TYPES]
 
static char isdsts [TZ_MAX_TYPES]
 
static unsigned char desigidx [TZ_MAX_TYPES]
 
static bool ttisstds [TZ_MAX_TYPES]
 
static bool ttisuts [TZ_MAX_TYPES]
 
static char chars [TZ_MAX_CHARS]
 
struct { 
 
   zic_t   trans 
 
   zic_t   corr 
 
   char   roll 
 
} * leap 
 
static mode_t const no_mode = -1
 
static mode_t output_mode = -1
 
static sig_atomic_t got_signal
 
static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE)
 
static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE)
 
static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE)
 
static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE)
 
static zic_t redundant_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE)
 
static zic_t leapexpires = -1
 
static const charpsxrules
 
static const charlcltime
 
static const chardirectory
 
static const chartzdefault
 
static bool directory_ends_in_slash
 
static int bloat
 
static char const disable_percent_s [] = ""
 

Macro Definition Documentation

◆ _POSIX2_LINE_MAX

#define _POSIX2_LINE_MAX   2048

Definition at line 99 of file zic.c.

◆ alignof

#define alignof (   type)    offsetof(struct { char a; type b; }, b)

Definition at line 87 of file zic.c.

◆ ALL_PERMS

#define ALL_PERMS   (S_IRWXU | S_IRWXG | S_IRWXO)

Definition at line 52 of file zic.c.

◆ CREAT_PERMS

#define CREAT_PERMS   (MKDIR_PERMS & ~(S_IXUSR | S_IXGRP | S_IXOTH))

Definition at line 67 of file zic.c.

◆ DO

#define DO (   field)    fwrite(tzh.field, sizeof tzh.field, 1, fp)

◆ GID_T_MAX

#define GID_T_MAX   MAXVAL(gid_t, TYPE_BIT(gid_t))

Definition at line 75 of file zic.c.

◆ HAVE_SETMODE

#define HAVE_SETMODE   0

Definition at line 722 of file zic.c.

◆ linkat

#define linkat (   targetdir,
  target,
  linknamedir,
  linkname,
  flag 
)     (errno = ENOTSUP, -1)

Definition at line 168 of file zic.c.

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

◆ MKDIR_PERMS

#define MKDIR_PERMS   (ALL_PERMS & ~TROUBLE_PERMS)

Definition at line 61 of file zic.c.

◆ MODE_T_MAX

#define MODE_T_MAX   MAXVAL(mode_t, TYPE_BIT(mode_t))

Definition at line 714 of file zic.c.

◆ O_BINARY

#define O_BINARY   0 /* MS-Windows */

Definition at line 26 of file zic.c.

◆ SCNdZIC

#define SCNdZIC   SCNdFAST64

Definition at line 35 of file zic.c.

◆ TROUBLE_PERMS

#define TROUBLE_PERMS   (S_IWGRP | S_IWOTH)

Definition at line 55 of file zic.c.

◆ TZDEFRULES

#define TZDEFRULES   "posixrules"

Definition at line 94 of file zic.c.

◆ UID_T_MAX

#define UID_T_MAX   MAXVAL(uid_t, TYPE_BIT(uid_t))

Definition at line 78 of file zic.c.

◆ ZIC_BLOAT_DEFAULT

#define ZIC_BLOAT_DEFAULT   "slim"

Definition at line 1249 of file zic.c.

◆ ZIC_MAX_ABBR_LEN_WO_WARN

#define ZIC_MAX_ABBR_LEN_WO_WARN   6

Definition at line 38 of file zic.c.

Typedef Documentation

◆ lineno_t

Definition at line 107 of file zic.c.

◆ zic_t

Definition at line 29 of file zic.c.

Enumeration Type Documentation

◆ anonymous enum

Enumerator
YEAR_32BIT_MIN 
YEAR_32BIT_MAX 

Definition at line 42 of file zic.c.

43{
44YEAR_32BIT_MIN = 1901, YEAR_32BIT_MAX = 2038};

◆ anonymous enum

Enumerator
FORMAT_LEN_GROWTH_BOUND 

Definition at line 47 of file zic.c.

◆ anonymous enum

Enumerator
DC_DOM 
DC_DOWGEQ 
DC_DOWLEQ 

Definition at line 139 of file zic.c.

140{
141 DC_DOM, /* 1..31 */ /* unused */
142 DC_DOWGEQ, /* 1..31 */ /* 0..6 (Sun..Sat) */
143 DC_DOWLEQ /* 1..31 */ /* 0..6 (Sun..Sat) */
144};

◆ anonymous enum

Enumerator
PERCENT_Z_LEN_BOUND 

Definition at line 218 of file zic.c.

219{
220PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1};

◆ anonymous enum

Enumerator
LC_RULE 
LC_ZONE 
LC_LINK 
LC_LEAP 
LC_EXPIRES 

Definition at line 254 of file zic.c.

255{
256 LC_RULE,
257 LC_ZONE,
258 LC_LINK,
259 LC_LEAP,
261};

◆ anonymous enum

Enumerator
ZF_NAME 
ZF_STDOFF 
ZF_RULE 
ZF_FORMAT 
ZF_TILYEAR 
ZF_TILMONTH 
ZF_TILDAY 
ZF_TILTIME 
ZONE_MAXFIELDS 
ZONE_MINFIELDS 

Definition at line 267 of file zic.c.

268{
269 ZF_NAME = 1,
270 ZF_STDOFF,
271 ZF_RULE,
272 ZF_FORMAT,
275 ZF_TILDAY,
279};

◆ anonymous enum

Enumerator
ZFC_STDOFF 
ZFC_RULE 
ZFC_FORMAT 
ZFC_TILYEAR 
ZFC_TILMONTH 
ZFC_TILDAY 
ZFC_TILTIME 
ZONEC_MAXFIELDS 
ZONEC_MINFIELDS 

Definition at line 285 of file zic.c.

◆ anonymous enum

Enumerator
RF_NAME 
RF_LOYEAR 
RF_HIYEAR 
RF_COMMAND 
RF_MONTH 
RF_DAY 
RF_TOD 
RF_SAVE 
RF_ABBRVAR 
RULE_FIELDS 

Definition at line 302 of file zic.c.

303{
304 RF_NAME = 1,
305 RF_LOYEAR,
306 RF_HIYEAR,
308 RF_MONTH,
309 RF_DAY,
310 RF_TOD,
311 RF_SAVE,
314};

◆ anonymous enum

Enumerator
LF_TARGET 
LF_LINKNAME 
LINK_FIELDS 

Definition at line 320 of file zic.c.

321{
322 LF_TARGET = 1,
325};

◆ anonymous enum

Enumerator
LP_YEAR 
LP_MONTH 
LP_DAY 
LP_TIME 
LP_CORR 
LP_ROLL 
LEAP_FIELDS 
EXPIRES_FIELDS 

Definition at line 331 of file zic.c.

332{
333 LP_YEAR = 1,
334 LP_MONTH,
335 LP_DAY,
336 LP_TIME,
337 LP_CORR,
338 LP_ROLL,
340
341 /*
342 * Expires lines are like Leap lines, except without CORR and ROLL fields.
343 */
345};

◆ anonymous enum

Enumerator
MAX_FIELDS 

Definition at line 351 of file zic.c.

◆ anonymous enum

Enumerator
YR_MINIMUM 
YR_MAXIMUM 
YR_ONLY 

Definition at line 361 of file zic.c.

362{
363 YR_MINIMUM, /* "minimum" is for backward compatibility
364 * only */
366 YR_ONLY
367};

◆ anonymous enum

Enumerator
LEAPSEC_FILENUM 
COMMAND_LINE_FILENUM 

Definition at line 618 of file zic.c.

619{

◆ anonymous enum

Enumerator
TIME_T_BITS_IN_FILE 

Definition at line 1149 of file zic.c.

1150{

Function Documentation

◆ abbroffset()

static char const * abbroffset ( char buf,
zic_t  offset 
)
static

Definition at line 3501 of file zic.c.

3502{
3503 char sign = '+';
3504 int seconds,
3505 minutes;
3506
3507 if (offset < 0)
3508 {
3509 offset = -offset;
3510 sign = '-';
3511 }
3512
3513 seconds = offset % SECSPERMIN;
3514 offset /= SECSPERMIN;
3515 minutes = offset % MINSPERHOUR;
3516 offset /= MINSPERHOUR;
3517 if (100 <= offset)
3518 {
3519 error(_("%%z UT offset magnitude exceeds 99:59:59"));
3520 return "%z";
3521 }
3522 else
3523 {
3524 char *p = buf;
3525
3526 *p++ = sign;
3527 *p++ = '0' + offset / 10;
3528 *p++ = '0' + offset % 10;
3529 if (minutes | seconds)
3530 {
3531 *p++ = '0' + minutes / 10;
3532 *p++ = '0' + minutes % 10;
3533 if (seconds)
3534 {
3535 *p++ = '0' + seconds / 10;
3536 *p++ = '0' + seconds % 10;
3537 }
3538 }
3539 *p = '\0';
3540 return buf;
3541 }
3542}

References _, buf, error(), fb(), MINSPERHOUR, SECSPERMIN, and sign.

Referenced by doabbr().

◆ addabbr()

static int addabbr ( char  chs[TZ_MAX_CHARS],
int pnchs,
char const abbr 
)
static

Definition at line 4905 of file zic.c.

4906{
4907 int nchs = *pnchs;
4908 int alen = strlen(abbr),
4909 nchs_incr = alen + 1;
4910 int i;
4911
4912 for (i = 0; i < nchs;)
4913 {
4914 int clen = strlen(&chs[i]);
4915
4916 if (alen <= clen)
4917 {
4918 /*
4919 * If ABBR is a suffix of an abbreviation in CHS, return the index
4920 * of ABBR in CHS.
4921 */
4922 int isuff = i + (clen - alen);
4923
4924 if (memcmp(&chs[isuff], abbr, alen) == 0)
4925 return isuff;
4926 }
4927 else if (memcmp(&chs[i], &abbr[alen - clen], clen) == 0)
4928 {
4929 /*
4930 * An abbreviation in CHS is a substring of ABBR. Replace it with
4931 * ABBR, instead of the more-common actions of appending ABBR or
4932 * doing nothing.
4933 */
4934 nchs_incr = alen - clen;
4935 break;
4936 }
4937 i += clen + 1;
4938 }
4939 if (TZ_MAX_CHARS < nchs + nchs_incr)
4940 {
4941 error(_("too many, or too long, time zone abbreviations"));
4943 }
4944 memmove(&chs[i + nchs_incr], &chs[i], nchs - i);
4945 memcpy(&chs[i], abbr, nchs_incr);
4946 *pnchs = nchs + nchs_incr;
4947 return i;
4948}

References _, error(), EXIT_FAILURE, fb(), i, memcpy(), and TZ_MAX_CHARS.

Referenced by addtype(), and writezone().

◆ addtt()

static void addtt ( zic_t  starttime,
int  type 
)
static

Definition at line 4301 of file zic.c.

4302{
4304 attypes[timecnt].at = starttime;
4305 attypes[timecnt].dontmerge = false;
4307 ++timecnt;
4308}

References attype::at, attypes, attype::dontmerge, growalloc(), timecnt, timecnt_alloc, type, and attype::type.

Referenced by outzone().

◆ addtype()

static int addtype ( zic_t  utoff,
char const abbr,
bool  isdst,
bool  ttisstd,
bool  ttisut 
)
static

Definition at line 4311 of file zic.c.

4312{
4313 int i,
4314 j;
4315 int charcnt0;
4316
4317 /* RFC 9636 section 3.2 specifies this range for utoff. */
4318 if (!(-TWO_31_MINUS_1 <= utoff && utoff <= TWO_31_MINUS_1))
4319 {
4320 error(_("UT offset out of range"));
4322 }
4323 if (!want_bloat())
4324 ttisstd = ttisut = false;
4325
4326 checkabbr(abbr);
4327
4328 charcnt0 = charcnt;
4329 j = addabbr(chars, &charcnt, abbr);
4330 if (charcnt0 < charcnt)
4331 {
4332 /*
4333 * If an abbreviation was inserted, increment indexes no earlier than
4334 * the insert by the size of the insertion, so that they continue to
4335 * point to the same contents.
4336 */
4337 for (i = 0; i < typecnt; i++)
4338 if (j <= desigidx[i])
4339 desigidx[i] += charcnt - charcnt0;
4340 }
4341 else
4342 {
4343 /* If there's already an entry, return its index. */
4344 for (i = 0; i < typecnt; i++)
4345 if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
4346 && ttisstd == ttisstds[i] && ttisut == ttisuts[i])
4347 return i;
4348 }
4349
4350 /*
4351 * There isn't one; add a new one, unless there are already too many.
4352 */
4353 if (typecnt >= TZ_MAX_TYPES)
4354 {
4355 error(_("too many local time types"));
4357 }
4358 i = typecnt++;
4359 utoffs[i] = utoff;
4360 isdsts[i] = isdst;
4361 ttisstds[i] = ttisstd;
4362 ttisuts[i] = ttisut;
4363 desigidx[i] = j;
4364 return i;
4365}

References _, addabbr(), charcnt, chars, checkabbr(), desigidx, error(), EXIT_FAILURE, fb(), i, isdsts, j, ttisstds, ttisuts, TWO_31_MINUS_1, typecnt, TZ_MAX_TYPES, utoffs, and want_bloat().

Referenced by outzone(), and writezone().

◆ adjleap()

static void adjleap ( void  )
static

Definition at line 4389 of file zic.c.

4390{
4391 ptrdiff_t i;
4392 zic_t last = 0;
4393 zic_t prevtrans = 0;
4394
4395 /*
4396 * propagate leap seconds forward
4397 */
4398 for (i = 0; i < leapcnt; ++i)
4399 {
4400 if (leap[i].trans - prevtrans < 28 * SECSPERDAY)
4401 {
4402 error(_("Leap seconds too close together"));
4404 }
4405 prevtrans = leap[i].trans;
4406 leap[i].trans = tadd(prevtrans, last);
4407 last = leap[i].corr += last;
4408 }
4409
4410 if (0 <= leapexpires)
4411 {
4412 leapexpires = oadd(leapexpires, last);
4413 if (!(leapcnt == 0 || (leap[leapcnt - 1].trans < leapexpires)))
4414 {
4415 error(_("last Leap time does not precede Expires time"));
4417 }
4418 }
4419}

References _, error(), EXIT_FAILURE, fb(), i, leap, leapcnt, leapexpires, oadd(), SECSPERDAY, tadd(), and trans.

Referenced by main().

◆ align_to()

static ATTRIBUTE_PURE_114833_HACK ptrdiff_t align_to ( ptrdiff_t  size,
ptrdiff_t  alignment 
)
static

Definition at line 546 of file zic.c.

547{
548 ptrdiff_t lo_bits = alignment - 1,
549 sum = size_sum(size, lo_bits);
550
551 return sum & ~lo_bits;
552}

References fb(), and size_sum().

Referenced by writezone().

◆ arg2num()

static unsigned long arg2num ( char const arg,
int  base,
unsigned long  maxval,
char const msgid 
)
static

Definition at line 698 of file zic.c.

699{
700 unsigned long n;
701 char *ep;
702
703 errno = 0;
704 n = strtoul(arg, &ep, base);
705 if (ep == arg || *ep || maxval < n || errno)
706 {
709 }
710 return n;
711}

References _, arg, EXIT_FAILURE, fb(), fprintf, and progname.

Referenced by group_option(), mode_option(), and owner_option().

◆ associate()

static void associate ( void  )
static

Definition at line 2040 of file zic.c.

2041{
2042 struct zone *zp;
2043 struct rule *rp;
2044 ptrdiff_t i,
2045 j,
2046 base,
2047 out;
2048
2049 if (1 < nrules)
2050 {
2051 qsort(rules, nrules, sizeof *rules, rcomp);
2052 for (i = 0; i < nrules - 1; ++i)
2053 {
2054 if (strcmp(rules[i].r_name,
2055 rules[i + 1].r_name) != 0)
2056 continue;
2057 if (rules[i].r_filenum == rules[i + 1].r_filenum)
2058 continue;
2060 warning(_("same rule name in multiple files"));
2061 eat(rules[i + 1].r_filenum, rules[i + 1].r_linenum);
2062 warning(_("same rule name in multiple files"));
2063 for (j = i + 2; j < nrules; ++j)
2064 {
2065 if (strcmp(rules[i].r_name,
2066 rules[j].r_name) != 0)
2067 break;
2068 if (rules[i].r_filenum == rules[j].r_filenum)
2069 continue;
2070 if (rules[i + 1].r_filenum
2071 == rules[j].r_filenum)
2072 continue;
2073 break;
2074 }
2075 i = j - 1;
2076 }
2077 }
2078 for (i = 0; i < nzones; ++i)
2079 {
2080 zp = &zones[i];
2081 zp->z_rules = NULL;
2082 zp->z_nrules = 0;
2083 }
2084 for (base = 0; base < nrules; base = out)
2085 {
2086 rp = &rules[base];
2087 for (out = base + 1; out < nrules; ++out)
2088 if (strcmp(rp->r_name, rules[out].r_name) != 0)
2089 break;
2090 for (i = 0; i < nzones; ++i)
2091 {
2092 zp = &zones[i];
2093 if (strcmp(zp->z_rule, rp->r_name) != 0)
2094 continue;
2095 zp->z_rules = rp;
2096 zp->z_nrules = out - base;
2097 }
2098 }
2099 for (i = 0; i < nzones; ++i)
2100 {
2101 zp = &zones[i];
2102 if (zp->z_nrules == 0)
2103 {
2104 /*
2105 * Maybe we have a local standard time offset.
2106 */
2107 eat(zp->z_filenum, zp->z_linenum);
2108 zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
2109
2110 /*
2111 * Note, though, that if there's no rule, a '%s' in the format is
2112 * a bad thing.
2113 */
2114 if (zp->z_format_specifier == 's')
2115 error("%s", _("%s in ruleless zone"));
2116 }
2117 }
2118 if (errors)
2120}

References _, eat(), error(), errors, EXIT_FAILURE, fb(), getsave(), i, j, nrules, nzones, qsort, rule::r_filenum, rule::r_linenum, rule::r_name, rcomp(), rules, warning(), zone::z_rules, and zones.

Referenced by main().

◆ atcomp()

static int atcomp ( const void avp,
const void bvp 
)
static

Definition at line 2899 of file zic.c.

2900{
2901 struct attype const *ap = avp,
2902 *bp = bvp;
2903 zic_t a = ap->at,
2904 b = bp->at;
2905
2906 return a < b ? -1 : a > b;
2907}

References a, attype::at, b, and fb().

Referenced by writezone().

◆ bsearch_linkcmp()

static int bsearch_linkcmp ( void const key,
void const b 
)
static

Definition at line 959 of file zic.c.

960{
961 struct link const *m = b;
962
963 return strcmp(key, m->l_linkname);
964}

References b, fb(), and link::l_linkname.

Referenced by make_links().

◆ byword()

static const struct lookup * byword ( const char word,
const struct lookup table 
)
static

Definition at line 4611 of file zic.c.

4612{
4613 const struct lookup *foundlp;
4614 const struct lookup *lp;
4615
4616 if (word == NULL || table == NULL)
4617 return NULL;
4618
4619 /*
4620 * If TABLE is LASTS and the word starts with "last" followed by a
4621 * non-'-', skip the "last" and look in WDAY_NAMES instead. Warn about any
4622 * usage of the undocumented prefix "last-".
4623 */
4624 if (table == lasts && ciprefix("last", word) && word[4])
4625 {
4626 if (word[4] == '-')
4627 warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
4628 word, word + 5);
4629 else
4630 {
4631 word += 4;
4632 table = wday_names;
4633 }
4634 }
4635
4636 /*
4637 * Look for exact match.
4638 */
4639 for (lp = table; lp->l_word != NULL; ++lp)
4640 if (ciequal(word, lp->l_word))
4641 return lp;
4642
4643 /*
4644 * Look for inexact match.
4645 */
4646 foundlp = NULL;
4647 for (lp = table; lp->l_word != NULL; ++lp)
4648 if (ciprefix(word, lp->l_word))
4649 {
4650 if (foundlp == NULL)
4651 foundlp = lp;
4652 else
4653 return NULL; /* multiple inexact matches */
4654 }
4655
4656 if (foundlp && noise)
4657 {
4658 /* Warn about any backward-compatibility issue with pre-2017c zic. */
4659 bool pre_2017c_match = false;
4660
4661 for (lp = table; lp->l_word; lp++)
4662 if (itsabbr(word, lp->l_word))
4663 {
4664 if (pre_2017c_match)
4665 {
4666 warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
4667 break;
4668 }
4669 pre_2017c_match = true;
4670 }
4671 }
4672
4673 return foundlp;
4674}

References _, ciequal(), ciprefix(), fb(), itsabbr(), lasts, noise, table, warning(), wday_names, and word().

Referenced by getleapdatetime(), infile(), inleap(), and rulesub().

◆ catch_signals()

static void catch_signals ( void  )
static

Definition at line 1096 of file zic.c.

1097{
1098 static int const signals[] = {
1099#ifdef SIGHUP
1100 SIGHUP,
1101#endif
1102 SIGINT,
1103#ifdef SIGPIPE
1104 SIGPIPE,
1105#endif
1106 SIGTERM
1107 };
1108 size_t i;
1109
1110 for (i = 0; i < sizeof signals / sizeof signals[0]; i++)
1111 {
1112#ifdef SA_SIGINFO
1113 struct sigaction act0,
1114 act;
1115
1116 act.sa_handler = signal_handler;
1117 sigemptyset(&act.sa_mask);
1118 act.sa_flags = 0;
1119 if (sigaction(signals[i], &act, &act0) == 0
1120 && !(act0.sa_flags & SA_SIGINFO) && act0.sa_handler == SIG_IGN)
1121 {
1123 got_signal = 0;
1124 }
1125#else
1127 {
1129 got_signal = 0;
1130 }
1131#endif
1132 }
1133}

References fb(), got_signal, i, SIGHUP, signal_handler(), and SIGPIPE.

Referenced by main().

◆ change_directory()

static void change_directory ( char const dir)
static

Definition at line 915 of file zic.c.

916{
917 if (chdir(dir) != 0)
918 {
919 int chdir_errno = errno;
920
921 if (chdir_errno == ENOENT)
922 {
923 mkdirs(dir, false);
924 chdir_errno = chdir(dir) == 0 ? 0 : errno;
925 }
926 if (chdir_errno != 0)
927 {
928 fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
931 }
932 }
933}

References _, EXIT_FAILURE, fb(), fprintf, mkdirs(), progname, and strerror.

Referenced by main().

◆ check_for_signal()

static void check_for_signal ( void  )
static

Definition at line 1137 of file zic.c.

1138{
1139 int sig = got_signal;
1140
1141 if (sig)
1142 {
1143 signal(sig, SIG_DFL);
1144 raise(sig);
1145 abort(); /* A bug in 'raise'. */
1146 }
1147}

References fb(), got_signal, and sig.

Referenced by dolink(), get_rand_u64(), infile(), inputline(), main(), make_links(), open_outfile(), outzone(), random_dirent(), and verror().

◆ checkabbr()

static void checkabbr ( char const string)
static

Definition at line 4868 of file zic.c.

4869{
4870 if (strcmp(string, GRANDPARENTED) != 0)
4871 {
4872 const char *cp;
4873 const char *mp;
4874
4875 cp = string;
4876 mp = NULL;
4877 while (is_alpha(*cp) || is_digit(*cp)
4878 || *cp == '-' || *cp == '+')
4879 ++cp;
4880 if (noise && cp - string < 3)
4881 mp = _("time zone abbreviation has fewer than 3 characters");
4882 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
4883 mp = _("time zone abbreviation has too many characters");
4884 if (*cp != '\0')
4885 mp = _("time zone abbreviation differs from POSIX standard");
4886 if (mp != NULL)
4887 warning("%s (%s)", mp, string);
4888 }
4889}

References _, fb(), GRANDPARENTED, is_alpha(), is_digit(), noise, warning(), and ZIC_MAX_ABBR_LEN_WO_WARN.

Referenced by addtype().

◆ chmetadata()

static int chmetadata ( FILE stream)
static

Definition at line 748 of file zic.c.

749{
750#ifndef WIN32
752 {
753 int r = fchown(fileno(stream), output_owner, output_group);
754
755 if (r < 0)
756 return r;
757 }
758 return output_mode == no_mode ? 0 : fchmod(fileno(stream), output_mode);
759#else
760 return 0;
761#endif
762}

References fb(), no_gid, no_mode, no_uid, output_group, output_mode, and output_owner.

Referenced by close_file().

◆ ciequal()

static ATTRIBUTE_PURE_114833 bool ciequal ( const char ap,
const char bp 
)
static

Definition at line 4572 of file zic.c.

4573{
4574 while (lowerit(*ap) == lowerit(*bp++))
4575 if (*ap++ == '\0')
4576 return true;
4577 return false;
4578}

References fb(), and lowerit().

Referenced by byword().

◆ ciprefix()

static ATTRIBUTE_PURE_114833 bool ciprefix ( char const abbr,
char const word 
)
static

Definition at line 4600 of file zic.c.

4601{
4602 do
4603 if (!*abbr)
4604 return true;
4605 while (lowerit(*abbr++) == lowerit(*word++));
4606
4607 return false;
4608}

References fb(), lowerit(), and word().

Referenced by byword().

◆ close_file()

static void close_file ( FILE stream,
char const dir,
char const name,
char const tempname 
)
static

Definition at line 772 of file zic.c.

774{
775 char const *e = (ferror(stream) ? _("I/O error")
776 : ((tempname
777 && (fflush(stream) < 0 || chmetadata(stream) < 0))
778 || fclose(stream) < 0)
779 ? strerror(errno) : NULL);
780
781 if (e)
782 {
783 if (name && *name == '/')
784 dir = NULL;
785 fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
786 dir ? dir : "", dir ? "/" : "",
787 name ? name : "", name ? ": " : "",
788 e);
789 if (tempname)
790 remove(tempname);
792 }
793}

References _, chmetadata(), EXIT_FAILURE, fb(), fprintf, name, progname, and strerror.

Referenced by dolink(), infile(), main(), usage(), and writezone().

◆ componentcheck()

static bool componentcheck ( char const name,
char const component,
char const component_end 
)
static

Definition at line 1457 of file zic.c.

1459{
1460 enum
1461 {
1462 component_len_max = 14};
1464
1465 if (component_len == 0)
1466 {
1467 if (!*name)
1468 error(_("empty file name"));
1469 else
1471 ? "file name '%s' begins with '/'"
1472 : *component_end
1473 ? "file name '%s' contains '//'"
1474 : "file name '%s' ends with '/'"),
1475 name);
1476 return false;
1477 }
1478 if (0 < component_len && component_len <= 2
1479 && component[0] == '.' && component_end[-1] == '.')
1480 {
1481 int len = component_len;
1482
1483 error(_("file name '%s' contains '%.*s' component"),
1484 name, len, component);
1485 return false;
1486 }
1487 if (noise)
1488 {
1489 if (0 < component_len && component[0] == '-')
1490 warning(_("file name '%s' component contains leading '-'"),
1491 name);
1493 warning(_("file name '%s' contains overlength component"
1494 " '%.*s...'"),
1496 }
1497 return true;
1498}

References _, error(), fb(), len, name, noise, and warning().

Referenced by namecheck().

◆ convert()

static void convert ( uint_fast32_t  val,
char buf 
)
static

Definition at line 2854 of file zic.c.

2855{
2856 int i;
2857 int shift;
2858 unsigned char *const b = (unsigned char *) buf;
2859
2860 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
2861 b[i] = (val >> shift) & 0xff;
2862}

References b, buf, i, and val.

Referenced by ExecInitExprRec(), fmtfloat(), fmtint(), fmtptr(), get_rule_expr(), pg_strfromd(), print_double(), print_double(), print_double(), print_double(), puttzcode(), and writezone().

◆ convert64()

static void convert64 ( uint_fast64_t  val,
char buf 
)
static

Definition at line 2865 of file zic.c.

2866{
2867 int i;
2868 int shift;
2869 unsigned char *const b = (unsigned char *) buf;
2870
2871 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
2872 b[i] = (val >> shift) & 0xff;
2873}

References b, buf, i, and val.

Referenced by puttzcodepass().

◆ diagdir()

static char const * diagdir ( char const filename)
static

Definition at line 1688 of file zic.c.

1689{
1690 return *filename == '/' ? "" : directory;
1691}

References directory, and filename.

Referenced by dolink(), open_outfile(), and rename_dest().

◆ diagslash()

static char const * diagslash ( char const filename)
static

Definition at line 1693 of file zic.c.

1694{
1695 return &"/"[*filename == '/' || directory_ends_in_slash];
1696}

References directory_ends_in_slash, and filename.

Referenced by dolink(), open_outfile(), and rename_dest().

◆ doabbr()

static ptrdiff_t doabbr ( char abbr,
struct zone const zp,
char const letters,
bool  isdst,
zic_t  save,
bool  doquotes 
)
static

Definition at line 3547 of file zic.c.

3549{
3550 char *cp;
3551 ptrdiff_t len;
3552 char const *format = zp->z_format;
3553 char const *slashp = strchr(format, '/');
3554
3555 if (slashp == NULL)
3556 {
3558
3559 if (zp->z_format_specifier == 'z')
3560 letters = abbroffset(letterbuf, zp->z_stdoff + save);
3561 else if (!letters)
3562 letters = "%s";
3563 else if (letters == disable_percent_s)
3564 return 0;
3566 }
3567 else if (isdst)
3568 strcpy(abbr, slashp + 1);
3569 else
3570 {
3572 abbr[slashp - format] = '\0';
3573 }
3574 len = strlen(abbr);
3575 if (!doquotes)
3576 return len;
3577 for (cp = abbr; is_alpha(*cp); cp++)
3578 continue;
3579 if (len > 0 && *cp == '\0')
3580 return len;
3581 abbr[len + 2] = '\0';
3582 abbr[len + 1] = '>';
3583 memmove(abbr + 1, abbr, len);
3584 abbr[0] = '<';
3585 return len + 2;
3586}

References abbroffset(), disable_percent_s, fb(), format, is_alpha(), len, memcpy(), PERCENT_Z_LEN_BOUND, and sprintf.

Referenced by outzone(), and stringzone().

◆ dolink()

static void dolink ( char const target,
char const linkname,
bool  staysymlink 
)
static

Definition at line 1851 of file zic.c.

1852{
1853 bool linkdirs_made = false;
1854 int link_errno;
1855 char *tempname = NULL;
1856 char const *outname = linkname;
1857 int targetissym = -2,
1858 linknameissym = -2;
1859
1860 if (strcmp(target, "-") == 0)
1861 {
1862 if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR)
1863 return;
1864 else
1865 {
1866 char const *e = strerror(errno);
1867
1868 fprintf(stderr, _("%s: Can't remove %s%s%s: %s\n"),
1870 e);
1872 }
1873 }
1874
1875 for (;; check_for_signal())
1876 {
1878 == 0)
1879 {
1880 link_errno = 0;
1881 break;
1882 }
1883 link_errno = errno;
1884 /* Linux 2.6.16 and 2.6.17 mishandle AT_SYMLINK_FOLLOW. */
1885 if (link_errno == EINVAL)
1887
1888 /*
1889 * If linkat is not supported, fall back on link(A, B). However, skip
1890 * this if A is a relative symlink and A and B might not have the same
1891 * parent directory. On some platforms link(A, B) does not follow a
1892 * symlink A, and if A is relative it might misbehave elsewhere.
1893 */
1894 if (link_errno == ENOTSUP
1895 && (same_parent_dirs(target, outname)
1896 || 0 <= itssymlink(target, &targetissym)))
1897 {
1898 if (link(target, outname) == 0)
1899 {
1900 link_errno = 0;
1901 break;
1902 }
1903 link_errno = errno;
1904 }
1905 if (link_errno == EXDEV || link_errno == ENOTSUP)
1906 break;
1907
1908 if (link_errno == EEXIST)
1909 {
1913 break;
1914 }
1915 else if (link_errno == ENOENT && !linkdirs_made)
1916 {
1917 mkdirs(linkname, true);
1918 linkdirs_made = true;
1919 }
1920 else
1921 {
1922 fprintf(stderr, _("%s: Can't link %s%s%s to %s%s%s: %s\n"),
1923 progname, diagdir(target), diagslash(target), target,
1927 }
1928 }
1929 if (link_errno != 0)
1930 {
1931#ifdef HAVE_SYMLINK
1932 bool absolute = *target == '/';
1933 char *linkalloc = absolute ? NULL : relname(target, linkname);
1934 char const *contents = absolute ? target : linkalloc;
1935 int symlink_errno = -1;
1936
1937 if (contents)
1938 {
1939 for (;; check_for_signal())
1940 {
1941 if (symlink(contents, outname) == 0)
1942 {
1943 symlink_errno = 0;
1944 break;
1945 }
1947 if (symlink_errno == EEXIST)
1949 else if (symlink_errno == ENOENT && !linkdirs_made)
1950 {
1951 mkdirs(linkname, true);
1952 linkdirs_made = true;
1953 }
1954 else
1955 break;
1956 }
1957 }
1958 free(linkalloc);
1959 if (symlink_errno == 0)
1960 {
1961 if (link_errno != ENOTSUP && link_errno != EEXIST)
1962 warning(_("symbolic link used because hard link failed: %s"),
1964 }
1965 else
1966#endif /* HAVE_SYMLINK */
1967 {
1968 FILE *fp,
1969 *tp;
1970 int c;
1971
1972 fp = fopen(target, "rb");
1973 if (!fp)
1974 {
1975 char const *e = strerror(errno);
1976
1977 fprintf(stderr, _("%s: Can't read %s%s%s: %s\n"),
1978 progname, diagdir(target), diagslash(target), target, e);
1980 }
1981 tp = open_outfile(&outname, &tempname);
1982 for (; (c = getc(fp)) != EOF; check_for_signal())
1983 putc(c, tp);
1985 close_file(fp, directory, target, NULL);
1986 if (link_errno != ENOTSUP)
1987 warning(_("copy used because hard link failed: %s"),
1989#ifdef HAVE_SYMLINK
1990 else if (symlink_errno < 0)
1991 warning(_("copy used because symbolic link not obvious"));
1992 else if (symlink_errno != ENOTSUP)
1993 warning(_("copy used because symbolic link failed: %s"),
1995#endif
1996 }
1997 }
1999}

References _, check_for_signal(), close_file(), diagdir(), diagslash(), directory, EINVAL, ENOTSUP, EXIT_FAILURE, fb(), fprintf, free, itssymlink(), linkat, mkdirs(), open_outfile(), progname, random_dirent(), relname, rename_dest(), same_parent_dirs(), strerror, symlink, and warning().

Referenced by main(), and make_links().

◆ duplicate_options()

static ATTRIBUTE_NORETURN void duplicate_options ( char const opt)
static

Definition at line 796 of file zic.c.

797{
798 fprintf(stderr, _("%s: More than one %s option specified\n"), progname, opt);
800}

References _, EXIT_FAILURE, fb(), fprintf, and progname.

Referenced by main().

◆ eat()

static void eat ( int  fnum,
lineno_t  num 
)
static

Definition at line 646 of file zic.c.

647{
648 eats(fnum, num, 0, -1);
649}

References eats(), and fb().

Referenced by associate(), infile(), main(), make_links(), and outzone().

◆ eats()

static void eats ( int  fnum,
lineno_t  num,
int  rfnum,
lineno_t  rnum 
)
static

Definition at line 637 of file zic.c.

638{
639 filenum = fnum;
640 linenum = num;
641 rfilenum = rfnum;
642 rlinenum = rnum;
643}

References fb(), filenum, linenum, rfilenum, and rlinenum.

Referenced by eat(), and outzone().

◆ error()

static void error ( const char *const  string,
  ... 
)
static

Definition at line 671 of file zic.c.

672{
674
675 va_start(args, string);
676 verror(string, args);
677 va_end(args);
678 errors = true;
679}

References errors, fb(), and verror().

◆ filename()

static char const * filename ( int  i)
static

Definition at line 624 of file zic.c.

625{
626 if (i == COMMAND_LINE_FILENUM)
627 return _("command line");
628 else
629 {
630 char const *fname = i == LEAPSEC_FILENUM ? leapsec : main_argv[i];
631
632 return strcmp(fname, "-") == 0 ? _("standard input") : fname;
633 }
634}

References _, COMMAND_LINE_FILENUM, fb(), i, leapsec, LEAPSEC_FILENUM, and main_argv.

◆ get_rand_u64()

static uint_fast64_t get_rand_u64 ( void  )
static

Definition at line 1543 of file zic.c.

1544{
1545#if HAVE_GETRANDOM
1546 static uint_fast64_t entropy_buffer[max(1, 256 / sizeof(uint_fast64_t))];
1547 static int nwords;
1548
1549 if (!nwords)
1550 {
1551 ssize_t s;
1552
1553 for (;; check_for_signal())
1554 {
1555 s = getrandom(entropy_buffer, sizeof entropy_buffer, 0);
1556 if (!(s < 0 && errno == EINTR))
1557 break;
1558 }
1559
1560 nwords = s < 0 ? -1 : s / sizeof *entropy_buffer;
1561 }
1562 if (0 < nwords)
1563 return entropy_buffer[--nwords];
1564#endif
1565
1566 /*
1567 * getrandom didn't work, so fall back on portable code that is not the
1568 * best because the seed isn't cryptographically random and 'rand' might
1569 * not be cryptographically secure.
1570 */
1571 {
1572 static bool initialized;
1573
1574 if (!initialized)
1575 {
1576 srand(time(NULL));
1577 initialized = true;
1578 }
1579 }
1580
1581 /*
1582 * Return a random number if rand() yields a random number and in the
1583 * typical case where RAND_MAX is one less than a power of two. In other
1584 * cases this code yields a sort-of-random number.
1585 */
1586 {
1588 nrand = rand_max < UINT_FAST64_MAX ? rand_max + 1 : 0,
1590 r = 0,
1591 rmax = 0;
1592
1593 for (;; check_for_signal())
1594 {
1596
1597 if (rmod)
1598 {
1599 /*
1600 * Avoid signed integer overflow on theoretical platforms
1601 * where uint_fast64_t promotes to int.
1602 */
1603 rmax1 %= rmod;
1604 r %= rmod;
1605 }
1606 rmax1 = nrand * rmax1 + rand_max;
1607 r = nrand * r + rand();
1609 if (UINT_FAST64_MAX <= rmax)
1610 break;
1611 }
1612
1613 return r;
1614 }
1615}

References check_for_signal(), EINTR, fb(), initialized, and max.

Referenced by random_dirent().

◆ getfields()

static int getfields ( char cp,
char **  array,
int  arrayelts 
)
static

Definition at line 4677 of file zic.c.

4678{
4679 char *dp;
4680 int nsubs;
4681
4682 nsubs = 0;
4683 for (;;)
4684 {
4685 char *dstart;
4686
4687 while (is_space(*cp))
4688 ++cp;
4689 if (*cp == '\0' || *cp == '#')
4690 break;
4691 dstart = dp = cp;
4692 do
4693 {
4694 if ((*dp = *cp++) != '"')
4695 ++dp;
4696 else
4697 while ((*dp = *cp++) != '"')
4698 if (*dp != '\0')
4699 ++dp;
4700 else
4701 {
4702 error(_("Odd number of quotation marks"));
4704 }
4705 } while (*cp && *cp != '#' && !is_space(*cp));
4706 if (is_space(*cp))
4707 ++cp;
4708 *dp = '\0';
4709 if (nsubs == arrayelts)
4710 {
4711 error(_("Too many input fields"));
4713 }
4714 array[nsubs++] = dstart + (*dstart == '-' && dp == dstart + 1);
4715 }
4716 return nsubs;
4717}

References _, error(), EXIT_FAILURE, fb(), and is_space().

Referenced by infile().

◆ gethms()

static zic_t gethms ( const char string,
const char errstring 
)
static

Definition at line 2258 of file zic.c.

2259{
2260 zic_t hh;
2261 int sign,
2262 mm = 0,
2263 ss = 0;
2264 char hhx,
2265 mmx,
2266 ssx,
2267 xr = '0',
2268 xs;
2269 int tenths = 0;
2270 bool ok = true;
2271
2272 if (string == NULL || *string == '\0')
2273 return 0;
2274 if (*string == '-')
2275 {
2276 sign = -1;
2277 ++string;
2278 }
2279 else
2280 sign = 1;
2281 switch (sscanf(string,
2282 "%" SCNdZIC "%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
2283 &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs))
2284 {
2285 default:
2286 ok = false;
2287 break;
2288 case 8:
2289 ok = is_digit(xr);
2291 case 7:
2292 ok &= ssx == '.';
2293 if (ok && noise)
2294 warning(_("fractional seconds rejected by"
2295 " pre-2018 versions of zic"));
2297 case 5:
2298 ok &= mmx == ':';
2300 case 3:
2301 ok &= hhx == ':';
2303 case 1:
2304 break;
2305 }
2306 if (!ok)
2307 {
2308 error("%s", errstring);
2309 return 0;
2310 }
2311 if (hh < 0 ||
2314 {
2315 error("%s", errstring);
2316 return 0;
2317 }
2318 ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */
2319 if (noise && (hh > HOURSPERDAY ||
2320 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
2321 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
2322 return oadd(omul(hh, sign * SECSPERHOUR),
2323 sign * (mm * SECSPERMIN + ss));
2324}

References _, ATTRIBUTE_FALLTHROUGH, error(), fb(), HOURSPERDAY, is_digit(), MINSPERHOUR, noise, oadd(), omul(), SCNdZIC, SECSPERHOUR, SECSPERMIN, sign, and warning().

Referenced by getleapdatetime(), getsave(), inzsub(), and rulesub().

◆ getleapdatetime()

static zic_t getleapdatetime ( char **  fields,
bool  expire_line 
)
static

Definition at line 2551 of file zic.c.

2552{
2553 const char *cp;
2554 const struct lookup *lp;
2555 zic_t i,
2556 j;
2557 zic_t year;
2558 int month,
2559 day;
2560 zic_t dayoff,
2561 tod;
2562 zic_t t;
2563 char xs;
2564
2565 dayoff = 0;
2566 cp = fields[LP_YEAR];
2567 if (sscanf(cp, "%" SCNdZIC "%c", &year, &xs) != 1)
2568 {
2569 /*
2570 * Leapin' Lizards!
2571 */
2572 error(_("invalid leaping year"));
2573 return -1;
2574 }
2575 if (!expire_line)
2576 {
2577 if (!leapseen || leapmaxyear < year)
2578 leapmaxyear = year;
2579 if (!leapseen || leapminyear > year)
2580 leapminyear = year;
2581 leapseen = true;
2582 }
2583 j = EPOCH_YEAR;
2584 while (j != year)
2585 {
2586 if (year > j)
2587 {
2588 i = len_years[isleap(j)];
2589 ++j;
2590 }
2591 else
2592 {
2593 --j;
2594 i = -len_years[isleap(j)];
2595 }
2596 dayoff = oadd(dayoff, i);
2597 }
2598 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL)
2599 {
2600 error(_("invalid month name"));
2601 return -1;
2602 }
2603 month = lp->l_value;
2604 j = TM_JANUARY;
2605 while (j != month)
2606 {
2607 i = len_months[isleap(year)][j];
2608 dayoff = oadd(dayoff, i);
2609 ++j;
2610 }
2611 cp = fields[LP_DAY];
2612 if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
2613 day <= 0 || day > len_months[isleap(year)][month])
2614 {
2615 error(_("invalid day of month"));
2616 return -1;
2617 }
2618 dayoff = oadd(dayoff, day - 1);
2619 t = omul(dayoff, SECSPERDAY);
2620 tod = gethms(fields[LP_TIME], _("invalid time of day"));
2621 t = tadd(t, tod);
2622 if (t < 0)
2623 error(_("leap second precedes Epoch"));
2624 return t;
2625}

References _, byword(), EPOCH_YEAR, error(), fb(), gethms(), i, isleap, j, leapmaxyear, leapminyear, leapseen, len_months, len_years, LP_DAY, LP_MONTH, LP_TIME, LP_YEAR, mon_names, oadd(), omul(), SCNdZIC, SECSPERDAY, tadd(), and TM_JANUARY.

Referenced by inexpires(), and inleap().

◆ getsave()

static zic_t getsave ( char field,
bool isdst 
)
static

Definition at line 2327 of file zic.c.

2328{
2329 int dst = -1;
2330 zic_t save;
2331 ptrdiff_t fieldlen = strlen(field);
2332
2333 if (fieldlen != 0)
2334 {
2335 char *ep = field + fieldlen - 1;
2336
2337 switch (*ep)
2338 {
2339 case 'd':
2340 dst = 1;
2341 *ep = '\0';
2342 break;
2343 case 's':
2344 dst = 0;
2345 *ep = '\0';
2346 break;
2347 }
2348 }
2349 save = gethms(field, _("invalid saved time"));
2350 *isdst = dst < 0 ? save != 0 : dst;
2351 return save;
2352}

References _, fb(), and gethms().

Referenced by associate(), and inrule().

◆ group_option()

static void group_option ( char const arg)
static

Definition at line 820 of file zic.c.

821{
822#ifndef WIN32
823 if (*arg)
824 {
825 if (output_group != no_gid)
826 {
827 fprintf(stderr, _("multiple groups specified"));
829 }
830 else
831 {
832 struct group *gr = getgrnam(arg);
833
834 output_group = (gr ? gr->gr_gid
836 N_("%s: invalid group: %s\n")));
837 }
838 }
839#endif
840}

References _, arg, arg2num(), EXIT_FAILURE, fb(), fprintf, GID_T_MAX, min, N_, no_gid, and output_group.

Referenced by main().

◆ grow_nitems_alloc()

static ptrdiff_t grow_nitems_alloc ( ptrdiff_t nitems_alloc,
ptrdiff_t  itemsize 
)
static

Definition at line 581 of file zic.c.

582{
583 ptrdiff_t addend = (*nitems_alloc >> 1) + 1;
584#if defined ckd_add && defined ckd_mul
586
589 return product;
590#else
591 if (*nitems_alloc <= ((INDEX_MAX - 1) / 3 * 2) / itemsize)
592 {
594 return *nitems_alloc * itemsize;
595 }
596#endif
597 memory_exhausted(_("integer overflow"));
598}

References _, fb(), INDEX_MAX, and memory_exhausted().

Referenced by growalloc().

◆ growalloc()

static void * growalloc ( void ptr,
ptrdiff_t  itemsize,
ptrdiff_t  nitems,
ptrdiff_t nitems_alloc 
)
static

Definition at line 601 of file zic.c.

603{
604 return (nitems < *nitems_alloc
605 ? ptr
607}

References fb(), grow_nitems_alloc(), nitems, and xrealloc().

Referenced by addtt(), inlink(), inrule(), inzsub(), leapadd(), and make_links().

◆ inexpires()

static void inexpires ( char **  fields,
int  nfields 
)
static

Definition at line 2660 of file zic.c.

2661{
2662 if (nfields != EXPIRES_FIELDS)
2663 error(_("wrong number of fields on Expires line"));
2664 else if (0 <= leapexpires)
2665 error(_("multiple Expires lines"));
2666 else
2667 leapexpires = getleapdatetime(fields, true);
2668}

References _, error(), EXPIRES_FIELDS, getleapdatetime(), and leapexpires.

Referenced by infile().

◆ infile()

static void infile ( int  fnum,
char const name 
)
static

Definition at line 2165 of file zic.c.

2166{
2167 FILE *fp;
2168 const struct lookup *lp;
2169 bool wantcont;
2170 lineno_t num;
2171
2172 if (strcmp(name, "-") == 0)
2173 {
2174 fp = stdin;
2175 }
2176 else if ((fp = fopen(name, "r")) == NULL)
2177 {
2178 const char *e = strerror(errno);
2179
2180 fprintf(stderr, _("%s: Cannot open %s: %s\n"),
2181 progname, name, e);
2183 }
2184 wantcont = false;
2185 for (num = 1;; ++num)
2186 {
2187 enum
2188 {
2192 int nfields;
2193 char *fields[MAX_FIELDS];
2194
2195 eat(fnum, num);
2196 if (!inputline(fp, buf, sizeof buf))
2197 break;
2198 nfields = getfields(buf, fields,
2199 sizeof fields / sizeof *fields);
2200 if (nfields == 0)
2201 {
2202 /* nothing to do */
2203 }
2204 else if (wantcont)
2205 {
2206 wantcont = inzcont(fields, nfields);
2207 }
2208 else
2209 {
2210 struct lookup const *line_codes
2212
2213 lp = byword(fields[0], line_codes);
2214 if (lp == NULL)
2215 error(_("input line of unknown type"));
2216 else
2217 switch (lp->l_value)
2218 {
2219 case LC_RULE:
2220 inrule(fields, nfields);
2221 wantcont = false;
2222 break;
2223 case LC_ZONE:
2224 wantcont = inzone(fields, nfields);
2225 break;
2226 case LC_LINK:
2227 inlink(fields, nfields);
2228 wantcont = false;
2229 break;
2230 case LC_LEAP:
2231 inleap(fields, nfields);
2232 wantcont = false;
2233 break;
2234 case LC_EXPIRES:
2235 inexpires(fields, nfields);
2236 wantcont = false;
2237 break;
2238 default:
2239 unreachable();
2240 }
2241 }
2243 }
2245 if (wantcont)
2246 error(_("expected continuation line not found"));
2247}

References _, _POSIX2_LINE_MAX, buf, byword(), check_for_signal(), close_file(), eat(), error(), EXIT_FAILURE, fb(), filename, FORMAT_LEN_GROWTH_BOUND, fprintf, getfields(), INDEX_MAX, inexpires(), inleap(), inlink(), inputline(), inrule(), inzcont(), inzone(), LC_EXPIRES, LC_LEAP, LC_LINK, LC_RULE, LC_ZONE, leap_line_codes, MAX_FIELDS, min, name, progname, strerror, unreachable, and zi_line_codes.

Referenced by AlterSystemSetConfigFile(), isolation_start_test(), main(), psql_start_test(), and readfile().

◆ inleap()

static void inleap ( char **  fields,
int  nfields 
)
static

Definition at line 2628 of file zic.c.

2629{
2630 if (nfields != LEAP_FIELDS)
2631 error(_("wrong number of fields on Leap line"));
2632 else
2633 {
2634 zic_t t = getleapdatetime(fields, false);
2635
2636 if (0 <= t)
2637 {
2638 struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
2639
2640 if (!lp)
2641 error(_("invalid Rolling/Stationary field on Leap line"));
2642 else
2643 {
2644 int correction = 0;
2645
2646 if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */
2647 correction = -1;
2648 else if (strcmp(fields[LP_CORR], "+") == 0)
2649 correction = 1;
2650 else
2651 error(_("invalid CORRECTION field on Leap line"));
2652 if (correction)
2653 leapadd(t, correction, lp->l_value);
2654 }
2655 }
2656 }
2657}

References _, byword(), error(), fb(), getleapdatetime(), LEAP_FIELDS, leap_types, leapadd(), LP_CORR, and LP_ROLL.

Referenced by infile().

◆ inlink()

static void inlink ( char **  fields,
int  nfields 
)
static

Definition at line 2671 of file zic.c.

2672{
2673 struct link l;
2674
2675 if (nfields != LINK_FIELDS)
2676 {
2677 error(_("wrong number of fields on Link line"));
2678 return;
2679 }
2680 if (*fields[LF_TARGET] == '\0')
2681 {
2682 error(_("blank TARGET field on Link line"));
2683 return;
2684 }
2685 if (!namecheck(fields[LF_LINKNAME]))
2686 return;
2687 l.l_filenum = filenum;
2688 l.l_linenum = linenum;
2689 l.l_target = xstrdup(fields[LF_TARGET]);
2690 l.l_linkname = xstrdup(fields[LF_LINKNAME]);
2692 links[nlinks++] = l;
2693}

References _, error(), filenum, growalloc(), link::l_filenum, link::l_linenum, link::l_linkname, link::l_target, LF_LINKNAME, LF_TARGET, linenum, LINK_FIELDS, links, namecheck(), nlinks, nlinks_alloc, and xstrdup().

Referenced by infile().

◆ inputline()

static bool inputline ( FILE fp,
char buf,
ptrdiff_t  bufsize 
)
static

Definition at line 2129 of file zic.c.

2130{
2131 ptrdiff_t linelen = 0,
2132 ch;
2133
2134 for (; (ch = getc(fp)) != '\n'; check_for_signal())
2135 {
2136 if (ch < 0)
2137 {
2138 if (ferror(fp))
2139 {
2140 error(_("input error"));
2142 }
2143 if (linelen == 0)
2144 return false;
2145 error(_("unterminated line"));
2147 }
2148 if (!ch)
2149 {
2150 error(_("NUL input byte"));
2152 }
2153 buf[linelen++] = ch;
2154 if (linelen == bufsize)
2155 {
2156 error(_("line too long"));
2158 }
2159 }
2160 buf[linelen] = '\0';
2161 return true;
2162}

References _, buf, bufsize, check_for_signal(), error(), EXIT_FAILURE, and fb().

Referenced by infile().

◆ inrule()

static void inrule ( char **  fields,
int  nfields 
)
static

Definition at line 2355 of file zic.c.

2356{
2357 struct rule r;
2358
2359 if (nfields != RULE_FIELDS)
2360 {
2361 error(_("wrong number of fields on Rule line"));
2362 return;
2363 }
2364 switch (*fields[RF_NAME])
2365 {
2366 case '\0':
2367 case ' ':
2368 case '\f':
2369 case '\n':
2370 case '\r':
2371 case '\t':
2372 case '\v':
2373 case '+':
2374 case '-':
2375 case '0':
2376 case '1':
2377 case '2':
2378 case '3':
2379 case '4':
2380 case '5':
2381 case '6':
2382 case '7':
2383 case '8':
2384 case '9':
2385 error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
2386 return;
2387 }
2388 r.r_filenum = filenum;
2389 r.r_linenum = linenum;
2390 r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
2391 if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR],
2392 fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
2393 fields[RF_TOD]))
2394 return;
2395 r.r_name = xstrdup(fields[RF_NAME]);
2396 r.r_abbrvar = xstrdup(fields[RF_ABBRVAR]);
2397 if (max_abbrvar_len < strlen(r.r_abbrvar))
2398 max_abbrvar_len = strlen(r.r_abbrvar);
2400 rules[nrules++] = r;
2401}

References _, error(), fb(), filenum, getsave(), growalloc(), linenum, max_abbrvar_len, nrules, nrules_alloc, rule::r_abbrvar, rule::r_filenum, rule::r_isdst, rule::r_linenum, rule::r_name, rule::r_save, RF_ABBRVAR, RF_COMMAND, RF_DAY, RF_HIYEAR, RF_LOYEAR, RF_MONTH, RF_NAME, RF_SAVE, RF_TOD, RULE_FIELDS, rules, rulesub(), and xstrdup().

Referenced by infile().

◆ inzcont()

static bool inzcont ( char **  fields,
int  nfields 
)
static

Definition at line 2440 of file zic.c.

2441{
2443 {
2444 error(_("wrong number of fields on Zone continuation line"));
2445 return false;
2446 }
2447 return inzsub(fields, nfields, true);
2448}

References _, error(), fb(), inzsub(), and ZONEC_MAXFIELDS.

Referenced by infile().

◆ inzone()

static bool inzone ( char **  fields,
int  nfields 
)
static

Definition at line 2404 of file zic.c.

2405{
2406 ptrdiff_t i;
2407
2409 {
2410 error(_("wrong number of fields on Zone line"));
2411 return false;
2412 }
2413 if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0)
2414 {
2415 error(_("\"Zone %s\" line and -l option are mutually exclusive"),
2416 tzdefault);
2417 return false;
2418 }
2419 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL)
2420 {
2421 error(_("\"Zone %s\" line and -p option are mutually exclusive"),
2422 TZDEFRULES);
2423 return false;
2424 }
2425 for (i = 0; i < nzones; ++i)
2426 if (zones[i].z_name != NULL &&
2427 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0)
2428 {
2429 error(_("duplicate zone name %s"
2430 " (file \"%s\", line %" PRIdMAX ")"),
2431 fields[ZF_NAME],
2432 filename(zones[i].z_filenum),
2433 zones[i].z_linenum);
2434 return false;
2435 }
2436 return inzsub(fields, nfields, false);
2437}

References _, error(), fb(), filename, i, inzsub(), lcltime, nzones, psxrules, tzdefault, TZDEFRULES, ZF_NAME, ZONE_MAXFIELDS, and zones.

Referenced by infile().

◆ inzsub()

static bool inzsub ( char **  fields,
int  nfields,
bool  iscont 
)
static

Definition at line 2451 of file zic.c.

2452{
2453 char *cp;
2454 char *cp1;
2455 struct zone z;
2456 int format_len;
2457 int i_stdoff,
2458 i_rule,
2459 i_format;
2460 int i_untilyear,
2462 int i_untilday,
2464 bool hasuntil;
2465
2466 if (iscont)
2467 {
2469 i_rule = ZFC_RULE;
2475 }
2476 else if (!namecheck(fields[ZF_NAME]))
2477 return false;
2478 else
2479 {
2481 i_rule = ZF_RULE;
2487 }
2488 z.z_filenum = filenum;
2489 z.z_linenum = linenum;
2490 z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
2491 cp = strchr(fields[i_format], '%');
2492 if (cp)
2493 {
2494 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
2495 || strchr(fields[i_format], '/'))
2496 {
2497 error(_("invalid abbreviation format"));
2498 return false;
2499 }
2500 }
2501 z.z_format_specifier = cp ? *cp : '\0';
2502 format_len = strlen(fields[i_format]);
2505 hasuntil = nfields > i_untilyear;
2506 if (hasuntil)
2507 {
2508 z.z_untilrule.r_filenum = filenum;
2509 z.z_untilrule.r_linenum = linenum;
2510 if (!rulesub(
2511 &z.z_untilrule,
2512 fields[i_untilyear],
2513 "only",
2514 "",
2515 (nfields > i_untilmonth) ?
2516 fields[i_untilmonth] : "Jan",
2517 (nfields > i_untilday) ? fields[i_untilday] : "1",
2518 (nfields > i_untiltime) ? fields[i_untiltime] : "0"))
2519 return false;
2520 z.z_untiltime = rpytime(&z.z_untilrule,
2521 z.z_untilrule.r_loyear);
2522 if (iscont && nzones > 0 &&
2524 {
2525 error(_("Zone continuation line end time is"
2526 " not after end time of previous line"));
2527 return false;
2528 }
2529 }
2530 z.z_name = iscont ? NULL : xstrdup(fields[ZF_NAME]);
2531 z.z_rule = xstrdup(fields[i_rule]);
2532 z.z_format = cp1 = xstrdup(fields[i_format]);
2533 if (z.z_format_specifier == 'z')
2534 {
2535 cp1[cp - fields[i_format]] = 's';
2536 if (noise)
2537 warning(_("format '%s' not handled by pre-2015 versions of zic"),
2538 fields[i_format]);
2539 }
2541 zones[nzones++] = z;
2542
2543 /*
2544 * If there was an UNTIL field on this line, there's more information
2545 * about the zone on the next line.
2546 */
2547 return hasuntil;
2548}

References _, error(), fb(), filenum, gethms(), growalloc(), linenum, max_format_len, namecheck(), noise, nzones, nzones_alloc, rule::r_filenum, rule::r_linenum, rule::r_loyear, rpytime(), rulesub(), warning(), xstrdup(), zone::z_filenum, zone::z_format, zone::z_format_specifier, zone::z_linenum, zone::z_name, zone::z_rule, zone::z_stdoff, zone::z_untilrule, zone::z_untiltime, ZF_FORMAT, ZF_NAME, ZF_RULE, ZF_STDOFF, ZF_TILDAY, ZF_TILMONTH, ZF_TILTIME, ZF_TILYEAR, ZFC_FORMAT, ZFC_RULE, ZFC_STDOFF, ZFC_TILDAY, ZFC_TILMONTH, ZFC_TILTIME, ZFC_TILYEAR, and zones.

Referenced by inzcont(), and inzone().

◆ is_alpha()

static bool is_alpha ( char  a)
static

Definition at line 4441 of file zic.c.

4442{
4443 switch (a)
4444 {
4445 default:
4446 return false;
4447 case 'A':
4448 case 'B':
4449 case 'C':
4450 case 'D':
4451 case 'E':
4452 case 'F':
4453 case 'G':
4454 case 'H':
4455 case 'I':
4456 case 'J':
4457 case 'K':
4458 case 'L':
4459 case 'M':
4460 case 'N':
4461 case 'O':
4462 case 'P':
4463 case 'Q':
4464 case 'R':
4465 case 'S':
4466 case 'T':
4467 case 'U':
4468 case 'V':
4469 case 'W':
4470 case 'X':
4471 case 'Y':
4472 case 'Z':
4473 case 'a':
4474 case 'b':
4475 case 'c':
4476 case 'd':
4477 case 'e':
4478 case 'f':
4479 case 'g':
4480 case 'h':
4481 case 'i':
4482 case 'j':
4483 case 'k':
4484 case 'l':
4485 case 'm':
4486 case 'n':
4487 case 'o':
4488 case 'p':
4489 case 'q':
4490 case 'r':
4491 case 's':
4492 case 't':
4493 case 'u':
4494 case 'v':
4495 case 'w':
4496 case 'x':
4497 case 'y':
4498 case 'z':
4499 return true;
4500 }
4501}

References a.

Referenced by checkabbr(), and doabbr().

◆ is_digit()

static bool is_digit ( char  c)
static

Definition at line 212 of file zic.c.

213{
214 return '0' <= c && c <= '9';
215}

Referenced by checkabbr(), and gethms().

◆ is_space()

static bool is_space ( char  a)
static

Definition at line 4423 of file zic.c.

4424{
4425 switch (a)
4426 {
4427 default:
4428 return false;
4429 case ' ':
4430 case '\f':
4431 case '\n':
4432 case '\r':
4433 case '\t':
4434 case '\v':
4435 return true;
4436 }
4437}

References a.

Referenced by getfields().

◆ itsabbr()

static ATTRIBUTE_PURE_114833 bool itsabbr ( const char abbr,
const char word 
)
static

Definition at line 4582 of file zic.c.

4583{
4584 if (lowerit(*abbr) != lowerit(*word))
4585 return false;
4586 ++word;
4587 while (*++abbr != '\0')
4588 do
4589 {
4590 if (*word == '\0')
4591 return false;
4592 } while (lowerit(*word++) != lowerit(*abbr));
4593 return true;
4594}

References fb(), lowerit(), and word().

Referenced by byword().

◆ itssymlink()

static int itssymlink ( char const name,
int cache 
)
static

Definition at line 2007 of file zic.c.

2008{
2009#ifdef HAVE_SYMLINK
2010 if (*cache == -2)
2011 {
2012 char c = '\0';
2013
2014 *cache = readlink(name, &c, 1) < 0 ? 0 : c == '/' ? 1 : -1;
2015 }
2016 return *cache;
2017#else
2018 return false;
2019#endif
2020}

References name, and readlink.

Referenced by dolink().

◆ leapadd()

static void leapadd ( zic_t  t,
int  correction,
int  rolling 
)
static

Definition at line 4368 of file zic.c.

4369{
4370 ptrdiff_t i;
4371
4372 if (rolling && (lo_time != min_time || hi_time != max_time))
4373 {
4374 error(_("Rolling leap seconds not supported with -r"));
4376 }
4377 leap = growalloc(leap, sizeof *leap, leapcnt, &leap_alloc);
4378 for (i = 0; i < leapcnt; ++i)
4379 if (t <= leap[i].trans)
4380 break;
4381 memmove(&leap[i + 1], &leap[i], (leapcnt - i) * sizeof *leap);
4382 leap[i].trans = t;
4383 leap[i].corr = correction;
4384 leap[i].roll = rolling;
4385 ++leapcnt;
4386}

References _, error(), EXIT_FAILURE, fb(), growalloc(), hi_time, i, leap, leap_alloc, leapcnt, lo_time, max_time, min_time, and trans.

Referenced by inleap().

◆ limitrange()

static struct timerange limitrange ( struct timerange  r,
zic_t  lo,
zic_t  hi,
zic_t const ats,
unsigned char const types 
)
static

Definition at line 2920 of file zic.c.

2922{
2923 /* Omit ordinary transitions < LO. */
2924 while (0 < r.count && ats[r.base] < lo)
2925 {
2926 r.defaulttype = types[r.base];
2927 r.count--;
2928 r.base++;
2929 }
2930
2931 /*
2932 * Omit as many initial leap seconds as possible, such that the first leap
2933 * second in the truncated list is <= LO, and is a positive leap second if
2934 * and only if it has a positive correction. This supports common TZif
2935 * readers that assume that the first leap second is positive if and only
2936 * if its correction is positive.
2937 */
2938 while (1 < r.leapcount && leap[r.leapbase + 1].trans <= lo)
2939 {
2940 r.leapcount--;
2941 r.leapbase++;
2942 }
2943 while (0 < r.leapbase
2944 && ((leap[r.leapbase - 1].corr < leap[r.leapbase].corr)
2945 != (0 < leap[r.leapbase].corr)))
2946 {
2947 r.leapcount++;
2948 r.leapbase--;
2949 }
2950
2951
2952 /* Omit ordinary and leap second transitions greater than HI + 1. */
2953 if (hi < max_time)
2954 {
2955 while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
2956 r.count--;
2957 while (0 < r.leapcount && hi + 1 < leap[r.leapbase + r.leapcount - 1].trans)
2958 r.leapcount--;
2959 }
2960
2961 /* Determine whether to append an expiration to the leap second table. */
2962 r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi;
2963
2964 return r;
2965}

References timerange::defaulttype, leap, leapexpires, max_time, and types.

Referenced by writezone().

◆ lowerit()

static char lowerit ( char  a)
static

Definition at line 4508 of file zic.c.

4509{
4510 switch (a)
4511 {
4512 default:
4513 return a;
4514 case 'A':
4515 return 'a';
4516 case 'B':
4517 return 'b';
4518 case 'C':
4519 return 'c';
4520 case 'D':
4521 return 'd';
4522 case 'E':
4523 return 'e';
4524 case 'F':
4525 return 'f';
4526 case 'G':
4527 return 'g';
4528 case 'H':
4529 return 'h';
4530 case 'I':
4531 return 'i';
4532 case 'J':
4533 return 'j';
4534 case 'K':
4535 return 'k';
4536 case 'L':
4537 return 'l';
4538 case 'M':
4539 return 'm';
4540 case 'N':
4541 return 'n';
4542 case 'O':
4543 return 'o';
4544 case 'P':
4545 return 'p';
4546 case 'Q':
4547 return 'q';
4548 case 'R':
4549 return 'r';
4550 case 'S':
4551 return 's';
4552 case 'T':
4553 return 't';
4554 case 'U':
4555 return 'u';
4556 case 'V':
4557 return 'v';
4558 case 'W':
4559 return 'w';
4560 case 'X':
4561 return 'x';
4562 case 'Y':
4563 return 'y';
4564 case 'Z':
4565 return 'z';
4566 }
4567}

References a.

Referenced by ciequal(), ciprefix(), itsabbr(), and rulesub().

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 1253 of file zic.c.

1254{
1255 int c,
1256 k;
1257 ptrdiff_t i,
1258 j;
1259 bool timerange_given = false;
1260
1261 main_argv = argv;
1262 progname = argv[0] ? argv[0] : "zic";
1263 if (TYPE_BIT(zic_t) < 64)
1264 {
1265 fprintf(stderr, "%s: %s\n", progname,
1266 _("wild compilation-time specification of zic_t"));
1267 return EXIT_FAILURE;
1268 }
1269 for (k = 1; k < argc; k++)
1270 if (strcmp(argv[k], "--version") == 0)
1271 {
1272 printf("zic %s\n", PG_VERSION);
1273 close_file(stdout, NULL, NULL, NULL);
1274 return EXIT_SUCCESS;
1275 }
1276 else if (strcmp(argv[k], "--help") == 0)
1277 {
1278 usage(stdout, EXIT_SUCCESS);
1279 }
1280 while ((c = getopt(argc, argv, "b:d:Dg:l:L:m:p:Pr:R:st:u:vy:")) != -1)
1281 switch (c)
1282 {
1283 default:
1285 case 'b':
1286 if (strcmp(optarg, "slim") == 0)
1287 {
1288 if (0 < bloat)
1289 error(_("incompatible -b options"));
1290 bloat = -1;
1291 }
1292 else if (strcmp(optarg, "fat") == 0)
1293 {
1294 if (bloat < 0)
1295 error(_("incompatible -b options"));
1296 bloat = 1;
1297 }
1298 else
1299 error(_("invalid option: -b '%s'"), optarg);
1300 break;
1301 case 'd':
1302 if (directory)
1303 duplicate_options("-d");
1305 break;
1306 case 'D':
1307 skip_mkdir = true;
1308 break;
1309 case 'g':
1310
1311 /*
1312 * This undocumented option is present for compatibility with
1313 * FreeBSD 14.
1314 */
1316 break;
1317 case 'l':
1318 if (lcltime)
1319 duplicate_options("-l");
1321 break;
1322 case 'm':
1323 if (output_mode != no_mode)
1324 duplicate_options("-m");
1326 break;
1327 case 'p':
1328 if (psxrules)
1329 duplicate_options("-p");
1330 if (strcmp(optarg, "-") != 0)
1331 warning(_("-p is obsolete"
1332 " and likely ineffective"));
1334 break;
1335 case 't':
1336 if (tzdefault)
1337 duplicate_options("-t");
1339 break;
1340 case 'u':
1341 {
1342 char *colon = strchr(optarg, ':');
1343
1344 if (colon)
1345 *colon = '\0';
1347 if (colon)
1348 group_option(colon + 1);
1349 }
1350 break;
1351 case 'y':
1352 warning(_("-y ignored"));
1353 break;
1354 case 'L':
1355 if (leapsec)
1356 duplicate_options("-L");
1358 break;
1359 case 'v':
1360 noise = true;
1361 break;
1362 case 'P':
1363 print_abbrevs = true;
1364 print_cutoff = time(NULL);
1365 break;
1366 case 'r':
1367 if (timerange_given)
1368 duplicate_options("-r");
1370 {
1372 _("%s: invalid time range: %s\n"),
1373 progname, optarg);
1374 return EXIT_FAILURE;
1375 }
1376 timerange_given = true;
1377 break;
1378 case 'R':
1380 {
1381 fprintf(stderr, _("%s: invalid time: %s\n"),
1382 progname, optarg);
1383 return EXIT_FAILURE;
1384 }
1385 break;
1386 case 's':
1387 warning(_("-s ignored"));
1388 break;
1389 }
1390 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
1391 usage(stderr, EXIT_FAILURE); /* usage message by request */
1393 {
1394 fprintf(stderr, _("%s: -R time exceeds -r cutoff\n"), progname);
1395 return EXIT_FAILURE;
1396 }
1397 if (redundant_time < lo_time)
1399 if (bloat == 0)
1400 {
1401 static char const bloat_default[] = ZIC_BLOAT_DEFAULT;
1402
1403 if (strcmp(bloat_default, "slim") == 0)
1404 bloat = -1;
1405 else if (strcmp(bloat_default, "fat") == 0)
1406 bloat = 1;
1407 else
1408 abort(); /* Configuration error. */
1409 }
1410 if (directory == NULL)
1411 directory = "data";
1412 if (tzdefault == NULL)
1414
1415 if (optind < argc && leapsec != NULL)
1416 {
1418 adjleap();
1419 }
1420
1421 for (k = optind; k < argc; k++)
1422 infile(k, argv[k]);
1423 if (errors)
1424 return EXIT_FAILURE;
1425 associate();
1429 catch_signals();
1430 for (i = 0; i < nzones; i = j)
1431 {
1432 /*
1433 * Find the next non-continuation zone entry.
1434 */
1435 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
1436 continue;
1437 outzone(&zones[i], j - i);
1439 }
1440 make_links();
1441 if (lcltime != NULL)
1442 {
1444 dolink(lcltime, tzdefault, true);
1445 }
1446 if (psxrules != NULL)
1447 {
1449 dolink(psxrules, TZDEFRULES, true);
1450 }
1451 if (warnings && (ferror(stderr) || fclose(stderr) != 0))
1452 return EXIT_FAILURE;
1453 return errors ? EXIT_FAILURE : EXIT_SUCCESS;
1454}

References _, adjleap(), associate(), bloat, catch_signals(), change_directory(), check_for_signal(), close_file(), colon, COMMAND_LINE_FILENUM, directory, directory_ends_in_slash, dolink(), duplicate_options(), eat(), error(), errors, EXIT_FAILURE, EXIT_SUCCESS, fb(), fprintf, getopt(), group_option(), hi_time, i, infile(), j, lcltime, leapsec, LEAPSEC_FILENUM, lo_time, main_argv, make_links(), mode_option(), no_mode, noise, nzones, optarg, optind, output_mode, outzone(), owner_option(), print_abbrevs, print_cutoff, printf, progname, psxrules, redundant_time, redundant_time_option(), skip_mkdir, timerange_option(), TYPE_BIT, TZDEFAULT, tzdefault, TZDEFRULES, usage(), use_safe_temp_permissions(), warning(), warnings, zone::z_name, ZIC_BLOAT_DEFAULT, ZIC_MAX, and zones.

◆ make_links()

static void make_links ( void  )
static

Definition at line 968 of file zic.c.

969{
970 ptrdiff_t i,
971 j,
972 nalinks,
973 pass_size;
974
975 if (1 < nlinks)
977
978 /* Ignore each link superseded by a later link with the same name. */
979 j = 0;
980 for (i = 0; i < nlinks; i++)
981 {
982 while (i + 1 < nlinks
983 && strcmp(links[i].l_linkname, links[i + 1].l_linkname) == 0)
984 i++;
985 links[j++] = links[i];
986 }
987 nlinks = pass_size = j;
988
989 /*
990 * Walk through the link array making links. However, if a link's target
991 * has not been made yet, append a copy to the end of the array. The end
992 * of the array will gradually fill up with a small sorted subsequence of
993 * not-yet-made links. nalinks counts all the links in the array,
994 * including copies. When we reach the copied subsequence, it may still
995 * contain a link to a not-yet-made link, so the process repeats. At any
996 * given point in time, the link array consists of the following
997 * subregions, where 0 <= i <= j <= nalinks and 0 <= nlinks <= nalinks:
998 *
999 * 0 .. (i - 1): links that either have been made, or have been copied to
1000 * a later point point in the array (this later point can be in any of the
1001 * three subregions) i .. (j - 1): not-yet-made links for this pass j ..
1002 * (nalinks - 1): not-yet-made links that this pass has skipped because
1003 * they were links to not-yet-made links
1004 *
1005 * The first subregion might not be sorted if nlinks < i; the other two
1006 * subregions are sorted. This algorithm does not alter entries 0 ..
1007 * (nlinks - 1), which remain sorted.
1008 *
1009 * If there are L links, this algorithm is O(C*L*log(L)) where C is the
1010 * length of the longest link chain. Usually C is short (e.g., 3) though
1011 * its worst-case value is L.
1012 */
1013
1014 j = nalinks = nlinks;
1015
1016 for (i = 0; i < nalinks; i++)
1017 {
1018 struct link *l;
1019
1021
1022 /* If this pass examined all its links, start the next pass. */
1023 if (i == j)
1024 {
1025 if (nalinks - i == pass_size)
1026 {
1027 error(_("\"Link %s %s\" is part of a link cycle"),
1029 break;
1030 }
1031 j = nalinks;
1032 pass_size = nalinks - i;
1033 }
1034
1035 /*
1036 * Diagnose self links, which the cycle detection algorithm would not
1037 * otherwise catch.
1038 */
1039 if (strcmp(links[i].l_target, links[i].l_linkname) == 0)
1040 {
1041 error(_("link %s targets itself"), links[i].l_target);
1042 continue;
1043 }
1044
1045 /* Make this link unless its target has not been made yet. */
1046 l = bsearch(links[i].l_target, &links[i + 1], j - (i + 1),
1047 sizeof *links, bsearch_linkcmp);
1048 if (!l)
1049 l = bsearch(links[i].l_target, &links[j], nalinks - j,
1050 sizeof *links, bsearch_linkcmp);
1051 if (!l)
1052 dolink(links[i].l_target, links[i].l_linkname, false);
1053 else
1054 {
1055 /*
1056 * The link target has not been made yet; copy the link to the
1057 * end.
1058 */
1060 links[nalinks++] = links[i];
1061 }
1062
1063 if (noise && i < nlinks)
1064 {
1065 if (l)
1066 warning(_("link %s targeting link %s mishandled by pre-2023 zic"),
1068 else if (bsearch(links[i].l_target, links, nlinks, sizeof *links,
1070 warning(_("link %s targeting link %s"),
1072 }
1074 }
1075}

References _, bsearch_linkcmp(), check_for_signal(), dolink(), eat(), error(), fb(), growalloc(), i, j, link::l_filenum, link::l_linenum, link::l_linkname, link::l_target, links, nlinks, nlinks_alloc, noise, qsort, qsort_linkcmp(), and warning().

Referenced by main().

◆ memcheck()

static void * memcheck ( void ptr)
static

Definition at line 555 of file zic.c.

556{
557 if (ptr == NULL)
559 return ptr;
560}

References fb(), memory_exhausted(), and strerror.

Referenced by xmalloc(), xrealloc(), and xstrdup().

◆ memory_exhausted()

static ATTRIBUTE_NORETURN void memory_exhausted ( const char msg)
static

Definition at line 498 of file zic.c.

499{
500 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
502}

References _, EXIT_FAILURE, fb(), fprintf, and progname.

Referenced by grow_nitems_alloc(), memcheck(), and size_overflow().

◆ mkdirs()

static void mkdirs ( char const argname,
bool  ancestors 
)
static

Definition at line 4957 of file zic.c.

4958{
4959 /*
4960 * If -D was specified, do not create directories. If a file operation's
4961 * parent directory is missing, the operation will fail and be diagnosed.
4962 */
4963 if (!skip_mkdir)
4964 {
4965
4966 char *name = xstrdup(argname);
4967 char *cp = name;
4968
4969 /*
4970 * On MS-Windows systems, do not worry about drive letters or
4971 * backslashes, as this should suffice in practice. Time zone names
4972 * do not use drive letters and backslashes. If the -d option of zic
4973 * does not name an already-existing directory, it can use slashes to
4974 * separate the already-existing ancestor prefix from the
4975 * to-be-created subdirectories.
4976 */
4977
4978 /* Do not mkdir a root directory, as it must exist. */
4979 while (*cp == '/')
4980 cp++;
4981
4982 while (cp && ((cp = strchr(cp, '/')) || !ancestors))
4983 {
4984 if (cp)
4985 *cp = '\0';
4986
4987 /*
4988 * Try to create it. It's OK if creation fails because the
4989 * directory already exists, perhaps because some other process
4990 * just created it. For simplicity do not check first whether it
4991 * already exists, as that is checked anyway if the mkdir fails.
4992 */
4993 if (mkdir(name, MKDIR_PERMS) < 0)
4994 {
4995 /*
4996 * Do not report an error if err == EEXIST, because some other
4997 * process might have made the directory in the meantime.
4998 * Likewise for ENOSYS, because Solaris 10 mkdir fails with
4999 * ENOSYS if the directory is an automounted mount point.
5000 * Likewise for EACCES, since mkdir can fail with EACCES
5001 * merely because the parent directory is unwritable. Likewise
5002 * for most other error numbers.
5003 */
5004 int err = errno;
5005
5006 if (err == ELOOP || err == ENAMETOOLONG
5007 || err == ENOENT || err == ENOTDIR)
5008 {
5009 error(_("%s: Cannot create directory %s: %s"),
5012 }
5013 }
5014 if (cp)
5015 *cp++ = '/';
5016 }
5017 free(name);
5018 }
5019}

References _, ELOOP, ENAMETOOLONG, err(), error(), EXIT_FAILURE, fb(), free, mkdir, MKDIR_PERMS, name, progname, skip_mkdir, strerror, and xstrdup().

Referenced by change_directory(), dolink(), and open_outfile().

◆ mode_option()

static mode_t mode_option ( char const arg)
static

Definition at line 730 of file zic.c.

731{
732#if HAVE_SETMODE
733 void *set = setmode(arg);
734
735 if (set)
736 {
738
739 free(set);
740 return mode;
741 }
742#endif
743 return arg2num(arg, 8, min(MODE_T_MAX, ULONG_MAX),
744 N_("%s: -m '%s': invalid mode\n"));
745}

References arg, arg2num(), CREAT_PERMS, fb(), free, min, mode, MODE_T_MAX, and N_.

Referenced by main().

◆ namecheck()

static bool namecheck ( const char name)
static

Definition at line 1501 of file zic.c.

1502{
1503 char const *cp;
1504
1505 /* Benign characters in a portable file name. */
1506 static char const benign[] =
1507 "-/_"
1508 "abcdefghijklmnopqrstuvwxyz"
1509 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1510
1511 /*
1512 * Non-control chars in the POSIX portable character set, excluding the
1513 * benign characters.
1514 */
1515 static char const printable_and_not_benign[] =
1516 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
1517
1518 char const *component = name;
1519
1520 for (cp = name; *cp; cp++)
1521 {
1522 unsigned char c = *cp;
1523
1524 if (noise && !strchr(benign, c))
1525 {
1527 ? _("file name '%s' contains byte '%c'")
1528 : _("file name '%s' contains byte '\\%o'")),
1529 name, c);
1530 }
1531 if (c == '/')
1532 {
1534 return false;
1535 component = cp + 1;
1536 }
1537 }
1538 return componentcheck(name, component, cp);
1539}

References _, componentcheck(), fb(), name, noise, and warning().

Referenced by inlink(), and inzsub().

◆ oadd()

static ATTRIBUTE_PURE_114833_HACK zic_t oadd ( zic_t  t1,
zic_t  t2 
)
static

Definition at line 4729 of file zic.c.

4730{
4731#ifdef ckd_add
4732 zic_t sum;
4733
4734 if (!ckd_add(&sum, t1, t2))
4735 return sum;
4736#else
4737 if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1)
4738 return t1 + t2;
4739#endif
4740 time_overflow();
4741}

References fb(), time_overflow(), ZIC_MAX, and ZIC_MIN.

Referenced by adjleap(), gethms(), getleapdatetime(), outzone(), rpytime(), and tadd().

◆ omul()

static ATTRIBUTE_PURE_114833_HACK zic_t omul ( zic_t  t1,
zic_t  t2 
)
static

Definition at line 4762 of file zic.c.

4763{
4764#ifdef ckd_mul
4765 zic_t product;
4766
4767 if (!ckd_mul(&product, t1, t2))
4768 return product;
4769#else
4770 if (t2 < 0
4771 ? ZIC_MAX / t2 <= t1 && (t2 == -1 || t1 <= ZIC_MIN / t2)
4772 : t2 == 0 || (ZIC_MIN / t2 <= t1 && t1 <= ZIC_MAX / t2))
4773 return t1 * t2;
4774#endif
4775 time_overflow();
4776}

References fb(), time_overflow(), ZIC_MAX, and ZIC_MIN.

Referenced by gethms(), getleapdatetime(), and rpytime().

◆ open_outfile()

static FILE * open_outfile ( char const **  outname,
char **  tempname 
)
static

Definition at line 1707 of file zic.c.

1708{
1709 bool dirs_made = false;
1710
1711 if (!*tempname)
1713
1714 for (;; check_for_signal())
1715 {
1717 int fd = open(*outname, oflags, creat_perms);
1718 int err;
1719
1720 if (fd < 0)
1721 err = errno;
1722 else
1723 {
1724 FILE *fp = fdopen(fd, "wb");
1725
1726 if (fp)
1727 return fp;
1728 err = errno;
1729 close(fd);
1730 }
1731 if (err == ENOENT && !dirs_made)
1732 {
1733 mkdirs(*outname, true);
1734 dirs_made = true;
1735 }
1736 else if (err == EEXIST)
1738 else
1739 {
1740 fprintf(stderr, _("%s: Can't create %s%s%s: %s\n"),
1742 strerror(err));
1744 }
1745 }
1746}

References _, check_for_signal(), close, creat_perms, diagdir(), diagslash(), err(), EXIT_FAILURE, fb(), fd(), fprintf, mkdirs(), O_BINARY, progname, random_dirent(), and strerror.

Referenced by dolink(), and writezone().

◆ outzone()

static void outzone ( const struct zone zpfirst,
ptrdiff_t  zonecount 
)
static

Definition at line 3876 of file zic.c.

3877{
3878 ptrdiff_t i,
3879 j;
3880 zic_t starttime,
3881 untiltime;
3882 bool startttisstd;
3883 bool startttisut;
3884 char *startbuf;
3885 char *ab;
3886 char *envvar;
3887 int max_abbr_len;
3888 int max_envvar_len;
3889 int compat;
3890 bool do_extend;
3891 char version;
3893 int nonTZlimtype = -1;
3895 int defaulttype = -1;
3896 int max_stringoffset_len = sizeof "-167:59:59" - 1;
3897 int max_comma_stringrule_len = (sizeof ",M12.5.6/" - 1
3899
3901
3902 /* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND. */
3906
3908 ab = xmalloc(max_abbr_len + 1);
3909 envvar = xmalloc(max_envvar_len + 1);
3911 INITIALIZE(starttime);
3912
3913 /*
3914 * Now. . .finally. . .generate some useful data!
3915 */
3916 timecnt = 0;
3917 typecnt = 0;
3918 charcnt = 0;
3919
3920 /*
3921 * Thanks to Earl Chew for noting the need to unconditionally initialize
3922 * startttisstd.
3923 */
3924 startttisstd = false;
3925 startttisut = false;
3927 if (leapseen)
3928 {
3931 }
3932 for (i = 0; i < zonecount; ++i)
3933 {
3934 struct zone const *zp = &zpfirst[i];
3935
3936 if (i < zonecount - 1)
3937 updateminmax(zp->z_untilrule.r_loyear);
3938 for (j = 0; j < zp->z_nrules; ++j)
3939 {
3940 struct rule *rp = &zp->z_rules[j];
3941
3942 updateminmax(rp->r_loyear);
3943 if (rp->r_hiwasnum)
3944 updateminmax(rp->r_hiyear);
3945 }
3946 }
3947
3948 /*
3949 * Generate lots of data if a rule can't cover all future times.
3950 */
3951 compat = stringzone(envvar, zpfirst, zonecount);
3952 version = compat < 2013 ? '2' : '3';
3953 do_extend = compat < 0;
3954 if (noise)
3955 {
3956 if (!*envvar)
3957 warning("%s %s",
3958 _("no proleptic TZ string for zone"),
3959 zpfirst->z_name);
3960 else if (compat != 0)
3961 {
3962 /*
3963 * Circa-COMPAT clients, and earlier clients, might not work for
3964 * this zone when given dates before 1970 or after 2038.
3965 */
3966 warning(_("%s: pre-%d clients may mishandle"
3967 " distant timestamps"),
3968 zpfirst->z_name, compat);
3969 }
3970 }
3971 if (do_extend)
3972 {
3975 else
3976 min_year = ZIC_MIN;
3979 else
3980 max_year = ZIC_MAX;
3981 }
3983 + EPOCH_YEAR + 1));
3985 if (want_bloat())
3986 {
3987 /*
3988 * For the benefit of older systems, generate data from 1900 through
3989 * 2038.
3990 */
3991 if (min_year > YEAR_32BIT_MIN - 1)
3995 }
3996
3997 if (min_time < lo_time || hi_time < max_time)
3998 unspecifiedtype = addtype(0, "-00", false, false, false);
3999
4000 for (i = 0; i < zonecount; ++i)
4001 {
4002 /*
4003 * A guess that may well be corrected later.
4004 */
4005 zic_t save = 0;
4006 struct zone const *zp = &zpfirst[i];
4007 bool usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
4008 bool useuntil = i < (zonecount - 1);
4011
4012 if (useuntil && zp->z_untiltime <= min_time)
4013 continue;
4014 eat(zp->z_filenum, zp->z_linenum);
4015 *startbuf = '\0';
4016 if (zp->z_nrules == 0)
4017 {
4018 int type;
4019
4020 save = zp->z_save;
4021 doabbr(startbuf, zp, NULL, zp->z_isdst, save, false);
4022 type = addtype(oadd(zp->z_stdoff, save),
4023 startbuf, zp->z_isdst, startttisstd,
4024 startttisut);
4025 if (usestart)
4026 {
4027 addtt(starttime, type);
4028 if (nonTZlimtime < starttime)
4029 {
4030 nonTZlimtime = starttime;
4032 }
4033 usestart = false;
4034 }
4035 else
4036 defaulttype = type;
4037 }
4038 else
4039 {
4040 zic_t year;
4041
4042 for (year = min_year; year <= max_year; ++year)
4043 {
4044 if (useuntil && year > zp->z_untilrule.r_hiyear)
4045 break;
4046
4047 /*
4048 * Mark which rules to do in the current year. For those to
4049 * do, calculate rpytime(rp, year); The former TYPE field was
4050 * also considered here.
4051 */
4052 for (j = 0; j < zp->z_nrules; ++j)
4053 {
4054 zic_t one = 1;
4055 zic_t y2038_boundary = one << 31;
4056 struct rule *rp = &zp->z_rules[j];
4057
4058 eats(zp->z_filenum, zp->z_linenum,
4059 rp->r_filenum, rp->r_linenum);
4060 rp->r_todo = year >= rp->r_loyear &&
4061 year <= rp->r_hiyear;
4062 if (rp->r_todo)
4063 {
4064 rp->r_temp = rpytime(rp, year);
4065 rp->r_todo
4066 = (rp->r_temp < y2038_boundary
4067 || year <= max_year0);
4068 }
4069 }
4070 for (;;)
4071 {
4072 ptrdiff_t k;
4073 zic_t jtime,
4074 ktime;
4075 zic_t offset;
4076 struct rule *rp;
4077 int type;
4078
4080 if (useuntil)
4081 {
4082 /*
4083 * Turn untiltime into UT assuming the current stdoff
4084 * and save values.
4085 */
4086 untiltime = zp->z_untiltime;
4087 if (!zp->z_untilrule.r_todisut)
4089 -stdoff);
4090 if (!zp->z_untilrule.r_todisstd)
4092 -save);
4093 }
4094
4095 /*
4096 * Find the rule (of those to do, if any) that takes
4097 * effect earliest in the year.
4098 */
4099 k = -1;
4100 for (j = 0; j < zp->z_nrules; ++j)
4101 {
4102 struct rule *r = &zp->z_rules[j];
4103
4104 if (!r->r_todo)
4105 continue;
4106 eats(zp->z_filenum, zp->z_linenum,
4107 r->r_filenum, r->r_linenum);
4108 offset = r->r_todisut ? 0 : stdoff;
4109 if (!r->r_todisstd)
4110 offset = oadd(offset, save);
4111 jtime = r->r_temp;
4112 jtime = tadd(jtime, -offset);
4113 if (k < 0 || jtime < ktime)
4114 {
4115 k = j;
4116 ktime = jtime;
4117 }
4118 else if (jtime == ktime)
4119 {
4120 char const *dup_rules_msg =
4121 _("two rules for same instant");
4122
4123 eats(zp->z_filenum, zp->z_linenum,
4124 r->r_filenum, r->r_linenum);
4125 warning("%s", dup_rules_msg);
4126 r = &zp->z_rules[k];
4127 eats(zp->z_filenum, zp->z_linenum,
4128 r->r_filenum, r->r_linenum);
4129 error("%s", dup_rules_msg);
4130 }
4131 }
4132 if (k < 0)
4133 break; /* go on to next year */
4134 rp = &zp->z_rules[k];
4135 rp->r_todo = false;
4136 if (useuntil && ktime >= untiltime)
4137 {
4138 if (!*startbuf
4139 && (oadd(zp->z_stdoff, rp->r_save)
4140 == startoff))
4141 doabbr(startbuf, zp, rp->r_abbrvar,
4142 rp->r_isdst, rp->r_save,
4143 false);
4144 break;
4145 }
4146 save = rp->r_save;
4147 if (usestart && ktime == starttime)
4148 usestart = false;
4149 if (usestart)
4150 {
4151 if (ktime < starttime)
4152 {
4153 startoff = oadd(zp->z_stdoff,
4154 save);
4156 rp->r_abbrvar,
4157 rp->r_isdst,
4158 rp->r_save,
4159 false);
4160 continue;
4161 }
4162 if (*startbuf == '\0'
4163 && startoff == oadd(zp->z_stdoff,
4164 save))
4165 {
4167 zp,
4168 rp->r_abbrvar,
4169 rp->r_isdst,
4170 rp->r_save,
4171 false);
4172 }
4173 }
4174 eats(zp->z_filenum, zp->z_linenum,
4175 rp->r_filenum, rp->r_linenum);
4176 doabbr(ab, zp, rp->r_abbrvar,
4177 rp->r_isdst, rp->r_save, false);
4178 offset = oadd(zp->z_stdoff, rp->r_save);
4179 type = addtype(offset, ab, rp->r_isdst,
4180 rp->r_todisstd, rp->r_todisut);
4182 defaulttype = type;
4183 addtt(ktime, type);
4184 if (nonTZlimtime < ktime
4185 && (useuntil || rp->r_hiyear != ZIC_MAX))
4186 {
4189 }
4190 }
4191 }
4192 }
4193 if (usestart)
4194 {
4195 bool isdst = startoff != zp->z_stdoff;
4196
4197 if (*startbuf == '\0' && zp->z_format)
4199 isdst, save, false);
4200 eat(zp->z_filenum, zp->z_linenum);
4201 if (*startbuf == '\0')
4202 error(_("cannot determine time zone abbreviation"
4203 " to use just after until time"));
4204 else
4205 {
4208
4209 if (defaulttype < 0 && !isdst)
4210 defaulttype = type;
4211 addtt(starttime, type);
4212 }
4213 }
4214
4215 /*
4216 * Now we may get to set starttime for the next zone line.
4217 */
4218 if (useuntil)
4219 {
4220 startttisstd = zp->z_untilrule.r_todisstd;
4221 startttisut = zp->z_untilrule.r_todisut;
4222 starttime = zp->z_untiltime;
4223 if (!startttisstd)
4224 starttime = tadd(starttime, -save);
4225 if (!startttisut)
4226 starttime = tadd(starttime, -stdoff);
4227 }
4228 }
4229 if (defaulttype < 0)
4230 defaulttype = 0;
4231 if (!do_extend && !want_bloat())
4232 {
4233 /* Keep trailing transitions that are no greater than this. */
4235
4236 /* The earliest transition into a time governed by the TZ string. */
4238
4239 for (i = 0; i < timecnt; i++)
4240 {
4241 zic_t at = attypes[i].at;
4242
4243 if (nonTZlimtime < at && at < TZstarttime)
4244 TZstarttime = at;
4245 }
4246 if (TZstarttime == ZIC_MAX)
4248
4249 /*
4250 * Omit trailing transitions deducible from the TZ string, and not
4251 * needed for -r or -R.
4252 */
4254 for (i = j = 0; i < timecnt; i++)
4255 if (attypes[i].at <= keep_at_max)
4256 {
4257 attypes[j].at = attypes[i].at;
4259 && (nonTZlimtype != attypes[i].type
4260 || strchr(envvar, ',')));
4261 attypes[j].type = attypes[i].type;
4262 j++;
4263 }
4264 timecnt = j;
4265 }
4266 if (do_extend)
4267 {
4268 /*
4269 * If we're extending the explicitly listed observations for 400 years
4270 * because we can't fill the proleptic TZ field, check whether we
4271 * actually ended up explicitly listing observations through that
4272 * period. If there aren't any near the end of the 400-year period,
4273 * add a redundant one at the end of the final year, to make it clear
4274 * that we are claiming to have definite knowledge of the lack of
4275 * transitions up to that point.
4276 */
4277 struct rule xr;
4278 struct attype *lastat;
4279
4280 xr.r_month = TM_JANUARY;
4281 xr.r_dycode = DC_DOM;
4282 xr.r_dayofmonth = 1;
4283 xr.r_tod = 0;
4284 for (lastat = attypes, i = 1; i < timecnt; i++)
4285 if (attypes[i].at > lastat->at)
4286 lastat = &attypes[i];
4287 if (!lastat || lastat->at < rpytime(&xr, max_year - 1))
4288 {
4289 addtt(rpytime(&xr, max_year + 1),
4290 lastat ? lastat->type : defaulttype);
4291 attypes[timecnt - 1].dontmerge = true;
4292 }
4293 }
4294 writezone(zpfirst->z_name, envvar, version, defaulttype);
4295 free(startbuf);
4296 free(ab);
4297 free(envvar);
4298}

References _, addtt(), addtype(), attype::at, attypes, charcnt, check_for_signal(), compat, DAYSPERNYEAR, DC_DOM, disable_percent_s, doabbr(), attype::dontmerge, eat(), eats(), EPOCH_YEAR, error(), fb(), free, hi_time, i, INITIALIZE, j, leapmaxyear, leapminyear, leapseen, lo_time, max, max_abbrvar_len, max_format_len, max_time, max_year, min_time, min_year, noise, oadd(), rule::r_filenum, rule::r_isdst, rule::r_linenum, rule::r_temp, rule::r_todisstd, rule::r_todisut, rule::r_todo, redundant_time, rpytime(), SECSPERDAY, stringzone(), tadd(), timecnt, TM_JANUARY, type, attype::type, typecnt, unspecifiedtype, updateminmax(), want_bloat(), warning(), writezone(), xmalloc(), YEAR_32BIT_MAX, YEAR_32BIT_MIN, years_of_observations, zone::z_stdoff, zone::z_untiltime, ZIC_MAX, and ZIC_MIN.

Referenced by main().

◆ owner_option()

static void owner_option ( char const arg)
static

Definition at line 843 of file zic.c.

844{
845#ifndef WIN32
846 if (*arg)
847 {
848 if (output_owner != no_uid)
849 {
850 fprintf(stderr, _("multiple owners specified"));
852 }
853 else
854 {
855 struct passwd *pw = getpwnam(arg);
856
857 output_owner = (pw ? pw->pw_uid
859 N_("%s: invalid owner: %s\n")));
860 }
861 }
862#endif
863}

References _, arg, arg2num(), EXIT_FAILURE, fb(), fprintf, min, N_, no_uid, output_owner, and UID_T_MAX.

Referenced by main().

◆ puttzcode()

static void puttzcode ( zic_t  val,
FILE fp 
)
static

Definition at line 2876 of file zic.c.

2877{
2878 char buf[4];
2879
2880 convert(val, buf);
2881 fwrite(buf, sizeof buf, 1, fp);
2882}

References buf, convert(), fb(), and val.

Referenced by puttzcodepass(), and writezone().

◆ puttzcodepass()

static void puttzcodepass ( zic_t  val,
FILE fp,
int  pass 
)
static

Definition at line 2885 of file zic.c.

2886{
2887 if (pass == 1)
2888 puttzcode(val, fp);
2889 else
2890 {
2891 char buf[8];
2892
2893 convert64(val, buf);
2894 fwrite(buf, sizeof buf, 1, fp);
2895 }
2896}

References buf, convert64(), fb(), puttzcode(), and val.

Referenced by writezone().

◆ qsort_linkcmp()

static int qsort_linkcmp ( void const a,
void const b 
)
static

Definition at line 937 of file zic.c.

938{
939 struct link const *l = a;
940 struct link const *m = b;
941 int cmp = strcmp(l->l_linkname, m->l_linkname);
942
943 if (cmp)
944 return cmp;
945
946 /*
947 * The link names are the same. Make the sort stable by comparing file
948 * numbers (where subtraction cannot overflow) and possibly line numbers
949 * (where it can).
950 */
951 cmp = l->l_filenum - m->l_filenum;
952 if (cmp)
953 return cmp;
954 return (l->l_linenum > m->l_linenum) - (l->l_linenum < m->l_linenum);
955}

References a, b, cmp(), fb(), link::l_filenum, link::l_linenum, and link::l_linkname.

Referenced by make_links().

◆ random_dirent()

static void random_dirent ( char const **  name,
char **  namealloc 
)
static

Definition at line 1625 of file zic.c.

1626{
1627 char const *src = *name;
1628 char *dst = *namealloc;
1629 static char const prefix[] = ".zic";
1630 static char const alphabet[] =
1631 "abcdefghijklmnopqrstuvwxyz"
1632 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1633 "0123456789";
1634 enum
1635 {
1636 prefixlen = sizeof prefix - 1, alphabetlen = sizeof alphabet - 1};
1637 int suffixlen = 6;
1638 char const *lastslash = strrchr(src, '/');
1639 ptrdiff_t dirlen = lastslash ? lastslash + 1 - src : 0;
1640 int i;
1641 uint_fast64_t r;
1643
1644 /* BASE**6 */
1645 uint_fast64_t base__6 = base * base * base * base * base * base;
1646
1647 /*
1648 * The largest uintmax_t that is a multiple of BASE**6. Any random
1649 * uintmax_t value that is this value or greater, yields a biased
1650 * remainder when divided by BASE**6. UNFAIR_MIN equals the mathematical
1651 * value of ((UINTMAX_MAX + 1) - (UINTMAX_MAX + 1) % BASE**6) computed
1652 * without overflow.
1653 */
1655
1656 if (!dst)
1657 {
1658 char *cp = dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
1659
1660 memcpy(cp, src, dirlen);
1661 cp += dirlen;
1662 memcpy(cp, prefix, prefixlen);
1663 cp += prefixlen;
1664 cp[suffixlen] = '\0';
1665 *name = *namealloc = dst;
1666 }
1667
1668 for (;; check_for_signal())
1669 {
1670 r = get_rand_u64();
1671 if (r < unfair_min)
1672 break;
1673 }
1674
1675 for (i = 0; i < suffixlen; i++)
1676 {
1678 r /= alphabetlen;
1679 }
1680}

References check_for_signal(), fb(), get_rand_u64(), i, memcpy(), name, size_sum(), and xmalloc().

Referenced by dolink(), and open_outfile().

◆ rcomp()

static int rcomp ( const void cp1,
const void cp2 
)
static

Definition at line 2031 of file zic.c.

2032{
2033 struct rule const *r1 = cp1,
2034 *r2 = cp2;
2035
2036 return strcmp(r1->r_name, r2->r_name);
2037}

References fb().

Referenced by associate().

◆ redundant_time_option()

static bool redundant_time_option ( char opt)
static

Definition at line 1210 of file zic.c.

1211{
1212 if (*opt == '@')
1213 {
1215 char *opt_end;
1216
1217 redundant = strtoimax(opt + 1, &opt_end, 10);
1218 if (opt_end != opt + 1 && !*opt_end)
1219 {
1221 return true;
1222 }
1223 }
1224 return false;
1225}

References fb(), max, and redundant_time.

Referenced by main().

◆ relname()

static char * relname ( char const target,
char const linkname 
)
static

Definition at line 1781 of file zic.c.

1782{
1783 size_t i,
1784 taillen,
1785 dir_len = 0,
1786 dotdots = 0;
1789 char const *f = target;
1790 char *result = NULL;
1791
1792 if (*linkname == '/')
1793 {
1794 /* Make F absolute too. */
1795 size_t len = strlen(directory);
1796 bool needs_slash = len && directory[len - 1] != '/';
1797 size_t lenslash = len + needs_slash;
1798 size_t targetsize = strlen(target) + 1;
1799 char *cp;
1800
1801 if (*directory != '/')
1802 return NULL;
1804 f = cp = result = xmalloc(linksize);
1806 cp += len;
1807 *cp = '/';
1808 memcpy(cp + needs_slash, target, targetsize);
1809 }
1810 for (i = 0; f[i] && f[i] == linkname[i]; i++)
1811 if (f[i] == '/')
1812 dir_len = i + 1;
1813 for (; linkname[i]; i++)
1814 dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
1815 taillen = strlen(f + dir_len);
1817 if (dotdotetcsize <= linksize)
1818 {
1819 char *cp;
1820
1821 if (!result)
1823 cp = result;
1824 for (i = 0; i < dotdots; i++)
1825 {
1826 memcpy(cp, "../", 3);
1827 cp += 3;
1828 }
1829 memmove(cp, f + dir_len, taillen + 1);
1830 }
1831 return result;
1832}

References directory, fb(), i, INDEX_MAX, len, memcpy(), result, size_product(), size_sum(), and xmalloc().

◆ rename_dest()

static void rename_dest ( char tempname,
char const name 
)
static

Definition at line 1754 of file zic.c.

1755{
1756 if (tempname)
1757 {
1758 if (rename(tempname, name) != 0)
1759 {
1760 int rename_errno = errno;
1761
1762 remove(tempname);
1763 fprintf(stderr, _("%s: rename to %s%s%s: %s\n"),
1767 }
1768 free(tempname);
1769 }
1770}

References _, diagdir(), diagslash(), EXIT_FAILURE, fb(), fprintf, free, name, progname, and strerror.

Referenced by dolink(), and writezone().

◆ rpytime()

static zic_t rpytime ( const struct rule rp,
zic_t  wantedy 
)
static

Definition at line 4785 of file zic.c.

4786{
4787 int m,
4788 i;
4789 zic_t dayoff; /* with a nod to Margaret O. */
4790 zic_t t,
4791 y;
4792 int yrem;
4793
4794 m = TM_JANUARY;
4795 y = EPOCH_YEAR;
4796
4797 /*
4798 * dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT, sans
4799 * overflow.
4800 */
4803 + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0))
4804 * DAYSPERREPEAT);
4805 /* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow. */
4807
4808 while (wantedy != y)
4809 {
4810 i = len_years[isleap(y)];
4811 dayoff = oadd(dayoff, i);
4812 y++;
4813 }
4814 while (m != rp->r_month)
4815 {
4816 i = len_months[isleap(y)][m];
4817 dayoff = oadd(dayoff, i);
4818 ++m;
4819 }
4820 i = rp->r_dayofmonth;
4821 if (m == TM_FEBRUARY && i == 29 && !isleap(y))
4822 {
4823 if (rp->r_dycode == DC_DOWLEQ)
4824 --i;
4825 else
4826 {
4827 error(_("use of 2/29 in non leap-year"));
4829 }
4830 }
4831 --i;
4832 dayoff = oadd(dayoff, i);
4833 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ)
4834 {
4835 /*
4836 * Don't trust mod of negative numbers.
4837 */
4839 % DAYSPERWEEK);
4840
4841 while (wday != rp->r_wday)
4842 if (rp->r_dycode == DC_DOWGEQ)
4843 {
4844 dayoff = oadd(dayoff, 1);
4845 if (++wday >= DAYSPERWEEK)
4846 wday = 0;
4847 ++i;
4848 }
4849 else
4850 {
4851 dayoff = oadd(dayoff, -1);
4852 if (--wday < 0)
4853 wday = DAYSPERWEEK - 1;
4854 --i;
4855 }
4856 if (i < 0 || i >= len_months[isleap(y)][m])
4857 {
4858 if (noise)
4859 warning(_("rule goes past start/end of month; \
4860will not work with pre-2004 versions of zic"));
4861 }
4862 }
4863 t = omul(dayoff, SECSPERDAY);
4864 return tadd(t, rp->r_tod);
4865}

References _, DAYSPERREPEAT, DAYSPERWEEK, DC_DOWGEQ, DC_DOWLEQ, EPOCH_WDAY, EPOCH_YEAR, error(), EXIT_FAILURE, fb(), i, isleap, len_months, len_years, noise, oadd(), omul(), SECSPERDAY, tadd(), TM_FEBRUARY, TM_JANUARY, warning(), y, and YEARSPERREPEAT.

Referenced by inzsub(), and outzone().

◆ rule_cmp()

static int rule_cmp ( struct rule const a,
struct rule const b 
)
static

Definition at line 3713 of file zic.c.

3714{
3715 if (!a)
3716 return -!!b;
3717 if (!b)
3718 return 1;
3719 if (a->r_hiyear != b->r_hiyear)
3720 return a->r_hiyear < b->r_hiyear ? -1 : 1;
3721 if (a->r_hiyear == ZIC_MAX)
3722 return 0;
3723 if (a->r_month - b->r_month != 0)
3724 return a->r_month - b->r_month;
3725 return a->r_dayofmonth - b->r_dayofmonth;
3726}

References a, b, and ZIC_MAX.

Referenced by stringzone().

◆ rulesub()

static bool rulesub ( struct rule rp,
const char loyearp,
const char hiyearp,
const char typep,
const char monthp,
const char dayp,
const char timep 
)
static

Definition at line 2696 of file zic.c.

2699{
2700 const struct lookup *lp;
2701 const char *cp;
2702 char *dp;
2703 char *ep;
2704 char xs;
2705
2706 if ((lp = byword(monthp, mon_names)) == NULL)
2707 {
2708 error(_("invalid month name"));
2709 return false;
2710 }
2711 rp->r_month = lp->l_value;
2712 rp->r_todisstd = false;
2713 rp->r_todisut = false;
2714 dp = xstrdup(timep);
2715 if (*dp != '\0')
2716 {
2717 ep = dp + strlen(dp) - 1;
2718 switch (lowerit(*ep))
2719 {
2720 case 's': /* Standard */
2721 rp->r_todisstd = true;
2722 rp->r_todisut = false;
2723 *ep = '\0';
2724 break;
2725 case 'w': /* Wall */
2726 rp->r_todisstd = false;
2727 rp->r_todisut = false;
2728 *ep = '\0';
2729 break;
2730 case 'g': /* Greenwich */
2731 case 'u': /* Universal */
2732 case 'z': /* Zulu */
2733 rp->r_todisstd = true;
2734 rp->r_todisut = true;
2735 *ep = '\0';
2736 break;
2737 }
2738 }
2739 rp->r_tod = gethms(dp, _("invalid time of day"));
2740 free(dp);
2741
2742 /*
2743 * Year work.
2744 */
2745 cp = loyearp;
2746 lp = byword(cp, begin_years);
2747 if (lp)
2748 switch (lp->l_value)
2749 {
2750 case YR_MINIMUM:
2751 warning(_("FROM year \"%s\" is obsolete;"
2752 " treated as %d"),
2753 cp, YEAR_32BIT_MIN - 1);
2754 rp->r_loyear = YEAR_32BIT_MIN - 1;
2755 break;
2756 default:
2757 unreachable();
2758 }
2759 else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_loyear, &xs) != 1)
2760 {
2761 error(_("invalid starting year"));
2762 return false;
2763 }
2764 cp = hiyearp;
2765 lp = byword(cp, end_years);
2766 rp->r_hiwasnum = lp == NULL;
2767 if (!rp->r_hiwasnum)
2768 switch (lp->l_value)
2769 {
2770 case YR_MAXIMUM:
2771 rp->r_hiyear = ZIC_MAX;
2772 break;
2773 case YR_ONLY:
2774 rp->r_hiyear = rp->r_loyear;
2775 break;
2776 default:
2777 unreachable();
2778 }
2779 else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_hiyear, &xs) != 1)
2780 {
2781 error(_("invalid ending year"));
2782 return false;
2783 }
2784 if (rp->r_loyear > rp->r_hiyear)
2785 {
2786 error(_("starting year greater than ending year"));
2787 return false;
2788 }
2789 if (*typep != '\0')
2790 {
2791 error(_("year type \"%s\" is unsupported; use \"-\" instead"),
2792 typep);
2793 return false;
2794 }
2795
2796 /*
2797 * Day work. Accept things such as: 1 lastSunday last-Sunday
2798 * (undocumented; warn about this) Sun<=20 Sun>=7
2799 */
2800 dp = xstrdup(dayp);
2801 if ((lp = byword(dp, lasts)) != NULL)
2802 {
2803 rp->r_dycode = DC_DOWLEQ;
2804 rp->r_wday = lp->l_value;
2805 rp->r_dayofmonth = len_months[1][rp->r_month];
2806 }
2807 else
2808 {
2809 ep = strchr(dp, '<');
2810 if (ep)
2811 rp->r_dycode = DC_DOWLEQ;
2812 else
2813 {
2814 ep = strchr(dp, '>');
2815 if (ep)
2816 rp->r_dycode = DC_DOWGEQ;
2817 else
2818 {
2819 ep = dp;
2820 rp->r_dycode = DC_DOM;
2821 }
2822 }
2823 if (rp->r_dycode != DC_DOM)
2824 {
2825 *ep++ = 0;
2826 if (*ep++ != '=')
2827 {
2828 error(_("invalid day of month"));
2829 free(dp);
2830 return false;
2831 }
2832 if ((lp = byword(dp, wday_names)) == NULL)
2833 {
2834 error(_("invalid weekday name"));
2835 free(dp);
2836 return false;
2837 }
2838 rp->r_wday = lp->l_value;
2839 }
2840 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
2841 rp->r_dayofmonth <= 0 ||
2842 (rp->r_dayofmonth > len_months[1][rp->r_month]))
2843 {
2844 error(_("invalid day of month"));
2845 free(dp);
2846 return false;
2847 }
2848 }
2849 free(dp);
2850 return true;
2851}

References _, begin_years, byword(), DC_DOM, DC_DOWGEQ, DC_DOWLEQ, end_years, error(), fb(), free, gethms(), lasts, len_months, lowerit(), mon_names, SCNdZIC, unreachable, warning(), wday_names, xstrdup(), YEAR_32BIT_MIN, YR_MAXIMUM, YR_MINIMUM, YR_ONLY, and ZIC_MAX.

Referenced by inrule(), and inzsub().

◆ same_parent_dirs()

static ATTRIBUTE_PURE_114833 bool same_parent_dirs ( char const a,
char const b 
)
static

Definition at line 1842 of file zic.c.

1843{
1844 for (; *a == *b; a++, b++)
1845 if (!*a)
1846 return true;
1847 return !(strchr(a, '/') || strchr(b, '/'));
1848}

References a, b, and fb().

Referenced by dolink().

◆ signal_handler()

static void signal_handler ( int  sig)
static

Definition at line 1086 of file zic.c.

1087{
1088#ifndef SA_SIGINFO
1090#endif
1091 got_signal = sig;
1092}

References fb(), got_signal, sig, and signal_handler().

Referenced by catch_signals(), and signal_handler().

◆ size_overflow()

static ATTRIBUTE_NORETURN void size_overflow ( void  )
static

Definition at line 505 of file zic.c.

506{
507 memory_exhausted(_("size overflow"));
508}

References _, and memory_exhausted().

Referenced by size_product(), and size_sum().

◆ size_product()

static ATTRIBUTE_PURE_114833_HACK ptrdiff_t size_product ( ptrdiff_t  nitems,
ptrdiff_t  itemsize 
)
static

Definition at line 528 of file zic.c.

529{
530#ifdef ckd_mul
532
534 return product;
535#else
537
538 if (nitems <= nitems_max)
539 return nitems * itemsize;
540#endif
542}

References fb(), INDEX_MAX, nitems, and size_overflow().

Referenced by relname(), and writezone().

◆ size_sum()

static ATTRIBUTE_PURE_114833_HACK ptrdiff_t size_sum ( size_t  a,
size_t  b 
)
static

Definition at line 512 of file zic.c.

513{
514#ifdef ckd_add
515 ptrdiff_t sum;
516
517 if (!ckd_add(&sum, a, b) && sum <= INDEX_MAX)
518 return sum;
519#else
520 if (a <= INDEX_MAX && b <= INDEX_MAX - a)
521 return a + b;
522#endif
524}

References a, b, fb(), INDEX_MAX, and size_overflow().

Referenced by align_to(), random_dirent(), and relname().

◆ stringoffset()

static int stringoffset ( char result,
zic_t  offset 
)
static

Definition at line 3598 of file zic.c.

3599{
3600 int hours;
3601 int minutes;
3602 int seconds;
3603 bool negative = offset < 0;
3604 int len = negative;
3605
3606 if (negative)
3607 {
3608 offset = -offset;
3609 result[0] = '-';
3610 }
3611 seconds = offset % SECSPERMIN;
3612 offset /= SECSPERMIN;
3613 minutes = offset % MINSPERHOUR;
3614 offset /= MINSPERHOUR;
3615 if (offset >= HOURSPERDAY * DAYSPERWEEK)
3616 {
3617 result[0] = '\0';
3618 return 0;
3619 }
3620 hours = offset;
3621 len += sprintf(result + len, "%d", hours);
3622 if (minutes != 0 || seconds != 0)
3623 {
3624 len += sprintf(result + len, ":%02d", minutes);
3625 if (seconds != 0)
3626 len += sprintf(result + len, ":%02d", seconds);
3627 }
3628 return len;
3629}

References DAYSPERWEEK, fb(), HOURSPERDAY, len, MINSPERHOUR, result, SECSPERMIN, and sprintf.

Referenced by stringrule(), and stringzone().

◆ stringrule()

static int stringrule ( char result,
struct rule *const  rp,
zic_t  save,
zic_t  stdoff 
)
static

Definition at line 3632 of file zic.c.

3633{
3634 zic_t tod = rp->r_tod;
3635 int compat = 0;
3636
3637 if (rp->r_dycode == DC_DOM)
3638 {
3639 int month,
3640 total;
3641
3642 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
3643 return -1;
3644 total = 0;
3645 for (month = 0; month < rp->r_month; ++month)
3646 total += len_months[0][month];
3647 /* Omit the "J" in Jan and Feb, as that's shorter. */
3648 if (rp->r_month <= 1)
3649 result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
3650 else
3651 result += sprintf(result, "J%d", total + rp->r_dayofmonth);
3652 }
3653 else
3654 {
3655 int week;
3656 int wday = rp->r_wday;
3657 int wdayoff;
3658
3659 if (rp->r_dycode == DC_DOWGEQ)
3660 {
3661 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
3662 if (wdayoff)
3663 compat = 2013;
3664 wday -= wdayoff;
3665 tod += wdayoff * SECSPERDAY;
3666 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
3667 }
3668 else if (rp->r_dycode == DC_DOWLEQ)
3669 {
3670 if (rp->r_dayofmonth == len_months[1][rp->r_month])
3671 week = 5;
3672 else
3673 {
3674 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
3675 if (wdayoff)
3676 compat = 2013;
3677 wday -= wdayoff;
3678 tod += wdayoff * SECSPERDAY;
3679 week = rp->r_dayofmonth / DAYSPERWEEK;
3680 }
3681 }
3682 else
3683 return -1; /* "cannot happen" */
3684 if (wday < 0)
3685 wday += DAYSPERWEEK;
3686 result += sprintf(result, "M%d.%d.%d",
3687 rp->r_month + 1, week, wday);
3688 }
3689 if (rp->r_todisut)
3690 tod += stdoff;
3691 if (rp->r_todisstd && !rp->r_isdst)
3692 tod += save;
3693 if (tod != 2 * SECSPERMIN * MINSPERHOUR)
3694 {
3695 *result++ = '/';
3696 if (!stringoffset(result, tod))
3697 return -1;
3698 if (tod < 0)
3699 {
3700 if (compat < 2013)
3701 compat = 2013;
3702 }
3703 else if (SECSPERDAY <= tod)
3704 {
3705 if (compat < 1994)
3706 compat = 1994;
3707 }
3708 }
3709 return compat;
3710}

References compat, DAYSPERWEEK, DC_DOM, DC_DOWGEQ, DC_DOWLEQ, fb(), len_months, MINSPERHOUR, result, SECSPERDAY, SECSPERMIN, sprintf, stringoffset(), and TM_FEBRUARY.

Referenced by stringzone().

◆ stringzone()

static int stringzone ( char result,
struct zone const zpfirst,
ptrdiff_t  zonecount 
)
static

Definition at line 3735 of file zic.c.

3736{
3737 const struct zone *zp;
3738 struct rule *rp;
3739 struct rule *stdrp;
3740 struct rule *dstrp;
3741 ptrdiff_t i;
3742 int compat = 0;
3743 int c;
3744 int offsetlen;
3745 struct rule stdr,
3746 dstr;
3747 ptrdiff_t len;
3748 int dstcmp;
3749 struct rule *lastrp[2] = {NULL, NULL};
3750 struct zone zstr[2];
3751 struct zone const *stdzp;
3752 struct zone const *dstzp;
3753
3754 result[0] = '\0';
3755
3756 /*
3757 * Internet RFC 9636 section 6.1 says to use an empty TZ string if future
3758 * timestamps are truncated.
3759 */
3760 if (hi_time < max_time)
3761 return -1;
3762
3763 zp = zpfirst + zonecount - 1;
3764 for (i = 0; i < zp->z_nrules; ++i)
3765 {
3766 struct rule **last;
3767 int cmp;
3768
3769 rp = &zp->z_rules[i];
3770 last = &lastrp[rp->r_isdst];
3771 cmp = rule_cmp(*last, rp);
3772 if (cmp < 0)
3773 *last = rp;
3774 else if (cmp == 0)
3775 return -1;
3776 }
3777 stdrp = lastrp[false];
3778 dstrp = lastrp[true];
3779 dstcmp = zp->z_nrules ? rule_cmp(dstrp, stdrp) : zp->z_isdst ? 1 : -1;
3780 stdzp = dstzp = zp;
3781
3782 if (dstcmp < 0)
3783 {
3784 /* Standard time all year. */
3785 dstrp = NULL;
3786 }
3787 else if (0 < dstcmp)
3788 {
3789 /*
3790 * DST all year. Use an abbreviation like "XXX3EDT4,0/0,J365/23" for
3791 * EDT (-04) all year.
3792 */
3793 zic_t save = dstrp ? dstrp->r_save : zp->z_save;
3794
3795 if (0 <= save)
3796 {
3797 /*
3798 * Positive DST, the typical case for all-year DST. Fake a
3799 * timezone with negative DST.
3800 */
3801 stdzp = &zstr[0];
3802 dstzp = &zstr[1];
3803 zstr[0].z_stdoff = zp->z_stdoff + 2 * save;
3804 zstr[0].z_format = "XXX"; /* Any 3 letters will do. */
3805 zstr[0].z_format_specifier = 0;
3806 zstr[1].z_stdoff = zstr[0].z_stdoff;
3807 zstr[1].z_format = zp->z_format;
3808 zstr[1].z_format_specifier = zp->z_format_specifier;
3809 }
3810 dstr.r_month = TM_JANUARY;
3811 dstr.r_dycode = DC_DOM;
3812 dstr.r_dayofmonth = 1;
3813 dstr.r_tod = 0;
3814 dstr.r_todisstd = dstr.r_todisut = false;
3815 dstr.r_isdst = true;
3816 dstr.r_save = save < 0 ? save : -save;
3817 dstr.r_abbrvar = dstrp ? dstrp->r_abbrvar : NULL;
3818 stdr.r_month = TM_DECEMBER;
3819 stdr.r_dycode = DC_DOM;
3820 stdr.r_dayofmonth = 31;
3821 stdr.r_tod = SECSPERDAY + dstr.r_save;
3822 stdr.r_todisstd = stdr.r_todisut = false;
3823 stdr.r_isdst = false;
3824 stdr.r_save = 0;
3825 stdr.r_abbrvar = save < 0 && stdrp ? stdrp->r_abbrvar : NULL;
3826 dstrp = &dstr;
3827 stdrp = &stdr;
3828 }
3829 len = doabbr(result, stdzp, stdrp ? stdrp->r_abbrvar : NULL,
3830 false, 0, true);
3831 offsetlen = stringoffset(result + len, -stdzp->z_stdoff);
3832 if (!offsetlen)
3833 {
3834 result[0] = '\0';
3835 return -1;
3836 }
3837 len += offsetlen;
3838 if (dstrp == NULL)
3839 return compat;
3840 len += doabbr(result + len, dstzp, dstrp->r_abbrvar,
3841 dstrp->r_isdst, dstrp->r_save, true);
3842 if (dstrp->r_save != SECSPERMIN * MINSPERHOUR)
3843 {
3845 -(dstzp->z_stdoff + dstrp->r_save));
3846 if (!offsetlen)
3847 {
3848 result[0] = '\0';
3849 return -1;
3850 }
3851 len += offsetlen;
3852 }
3853 result[len++] = ',';
3854 c = stringrule(result + len, dstrp, dstrp->r_save, stdzp->z_stdoff);
3855 if (c < 0)
3856 {
3857 result[0] = '\0';
3858 return -1;
3859 }
3860 if (compat < c)
3861 compat = c;
3862 len += strlen(result + len);
3863 result[len++] = ',';
3864 c = stringrule(result + len, stdrp, dstrp->r_save, stdzp->z_stdoff);
3865 if (c < 0)
3866 {
3867 result[0] = '\0';
3868 return -1;
3869 }
3870 if (compat < c)
3871 compat = c;
3872 return compat;
3873}

References cmp(), compat, DC_DOM, doabbr(), fb(), hi_time, i, len, max_time, MINSPERHOUR, result, rule_cmp(), SECSPERDAY, SECSPERMIN, stringoffset(), stringrule(), TM_DECEMBER, and TM_JANUARY.

Referenced by outzone().

◆ tadd()

static ATTRIBUTE_PURE_114833_HACK zic_t tadd ( zic_t  t1,
zic_t  t2 
)
static

Definition at line 4750 of file zic.c.

4751{
4752 zic_t sum = oadd(t1, t2);
4753
4754 if (min_time <= sum && sum <= max_time)
4755 return sum;
4756 time_overflow();
4757}

References fb(), max_time, min_time, oadd(), and time_overflow().

Referenced by adjleap(), getleapdatetime(), outzone(), rpytime(), and writezone().

◆ time_overflow()

static ATTRIBUTE_NORETURN void time_overflow ( void  )
static

Definition at line 4720 of file zic.c.

4721{
4722 error(_("time overflow"));
4724}

References _, error(), EXIT_FAILURE, and fb().

Referenced by oadd(), omul(), and tadd().

◆ timerange_option()

static bool timerange_option ( char timerange)
static

Definition at line 1178 of file zic.c.

1179{
1180 intmax_t lo = min_time,
1181 hi = max_time;
1182 char *lo_end = timerange,
1183 *hi_end;
1184
1185 if (*timerange == '@')
1186 {
1187 errno = 0;
1188 lo = strtoimax(timerange + 1, &lo_end, 10);
1189 if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE))
1190 return false;
1191 }
1192 hi_end = lo_end;
1193 if (lo_end[0] == '/' && lo_end[1] == '@')
1194 {
1195 errno = 0;
1196 hi = strtoimax(lo_end + 2, &hi_end, 10);
1197 if (hi_end == lo_end + 2 || hi == INTMAX_MIN)
1198 return false;
1199 hi -= !(hi == INTMAX_MAX && errno == ERANGE);
1200 }
1201 if (*hi_end || hi < lo || max_time < lo || hi < min_time)
1202 return false;
1203 lo_time = max(lo, min_time);
1204 hi_time = min(hi, max_time);
1205 return true;
1206}

References fb(), hi_time, lo_time, max, max_time, min, and min_time.

Referenced by main().

◆ updateminmax()

static void updateminmax ( const zic_t  x)
static

Definition at line 3589 of file zic.c.

3590{
3591 if (min_year > x)
3592 min_year = x;
3593 if (max_year < x)
3594 max_year = x;
3595}

References max_year, min_year, and x.

Referenced by outzone().

◆ usage()

static ATTRIBUTE_NORETURN void usage ( FILE stream,
int  status 
)
static

Definition at line 803 of file zic.c.

804{
805 fprintf(stream,
806 _("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -P ] \\\n"
807 "\t[ -b {slim|fat} ] [ -d directory ] [ -D ] \\\n"
808 "\t[ -l localtime ] [ -L leapseconds ] [ -m mode ] \\\n"
809 "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R @hi ] \\\n"
810 "\t[ -t localtime-link ] [ -u 'owner[:group]' ] \\\n"
811 "\t[ filename ... ]\n\n"
812 "Report bugs to %s.\n"),
814 if (status == EXIT_SUCCESS)
815 close_file(stream, NULL, NULL, NULL);
816 exit(status);
817}

References _, close_file(), EXIT_SUCCESS, fb(), fprintf, and progname.

◆ use_safe_temp_permissions()

static void use_safe_temp_permissions ( void  )
static

Definition at line 870 of file zic.c.

871{
873 {
874
875 /* The mode when done with the file. */
877
878 if (output_mode == no_mode)
879 {
880 mode_t cmask = umask(0);
881
882 umask(cmask);
884 }
885 else
887
888 /*
889 * The mode passed to open+O_CREAT. Do not bother with executable
890 * permissions, as they should not be used and this mode is merely a
891 * nicety (even a mode of 0 still work).
892 */
894 == (S_IRUSR | S_IRGRP | S_IROTH))
895 ? S_IRUSR | S_IRGRP | S_IROTH : 0)
896 | (((omode & (S_IWUSR | S_IWGRP | S_IWOTH))
897 == (S_IWUSR | S_IWGRP | S_IWOTH))
898 ? S_IWUSR | S_IWGRP | S_IWOTH : 0));
899
900 /*
901 * If creat_perms is not the final mode, arrange to run fchmod later,
902 * even if -m was not used.
903 */
904 if (creat_perms != omode)
906 }
907}

References CREAT_PERMS, creat_perms, fb(), no_gid, no_mode, no_uid, output_group, output_mode, output_owner, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, and S_IWUSR.

Referenced by main().

◆ verror()

static void verror ( const char *const  string,
va_list  args 
)
static

Definition at line 652 of file zic.c.

653{
655
656 /*
657 * Match the format of "cc" to allow sh users to zic ... 2>&1 | error -t
658 * "*" -v on BSD systems.
659 */
660 if (filenum)
661 fprintf(stderr, _("\"%s\", line %" PRIdMAX ": "),
663 vfprintf(stderr, string, args);
664 if (rfilenum)
665 fprintf(stderr, _(" (rule from \"%s\", line %" PRIdMAX ")"),
667 fprintf(stderr, "\n");
668}

References _, check_for_signal(), fb(), filename, filenum, fprintf, linenum, rfilenum, rlinenum, and vfprintf.

Referenced by error(), and warning().

◆ want_bloat()

static bool want_bloat ( void  )
static

Definition at line 1243 of file zic.c.

1244{
1245 return 0 <= bloat;
1246}

References bloat.

Referenced by addtype(), outzone(), and writezone().

◆ warning()

static void warning ( const char *const  string,
  ... 
)
static

Definition at line 682 of file zic.c.

683{
685
686 fprintf(stderr, _("warning: "));
687 va_start(args, string);
688 verror(string, args);
689 va_end(args);
690 warnings = true;
691}

References _, fb(), fprintf, verror(), and warnings.

Referenced by associate(), byword(), checkabbr(), componentcheck(), dolink(), EmitConnectionWarnings(), get_role_password(), gethms(), inzsub(), main(), make_links(), namecheck(), outzone(), queue_md5_password_warning(), rpytime(), rulesub(), StoreConnectionWarning(), and writezone().

◆ writezone()

static void writezone ( const char *const  name,
const char *const  string,
char  version,
int  defaulttype 
)
static

Definition at line 2968 of file zic.c.

2970{
2971 FILE *fp;
2972 ptrdiff_t i,
2973 j;
2974 int pass;
2975 char *tempname = NULL;
2976 char const *outname = name;
2977
2978 /*
2979 * Allocate the ATS and TYPES arrays via a single malloc, as this is a bit
2980 * faster. Do not malloc(0) if !timecnt, as that might return NULL even
2981 * on success.
2982 */
2984 sizeof *ats + 1),
2985 alignof(zic_t)));
2986 void *typesptr = ats + timecnt;
2987 unsigned char *types = typesptr;
2988 struct timerange rangeall = {0}, range32, range64;
2989
2990 /*
2991 * Sort.
2992 */
2993 if (timecnt > 1)
2994 qsort(attypes, timecnt, sizeof *attypes, atcomp);
2995
2996 /*
2997 * Optimize and skip unwanted transitions.
2998 */
2999 {
3001 toi;
3002
3003 toi = 0;
3004 fromi = 0;
3005 for (; fromi < timecnt; ++fromi)
3006 {
3007 if (toi != 0)
3008 {
3009 /*
3010 * Skip the previous transition if it is unwanted because its
3011 * local time is not earlier. The UT offset additions can't
3012 * overflow because of how the times were calculated.
3013 */
3014 unsigned char type_2 =
3015 toi == 1 ? 0 : attypes[toi - 2].type;
3016
3017 if ((attypes[fromi].at
3018 + utoffs[attypes[toi - 1].type])
3019 <= attypes[toi - 1].at + utoffs[type_2])
3020 {
3021 if (attypes[fromi].type == type_2)
3022 toi--;
3023 else
3024 attypes[toi - 1].type =
3026 continue;
3027 }
3028 }
3029
3030 /*
3031 * Use a transition if it is the first one, or if it cannot be
3032 * merged for other reasons, or if it transitions to different
3033 * timekeeping.
3034 */
3035 if (toi == 0
3036 || attypes[fromi].dontmerge
3037 || (utoffs[attypes[toi - 1].type]
3038 != utoffs[attypes[fromi].type])
3039 || (isdsts[attypes[toi - 1].type]
3040 != isdsts[attypes[fromi].type])
3041 || (desigidx[attypes[toi - 1].type]
3042 != desigidx[attypes[fromi].type]))
3043 attypes[toi++] = attypes[fromi];
3044 }
3045 timecnt = toi;
3046 }
3047
3048 if (noise)
3049 {
3050 if (1200 < timecnt)
3051 {
3052 if (TZ_MAX_TIMES < timecnt)
3053 warning(_("reference clients mishandle"
3054 " more than %d transition times"),
3055 TZ_MAX_TIMES);
3056 else
3057 warning(_("pre-2014 clients may mishandle"
3058 " more than 1200 transition times"));
3059 }
3060 if (TZ_MAX_LEAPS < leapcnt)
3061 warning(_("reference clients mishandle more than %d leap seconds"),
3062 TZ_MAX_LEAPS);
3063 }
3064
3065 /*
3066 * Transfer.
3067 */
3068 for (i = 0; i < timecnt; ++i)
3069 {
3070 ats[i] = attypes[i].at;
3071 types[i] = attypes[i].type;
3072 }
3073
3074 /*
3075 * Correct for leap seconds.
3076 */
3077 for (i = 0; i < timecnt; ++i)
3078 {
3079 j = leapcnt;
3080 while (--j >= 0)
3081 if (leap[j].trans - leap[j].corr < ats[i])
3082 {
3083 ats[i] = tadd(ats[i], leap[j].corr);
3084 break;
3085 }
3086 }
3087
3088 rangeall.defaulttype = defaulttype;
3089 rangeall.count = timecnt;
3090 rangeall.leapcount = leapcnt;
3092 max(hi_time,
3094 ats, types);
3096
3097 /*
3098 * TZif version 4 is needed if a no-op transition is appended to indicate
3099 * the expiration of the leap second table, or if the first leap second
3100 * transition is not to a +1 or -1 correction.
3101 */
3102 for (pass = 1; pass <= 2; pass++)
3103 {
3104 struct timerange const *r = pass == 1 ? &range32 : &range64;
3105
3106 if (pass == 1 && !want_bloat())
3107 continue;
3108 if (r->leapexpiry)
3109 {
3110 if (noise)
3111 warning(_("%s: pre-2021b clients may mishandle"
3112 " leap second expiry"),
3113 name);
3114 version = '4';
3115 }
3116 if (0 < r->leapcount
3117 && leap[r->leapbase].corr != 1 && leap[r->leapbase].corr != -1)
3118 {
3119 if (noise)
3120 warning(_("%s: pre-2021b clients may mishandle"
3121 " leap second table truncation"),
3122 name);
3123 version = '4';
3124 }
3125 if (version == '4')
3126 break;
3127 }
3128
3129 fp = open_outfile(&outname, &tempname);
3130
3131 for (pass = 1; pass <= 2; ++pass)
3132 {
3139 struct tzhead tzh;
3140 int pretranstype = -1,
3142 bool locut,
3143 hicut,
3145 zic_t lo,
3146 thismin,
3147 thismax;
3148 int old0;
3149 char omittype[TZ_MAX_TYPES];
3150 int typemap[TZ_MAX_TYPES];
3151 int thistypecnt,
3152 stdcnt,
3153 utcnt;
3154 char thischars[TZ_MAX_CHARS];
3155 int thischarcnt;
3156 bool toomanytimes;
3157 int indmap[TZ_MAX_CHARS];
3158
3159 if (pass == 1)
3160 {
3161 thisdefaulttype = range32.defaulttype;
3162 thistimei = range32.base;
3163 thistimecnt = range32.count;
3164 toomanytimes = thistimecnt >> 31 >> 1 != 0;
3165 thisleapi = range32.leapbase;
3166 thisleapcnt = range32.leapcount;
3167 thisleapexpiry = range32.leapexpiry;
3170 }
3171 else
3172 {
3173 thisdefaulttype = range64.defaulttype;
3174 thistimei = range64.base;
3175 thistimecnt = range64.count;
3176 toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
3177 thisleapi = range64.leapbase;
3178 thisleapcnt = range64.leapcount;
3179 thisleapexpiry = range64.leapexpiry;
3180 thismin = min_time;
3181 thismax = max_time;
3182 }
3183 if (toomanytimes)
3184 error(_("too many transition times"));
3185
3189 memset(omittype, true, typecnt);
3190
3191 /*
3192 * Determine whether to output a transition before the first
3193 * transition in range. This is needed when the output is truncated
3194 * at the start, and is also useful when catering to buggy 32-bit
3195 * clients that do not use time type 0 for timestamps before the first
3196 * transition.
3197 */
3198 if ((locut || (pass == 1 && thistimei))
3199 && !(thistimecnt && ats[thistimei] == lo_time))
3200 {
3202 omittype[pretranstype] = false;
3203 }
3204
3205 /*
3206 * Arguably the default time type in the 32-bit data should be
3207 * range32.defaulttype, which is suited for timestamps just before
3208 * ZIC32_MIN. However, zic traditionally used the time type of the
3209 * indefinite past instead. Internet RFC 8532 says readers should
3210 * ignore 32-bit data, so this discrepancy matters only to obsolete
3211 * readers where the traditional type might be more appropriate even
3212 * if it's "wrong". So, use the historical zic value, unless -r
3213 * specifies a low cutoff that excludes some 32-bit timestamps.
3214 */
3215 if (pass == 1 && lo_time <= thismin)
3216 thisdefaulttype = range64.defaulttype;
3217
3218 if (locut)
3220 omittype[thisdefaulttype] = false;
3221 for (i = thistimei; i < thistimelim; i++)
3222 omittype[types[i]] = false;
3223 if (hicut)
3224 omittype[unspecifiedtype] = false;
3225
3226 /*
3227 * Reorder types to make THISDEFAULTTYPE type 0. Use TYPEMAP to swap
3228 * OLD0 and THISDEFAULTTYPE so that THISDEFAULTTYPE appears as type 0
3229 * in the output instead of OLD0. TYPEMAP also omits unused types.
3230 */
3231 old0 = strlen(omittype);
3232
3233#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
3234
3235 /*
3236 * For some pre-2011 systems: if the last-to-be-written standard (or
3237 * daylight) type has an offset different from the most recently used
3238 * offset, append an (unused) copy of the most recently used type (to
3239 * help get global "altzone" and "timezone" variables set correctly).
3240 */
3241 if (want_bloat())
3242 {
3243 int mrudst,
3244 mrustd,
3245 hidst,
3246 histd,
3247 type;
3248
3249 hidst = histd = mrudst = mrustd = -1;
3250 if (0 <= pretranstype)
3251 {
3252 if (isdsts[pretranstype])
3254 else
3256 }
3257 for (i = thistimei; i < thistimelim; i++)
3258 if (isdsts[types[i]])
3259 mrudst = types[i];
3260 else
3261 mrustd = types[i];
3262 for (i = old0; i < typecnt; i++)
3263 {
3264 int h = (i == old0 ? thisdefaulttype
3265 : i == thisdefaulttype ? old0 : i);
3266
3267 if (!omittype[h])
3268 {
3269 if (isdsts[h])
3270 hidst = i;
3271 else
3272 histd = i;
3273 }
3274 }
3275 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
3277 {
3278 isdsts[mrudst] = -1;
3281 true,
3283 ttisuts[mrudst]);
3284 isdsts[mrudst] = 1;
3285 omittype[type] = false;
3286 }
3287 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
3289 {
3290 isdsts[mrustd] = -1;
3293 false,
3295 ttisuts[mrustd]);
3296 isdsts[mrustd] = 0;
3297 omittype[type] = false;
3298 }
3299 }
3300#endif /* !defined
3301 * LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
3302 thistypecnt = 0;
3303 for (i = old0; i < typecnt; i++)
3304 if (!omittype[i])
3306 : i == thisdefaulttype ? old0 : i]
3307 = thistypecnt++;
3308
3309 thischarcnt = stdcnt = utcnt = 0;
3310 for (i = old0; i < typecnt; i++)
3311 {
3312 if (omittype[i])
3313 continue;
3314 if (ttisstds[i])
3316 if (ttisuts[i])
3319 }
3320
3321 /*
3322 * Now that all abbrevs have been added to THISCHARS, it is safe to
3323 * set INDMAP without worrying about whether the abbrevs might move
3324 * later.
3325 */
3326 for (i = 0; i < TZ_MAX_CHARS; i++)
3327 indmap[i] = -1;
3328 for (i = old0; i < typecnt; i++)
3329 if (!omittype[i] && indmap[desigidx[i]] < 0)
3331 &chars[desigidx[i]]);
3332
3333 if (pass == 1 && !want_bloat())
3334 {
3335 hicut = thisleapexpiry = false;
3336 pretranstype = -1;
3339 }
3340#define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
3341 memset(&tzh, 0, sizeof tzh);
3342 memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
3343 tzh.tzh_version[0] = version;
3344 convert(utcnt, tzh.tzh_ttisutcnt);
3345 convert(stdcnt, tzh.tzh_ttisstdcnt);
3346 convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt);
3348 tzh.tzh_timecnt);
3349 convert(thistypecnt, tzh.tzh_typecnt);
3350 convert(thischarcnt, tzh.tzh_charcnt);
3351 DO(tzh_magic);
3352 DO(tzh_version);
3356 DO(tzh_leapcnt);
3357 DO(tzh_timecnt);
3358 DO(tzh_typecnt);
3359 DO(tzh_charcnt);
3360#undef DO
3361 if (pass == 1 && !want_bloat())
3362 {
3363 /* Output a minimal data block with just one time type. */
3364 puttzcode(0, fp); /* utoff */
3365 putc(0, fp); /* dst */
3366 putc(0, fp); /* index of abbreviation */
3367 putc(0, fp); /* empty-string abbreviation */
3368 continue;
3369 }
3370
3371 /* PG: print current timezone abbreviations if requested */
3372 if (print_abbrevs && pass == 2)
3373 {
3374 /* Print "type" data for periods ending after print_cutoff */
3375 for (i = thistimei; i < thistimelim; ++i)
3376 {
3377 if (i == thistimelim - 1 || ats[i + 1] > print_cutoff)
3378 {
3379 unsigned char tm = types[i];
3381
3382 fprintf(stdout, "%s\t%" PRIdFAST64 "%s\n",
3383 thisabbrev,
3384 utoffs[tm],
3385 isdsts[tm] ? "\tD" : "");
3386 }
3387 }
3388 /* Print the default type if we have no transitions at all */
3389 if (thistimei >= thistimelim)
3390 {
3391 unsigned char tm = defaulttype;
3393
3394 fprintf(stdout, "%s\t%" PRIdFAST64 "%s\n",
3395 thisabbrev,
3396 utoffs[tm],
3397 isdsts[tm] ? "\tD" : "");
3398 }
3399 }
3400
3401 if (pass == 2 && noise && 50 < thischarcnt)
3402 warning(_("%s: pre-2026 reference clients mishandle"
3403 " more than 50 bytes of abbreviations"),
3404 name);
3405
3406 /*
3407 * Output a LO_TIME transition if needed; see limitrange. But do not
3408 * go below the minimum representable value for this pass.
3409 */
3410 lo = pass == 1 && lo_time < ZIC32_MIN ? ZIC32_MIN : lo_time;
3411
3412 if (0 <= pretranstype)
3413 puttzcodepass(lo, fp, pass);
3414 for (i = thistimei; i < thistimelim; ++i)
3415 {
3416 puttzcodepass(ats[i], fp, pass);
3417 }
3418 if (hicut)
3419 puttzcodepass(hi_time + 1, fp, pass);
3420 if (0 <= pretranstype)
3422 for (i = thistimei; i < thistimelim; i++)
3423 putc(typemap[types[i]], fp);
3424 if (hicut)
3426
3427 for (i = old0; i < typecnt; i++)
3428 {
3429 int h = (i == old0 ? thisdefaulttype
3430 : i == thisdefaulttype ? old0 : i);
3431
3432 if (!omittype[h])
3433 {
3434 puttzcode(utoffs[h], fp);
3435 putc(isdsts[h], fp);
3436 putc(indmap[desigidx[h]], fp);
3437 }
3438 }
3439 if (thischarcnt != 0)
3440 fwrite(thischars, sizeof thischars[0],
3441 thischarcnt, fp);
3443 for (i = thisleapi; i < thisleaplim; ++i)
3444 {
3445 zic_t todo;
3446
3447 if (leap[i].roll)
3448 {
3449 if (timecnt == 0 || leap[i].trans < ats[0])
3450 {
3451 j = 0;
3452 while (isdsts[j])
3453 if (++j >= typecnt)
3454 {
3455 j = 0;
3456 break;
3457 }
3458 }
3459 else
3460 {
3461 j = 1;
3462 while (j < timecnt &&
3463 ats[j] <= leap[i].trans)
3464 ++j;
3465 j = types[j - 1];
3466 }
3467 todo = tadd(leap[i].trans, -utoffs[j]);
3468 }
3469 else
3470 todo = leap[i].trans;
3471 puttzcodepass(todo, fp, pass);
3472 puttzcode(leap[i].corr, fp);
3473 }
3474 if (thisleapexpiry)
3475 {
3476 /*
3477 * Append a no-op leap correction indicating when the leap second
3478 * table expires. Although this does not conform to Internet RFC
3479 * 9636, most clients seem to accept this and the plan is to amend
3480 * the RFC to allow this in version 4 TZif files.
3481 */
3483 puttzcode(thisleaplim ? leap[thisleaplim - 1].corr : 0, fp);
3484 }
3485 if (stdcnt != 0)
3486 for (i = old0; i < typecnt; i++)
3487 if (!omittype[i])
3488 putc(ttisstds[i], fp);
3489 if (utcnt != 0)
3490 for (i = old0; i < typecnt; i++)
3491 if (!omittype[i])
3492 putc(ttisuts[i], fp);
3493 }
3494 fprintf(fp, "\n%s\n", string);
3497 free(ats);
3498}

References _, addabbr(), addtype(), align_to(), attype::at, atcomp(), attypes, chars, close_file(), convert(), corr, timerange::defaulttype, desigidx, directory, DO, error(), fb(), fprintf, free, hi_time, i, isdsts, j, leap, timerange::leapbase, leapcnt, timerange::leapcount, leapexpires, timerange::leapexpiry, limitrange(), lo_time, max, max_time, memcpy(), min_time, name, noise, open_outfile(), print_abbrevs, print_cutoff, puttzcode(), puttzcodepass(), qsort, redundant_time, rename_dest(), roll, size_product(), tadd(), timecnt, tm, trans, ttisstds, ttisuts, type, attype::type, typecnt, types, TZ_MAGIC, TZ_MAX_CHARS, TZ_MAX_LEAPS, TZ_MAX_TIMES, TZ_MAX_TYPES, tzhead::tzh_charcnt, tzhead::tzh_leapcnt, tzhead::tzh_magic, tzhead::tzh_reserved, tzhead::tzh_timecnt, tzhead::tzh_ttisstdcnt, tzhead::tzh_ttisutcnt, tzhead::tzh_typecnt, tzhead::tzh_version, unspecifiedtype, utoffs, want_bloat(), warning(), xmalloc(), ZIC32_MAX, ZIC32_MIN, and ZIC_MIN.

Referenced by outzone().

◆ xmalloc()

static void * xmalloc ( size_t  size)
static

Definition at line 563 of file zic.c.

564{
565 return memcheck(malloc(size));
566}

References malloc, and memcheck().

Referenced by outzone(), random_dirent(), relname(), and writezone().

◆ xrealloc()

static void * xrealloc ( void ptr,
size_t  size 
)
static

Definition at line 569 of file zic.c.

570{
571 return memcheck(realloc(ptr, size));
572}

References memcheck(), and realloc.

Referenced by growalloc().

◆ xstrdup()

static char * xstrdup ( char const str)
static

Definition at line 575 of file zic.c.

576{
577 return memcheck(strdup(str));
578}

References fb(), memcheck(), and str.

Referenced by inlink(), inrule(), inzsub(), mkdirs(), and rulesub().

Variable Documentation

◆ attypes

struct attype * attypes
static

Referenced by addtt(), outzone(), and writezone().

◆ begin_years

struct lookup const begin_years[]
static
Initial value:
= {
{"minimum", YR_MINIMUM},
{NULL, 0}
}

Definition at line 448 of file zic.c.

448 {
449 {"minimum", YR_MINIMUM},
450 {NULL, 0}
451};

Referenced by rulesub().

◆ bloat

int bloat
static

Definition at line 1240 of file zic.c.

Referenced by main(), and want_bloat().

◆ charcnt

int charcnt
static

◆ chars

char chars[TZ_MAX_CHARS]
static

Definition at line 485 of file zic.c.

Referenced by addtype(), getColorInfo(), initPopulateTable(), pg_reg_getcharacters(), and writezone().

◆ corr

zic_t corr

Definition at line 489 of file zic.c.

Referenced by import_pg_statistic(), timesub(), tzloadbody(), and writezone().

◆ creat_perms

mode_t creat_perms = CREAT_PERMS
static

Definition at line 68 of file zic.c.

Referenced by open_outfile(), and use_safe_temp_permissions().

◆ desigidx

unsigned char desigidx[TZ_MAX_TYPES]
static

Definition at line 482 of file zic.c.

Referenced by addtype(), init_ttinfo(), tzloadbody(), and writezone().

◆ directory

◆ directory_ends_in_slash

bool directory_ends_in_slash
static

Definition at line 1233 of file zic.c.

Referenced by diagslash(), and main().

◆ disable_percent_s

char const disable_percent_s[] = ""
static

Definition at line 3544 of file zic.c.

Referenced by doabbr(), and outzone().

◆ end_years

struct lookup const end_years[]
static
Initial value:
= {
{"maximum", YR_MAXIMUM},
{"only", YR_ONLY},
{NULL, 0}
}

Definition at line 453 of file zic.c.

453 {
454 {"maximum", YR_MAXIMUM},
455 {"only", YR_ONLY},
456 {NULL, 0}
457};

Referenced by rulesub().

◆ errors

bool errors
static

Definition at line 223 of file zic.c.

Referenced by associate(), error(), and main().

◆ filenum

int filenum
static

Definition at line 225 of file zic.c.

Referenced by eats(), inlink(), inrule(), inzsub(), and verror().

◆ got_signal

sig_atomic_t got_signal
static

Definition at line 1083 of file zic.c.

Referenced by catch_signals(), check_for_signal(), and signal_handler().

◆ hi_time

zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE)
static

Definition at line 1162 of file zic.c.

Referenced by leapadd(), main(), outzone(), stringzone(), timerange_option(), and writezone().

◆ isdsts

char isdsts[TZ_MAX_TYPES]
static

Definition at line 481 of file zic.c.

Referenced by addtype(), and writezone().

◆ lasts

struct lookup const lasts[]
static
Initial value:
= {
{"last-Sunday", TM_SUNDAY},
{"last-Monday", TM_MONDAY},
{"last-Tuesday", TM_TUESDAY},
{"last-Wednesday", TM_WEDNESDAY},
{"last-Thursday", TM_THURSDAY},
{"last-Friday", TM_FRIDAY},
{"last-Saturday", TM_SATURDAY},
{NULL, 0}
}

Definition at line 437 of file zic.c.

437 {
438 {"last-Sunday", TM_SUNDAY},
439 {"last-Monday", TM_MONDAY},
440 {"last-Tuesday", TM_TUESDAY},
441 {"last-Wednesday", TM_WEDNESDAY},
442 {"last-Thursday", TM_THURSDAY},
443 {"last-Friday", TM_FRIDAY},
444 {"last-Saturday", TM_SATURDAY},
445 {NULL, 0}
446};

Referenced by byword(), and rulesub().

◆ lcltime

const char* lcltime
static

Definition at line 1228 of file zic.c.

Referenced by inzone(), and main().

◆ [struct]

struct { ... } * leap

◆ leap_alloc

ptrdiff_t leap_alloc
static

Definition at line 227 of file zic.c.

Referenced by leapadd().

◆ leap_line_codes

struct lookup const leap_line_codes[]
static
Initial value:
= {
{"Leap", LC_LEAP},
{"Expires", LC_EXPIRES},
{NULL, 0}
}

Definition at line 404 of file zic.c.

404 {
405 {"Leap", LC_LEAP},
406 {"Expires", LC_EXPIRES},
407 {NULL, 0}
408};

Referenced by infile().

◆ leap_types

struct lookup const leap_types[]
static
Initial value:
= {
{"Rolling", true},
{"Stationary", false},
{NULL, 0}
}

Definition at line 459 of file zic.c.

459 {
460 {"Rolling", true},
461 {"Stationary", false},
462 {NULL, 0}
463};

Referenced by inleap().

◆ leapcnt

ptrdiff_t leapcnt
static

Definition at line 226 of file zic.c.

Referenced by adjleap(), leapadd(), set_leapcount(), tzloadbody(), and writezone().

◆ leapexpires

zic_t leapexpires = -1
static

Definition at line 1171 of file zic.c.

Referenced by adjleap(), inexpires(), limitrange(), and writezone().

◆ leapmaxyear

zic_t leapmaxyear
static

Definition at line 230 of file zic.c.

Referenced by getleapdatetime(), and outzone().

◆ leapminyear

zic_t leapminyear
static

Definition at line 229 of file zic.c.

Referenced by getleapdatetime(), and outzone().

◆ leapsec

char const* leapsec
static

Definition at line 243 of file zic.c.

Referenced by filename(), and main().

◆ leapseen

bool leapseen
static

Definition at line 228 of file zic.c.

Referenced by getleapdatetime(), and outzone().

◆ len_months

const int len_months[2][MONSPERYEAR]
static
Initial value:
= {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
}

Definition at line 465 of file zic.c.

465 {
466 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
467 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
468};

Referenced by getleapdatetime(), rpytime(), rulesub(), and stringrule().

◆ len_years

const int len_years[2]
static
Initial value:

Definition at line 470 of file zic.c.

470 {
472};

Referenced by getleapdatetime(), and rpytime().

◆ linenum

lineno_t linenum
static

Definition at line 231 of file zic.c.

Referenced by eats(), inlink(), inrule(), inzsub(), and verror().

◆ links

struct link* links
static

Definition at line 385 of file zic.c.

Referenced by inlink(), and make_links().

◆ lo_time

zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE)
static

Definition at line 1161 of file zic.c.

Referenced by leapadd(), main(), outzone(), timerange_option(), and writezone().

◆ main_argv

char* const* main_argv
static

Definition at line 244 of file zic.c.

Referenced by filename(), and main().

◆ max_abbrvar_len

int max_abbrvar_len = PERCENT_Z_LEN_BOUND
static

Definition at line 232 of file zic.c.

Referenced by inrule(), and outzone().

◆ max_format_len

int max_format_len
static

Definition at line 233 of file zic.c.

Referenced by inzsub(), and outzone().

◆ max_time

Definition at line 1155 of file zic.c.

Referenced by leapadd(), limitrange(), outzone(), stringzone(), tadd(), timerange_option(), and writezone().

◆ max_year

zic_t max_year
static

Definition at line 234 of file zic.c.

Referenced by outzone(), and updateminmax().

◆ min_time

Definition at line 1154 of file zic.c.

Referenced by leapadd(), outzone(), tadd(), timerange_option(), and writezone().

◆ min_year

zic_t min_year
static

Definition at line 235 of file zic.c.

Referenced by outzone(), and updateminmax().

◆ mon_names

struct lookup const mon_names[]
static
Initial value:
= {
{"January", TM_JANUARY},
{"February", TM_FEBRUARY},
{"March", TM_MARCH},
{"April", TM_APRIL},
{"May", TM_MAY},
{"June", TM_JUNE},
{"July", TM_JULY},
{"August", TM_AUGUST},
{"September", TM_SEPTEMBER},
{"October", TM_OCTOBER},
{"November", TM_NOVEMBER},
{"December", TM_DECEMBER},
{NULL, 0}
}

Definition at line 410 of file zic.c.

410 {
411 {"January", TM_JANUARY},
412 {"February", TM_FEBRUARY},
413 {"March", TM_MARCH},
414 {"April", TM_APRIL},
415 {"May", TM_MAY},
416 {"June", TM_JUNE},
417 {"July", TM_JULY},
418 {"August", TM_AUGUST},
419 {"September", TM_SEPTEMBER},
420 {"October", TM_OCTOBER},
421 {"November", TM_NOVEMBER},
422 {"December", TM_DECEMBER},
423 {NULL, 0}
424};

Referenced by getleapdatetime(), and rulesub().

◆ nlinks

ptrdiff_t nlinks
static

Definition at line 386 of file zic.c.

Referenced by inlink(), and make_links().

◆ nlinks_alloc

ptrdiff_t nlinks_alloc
static

Definition at line 387 of file zic.c.

Referenced by inlink(), and make_links().

◆ no_gid

gid_t const no_gid = -1
static

Definition at line 70 of file zic.c.

Referenced by chmetadata(), group_option(), and use_safe_temp_permissions().

◆ no_mode

mode_t const no_mode = -1
static

Definition at line 726 of file zic.c.

Referenced by chmetadata(), main(), and use_safe_temp_permissions().

◆ no_uid

uid_t const no_uid = -1
static

Definition at line 71 of file zic.c.

Referenced by chmetadata(), owner_option(), and use_safe_temp_permissions().

◆ noise

bool noise
static

◆ nrules

ptrdiff_t nrules
static

Definition at line 370 of file zic.c.

Referenced by associate(), and inrule().

◆ nrules_alloc

ptrdiff_t nrules_alloc
static

Definition at line 371 of file zic.c.

Referenced by inrule().

◆ nzones

ptrdiff_t nzones
static

Definition at line 374 of file zic.c.

Referenced by associate(), inzone(), inzsub(), and main().

◆ nzones_alloc

ptrdiff_t nzones_alloc
static

Definition at line 375 of file zic.c.

Referenced by inzsub().

◆ output_group

gid_t output_group = -1
static

Definition at line 72 of file zic.c.

Referenced by chmetadata(), group_option(), and use_safe_temp_permissions().

◆ output_mode

mode_t output_mode = -1
static

Definition at line 727 of file zic.c.

Referenced by chmetadata(), main(), and use_safe_temp_permissions().

◆ output_owner

uid_t output_owner = -1
static

Definition at line 73 of file zic.c.

Referenced by chmetadata(), owner_option(), and use_safe_temp_permissions().

◆ print_abbrevs

bool print_abbrevs
static

Definition at line 237 of file zic.c.

Referenced by main(), and writezone().

◆ print_cutoff

zic_t print_cutoff
static

Definition at line 238 of file zic.c.

Referenced by main(), and writezone().

◆ progname

◆ psxrules

const char* psxrules
static

Definition at line 1227 of file zic.c.

Referenced by inzone(), and main().

◆ redundant_time

zic_t redundant_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE)
static

Definition at line 1168 of file zic.c.

Referenced by main(), outzone(), redundant_time_option(), and writezone().

◆ rfilenum

int rfilenum
static

Definition at line 240 of file zic.c.

Referenced by eats(), and verror().

◆ rlinenum

lineno_t rlinenum
static

Definition at line 241 of file zic.c.

Referenced by eats(), and verror().

◆ roll

char roll

Definition at line 490 of file zic.c.

Referenced by writezone().

◆ rules

struct rule* rules
static

Definition at line 369 of file zic.c.

Referenced by associate(), fireRIRrules(), inrule(), and RelationBuildRuleLock().

◆ skip_mkdir

bool skip_mkdir
static

Definition at line 239 of file zic.c.

Referenced by main(), and mkdirs().

◆ timecnt

ptrdiff_t timecnt
static

Definition at line 245 of file zic.c.

Referenced by addtt(), outzone(), tzloadbody(), tzparse(), and writezone().

◆ timecnt_alloc

ptrdiff_t timecnt_alloc
static

Definition at line 246 of file zic.c.

Referenced by addtt().

◆ trans

◆ ttisstds

bool ttisstds[TZ_MAX_TYPES]
static

Definition at line 483 of file zic.c.

Referenced by addtype(), and writezone().

◆ ttisuts

bool ttisuts[TZ_MAX_TYPES]
static

Definition at line 484 of file zic.c.

Referenced by addtype(), and writezone().

◆ typecnt

int typecnt
static

Definition at line 247 of file zic.c.

Referenced by addtype(), outzone(), tzloadbody(), and writezone().

◆ tzdefault

const char* tzdefault
static

Definition at line 1230 of file zic.c.

Referenced by inzone(), and main().

◆ unspecifiedtype

int unspecifiedtype
static

Definition at line 248 of file zic.c.

Referenced by outzone(), and writezone().

◆ utoffs

zic_t utoffs[TZ_MAX_TYPES]
static

Definition at line 480 of file zic.c.

Referenced by addtype(), and writezone().

◆ warnings

bool warnings
static

Definition at line 224 of file zic.c.

Referenced by main(), and warning().

◆ wday_names

struct lookup const wday_names[]
static
Initial value:
= {
{"Sunday", TM_SUNDAY},
{"Monday", TM_MONDAY},
{"Tuesday", TM_TUESDAY},
{"Wednesday", TM_WEDNESDAY},
{"Thursday", TM_THURSDAY},
{"Friday", TM_FRIDAY},
{"Saturday", TM_SATURDAY},
{NULL, 0}
}

Definition at line 426 of file zic.c.

426 {
427 {"Sunday", TM_SUNDAY},
428 {"Monday", TM_MONDAY},
429 {"Tuesday", TM_TUESDAY},
430 {"Wednesday", TM_WEDNESDAY},
431 {"Thursday", TM_THURSDAY},
432 {"Friday", TM_FRIDAY},
433 {"Saturday", TM_SATURDAY},
434 {NULL, 0}
435};

Referenced by byword(), and rulesub().

◆ zi_line_codes

struct lookup const zi_line_codes[]
static
Initial value:
= {
{"Rule", LC_RULE},
{"Zone", LC_ZONE},
{"Link", LC_LINK},
{NULL, 0}
}

Definition at line 398 of file zic.c.

398 {
399 {"Rule", LC_RULE},
400 {"Zone", LC_ZONE},
401 {"Link", LC_LINK},
402 {NULL, 0}
403};

Referenced by infile().

◆ ZIC32_MAX

zic_t const ZIC32_MAX = TWO_31_MINUS_1
static

Definition at line 34 of file zic.c.

Referenced by writezone().

◆ ZIC32_MIN

zic_t const ZIC32_MIN = -1 - (zic_t) TWO_31_MINUS_1
static

Definition at line 33 of file zic.c.

Referenced by writezone().

◆ ZIC_MAX

zic_t const ZIC_MAX = INT_FAST64_MAX
static

Definition at line 32 of file zic.c.

Referenced by main(), oadd(), omul(), outzone(), rule_cmp(), and rulesub().

◆ ZIC_MIN

zic_t const ZIC_MIN = INT_FAST64_MIN
static

Definition at line 31 of file zic.c.

Referenced by oadd(), omul(), outzone(), and writezone().

◆ zones

struct zone* zones
static

Definition at line 373 of file zic.c.

Referenced by associate(), inzone(), inzsub(), and main().