git: d3ed105942bb - stable/13 - tzcode: Implement timezone change detection
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 31 Jan 2023 09:46:44 UTC
The branch stable/13 has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=d3ed105942bbd8457e0c307ddc9d8ac95b365c2b commit d3ed105942bbd8457e0c307ddc9d8ac95b365c2b Author: Edward Tomasz Napierala <trasz@FreeBSD.org> AuthorDate: 2021-09-12 03:07:26 +0000 Commit: Dag-Erling Smørgrav <des@FreeBSD.org> CommitDate: 2023-01-31 09:44:18 +0000 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 (cherry picked from commit ddedf2a11eb20af1ee52cb3da70a57c21904af8f) tzcode: Fix operation without WITH_DETECT_TZ_CHANGES Reviewed By: bdrewery, kevans, cy Reported By: lwhsu, bdrewery Fixes: ddedf2a11eb Sponsored by: NetApp, Inc. Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D31961 (cherry picked from commit 6f43f86bf36dba158355593bab5f81a7f8e2773c) tzcode: fix tz change detection logic clock_gettime() returns 0 if it succeeds, so don't capture that into the fail logic. With this, WITH_DETECT_TZ_CHANGES successfully detects a change after 61 seconds. Reviewed by: imp, trasz Differential Revision: https://reviews.freebsd.org/D33494 (cherry picked from commit a2c51da6581dbc38c60c9fc41d1b624ff2c8de97) --- contrib/tzcode/stdtime/localtime.c | 89 +++++++++++++++++++++++++++++- lib/libc/stdtime/Makefile.inc | 4 ++ share/mk/src.opts.mk | 1 + tools/build/options/WITH_DETECT_TZ_CHANGES | 2 + 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/contrib/tzcode/stdtime/localtime.c b/contrib/tzcode/stdtime/localtime.c index e221c1fa3964..6a0e0ce4fe4b 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) 1 +#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 962b58b82a25..76185a2bca49 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -201,6 +201,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.