version 1.76, 2020/05/25 14:52:48 |
version 1.77, 2020/10/09 18:38:48 |
|
|
|
|
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; |
|
|
|
|
#if !HAVE_POSIX_DECLS |
#if !HAVE_POSIX_DECLS |
extern int getopt(int argc, char * const argv[], |
extern int getopt(int argc, char * const argv[], |
const char * options); |
const char * options); |
extern int link(const char * fromname, const char * toname); |
extern int link(const char * target, const char * linkname); |
extern char * optarg; |
extern char * optarg; |
extern int optind; |
extern int optind; |
#endif |
#endif |
|
|
#if ! HAVE_LINK |
#if ! HAVE_LINK |
# define link(from, to) (errno = ENOTSUP, -1) |
# define link(target, linkname) (errno = ENOTSUP, -1) |
#endif |
#endif |
#if ! HAVE_SYMLINK |
#if ! HAVE_SYMLINK |
# define readlink(file, buf, size) (errno = ENOTSUP, -1) |
# define readlink(file, buf, size) (errno = ENOTSUP, -1) |
# define symlink(from, to) (errno = ENOTSUP, -1) |
# define symlink(target, linkname) (errno = ENOTSUP, -1) |
# define S_ISLNK(m) 0 |
# define S_ISLNK(m) 0 |
#endif |
#endif |
#ifndef AT_SYMLINK_FOLLOW |
#ifndef AT_SYMLINK_FOLLOW |
# define linkat(fromdir, from, todir, to, flag) \ |
# define linkat(targetdir, target, linknamedir, linkname, flag) \ |
(itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to)) |
(itssymlink(target) ? (errno = ENOTSUP, -1) : link(target, linkname)) |
#endif |
#endif |
|
|
static void addtt(zic_t starttime, int type); |
static void addtt(zic_t starttime, int type); |
Line 192 static void rulesub(struct rule * rp, |
|
Line 191 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 { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 }; |
enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 }; |
Line 285 static int typecnt; |
|
Line 283 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 |
|
|
/* |
/* |
Line 323 static ptrdiff_t nzones_alloc; |
|
Line 321 static ptrdiff_t nzones_alloc; |
|
struct link { |
struct link { |
const char * l_filename; |
const char * l_filename; |
lineno l_linenum; |
lineno 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; |
Line 669 static const char * lcltime; |
|
Line 667 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 |
Line 683 want_bloat(void) |
|
Line 679 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 |
Line 774 _("%s: More than one -p option specified |
|
Line 770 _("%s: More than one -p option specified |
|
tzdefault = optarg; |
tzdefault = optarg; |
break; |
break; |
case 'y': |
case 'y': |
if (yitcommand == NULL) { |
warning(_("-y ignored")); |
warning(_("-y is obsolescent")); |
|
yitcommand = 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) |
Line 824 _("%s: invalid time range: %s\n"), |
|
Line 812 _("%s: invalid time range: %s\n"), |
|
directory = TZDIR; |
directory = TZDIR; |
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) { |
infile(leapsec); |
infile(leapsec); |
Line 851 _("%s: invalid time range: %s\n"), |
|
Line 837 _("%s: invalid time range: %s\n"), |
|
*/ |
*/ |
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) { |
Line 947 namecheck(const char *name) |
|
Line 933 namecheck(const char *name) |
|
is relative to the global variable DIRECTORY. TO can be either |
is relative to the global variable DIRECTORY. TO can be either |
relative or absolute. */ |
relative or absolute. */ |
static char * |
static char * |
relname(char const *from, char const *to) |
relname(char const *target, char const *linkname) |
{ |
{ |
size_t i, taillen, dotdotetcsize; |
size_t i, taillen, dotdotetcsize; |
size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX; |
size_t dir_len = 0, dotdots = 0, 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) { |
Line 983 relname(char const *from, char const *to |
|
Line 969 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 |
** We get to be careful here since |
** there's a fair chance of root running us. |
** 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"), |
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; |
mkdirs(tofield, true); |
link_errno = staysymlink ? ENOTSUP : hardlinkerr(target, linkname); |
todirs_made = true; |
if (link_errno == ENOENT && !linkdirs_made) { |
link_errno = hardlinkerr(fromfield, tofield); |
mkdirs(linkname, true); |
|
linkdirs_made = true; |
|
link_errno = hardlinkerr(target, linkname); |
} |
} |
if (link_errno != 0) { |
if (link_errno != 0) { |
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) { |
Line 1039 dolink(char const *fromfield, char const |
|
Line 1028 dolink(char const *fromfield, char const |
|
} else { |
} else { |
FILE *fp, *tp; |
FILE *fp, *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)); |
Line 1635 inlink(char **fields, int nfields) |
|
Line 1624 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; |
} |
} |
Line 1740 rulesub(struct rule *rp, const char *loy |
|
Line 1729 rulesub(struct rule *rp, const char *loy |
|
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; |
error(_("year type \"%s\" is unsupported; use \"-\" instead"), |
else { |
|
if (rp->r_loyear == rp->r_hiyear) { |
|
error(_("typed single year")); |
|
return; |
|
} |
|
warning(_("year type \"%s\" is obsolete; use \"-\" instead"), |
|
typep); |
typep); |
rp->r_yrtype = ecpyalloc(typep); |
return; |
} |
} |
/* |
/* |
** Day work. |
** Day work. |
Line 2512 stringzone(char *result, int resultlen, |
|
Line 2495 stringzone(char *result, int resultlen, |
|
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) |
stdrp = rp; |
stdrp = rp; |
Line 2769 outzone(const struct zone *zpfirst, ptrd |
|
Line 2750 outzone(const struct zone *zpfirst, ptrd |
|
/* |
/* |
** Mark which rules to do in the current year. |
** Mark which rules to do in the current year. |
** For those to do, calculate rpytime(rp, year); |
** For those to 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) { |
rp = &zp->z_rules[j]; |
rp = &zp->z_rules[j]; |
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); |
rp->r_todo |
rp->r_todo |
|
|
} |
} |
} |
} |
|
|
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; |
|
size_t len; |
|
|
|
if (type == NULL || *type == '\0') |
|
return true; |
|
buf = zic_malloc(len = 1 + 4 * strlen(yitcommand) + 2 |
|
+ INT_STRLEN_MAXIMUM(zic_t) + 2 + 4 * strlen(type) + 2); |
|
b = shellquote(buf, yitcommand); |
|
*b++ = ' '; |
|
b += snprintf(b, len - (b - buf), "%"PRIdZIC, 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) |