Skip to content

Commit

Permalink
tzcode: Implement timezone change detection
Browse files Browse the repository at this point in the history
Implement optional timezone change detection for local time libc
functions.  This is disabled by default; set WITH_DETECT_TZ_CHANGES
to build it.

Reviewed By:	imp
Sponsored by:	NetApp, Inc.
Sponsored by:	Klara, Inc.
X-NetApp-PR:	freebsd#47
Differential Revision:	https://reviews.freebsd.org/D30183
  • Loading branch information
trasz committed Sep 12, 2021
1 parent b9df18d commit ddedf2a
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 1 deletion.
89 changes: 88 additions & 1 deletion contrib/tzcode/stdtime/localtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,45 @@ settzname(void)
}
}

#ifdef DETECT_TZ_CHANGES
/*
* Determine if there's a change in the timezone since the last time we checked.
* Returns: -1 on error
* 0 if the timezone has not changed
* 1 if the timezone has changed
*/
static int
change_in_tz(const char *name)
{
static char old_name[PATH_MAX];
static struct stat old_sb;
struct stat sb;
int error;

error = stat(name, &sb);
if (error != 0)
return -1;

if (strcmp(name, old_name) != 0) {
strlcpy(old_name, name, sizeof(old_name));
old_sb = sb;
return 1;
}

if (sb.st_dev != old_sb.st_dev ||
sb.st_ino != old_sb.st_ino ||
sb.st_ctime != old_sb.st_ctime ||
sb.st_mtime != old_sb.st_mtime) {
old_sb = sb;
return 1;
}

return 0;
}
#else /* !DETECT_TZ_CHANGES */
#define change_in_tz(X) 0
#endif /* !DETECT_TZ_CHANGES */

static int
differ_by_repeat(const time_t t1, const time_t t0)
{
Expand All @@ -379,6 +418,7 @@ register const int doextend;
int stored;
int nread;
int res;
int ret;
union {
struct tzhead tzhead;
char buf[2 * sizeof(struct tzhead) +
Expand Down Expand Up @@ -427,6 +467,22 @@ register const int doextend;
(void) strcat(fullname, name);
name = fullname;
}
if (doextend == TRUE) {
/*
* Detect if the timezone file has changed. Check
* 'doextend' to ignore TZDEFRULES; the change_in_tz()
* function can only keep state for a single file.
*/
ret = change_in_tz(name);
if (ret <= 0) {
/*
* Returns -1 if there was an error,
* and 0 if the timezone had not changed.
*/
free(fullname);
return ret;
}
}
if ((fid = _open(name, OPEN_MODE)) == -1) {
free(fullname);
return -1;
Expand Down Expand Up @@ -1209,12 +1265,43 @@ gmtload(struct state *const sp)
(void) tzparse(gmt, sp, TRUE);
}

#ifdef DETECT_TZ_CHANGES
static int
recheck_tzdata()
{
static time_t last_checked;
struct timespec now;
time_t current_time;
int error;

/*
* We want to recheck the timezone file every 61 sec.
*/
error = clock_gettime(CLOCK_MONOTONIC, &now);
if (error <= 0) {
/* XXX: Can we somehow report this? */
return 0;
}

current_time = now.tv_sec;
if ((current_time - last_checked > 61) ||
(last_checked > current_time)) {
last_checked = current_time;
return 1;
}

return 0;
}
#else /* !DETECT_TZ_CHANGES */
#define recheck_tzdata() 0
#endif /* !DETECT_TZ_CHANGES */

static void
tzsetwall_basic(int rdlocked)
{
if (!rdlocked)
_RWLOCK_RDLOCK(&lcl_rwlock);
if (lcl_is_set < 0) {
if (lcl_is_set < 0 && recheck_tzdata() == 0) {
if (!rdlocked)
_RWLOCK_UNLOCK(&lcl_rwlock);
return;
Expand Down
4 changes: 4 additions & 0 deletions lib/libc/stdtime/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ CFLAGS+= -I${SRCTOP}/contrib/tzcode/stdtime -I${LIBC_SRCTOP}/stdtime

CFLAGS.localtime.c= -fwrapv

.if ${MK_DETECT_TZ_CHANGES} != "no"
CFLAGS+= -DDETECT_TZ_CHANGES
.endif

MAN+= ctime.3 strftime.3 strptime.3 time2posix.3
MAN+= tzfile.5

Expand Down
1 change: 1 addition & 0 deletions share/mk/src.opts.mk
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ __DEFAULT_NO_OPTIONS = \
BHYVE_SNAPSHOT \
CLANG_EXTRAS \
CLANG_FORMAT \
DETECT_TZ_CHANGES \
DTRACE_TESTS \
EXPERIMENTAL \
HESIOD \
Expand Down
2 changes: 2 additions & 0 deletions tools/build/options/WITH_DETECT_TZ_CHANGES
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.\" $FreeBSD$
Make the time handling code detect changes to the timezone files.

0 comments on commit ddedf2a

Please sign in to comment.