#include "postgres_fe.h"
+#include <fcntl.h>
#include <locale.h>
#include <sys/stat.h>
#include <time.h>
+#include <unistd.h>
#include "pg_getopt.h"
#define MKDIR_UMASK 0755
#endif
#endif
-#ifndef S_ISLNK
-#define S_ISLNK(m) 0
+#ifndef AT_SYMLINK_FOLLOW
+#define linkat(fromdir, from, todir, to, flag) \
+ (itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to))
#endif
+/* The maximum ptrdiff_t value, for pre-C99 platforms. */
+#ifndef PTRDIFF_MAX
+static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
+#endif
+
+/* The type and printf format for line numbers. */
+typedef int lineno;
+#define PRIdLINENO "d"
+
struct rule
{
const char *r_filename;
- int r_linenum;
+ lineno r_linenum;
const char *r_name;
zic_t r_loyear; /* for example, 1986 */
zic_t r_stdoff; /* offset from standard time */
const char *r_abbrvar; /* variable part of abbreviation */
- int r_todo; /* a rule to do (used in outzone) */
+ bool r_todo; /* a rule to do (used in outzone) */
zic_t r_temp; /* used in outzone */
};
struct zone
{
const char *z_filename;
- int z_linenum;
+ lineno z_linenum;
const char *z_name;
zic_t z_gmtoff;
zic_t z_stdoff;
struct rule *z_rules;
- int z_nrules;
+ ptrdiff_t z_nrules;
struct rule z_untilrule;
zic_t z_untiltime;
static bool inzcont(char **fields, int nfields);
static bool inzone(char **fields, int nfields);
static bool inzsub(char **, int, bool);
-static int itsdir(const char *name);
+static bool itsdir(char const *);
+static bool itssymlink(char const *);
static bool is_alpha(char a);
static char lowerit(char);
static void mkdirs(char const *, bool);
static void newabbr(const char *abbr);
static zic_t oadd(zic_t t1, zic_t t2);
-static void outzone(const struct zone * zp, int ntzones);
+static void outzone(const struct zone * zp, ptrdiff_t ntzones);
static zic_t rpytime(const struct rule * rp, zic_t wantedy);
static void 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 yearistype(int year, const char *type);
+static bool yearistype(zic_t year, const char *type);
/* Bound on length of what %z can expand to. */
enum
static bool leapseen;
static zic_t leapminyear;
static zic_t leapmaxyear;
-static int linenum;
+static lineno linenum;
static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
static int max_format_len;
static zic_t max_year;
static bool print_abbrevs;
static zic_t print_cutoff;
static const char *rfilename;
-static int rlinenum;
+static lineno rlinenum;
static const char *progname;
-static int timecnt;
-static int timecnt_alloc;
+static ptrdiff_t timecnt;
+static ptrdiff_t timecnt_alloc;
static int typecnt;
/*
#define YR_ONLY 2
static struct rule *rules;
-static int nrules; /* number of rules */
-static int nrules_alloc;
+static ptrdiff_t nrules; /* number of rules */
+static ptrdiff_t nrules_alloc;
static struct zone *zones;
-static int nzones; /* number of zones */
-static int nzones_alloc;
+static ptrdiff_t nzones; /* number of zones */
+static ptrdiff_t nzones_alloc;
struct link
{
const char *l_filename;
- int l_linenum;
+ lineno l_linenum;
const char *l_from;
const char *l_to;
};
static struct link *links;
-static int nlinks;
-static int nlinks_alloc;
+static ptrdiff_t nlinks;
+static ptrdiff_t nlinks_alloc;
struct lookup
{
}
static void *
-growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
+growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t * nitems_alloc)
{
if (nitems < *nitems_alloc)
return ptr;
else
{
- int nitems_max = INT_MAX - WORK_AROUND_QTBUG_53071;
+ ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
+ ptrdiff_t amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
- if ((nitems_max - 1) / 3 * 2 < *nitems_alloc)
- memory_exhausted(_("int overflow"));
- *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1;
+ if ((amax - 1) / 3 * 2 < *nitems_alloc)
+ memory_exhausted(_("integer overflow"));
+ *nitems_alloc += (*nitems_alloc >> 1) + 1;
return erealloc(ptr, size_product(*nitems_alloc, itemsize));
}
}
*/
static void
-eats(const char *name, int num, const char *rname, int rnum)
+eats(char const * name, lineno num, char const * rname, lineno rnum)
{
filename = name;
linenum = num;
}
static void
-eat(const char *name, int num)
+eat(char const * name, lineno num)
{
eats(name, num, NULL, -1);
}
* "*" -v on BSD systems.
*/
if (filename)
- fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
+ fprintf(stderr, _("\"%s\", line %" PRIdLINENO ": "), filename, linenum);
vfprintf(stderr, string, args);
if (rfilename != NULL)
- fprintf(stderr, _(" (rule from \"%s\", line %d)"),
+ fprintf(stderr, _(" (rule from \"%s\", line %" PRIdLINENO ")"),
rfilename, rlinenum);
fprintf(stderr, "\n");
}
int
main(int argc, char *argv[])
{
- int i;
- int j;
- int c;
+ int c,
+ k;
+ ptrdiff_t i,
+ j;
#ifndef WIN32
umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
_("wild compilation-time specification of zic_t"));
return EXIT_FAILURE;
}
- for (i = 1; i < argc; ++i)
- if (strcmp(argv[i], "--version") == 0)
+ for (k = 1; k < argc; k++)
+ if (strcmp(argv[k], "--version") == 0)
{
printf("zic %s\n", PG_VERSION);
close_file(stdout, NULL, NULL);
return EXIT_SUCCESS;
}
- else if (strcmp(argv[i], "--help") == 0)
+ else if (strcmp(argv[k], "--help") == 0)
{
usage(stdout, EXIT_SUCCESS);
}
adjleap();
}
- for (i = optind; i < argc; ++i)
- infile(argv[i]);
+ for (k = optind; k < argc; k++)
+ infile(argv[k]);
if (errors)
return EXIT_FAILURE;
associate();
enum
{
component_len_max = 14};
- size_t component_len = component_end - component;
+ ptrdiff_t component_len = component_end - component;
if (component_len == 0)
{
if (0 < component_len && component_len <= 2
&& component[0] == '.' && component_end[-1] == '.')
{
+ int len = component_len;
+
error(_("file name '%s' contains '%.*s' component"),
- name, (int) component_len, component);
+ name, len, component);
return false;
}
if (noise)
for (i = 0; f[i] && f[i] == to[i]; i++)
if (f[i] == '/')
dir_len = i + 1;
- for (; f[i]; i++)
- dotdots += f[i] == '/' && f[i - 1] != '/';
- taillen = i - dir_len;
+ for (; to[i]; i++)
+ dotdots += to[i] == '/' && to[i - 1] != '/';
+ taillen = strlen(f + dir_len);
dotdotetcsize = 3 * dotdots + taillen + 1;
if (dotdotetcsize <= linksize)
{
}
#endif /* HAVE_SYMLINK */
+/* 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)
+{
+ int r = linkat(AT_FDCWD, from, AT_FDCWD, to, AT_SYMLINK_FOLLOW);
+
+ return r == 0 ? 0 : errno;
+}
+
static void
dolink(char const * fromfield, char const * tofield, bool staysymlink)
{
- int fromisdir;
bool todirs_made = false;
int link_errno;
* We get to be careful here since there's a fair chance of root running
* us.
*/
- fromisdir = itsdir(fromfield);
- if (fromisdir)
+ if (itsdir(fromfield))
{
- char const *e = strerror(fromisdir < 0 ? errno : EPERM);
-
fprintf(stderr, _("%s: link from %s/%s failed: %s\n"),
- progname, directory, fromfield, e);
+ progname, directory, fromfield, strerror(EPERM));
exit(EXIT_FAILURE);
}
if (staysymlink)
- staysymlink = itsdir(tofield) == 2;
+ staysymlink = itssymlink(tofield);
if (remove(tofield) == 0)
todirs_made = true;
else if (errno != ENOENT)
progname, directory, tofield, e);
exit(EXIT_FAILURE);
}
- link_errno = (staysymlink ? ENOTSUP
- : link(fromfield, tofield) == 0 ? 0 : errno);
+ link_errno = staysymlink ? ENOTSUP : hardlinkerr(fromfield, tofield);
if (link_errno == ENOENT && !todirs_made)
{
mkdirs(tofield, true);
todirs_made = true;
- link_errno = link(fromfield, tofield) == 0 ? 0 : errno;
+ link_errno = hardlinkerr(fromfield, tofield);
}
if (link_errno != 0)
{
? BIG_BANG
: MINVAL(zic_t, TIME_T_BITS_IN_FILE));
-/* Return 1 if NAME is a directory, 2 if a symbolic link, 0 if
- something else, -1 (setting errno) if trouble. */
-static int
+/* Return true if NAME is a directory. */
+static bool
itsdir(char const * name)
{
struct stat st;
- int res = lstat(name, &st);
-
+ int res = stat(name, &st);
+#ifdef S_ISDIR
if (res == 0)
+ return S_ISDIR(st.st_mode) != 0;
+#endif
+ if (res == 0 || errno == EOVERFLOW)
{
-#ifdef S_ISDIR
- return S_ISDIR(st.st_mode) ? 1 : S_ISLNK(st.st_mode) ? 2 : 0;
-#else
size_t n = strlen(name);
char *nameslashdot = emalloc(n + 3);
bool dir;
memcpy(nameslashdot, name, n);
strcpy(&nameslashdot[n], &"/."[!(n && name[n - 1] != '/')]);
- dir = lstat(nameslashdot, &st) == 0;
+ dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
free(nameslashdot);
return dir;
-#endif
}
- return -1;
+ return false;
+}
+
+/* Return true if NAME is a symbolic link. */
+static bool
+itssymlink(char const * name)
+{
+#ifdef HAVE_SYMLINK
+ char c;
+
+ return 0 <= readlink(name, &c, 1);
+#else
+ return false;
+#endif
}
/*
{
struct zone *zp;
struct rule *rp;
- int base,
+ ptrdiff_t i,
+ j,
+ base,
out;
- int i,
- j;
if (nrules != 0)
{
const struct lookup *lp;
int nfields;
bool wantcont;
- int num;
+ lineno num;
char buf[BUFSIZ];
if (strcmp(name, "-") == 0)
if (lp == NULL)
error(_("input line of unknown type"));
else
- switch ((int) (lp->l_value))
+ switch (lp->l_value)
{
case LC_RULE:
inrule(fields, nfields);
static bool
inzone(char **fields, int nfields)
{
- int i;
+ ptrdiff_t i;
if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS)
{
if (zones[i].z_name != NULL &&
strcmp(zones[i].z_name, fields[ZF_NAME]) == 0)
{
- error(
- _("duplicate zone name %s (file \"%s\", line %d)"),
+ error(_("duplicate zone name %s"
+ " (file \"%s\", line %" PRIdLINENO ")"),
fields[ZF_NAME],
zones[i].z_filename,
zones[i].z_linenum);
{
const char *cp;
const struct lookup *lp;
- int i,
+ zic_t i,
j;
/* PG: make year be int not zic_t to avoid sscanf portability issues */
lp = byword(cp, begin_years);
rp->r_lowasnum = lp == NULL;
if (!rp->r_lowasnum)
- switch ((int) lp->l_value)
+ switch (lp->l_value)
{
case YR_MINIMUM:
rp->r_loyear = ZIC_MIN;
lp = byword(cp, end_years);
rp->r_hiwasnum = lp == NULL;
if (!rp->r_hiwasnum)
- switch ((int) lp->l_value)
+ switch (lp->l_value)
{
case YR_MINIMUM:
rp->r_hiyear = ZIC_MIN;
writezone(const char *const name, const char *const string, char version)
{
FILE *fp;
- int i,
+ ptrdiff_t i,
j;
int leapcnt32,
leapi32;
- int timecnt32,
+ ptrdiff_t timecnt32,
timei32;
int pass;
static const struct tzhead tzh0;
bool dir_checked = false;
zic_t one = 1;
zic_t y2038_boundary = one << 31;
- int nats = timecnt + WORK_AROUND_QTBUG_53071;
+ ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
zic_t *ats = emalloc(size_product(nats, sizeof *ats + 1));
void *typesptr = ats + nats;
unsigned char *types = typesptr;
* Optimize.
*/
{
- int fromi;
- int toi;
+ ptrdiff_t fromi,
+ toi;
toi = 0;
fromi = 0;
}
timecnt = toi;
}
+
if (noise && timecnt > 1200)
- warning(_("pre-2014 clients may mishandle"
- " more than 1200 transition times"));
+ {
+ if (timecnt > TZ_MAX_TIMES)
+ warning(_("reference clients mishandle"
+ " more than %d transition times"),
+ TZ_MAX_TIMES);
+ else
+ warning(_("pre-2014 clients may mishandle"
+ " more than 1200 transition times"));
+ }
/*
* Transfer.
}
for (pass = 1; pass <= 2; ++pass)
{
- int thistimei,
- thistimecnt;
+ ptrdiff_t thistimei,
+ thistimecnt,
+ thistimelim;
int thisleapi,
- thisleapcnt;
- int thistimelim,
+ thisleapcnt,
thisleaplim;
int writetype[TZ_MAX_TYPES];
int typemap[TZ_MAX_TYPES];
int thistypecnt;
char thischars[TZ_MAX_CHARS];
- char thischarcnt;
+ int thischarcnt;
+ bool toomanytimes;
int indmap[TZ_MAX_CHARS];
if (pass == 1)
{
thistimei = timei32;
thistimecnt = timecnt32;
+ toomanytimes = thistimecnt >> 31 >> 1 != 0;
thisleapi = leapi32;
thisleapcnt = leapcnt32;
}
{
thistimei = 0;
thistimecnt = timecnt;
+ toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
thisleapi = 0;
thisleapcnt = leapcnt;
}
+ if (toomanytimes)
+ error(_("too many transition times"));
thistimelim = thistimei + thistimecnt;
thisleaplim = thisleapi + thisleapcnt;
for (i = 0; i < typecnt; ++i)
break;
if (j == thischarcnt)
{
- strcpy(&thischars[(int) thischarcnt],
- thisabbr);
+ strcpy(&thischars[thischarcnt], thisabbr);
thischarcnt += strlen(thisabbr) + 1;
}
indmap[abbrinds[i]] = j;
YEAR_BY_YEAR_ZONE = 1};
static int
-stringzone(char *result, const struct zone * const zpfirst, const int zonecount)
+stringzone(char *result, struct zone const * zpfirst, ptrdiff_t zonecount)
{
const struct zone *zp;
struct rule *rp;
struct rule *stdrp;
struct rule *dstrp;
- int i;
+ ptrdiff_t i;
const char *abbrvar;
int compat = 0;
int c;
}
static void
-outzone(const struct zone * zpfirst, int zonecount)
+outzone(const struct zone * zpfirst, ptrdiff_t zonecount)
{
const struct zone *zp;
struct rule *rp;
- int i,
+ ptrdiff_t i,
j;
bool usestart,
useuntil;
int compat;
bool do_extend;
char version;
- int lastatmax = -1;
+ ptrdiff_t lastatmax = -1;
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
max_envvar_len = 2 * max_abbr_len + 5 * 9;
}
for (;;)
{
- int k;
+ ptrdiff_t k;
zic_t jtime,
ktime = 0;
zic_t offset;
}
}
+static char *
+shellquote(char *b, char const * s)
+{
+ *b++ = '\'';
+ while (*s)
+ {
+ if (*s == '\'')
+ *b++ = '\'', *b++ = '\\', *b++ = '\'';
+ *b++ = *s++;
+ }
+ *b++ = '\'';
+ return b;
+}
+
static bool
-yearistype(int year, const char *type)
+yearistype(zic_t year, const char *type)
{
- static char *buf;
+ char *buf;
+ char *b;
int result;
if (type == NULL || *type == '\0')
return true;
- buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type));
- sprintf(buf, "%s %d %s", yitcommand, year, type);
+ 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))
- switch (WEXITSTATUS(result))
+ {
+ int status = WEXITSTATUS(result);
+
+ if (status <= 1)
{
- case 0:
- return true;
- case 1:
- return false;
+ free(buf);
+ return status == 0;
}
+ }
error(_("Wild result from command execution"));
fprintf(stderr, _("%s: command was '%s', result was %d\n"),
progname, buf, result);
- for (;;)
- exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
/* Is A a space character in the C locale? */
else
{
error(_("Odd number of quotation marks"));
- exit(1);
+ exit(EXIT_FAILURE);
}
} while (*cp && *cp != '#' && !is_space(*cp));
if (is_space(*cp))
/* Ensure that the directories of ARGNAME exist, by making any missing
ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
- do it for ARGNAME too. Exit with failure if there is trouble. */
+ do it for ARGNAME too. Exit with failure if there is trouble.
+ Do not consider an existing non-directory to be trouble. */
static void
mkdirs(char const * argname, bool ancestors)
{
{
int err = errno;
- if (err != EEXIST && itsdir(name) < 0)
+ if (err != EEXIST && !itsdir(name))
{
error(_("%s: Cannot create directory %s: %s"),
progname, name, strerror(err));