Commit ce0e97f8 authored by Tom Lane's avatar Tom Lane

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 a1207910, 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.
parent 02a75f83
...@@ -56,7 +56,7 @@ zic: $(ZICOBJS) | submake-libpgport ...@@ -56,7 +56,7 @@ zic: $(ZICOBJS) | submake-libpgport
install: all installdirs install: all installdirs
ifeq (,$(with_system_tzdata)) ifeq (,$(with_system_tzdata))
$(ZIC) -d '$(DESTDIR)$(datadir)/timezone' -b slim $(ZIC_OPTIONS) $(TZDATAFILES) $(ZIC) -d '$(DESTDIR)$(datadir)/timezone' $(ZIC_OPTIONS) $(TZDATAFILES)
endif endif
$(MAKE) -C tznames $@ $(MAKE) -C tznames $@
......
...@@ -55,7 +55,7 @@ match properly on the old version. ...@@ -55,7 +55,7 @@ match properly on the old version.
Time Zone code 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 There are many cosmetic (and not so cosmetic) differences from the
original tzcode library, but diffs in the upstream version should usually original tzcode library, but diffs in the upstream version should usually
be propagated to our version. Here are some notes about that. be propagated to our version. Here are some notes about that.
......
...@@ -128,12 +128,22 @@ size_t ...@@ -128,12 +128,22 @@ size_t
pg_strftime(char *s, size_t maxsize, const char *format, const struct pg_tm *t) pg_strftime(char *s, size_t maxsize, const char *format, const struct pg_tm *t)
{ {
char *p; char *p;
int saved_errno = errno;
enum warn warn = IN_NONE; enum warn warn = IN_NONE;
p = _fmt(format, t, s, s + maxsize, &warn); p = _fmt(format, t, s, s + maxsize, &warn);
if (!p)
{
errno = EOVERFLOW;
return 0;
}
if (p == s + maxsize) if (p == s + maxsize)
{
errno = ERANGE;
return 0; return 0;
}
*p = '\0'; *p = '\0';
errno = saved_errno;
return p - s; return p - s;
} }
......
...@@ -37,10 +37,6 @@ typedef int64 zic_t; ...@@ -37,10 +37,6 @@ typedef int64 zic_t;
#define MKDIR_UMASK 0755 #define MKDIR_UMASK 0755
#endif #endif
#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. */ /* Port to native MS-Windows and to ancient UNIX. */
#if !defined S_ISDIR && defined S_IFDIR && defined S_IFMT #if !defined S_ISDIR && defined S_IFDIR && defined S_IFMT
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
...@@ -66,7 +62,6 @@ struct rule ...@@ -66,7 +62,6 @@ struct rule
zic_t r_loyear; /* for example, 1986 */ zic_t r_loyear; /* for example, 1986 */
zic_t r_hiyear; /* for example, 1986 */ zic_t r_hiyear; /* for example, 1986 */
const char *r_yrtype;
bool r_lowasnum; bool r_lowasnum;
bool r_hiwasnum; bool r_hiwasnum;
...@@ -116,7 +111,11 @@ struct zone ...@@ -116,7 +111,11 @@ struct zone
zic_t z_untiltime; 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 memory_exhausted(const char *msg) pg_attribute_noreturn();
static void verror(const char *string, va_list args) pg_attribute_printf(1, 0); static void verror(const char *string, va_list args) pg_attribute_printf(1, 0);
...@@ -154,7 +153,6 @@ static void rulesub(struct rule *rp, ...@@ -154,7 +153,6 @@ static void rulesub(struct rule *rp,
const char *typep, const char *monthp, const char *typep, const char *monthp,
const char *dayp, const char *timep); const char *dayp, const char *timep);
static zic_t tadd(zic_t t1, zic_t t2); 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. */ /* Bound on length of what %z can expand to. */
enum enum
...@@ -253,8 +251,8 @@ static int typecnt; ...@@ -253,8 +251,8 @@ static int typecnt;
* Which fields are which on a Link line. * Which fields are which on a Link line.
*/ */
#define LF_FROM 1 #define LF_TARGET 1
#define LF_TO 2 #define LF_LINKNAME 2
#define LINK_FIELDS 3 #define LINK_FIELDS 3
/* /*
...@@ -292,8 +290,8 @@ struct link ...@@ -292,8 +290,8 @@ struct link
{ {
const char *l_filename; const char *l_filename;
lineno_t l_linenum; lineno_t l_linenum;
const char *l_from; const char *l_target;
const char *l_to; const char *l_linkname;
}; };
static struct link *links; static struct link *links;
...@@ -634,11 +632,9 @@ static const char *lcltime; ...@@ -634,11 +632,9 @@ static const char *lcltime;
static const char *directory; static const char *directory;
static const char *leapsec; static const char *leapsec;
static const char *tzdefault; static const char *tzdefault;
static const char *yitcommand;
/* -1 if the TZif output file should be slim, 0 if default, 1 if the /* -1 if the TZif output file should be slim, 0 if default, 1 if the
output should be fat for backward compatibility. Currently the output should be fat for backward compatibility. The default is slim. */
default is fat, although this may change. */
static int bloat; static int bloat;
static bool static bool
...@@ -648,7 +644,7 @@ want_bloat(void) ...@@ -648,7 +644,7 @@ want_bloat(void)
} }
#ifndef ZIC_BLOAT_DEFAULT #ifndef ZIC_BLOAT_DEFAULT
#define ZIC_BLOAT_DEFAULT "fat" #define ZIC_BLOAT_DEFAULT "slim"
#endif #endif
int int
...@@ -747,18 +743,7 @@ main(int argc, char **argv) ...@@ -747,18 +743,7 @@ main(int argc, char **argv)
tzdefault = optarg; tzdefault = optarg;
break; break;
case 'y': case 'y':
if (yitcommand == NULL) warning(_("-y ignored"));
{
warning(_("-y is obsolescent"));
yitcommand = strdup(optarg);
}
else
{
fprintf(stderr,
_("%s: More than one -y option specified\n"),
progname);
return EXIT_FAILURE;
}
break; break;
case 'L': case 'L':
if (leapsec == NULL) if (leapsec == NULL)
...@@ -807,8 +792,6 @@ main(int argc, char **argv) ...@@ -807,8 +792,6 @@ main(int argc, char **argv)
directory = "data"; directory = "data";
if (tzdefault == NULL) if (tzdefault == NULL)
tzdefault = TZDEFAULT; tzdefault = TZDEFAULT;
if (yitcommand == NULL)
yitcommand = "yearistype";
if (optind < argc && leapsec != NULL) if (optind < argc && leapsec != NULL)
{ {
...@@ -838,11 +821,11 @@ main(int argc, char **argv) ...@@ -838,11 +821,11 @@ main(int argc, char **argv)
for (i = 0; i < nlinks; ++i) for (i = 0; i < nlinks; ++i)
{ {
eat(links[i].l_filename, links[i].l_linenum); 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) if (noise)
for (j = 0; j < nlinks; ++j) for (j = 0; j < nlinks; ++j)
if (strcmp(links[i].l_to, if (strcmp(links[i].l_linkname,
links[j].l_from) == 0) links[j].l_target) == 0)
warning(_("link to link")); warning(_("link to link"));
} }
if (lcltime != NULL) if (lcltime != NULL)
...@@ -953,7 +936,7 @@ namecheck(const char *name) ...@@ -953,7 +936,7 @@ namecheck(const char *name)
*/ */
#ifdef HAVE_SYMLINK #ifdef HAVE_SYMLINK
static char * static char *
relname(char const *from, char const *to) relname(char const *target, char const *linkname)
{ {
size_t i, size_t i,
taillen, taillen,
...@@ -961,26 +944,26 @@ relname(char const *from, char const *to) ...@@ -961,26 +944,26 @@ relname(char const *from, char const *to)
size_t dir_len = 0, size_t dir_len = 0,
dotdots = 0, dotdots = 0,
linksize = SIZE_MAX; linksize = SIZE_MAX;
char const *f = from; char const *f = target;
char *result = NULL; char *result = NULL;
if (*to == '/') if (*linkname == '/')
{ {
/* Make F absolute too. */ /* Make F absolute too. */
size_t len = strlen(directory); size_t len = strlen(directory);
bool needslash = len && directory[len - 1] != '/'; bool needslash = len && directory[len - 1] != '/';
linksize = len + needslash + strlen(from) + 1; linksize = len + needslash + strlen(target) + 1;
f = result = emalloc(linksize); f = result = emalloc(linksize);
strcpy(result, directory); strcpy(result, directory);
result[len] = '/'; 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] == '/') if (f[i] == '/')
dir_len = i + 1; dir_len = i + 1;
for (; to[i]; i++) for (; linkname[i]; i++)
dotdots += to[i] == '/' && to[i - 1] != '/'; dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
taillen = strlen(f + dir_len); taillen = strlen(f + dir_len);
dotdotetcsize = 3 * dotdots + taillen + 1; dotdotetcsize = 3 * dotdots + taillen + 1;
if (dotdotetcsize <= linksize) if (dotdotetcsize <= linksize)
...@@ -998,62 +981,65 @@ relname(char const *from, char const *to) ...@@ -998,62 +981,65 @@ relname(char const *from, char const *to)
/* Hard link FROM to TO, following any symbolic links. /* Hard link FROM to TO, following any symbolic links.
Return 0 if successful, an error number otherwise. */ Return 0 if successful, an error number otherwise. */
static int 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; return r == 0 ? 0 : errno;
} }
static void 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; int link_errno;
/* /*
* We get to be careful here since there's a fair chance of root running * We get to be careful here since there's a fair chance of root running
* us. * us.
*/ */
if (itsdir(fromfield)) if (!remove_only && itsdir(target))
{ {
fprintf(stderr, _("%s: link from %s/%s failed: %s\n"), fprintf(stderr, _("%s: linking target %s/%s failed: %s\n"),
progname, directory, fromfield, strerror(EPERM)); progname, directory, target, strerror(EPERM));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (staysymlink) if (staysymlink)
staysymlink = itssymlink(tofield); staysymlink = itssymlink(linkname);
if (remove(tofield) == 0) if (remove(linkname) == 0)
todirs_made = true; linkdirs_made = true;
else if (errno != ENOENT) else if (errno != ENOENT)
{ {
char const *e = strerror(errno); char const *e = strerror(errno);
fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
progname, directory, tofield, e); progname, directory, linkname, e);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
link_errno = staysymlink ? ENOTSUP : hardlinkerr(fromfield, tofield); if (remove_only)
if (link_errno == ENOENT && !todirs_made) return;
link_errno = staysymlink ? ENOTSUP : hardlinkerr(target, linkname);
if (link_errno == ENOENT && !linkdirs_made)
{ {
mkdirs(tofield, true); mkdirs(linkname, true);
todirs_made = true; linkdirs_made = true;
link_errno = hardlinkerr(fromfield, tofield); link_errno = hardlinkerr(target, linkname);
} }
if (link_errno != 0) if (link_errno != 0)
{ {
#ifdef HAVE_SYMLINK #ifdef HAVE_SYMLINK
bool absolute = *fromfield == '/'; bool absolute = *target == '/';
char *linkalloc = absolute ? NULL : relname(fromfield, tofield); char *linkalloc = absolute ? NULL : relname(target, linkname);
char const *contents = absolute ? fromfield : linkalloc; char const *contents = absolute ? target : linkalloc;
int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno; int symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno;
if (!todirs_made if (!linkdirs_made
&& (symlink_errno == ENOENT || symlink_errno == ENOTSUP)) && (symlink_errno == ENOENT || symlink_errno == ENOTSUP))
{ {
mkdirs(tofield, true); mkdirs(linkname, true);
if (symlink_errno == ENOENT) if (symlink_errno == ENOENT)
symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno; symlink_errno = symlink(contents, linkname) == 0 ? 0 : errno;
} }
free(linkalloc); free(linkalloc);
if (symlink_errno == 0) if (symlink_errno == 0)
...@@ -1069,28 +1055,28 @@ dolink(char const *fromfield, char const *tofield, bool staysymlink) ...@@ -1069,28 +1055,28 @@ dolink(char const *fromfield, char const *tofield, bool staysymlink)
*tp; *tp;
int c; int c;
fp = fopen(fromfield, "rb"); fp = fopen(target, "rb");
if (!fp) if (!fp)
{ {
char const *e = strerror(errno); char const *e = strerror(errno);
fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
progname, directory, fromfield, e); progname, directory, target, e);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
tp = fopen(tofield, "wb"); tp = fopen(linkname, "wb");
if (!tp) if (!tp)
{ {
char const *e = strerror(errno); char const *e = strerror(errno);
fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
progname, directory, tofield, e); progname, directory, linkname, e);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
while ((c = getc(fp)) != EOF) while ((c = getc(fp)) != EOF)
putc(c, tp); putc(c, tp);
close_file(fp, directory, fromfield); close_file(fp, directory, target);
close_file(tp, directory, tofield); close_file(tp, directory, linkname);
if (link_errno != ENOTSUP) if (link_errno != ENOTSUP)
warning(_("copy used because hard link failed: %s"), warning(_("copy used because hard link failed: %s"),
strerror(link_errno)); strerror(link_errno));
...@@ -1806,17 +1792,17 @@ inlink(char **fields, int nfields) ...@@ -1806,17 +1792,17 @@ inlink(char **fields, int nfields)
error(_("wrong number of fields on Link line")); error(_("wrong number of fields on Link line"));
return; 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; return;
} }
if (!namecheck(fields[LF_TO])) if (!namecheck(fields[LF_LINKNAME]))
return; return;
l.l_filename = filename; l.l_filename = filename;
l.l_linenum = linenum; l.l_linenum = linenum;
l.l_from = ecpyalloc(fields[LF_FROM]); l.l_target = ecpyalloc(fields[LF_TARGET]);
l.l_to = ecpyalloc(fields[LF_TO]); l.l_linkname = ecpyalloc(fields[LF_LINKNAME]);
links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
links[nlinks++] = l; links[nlinks++] = l;
} }
...@@ -1932,18 +1918,11 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, ...@@ -1932,18 +1918,11 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
error(_("starting year greater than ending year")); error(_("starting year greater than ending year"));
return; return;
} }
if (*typep == '\0') if (*typep != '\0')
rp->r_yrtype = NULL;
else
{ {
if (rp->r_loyear == rp->r_hiyear) error(_("year type \"%s\" is unsupported; use \"-\" instead"),
{ typep);
error(_("typed single year")); return;
return;
}
warning(_("year type \"%s\" is obsolete; use \"-\" instead"),
typep);
rp->r_yrtype = ecpyalloc(typep);
} }
/* /*
...@@ -2848,8 +2827,6 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) ...@@ -2848,8 +2827,6 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
rp = &zp->z_rules[i]; rp = &zp->z_rules[i];
if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX) if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
continue; continue;
if (rp->r_yrtype != NULL)
continue;
if (!rp->r_isdst) if (!rp->r_isdst)
{ {
if (stdrp == NULL) if (stdrp == NULL)
...@@ -3145,7 +3122,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) ...@@ -3145,7 +3122,8 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
/* /*
* Mark which rules to do in the current year. For those to * 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) for (j = 0; j < zp->z_nrules; ++j)
{ {
...@@ -3153,8 +3131,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) ...@@ -3153,8 +3131,7 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
eats(zp->z_filename, zp->z_linenum, eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum); rp->r_filename, rp->r_linenum);
rp->r_todo = year >= rp->r_loyear && rp->r_todo = year >= rp->r_loyear &&
year <= rp->r_hiyear && year <= rp->r_hiyear;
yearistype(year, rp->r_yrtype);
if (rp->r_todo) if (rp->r_todo)
{ {
rp->r_temp = rpytime(rp, year); rp->r_temp = rpytime(rp, year);
...@@ -3474,54 +3451,6 @@ adjleap(void) ...@@ -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? */ /* Is A a space character in the C locale? */
static bool static bool
is_space(char a) is_space(char a)
......
...@@ -369,7 +369,7 @@ sub GenerateTimezoneFiles ...@@ -369,7 +369,7 @@ sub GenerateTimezoneFiles
print "Generating timezone files..."; print "Generating timezone files...";
my @args = ( my @args = (
"$conf/zic/zic", '-d', "$target/share/timezone", '-b', 'slim'); "$conf/zic/zic", '-d', "$target/share/timezone");
foreach (@tzfiles) foreach (@tzfiles)
{ {
my $tzfile = $_; my $tzfile = $_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment