aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Tomasz Napierala <trasz@FreeBSD.org>2021-09-12 03:07:26 +0000
committerEdward Tomasz Napierala <trasz@FreeBSD.org>2021-09-12 03:07:58 +0000
commitddedf2a11eb20af1ee52cb3da70a57c21904af8f (patch)
tree6bb44b9953c1626ac6a169b406b4081f19026fc2
parentb9df18d6e8917a9bfb62babb7cf9efeca23aa2fc (diff)
downloadsrc-ddedf2a11eb20af1ee52cb3da70a57c2.tar.gz
src-ddedf2a11eb20af1ee52cb3da70a57c2.zip
tzcode: Implement timezone change detection
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: #47 Differential Revision: https://reviews.freebsd.org/D30183
-rw-r--r--contrib/tzcode/stdtime/localtime.c89
-rw-r--r--lib/libc/stdtime/Makefile.inc4
-rw-r--r--share/mk/src.opts.mk1
-rw-r--r--tools/build/options/WITH_DETECT_TZ_CHANGES2
4 files changed, 95 insertions, 1 deletions
diff --git a/contrib/tzcode/stdtime/localtime.c b/contrib/tzcode/stdtime/localtime.c
index e221c1fa3964..926b24470e19 100644
--- a/contrib/tzcode/stdtime/localtime.c
+++ b/contrib/tzcode/stdtime/localtime.c
@@ -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)
{
@@ -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) +
@@ -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;
@@ -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;
diff --git a/lib/libc/stdtime/Makefile.inc b/lib/libc/stdtime/Makefile.inc
index fb0d2b934148..3d483469bc97 100644
--- a/lib/libc/stdtime/Makefile.inc
+++ b/lib/libc/stdtime/Makefile.inc
@@ -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
diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
index 28e18260affd..ff894d3b3517 100644
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -196,6 +196,7 @@ __DEFAULT_NO_OPTIONS = \
BHYVE_SNAPSHOT \
CLANG_EXTRAS \
CLANG_FORMAT \
+ DETECT_TZ_CHANGES \
DTRACE_TESTS \
EXPERIMENTAL \
HESIOD \
diff --git a/tools/build/options/WITH_DETECT_TZ_CHANGES b/tools/build/options/WITH_DETECT_TZ_CHANGES
new file mode 100644
index 000000000000..6a2d18473892
--- /dev/null
+++ b/tools/build/options/WITH_DETECT_TZ_CHANGES
@@ -0,0 +1,2 @@
+.\" $FreeBSD$
+Make the time handling code detect changes to the timezone files.