diff options
Diffstat (limited to 'contrib/tzcode/zic.c')
-rw-r--r-- | contrib/tzcode/zic.c | 142 |
1 files changed, 89 insertions, 53 deletions
diff --git a/contrib/tzcode/zic.c b/contrib/tzcode/zic.c index 2605f65dcd23..80902ce534a1 100644 --- a/contrib/tzcode/zic.c +++ b/contrib/tzcode/zic.c @@ -526,19 +526,19 @@ memcheck(void *ptr) } static void * -emalloc(size_t size) +xmalloc(size_t size) { return memcheck(malloc(size)); } static void * -erealloc(void *ptr, size_t size) +xrealloc(void *ptr, size_t size) { return memcheck(realloc(ptr, size)); } static char * -estrdup(char const *str) +xstrdup(char const *str) { return memcheck(strdup(str)); } @@ -567,7 +567,7 @@ growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems, { return (nitems < *nitems_alloc ? ptr - : erealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize))); + : xrealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize))); } /* @@ -654,6 +654,8 @@ close_file(FILE *stream, char const *dir, char const *name, char const *e = (ferror(stream) ? _("I/O error") : fclose(stream) != 0 ? strerror(errno) : NULL); if (e) { + if (name && *name == '/') + dir = NULL; fprintf(stderr, "%s: %s%s%s%s%s\n", progname, dir ? dir : "", dir ? "/" : "", name ? name : "", name ? ": " : "", @@ -961,6 +963,9 @@ static mode_t mflag = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR); static const char * tzdefault; +/* True if DIRECTORY ends in '/'. */ +static bool directory_ends_in_slash; + /* -1 if the TZif output file should be slim, 0 if default, 1 if the output should be fat for backward compatibility. ZIC_BLOAT_DEFAULT determines the default. */ @@ -1166,6 +1171,7 @@ _("invalid file mode")); return EXIT_FAILURE; associate(); change_directory(directory); + directory_ends_in_slash = directory[strlen(directory) - 1] == '/'; catch_signals(); for (i = 0; i < nzones; i = j) { /* @@ -1353,7 +1359,7 @@ random_dirent(char const **name, char **namealloc) uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6); if (!dst) { - dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); + dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); memcpy(dst, src, dirlen); memcpy(dst + dirlen, prefix, prefixlen); dst[dirlen + prefixlen + suffixlen] = '\0'; @@ -1370,6 +1376,20 @@ random_dirent(char const **name, char **namealloc) } } +/* For diagnostics the directory, and file name relative to that + directory, respectively. A diagnostic routine can name FILENAME by + outputting diagdir(FILENAME), then diagslash(FILENAME), then FILENAME. */ +static char const * +diagdir(char const *filename) +{ + return *filename == '/' ? "" : directory; +} +static char const * +diagslash(char const *filename) +{ + return &"/"[*filename == '/' || directory_ends_in_slash]; +} + /* Prepare to write to the file *OUTNAME, using *TEMPNAME to store the name of the temporary file that will eventually be renamed to *OUTNAME. Assign the temporary file's name to both *OUTNAME and @@ -1406,8 +1426,9 @@ open_outfile(char const **outname, char **tempname) } else if (fopen_errno == EEXIST) random_dirent(outname, tempname); else { - fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), - progname, directory, *outname, strerror(fopen_errno)); + fprintf(stderr, _("%s: Can't create %s%s%s: %s\n"), + progname, diagdir(*outname), diagslash(*outname), *outname, + strerror(fopen_errno)); exit(EXIT_FAILURE); } } @@ -1424,9 +1445,10 @@ rename_dest(char *tempname, char const *name) if (tempname) { if (rename(tempname, name) != 0) { int rename_errno = errno; - (void)remove(tempname); - fprintf(stderr, _("%s: rename to %s/%s: %s\n"), - progname, directory, name, strerror(rename_errno)); + remove(tempname); + fprintf(stderr, _("%s: rename to %s%s%s: %s\n"), + progname, diagdir(name), diagslash(name), name, + strerror(rename_errno)); exit(EXIT_FAILURE); } free(tempname); @@ -1436,7 +1458,8 @@ rename_dest(char *tempname, char const *name) /* Create symlink contents suitable for symlinking TARGET to LINKNAME, as a freshly allocated string. TARGET should be a relative file name, and is relative to the global variable DIRECTORY. LINKNAME can be either - relative or absolute. */ + relative or absolute. Return a null pointer if the symlink contents + was not computed because LINKNAME is absolute but DIRECTORY is not. */ static char * relname(char const *target, char const *linkname) { @@ -1449,8 +1472,10 @@ relname(char const *target, char const *linkname) size_t len = strlen(directory); size_t lenslash = len + (len && directory[len - 1] != '/'); size_t targetsize = strlen(target) + 1; + if (*directory != '/') + return NULL; linksize = size_sum(lenslash, targetsize); - f = result = emalloc(linksize); + f = result = xmalloc(linksize); memcpy(result, directory, len); result[len] = '/'; memcpy(result + lenslash, target, targetsize); @@ -1464,7 +1489,7 @@ relname(char const *target, char const *linkname) dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1); if (dotdotetcsize <= linksize) { if (!result) - result = emalloc(dotdotetcsize); + result = xmalloc(dotdotetcsize); for (i = 0; i < dotdots; i++) memcpy(result + 3 * i, "../", 3); memmove(result + 3 * dotdots, f + dir_len, taillen + 1); @@ -1500,8 +1525,9 @@ dolink(char const *target, char const *linkname, bool staysymlink) return; else { char const *e = strerror(errno); - fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), - progname, directory, linkname, e); + fprintf(stderr, _("%s: Can't remove %s%s%s: %s\n"), + progname, diagdir(linkname), diagslash(linkname), linkname, + e); exit(EXIT_FAILURE); } } @@ -1544,8 +1570,9 @@ dolink(char const *target, char const *linkname, bool staysymlink) mkdirs(linkname, true); linkdirs_made = true; } else { - fprintf(stderr, _("%s: Can't link %s/%s to %s/%s: %s\n"), - progname, directory, target, directory, outname, + fprintf(stderr, _("%s: Can't link %s%s%s to %s%s%s: %s\n"), + progname, diagdir(target), diagslash(target), target, + diagdir(outname), diagslash(outname), outname, strerror(link_errno)); exit(EXIT_FAILURE); } @@ -1554,21 +1581,23 @@ dolink(char const *target, char const *linkname, bool staysymlink) bool absolute = *target == '/'; char *linkalloc = absolute ? NULL : relname(target, linkname); char const *contents = absolute ? target : linkalloc; - int symlink_errno; + int symlink_errno = -1; - while (true) { - if (symlink(contents, outname) == 0) { - symlink_errno = 0; - break; + if (contents) { + while (true) { + if (symlink(contents, outname) == 0) { + symlink_errno = 0; + break; + } + symlink_errno = errno; + if (symlink_errno == EEXIST) + random_dirent(&outname, &tempname); + else if (symlink_errno == ENOENT && !linkdirs_made) { + mkdirs(linkname, true); + linkdirs_made = true; + } else + break; } - symlink_errno = errno; - if (symlink_errno == EEXIST) - random_dirent(&outname, &tempname); - else if (symlink_errno == ENOENT && !linkdirs_made) { - mkdirs(linkname, true); - linkdirs_made = true; - } else - break; } free(linkalloc); if (symlink_errno == 0) { @@ -1581,8 +1610,8 @@ dolink(char const *target, char const *linkname, bool staysymlink) fp = fopen(target, "rb"); if (!fp) { char const *e = strerror(errno); - fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), - progname, directory, target, e); + fprintf(stderr, _("%s: Can't read %s%s%s: %s\n"), + progname, diagdir(target), diagslash(target), target, e); exit(EXIT_FAILURE); } tp = open_outfile(&outname, &tempname); @@ -1593,6 +1622,8 @@ dolink(char const *target, char const *linkname, bool staysymlink) if (link_errno != ENOTSUP) warning(_("copy used because hard link failed: %s"), strerror(link_errno)); + else if (symlink_errno < 0) + warning(_("copy used because symbolic link not obvious")); else if (symlink_errno != ENOTSUP) warning(_("copy used because symbolic link failed: %s"), strerror(symlink_errno)); @@ -1906,8 +1937,8 @@ inrule(char **fields, int nfields) fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD])) return; - r.r_name = estrdup(fields[RF_NAME]); - r.r_abbrvar = estrdup(fields[RF_ABBRVAR]); + r.r_name = xstrdup(fields[RF_NAME]); + r.r_abbrvar = xstrdup(fields[RF_ABBRVAR]); if (max_abbrvar_len < strlen(r.r_abbrvar)) max_abbrvar_len = strlen(r.r_abbrvar); rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); @@ -1990,7 +2021,8 @@ inzsub(char **fields, int nfields, bool iscont) z.z_filenum = filenum; z.z_linenum = linenum; z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset")); - if ((cp = strchr(fields[i_format], '%')) != 0) { + cp = strchr(fields[i_format], '%'); + if (cp) { if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') || strchr(fields[i_format], '/')) { error(_("invalid abbreviation format")); @@ -2028,9 +2060,9 @@ inzsub(char **fields, int nfields, bool iscont) return false; } } - z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]); - z.z_rule = estrdup(fields[i_rule]); - z.z_format = cp1 = estrdup(fields[i_format]); + z.z_name = iscont ? NULL : xstrdup(fields[ZF_NAME]); + z.z_rule = xstrdup(fields[i_rule]); + z.z_format = cp1 = xstrdup(fields[i_format]); if (z.z_format_specifier == 'z') { cp1[cp - fields[i_format]] = 's'; if (noise) @@ -2173,8 +2205,8 @@ inlink(char **fields, int nfields) return; l.l_filenum = filenum; l.l_linenum = linenum; - l.l_target = estrdup(fields[LF_TARGET]); - l.l_linkname = estrdup(fields[LF_LINKNAME]); + l.l_target = xstrdup(fields[LF_TARGET]); + l.l_linkname = xstrdup(fields[LF_LINKNAME]); links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); links[nlinks++] = l; } @@ -2197,7 +2229,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, rp->r_month = lp->l_value; rp->r_todisstd = false; rp->r_todisut = false; - dp = estrdup(timep); + dp = xstrdup(timep); if (*dp != '\0') { ep = dp + strlen(dp) - 1; switch (lowerit(*ep)) { @@ -2272,19 +2304,23 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, ** Sun<=20 ** Sun>=7 */ - dp = estrdup(dayp); + dp = xstrdup(dayp); if ((lp = byword(dp, lasts)) != NULL) { rp->r_dycode = DC_DOWLEQ; rp->r_wday = lp->l_value; rp->r_dayofmonth = len_months[1][rp->r_month]; } else { - if ((ep = strchr(dp, '<')) != 0) - rp->r_dycode = DC_DOWLEQ; - else if ((ep = strchr(dp, '>')) != 0) - rp->r_dycode = DC_DOWGEQ; + ep = strchr(dp, '<'); + if (ep) + rp->r_dycode = DC_DOWLEQ; else { + ep = strchr(dp, '>'); + if (ep) + rp->r_dycode = DC_DOWGEQ; + else { ep = dp; rp->r_dycode = DC_DOM; + } } if (rp->r_dycode != DC_DOM) { *ep++ = 0; @@ -2427,7 +2463,7 @@ writezone(const char *const name, const char *const string, char version, /* Allocate the ATS and TYPES arrays via a single malloc, as this is a bit faster. Do not malloc(0) if !timecnt, as that might return NULL even on success. */ - zic_t *ats = emalloc(align_to(size_product(timecnt + !timecnt, + zic_t *ats = xmalloc(align_to(size_product(timecnt + !timecnt, sizeof *ats + 1), alignof(zic_t))); void *typesptr = ats + timecnt; @@ -2802,7 +2838,7 @@ writezone(const char *const name, const char *const string, char version, if (thisleapexpiry) { /* Append a no-op leap correction indicating when the leap second table expires. Although this does not conform to - Internet RFC 8536, most clients seem to accept this and + Internet RFC 9636, most clients seem to accept this and the plan is to amend the RFC to allow this in version 4 TZif files. */ puttzcodepass(leapexpires, fp, pass); @@ -3059,7 +3095,7 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) result[0] = '\0'; - /* Internet RFC 8536 section 5.1 says to use an empty TZ string if + /* Internet RFC 9636 section 6.1 says to use an empty TZ string if future timestamps are truncated. */ if (hi_time < max_time) return -1; @@ -3187,9 +3223,9 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) max_abbr_len = 2 + max_format_len + max_abbrvar_len; max_envvar_len = 2 * max_abbr_len + 5 * 9; - startbuf = emalloc(max_abbr_len + 1); - ab = emalloc(max_abbr_len + 1); - envvar = emalloc(max_envvar_len + 1); + startbuf = xmalloc(max_abbr_len + 1); + ab = xmalloc(max_abbr_len + 1); + envvar = xmalloc(max_envvar_len + 1); INITIALIZE(untiltime); INITIALIZE(starttime); /* @@ -3972,7 +4008,7 @@ mkdirs(char const *argname, bool ancestors) if (Dflag) return; - char *name = estrdup(argname); + char *name = xstrdup(argname); char *cp = name; /* On MS-Windows systems, do not worry about drive letters or |