Sync our copy of the timezone library with IANA release tzcode2020c.

This changes zic's default output format from "-b fat" to "-b slim".
We were already using "slim" in v13/HEAD, so those branches drop
the explicit -b switch in the Makefiles.  Instead, add an explicit
"-b fat" in v12 and before, so that we don't change the output file
format in those branches.  (This is perhaps excessively conservative,
but we decided not to do so in a12079109, and I'll stick with that.)

Other non-cosmetic changes are to drop support for zic's long-obsolete
"-y" switch, and to ensure that strftime() does not change errno
unless it fails.

As usual with tzcode changes, back-patch to all supported branches.
This commit is contained in:
Tom Lane 2020-10-16 21:40:16 -04:00
parent 02a75f8369
commit ce0e97f808
5 changed files with 81 additions and 142 deletions

View File

@ -56,7 +56,7 @@ zic: $(ZICOBJS) | submake-libpgport
install: all installdirs
ifeq (,$(with_system_tzdata))
$(ZIC) -d '$(DESTDIR)$(datadir)/timezone' -b slim $(ZIC_OPTIONS) $(TZDATAFILES)
$(ZIC) -d '$(DESTDIR)$(datadir)/timezone' $(ZIC_OPTIONS) $(TZDATAFILES)
endif
$(MAKE) -C tznames $@

View File

@ -55,7 +55,7 @@ match properly on the old version.
Time Zone code
==============
The code in this directory is currently synced with tzcode release 2020a.
The code in this directory is currently synced with tzcode release 2020c.
There are many cosmetic (and not so cosmetic) differences from the
original tzcode library, but diffs in the upstream version should usually
be propagated to our version. Here are some notes about that.

View File

@ -128,12 +128,22 @@ size_t
pg_strftime(char *s, size_t maxsize, const char *format, const struct pg_tm *t)
{
char *p;
int saved_errno = errno;
enum warn warn = IN_NONE;
p = _fmt(format, t, s, s + maxsize, &warn);
if (p == s + maxsize)
if (!p)
{
errno = EOVERFLOW;
return 0;
}
if (p == s + maxsize)
{
errno = ERANGE;
return 0;
}
*p = '\0';
errno = saved_errno;
return p - s;
}

View File

@ -37,10 +37,6 @@ typedef int64 zic_t;
#define MKDIR_UMASK 0755
#endif
#endif
#ifndef AT_SYMLINK_FOLLOW
#define linkat(fromdir, from, todir, to, flag) \
(itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to))
#endif
/* Port to native MS-Windows and to ancient UNIX. */
#if !defined S_ISDIR && defined S_IFDIR && defined S_IFMT
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
@ -66,7 +62,6 @@ struct rule
zic_t r_loyear; /* for example, 1986 */
zic_t r_hiyear; /* for example, 1986 */
const char *r_yrtype;
bool r_lowasnum;
bool r_hiwasnum;
@ -116,7 +111,11 @@ struct zone
zic_t z_untiltime;
};
extern int link(const char *fromname, const char *toname);
extern int link(const char *target, const char *linkname);
#ifndef AT_SYMLINK_FOLLOW
#define linkat(targetdir, target, linknamedir, linkname, flag) \
(itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname))
#endif
static void memory_exhausted(const char *msg) pg_attribute_noreturn();
static void verror(const char *string, va_list args) pg_attribute_printf(1, 0);
@ -154,7 +153,6 @@ static void rulesub(struct rule *rp,
const char *typep, const char *monthp,
const char *dayp, const char *timep);
static zic_t tadd(zic_t t1, zic_t t2);
static bool yearistype(zic_t year, const char *type);
/* Bound on length of what %z can expand to. */
enum
@ -253,8 +251,8 @@ static int typecnt;
* Which fields are which on a Link line.
*/
#define LF_FROM 1
#define LF_TO 2
#define LF_TARGET 1
#define LF_LINKNAME 2
#define LINK_FIELDS 3
/*
@ -292,8 +290,8 @@ struct link
{
const char *l_filename;
lineno_t l_linenum;
const char *l_from;
const char *l_to;
const char *l_target;
const char *l_linkname;
};
static struct link *links;
@ -634,11 +632,9 @@ static const char *lcltime;
static const char *directory;
static const char *leapsec;
static const char *tzdefault;
static const char *yitcommand;
/* -1 if the TZif output file should be slim, 0 if default, 1 if the
output should be fat for backward compatibility. Currently the
default is fat, although this may change. */
output should be fat for backward compatibility. The default is slim. */
static int bloat;
static bool
@ -648,7 +644,7 @@ want_bloat(void)
}
#ifndef ZIC_BLOAT_DEFAULT
#define ZIC_BLOAT_DEFAULT "fat"
#define ZIC_BLOAT_DEFAULT "slim"
#endif
int
@ -747,18 +743,7 @@ main(int argc, char **argv)
tzdefault = optarg;
break;
case 'y':
if (yitcommand == NULL)
{
warning(_("-y is obsolescent"));
yitcommand = strdup(optarg);
}
else
{
fprintf(stderr,
_("%s: More than one -y option specified\n"),
progname);
return EXIT_FAILURE;
}
warning(_("-y ignored"));
break;
case 'L':
if (leapsec == NULL)
@ -807,8 +792,6 @@ main(int argc, char **argv)
directory = "data";
if (tzdefault == NULL)
tzdefault = TZDEFAULT;
if (yitcommand == NULL)
yitcommand = "yearistype";
if (optind < argc && leapsec != NULL)
{
@ -838,11 +821,11 @@ main(int argc, char **argv)
for (i = 0; i < nlinks; ++i)
{
eat(links[i].l_filename, links[i].l_linenum);
dolink(links[i].l_from, links[i].l_to, false);
dolink(links[i].l_target, links[i].l_linkname, false);
if (noise)
for (j = 0; j < nlinks; ++j)
if (strcmp(links[i].l_to,
links[j].l_from) == 0)
if (strcmp(links[i].l_linkname,
links[j].l_target) == 0)
warning(_("link to link"));
}
if (lcltime != NULL)
@ -953,7 +936,7 @@ namecheck(const char *name)
*/
#ifdef HAVE_SYMLINK
static char *
relname(char const *from, char const *to)
relname(char const *target, char const *linkname)
{
size_t i,
taillen,
@ -961,26 +944,26 @@ relname(char const *from, char const *to)
size_t dir_len = 0,
dotdots = 0,
linksize = SIZE_MAX;
char const *f = from;
char const *f = target;
char *result = NULL;
if (*to == '/')
if (*linkname == '/')
{
/* Make F absolute too. */
size_t len = strlen(directory);
bool needslash = len && directory[len - 1] != '/';
linksize = len + needslash + strlen(from) + 1;
linksize = len + needslash + strlen(target) + 1;
f = result = emalloc(linksize);
strcpy(result, directory);
result[len] = '/';
strcpy(result + len + needslash, from);
strcpy(result + len + needslash, target);
}
for (i = 0; f[i] && f[i] == to[i]; i++)
for (i = 0; f[i] && f[i] == linkname[i]; i++)
if (f[i] == '/')
dir_len = i + 1;
for (; to[i]; i++)
dotdots += to[i] == '/' && to[i - 1] != '/';
for (; linkname[i]; i++)
dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
taillen = strlen(f + dir_len);
dotdotetcsize = 3 * dotdots + taillen + 1;
if (dotdotetcsize <= linksize)
@ -998,62 +981,65 @@ relname(char const *from, char const *to)
/* Hard link FROM to TO, following any symbolic links.
Return 0 if successful, an error number otherwise. */
static int
hardlinkerr(char const *from, char const *to)
hardlinkerr(char const *target, char const *linkname)
{
int r = linkat(AT_FDCWD, from, AT_FDCWD, to, AT_SYMLINK_FOLLOW);
int r = linkat(AT_FDCWD, target, AT_FDCWD, linkname, AT_SYMLINK_FOLLOW);
return r == 0 ? 0 : errno;
}
static void
dolink(char const *fromfield, char const *tofield, bool staysymlink)
dolink(char const *target, char const *linkname, bool staysymlink)
{
bool todirs_made = false;
bool remove_only = strcmp(target, "-") == 0;
bool linkdirs_made = false;
int link_errno;
/*
* We get to be careful here since there's a fair chance of root running
* us.
*/
if (itsdir(fromfield))
if (!remove_only && itsdir(target))
{
fprintf(stderr, _("%s: link from %s/%s failed: %s\n"),
progname, directory, fromfield, strerror(EPERM));
fprintf(stderr, _("%s: linking target %s/%s failed: %s\n"),
progname, directory, target, strerror(EPERM));
exit(EXIT_FAILURE);
}
if (staysymlink)
staysymlink = itssymlink(tofield);
if (remove(tofield) == 0)
todirs_made = true;
staysymlink = itssymlink(linkname);
if (remove(linkname) == 0)
linkdirs_made = true;
else if (errno != ENOENT)
{
char const *e = strerror(errno);
fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
progname, directory, tofield, e);
progname, directory, linkname, e);
exit(EXIT_FAILURE);
}
link_errno = staysymlink ? ENOTSUP : hardlinkerr(fromfield, tofield);
if (link_errno == ENOENT && !todirs_made)
if (remove_only)
return;
link_errno = staysymlink ? ENOTSUP : hardlinkerr(target, linkname);
if (link_errno == ENOENT && !linkdirs_made)
{
mkdirs(tofield, true);
todirs_made = true;
link_errno = hardlinkerr(fromfield, tofield);
mkdirs(linkname, true);
linkdirs_made = true;
link_errno = hardlinkerr(target, linkname);
}
if (link_errno != 0)
{
#ifdef HAVE_SYMLINK
bool absolute = *fromfield == '/';
char *linkalloc = absolute ? NULL : relname(fromfield, tofield);
char const *contents = absolute ? fromfield : linkalloc;
int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
bool absolute = *target == '/';
char *linkalloc = absolute ? NULL : relname(target, linkname);
char const *contents = absolute ? target : linkalloc;
int symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno;
if (!todirs_made
if (!linkdirs_made
&& (symlink_errno == ENOENT || symlink_errno == ENOTSUP))
{
mkdirs(tofield, true);
mkdirs(linkname, true);
if (symlink_errno == ENOENT)
symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno;
}
free(linkalloc);
if (symlink_errno == 0)
@ -1069,28 +1055,28 @@ dolink(char const *fromfield, char const *tofield, bool staysymlink)
*tp;
int c;
fp = fopen(fromfield, "rb");
fp = fopen(target, "rb");
if (!fp)
{
char const *e = strerror(errno);
fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
progname, directory, fromfield, e);
progname, directory, target, e);
exit(EXIT_FAILURE);
}
tp = fopen(tofield, "wb");
tp = fopen(linkname, "wb");
if (!tp)
{
char const *e = strerror(errno);
fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
progname, directory, tofield, e);
progname, directory, linkname, e);
exit(EXIT_FAILURE);
}
while ((c = getc(fp)) != EOF)
putc(c, tp);
close_file(fp, directory, fromfield);
close_file(tp, directory, tofield);
close_file(fp, directory, target);
close_file(tp, directory, linkname);
if (link_errno != ENOTSUP)
warning(_("copy used because hard link failed: %s"),
strerror(link_errno));
@ -1806,17 +1792,17 @@ inlink(char **fields, int nfields)
error(_("wrong number of fields on Link line"));
return;
}
if (*fields[LF_FROM] == '\0')
if (*fields[LF_TARGET] == '\0')
{
error(_("blank FROM field on Link line"));
error(_("blank TARGET field on Link line"));
return;
}
if (!namecheck(fields[LF_TO]))
if (!namecheck(fields[LF_LINKNAME]))
return;
l.l_filename = filename;
l.l_linenum = linenum;
l.l_from = ecpyalloc(fields[LF_FROM]);
l.l_to = ecpyalloc(fields[LF_TO]);
l.l_target = ecpyalloc(fields[LF_TARGET]);
l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
links[nlinks++] = l;
}
@ -1932,18 +1918,11 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
error(_("starting year greater than ending year"));
return;
}
if (*typep == '\0')
rp->r_yrtype = NULL;
else
if (*typep != '\0')
{
if (rp->r_loyear == rp->r_hiyear)
{
error(_("typed single year"));
return;
}
warning(_("year type \"%s\" is obsolete; use \"-\" instead"),
typep);
rp->r_yrtype = ecpyalloc(typep);
error(_("year type \"%s\" is unsupported; use \"-\" instead"),
typep);
return;
}
/*
@ -2848,8 +2827,6 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
rp = &zp->z_rules[i];
if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
continue;
if (rp->r_yrtype != NULL)
continue;
if (!rp->r_isdst)
{
if (stdrp == NULL)
@ -3145,7 +3122,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
/*
* Mark which rules to do in the current year. For those to
* do, calculate rpytime(rp, year);
* do, calculate rpytime(rp, year); The former TYPE field was
* also considered here.
*/
for (j = 0; j < zp->z_nrules; ++j)
{
@ -3153,8 +3131,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
rp->r_todo = year >= rp->r_loyear &&
year <= rp->r_hiyear &&
yearistype(year, rp->r_yrtype);
year <= rp->r_hiyear;
if (rp->r_todo)
{
rp->r_temp = rpytime(rp, year);
@ -3474,54 +3451,6 @@ adjleap(void)
}
}
static char *
shellquote(char *b, char const *s)
{
*b++ = '\'';
while (*s)
{
if (*s == '\'')
*b++ = '\'', *b++ = '\\', *b++ = '\'';
*b++ = *s++;
}
*b++ = '\'';
return b;
}
static bool
yearistype(zic_t year, const char *type)
{
char *buf;
char *b;
int result;
if (type == NULL || *type == '\0')
return true;
buf = emalloc(1 + 4 * strlen(yitcommand) + 2
+ INT_STRLEN_MAXIMUM(zic_t) + 2 + 4 * strlen(type) + 2);
b = shellquote(buf, yitcommand);
*b++ = ' ';
b += sprintf(b, INT64_FORMAT, year);
*b++ = ' ';
b = shellquote(b, type);
*b = '\0';
result = system(buf);
if (WIFEXITED(result))
{
int status = WEXITSTATUS(result);
if (status <= 1)
{
free(buf);
return status == 0;
}
}
error(_("Wild result from command execution"));
fprintf(stderr, _("%s: command was '%s', result was %d\n"),
progname, buf, result);
exit(EXIT_FAILURE);
}
/* Is A a space character in the C locale? */
static bool
is_space(char a)

View File

@ -369,7 +369,7 @@ sub GenerateTimezoneFiles
print "Generating timezone files...";
my @args = (
"$conf/zic/zic", '-d', "$target/share/timezone", '-b', 'slim');
"$conf/zic/zic", '-d', "$target/share/timezone");
foreach (@tzfiles)
{
my $tzfile = $_;