git: f5efc804294c - main - tzcode: Reduce diff to upstream
Date: Thu, 21 Aug 2025 18:59:46 UTC
The branch main has been updated by des:
URL: https://cgit.FreeBSD.org/src/commit/?id=f5efc804294c6bb24bd6d14bf2fb883a7320956c
commit f5efc804294c6bb24bd6d14bf2fb883a7320956c
Author: Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2025-08-21 16:34:27 +0000
Commit: Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2025-08-21 18:59:37 +0000
tzcode: Reduce diff to upstream
Reviewed by: imp, jhb, emaste
Differential Revision: https://reviews.freebsd.org/D51997
---
contrib/tzcode/localtime.c | 292 ++++++++++++++++++++++++++-------------------
1 file changed, 169 insertions(+), 123 deletions(-)
diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c
index a6ec3d8e4e21..6eabe0afe570 100644
--- a/contrib/tzcode/localtime.c
+++ b/contrib/tzcode/localtime.c
@@ -13,37 +13,36 @@
/*LINTLIBRARY*/
#define LOCALTIME_IMPLEMENTATION
+#ifdef __FreeBSD__
#include "namespace.h"
+#include <pthread.h>
+#endif /* __FreeBSD__ */
#ifdef DETECT_TZ_CHANGES
-#ifndef DETECT_TZ_CHANGES_INTERVAL
-#define DETECT_TZ_CHANGES_INTERVAL 61
-#endif
+# ifndef DETECT_TZ_CHANGES_INTERVAL
+# define DETECT_TZ_CHANGES_INTERVAL 61
+# endif
int __tz_change_interval = DETECT_TZ_CHANGES_INTERVAL;
-#include <sys/stat.h>
-#endif
-#include <fcntl.h>
-#if THREAD_SAFE
-#include <pthread.h>
-#endif
+# include <sys/stat.h>
+#endif /* DETECT_TZ_CHANGES */
#include "private.h"
-#include "un-namespace.h"
#include "tzdir.h"
#include "tzfile.h"
-
+#include <fcntl.h>
+#ifdef __FreeBSD__
#include "libc_private.h"
+#include "un-namespace.h"
+#endif /* __FreeBSD__ */
#if defined THREAD_SAFE && THREAD_SAFE
+# include <pthread.h>
+#ifdef __FreeBSD__
+# define pthread_mutex_lock(l) (__isthreaded ? _pthread_mutex_lock(l) : 0)
+# define pthread_mutex_unlock(l) (__isthreaded ? _pthread_mutex_unlock(l) : 0)
+#endif /* __FreeBSD__ */
static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
-static int lock(void) {
- if (__isthreaded)
- return _pthread_mutex_lock(&locallock);
- return 0;
-}
-static void unlock(void) {
- if (__isthreaded)
- _pthread_mutex_unlock(&locallock);
-}
+static int lock(void) { return pthread_mutex_lock(&locallock); }
+static void unlock(void) { pthread_mutex_unlock(&locallock); }
#else
static int lock(void) { return 0; }
static void unlock(void) { }
@@ -166,6 +165,9 @@ struct rule {
int_fast32_t r_time; /* transition time of rule */
};
+#ifdef __FreeBSD__
+static void tzset_unlocked_name(char const *);
+#endif /* __FreeBSD__ */
static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
struct tm *);
static bool increment_overflow(int *, int);
@@ -194,7 +196,7 @@ static struct state *const gmtptr = &gmtmem;
static char lcl_TZname[TZ_STRLEN_MAX + 1];
static int lcl_is_set;
-
+#ifdef __FreeBSD__
static pthread_once_t gmt_once = PTHREAD_ONCE_INIT;
static pthread_once_t gmtime_once = PTHREAD_ONCE_INIT;
static pthread_key_t gmtime_key;
@@ -205,6 +207,7 @@ static int offtime_key_error;
static pthread_once_t localtime_once = PTHREAD_ONCE_INIT;
static pthread_key_t localtime_key;
static int localtime_key_error;
+#endif /* __FreeBSD__ */
/*
** Section 4.12.3 of X3.159-1989 requires that
@@ -398,13 +401,14 @@ scrub_abbrs(struct state *sp)
#ifdef DETECT_TZ_CHANGES
/*
- * Determine if there's a change in the timezone since the last time we checked.
+ * Check whether either the time zone name or the file it refers to has
+ * changed since the last time we checked.
* Returns: -1 on error
- * 0 if the timezone has not changed
- * 1 if the timezone has changed
+ * 0 if the time zone has not changed
+ * 1 if the time zone has changed
*/
static int
-change_in_tz(const char *name)
+tzfile_changed(const char *name)
{
static char old_name[PATH_MAX];
static struct stat old_sb;
@@ -429,9 +433,7 @@ change_in_tz(const char *name)
return 0;
}
-#else /* !DETECT_TZ_CHANGES */
-#define change_in_tz(X) 1
-#endif /* !DETECT_TZ_CHANGES */
+#endif /* DETECT_TZ_CHANGES */
/* Input buffer for data read from a compiled tz file. */
union input_buffer {
@@ -478,6 +480,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
register int fid;
register int stored;
register ssize_t nread;
+ register bool doaccess;
register union input_buffer *up = &lsp->u.u;
register int tzheadsize = sizeof(struct tzhead);
@@ -491,7 +494,17 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
if (name[0] == ':')
++name;
- if (name[0] != '/') {
+#ifdef SUPPRESS_TZDIR
+ /* Do not prepend TZDIR. This is intended for specialized
+ applications only, due to its security implications. */
+ doaccess = true;
+#else
+ doaccess = name[0] == '/';
+#endif
+ if (!doaccess) {
+#ifndef __FreeBSD__
+ char const *dot;
+#endif /* !__FreeBSD__ */
if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
return ENAMETOOLONG;
@@ -501,15 +514,32 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
strcpy(lsp->fullname + sizeof tzdirslash, name);
+#ifndef __FreeBSD__
+ /* Set doaccess if NAME contains a ".." file name
+ component, as such a name could read a file outside
+ the TZDIR virtual subtree. */
+ for (dot = name; (dot = strchr(dot, '.')); dot++)
+ if ((dot == name || dot[-1] == '/') && dot[1] == '.'
+ && (dot[2] == '/' || !dot[2])) {
+ doaccess = true;
+ break;
+ }
+#endif /* !__FreeBSD__ */
+
name = lsp->fullname;
}
+#ifndef __FreeBSD__
+ if (doaccess && access(name, R_OK) != 0)
+ return errno;
+#endif /* !__FreeBSD__ */
+#ifdef DETECT_TZ_CHANGES
if (doextend) {
/*
* Detect if the timezone file has changed. Check
- * 'doextend' to ignore TZDEFRULES; the change_in_tz()
+ * 'doextend' to ignore TZDEFRULES; the tzfile_changed()
* function can only keep state for a single file.
*/
- switch (change_in_tz(name)) {
+ switch (tzfile_changed(name)) {
case -1:
return errno;
case 0:
@@ -518,6 +548,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
break;
}
}
+#endif /* DETECT_TZ_CHANGES */
fid = _open(name, O_RDONLY | O_BINARY);
if (fid < 0)
return errno;
@@ -1370,8 +1401,11 @@ gmtload(struct state *const sp)
}
#ifdef DETECT_TZ_CHANGES
+/*
+ * Check if the time zone data we have is still fresh.
+ */
static int
-recheck_tzdata()
+tzdata_is_fresh(void)
{
static time_t last_checked;
struct timespec now;
@@ -1387,9 +1421,7 @@ recheck_tzdata()
return 0;
}
-#else /* !DETECT_TZ_CHANGES */
-#define recheck_tzdata() 0
-#endif /* !DETECT_TZ_CHANGES */
+#endif /* DETECT_TZ_CHANGES */
/* Initialize *SP to a value appropriate for the TZ setting NAME.
Return 0 on success, an errno value on failure. */
@@ -1418,16 +1450,27 @@ zoneinit(struct state *sp, char const *name)
}
}
+static void
+tzset_unlocked(void)
+{
+#ifdef __FreeBSD__
+ tzset_unlocked_name(getenv("TZ"));
+}
static void
tzset_unlocked_name(char const *name)
{
+#else
+ char const *name = getenv("TZ");
+#endif
struct state *sp = lclptr;
int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
if (lcl < 0
? lcl_is_set < 0
: 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
- if (recheck_tzdata() == 0)
- return;
+#ifdef DETECT_TZ_CHANGES
+ if (tzdata_is_fresh() == 0)
+#endif /* DETECT_TZ_CHANGES */
+ return;
#ifdef ALL_STATE
if (! sp)
lclptr = sp = malloc(sizeof *lclptr);
@@ -1442,12 +1485,6 @@ tzset_unlocked_name(char const *name)
lcl_is_set = lcl;
}
-static void
-tzset_unlocked(void)
-{
- tzset_unlocked_name(getenv("TZ"));
-}
-
void
tzset(void)
{
@@ -1457,6 +1494,7 @@ tzset(void)
unlock();
}
+#ifdef __FreeBSD__
void
freebsd13_tzsetwall(void)
{
@@ -1468,7 +1506,7 @@ freebsd13_tzsetwall(void)
__sym_compat(tzsetwall, freebsd13_tzsetwall, FBSD_1.0);
__warn_references(tzsetwall,
"warning: tzsetwall() is deprecated, use tzset() instead.");
-
+#endif /* __FreeBSD__ */
static void
gmtcheck(void)
{
@@ -1485,6 +1523,9 @@ gmtcheck(void)
}
unlock();
}
+#ifdef __FreeBSD__
+#define gmtcheck() _once(&gmt_once, gmtcheck)
+#endif
#if NETBSD_INSPIRED
@@ -1652,45 +1693,47 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
}
#ifndef DETECT_TZ_CHANGES
if (setname || !lcl_is_set)
-#endif
+#endif /* DETECT_TZ_CHANGES */
tzset_unlocked();
tmp = localsub(lclptr, timep, setname, tmp);
unlock();
return tmp;
}
+#ifdef __FreeBSD__
static void
localtime_key_init(void)
{
-
- localtime_key_error = _pthread_key_create(&localtime_key, free);
+ localtime_key_error = _pthread_key_create(&localtime_key, free);
}
-
+#endif /* __FreeBSD__ */
struct tm *
localtime(const time_t *timep)
{
#if !SUPPORT_C89
- static struct tm tm;
+ static struct tm tm;
#endif
- struct tm *p_tm = &tm;
-
- if (__isthreaded != 0) {
- _pthread_once(&localtime_once, localtime_key_init);
- if (localtime_key_error != 0) {
- errno = localtime_key_error;
- return (NULL);
- }
- if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) {
- if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
- return (NULL);
- }
- if (_pthread_setspecific(localtime_key, p_tm) != 0) {
- free(p_tm);
- return (NULL);
- }
- }
- }
- return localtime_tzset(timep, p_tm, true);
+#ifdef __FreeBSD__
+ struct tm *p_tm = &tm;
+
+ if (__isthreaded != 0) {
+ _pthread_once(&localtime_once, localtime_key_init);
+ if (localtime_key_error != 0) {
+ errno = localtime_key_error;
+ return (NULL);
+ }
+ if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) {
+ if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
+ return (NULL);
+ }
+ if (_pthread_setspecific(localtime_key, p_tm) != 0) {
+ free(p_tm);
+ return (NULL);
+ }
+ }
+ }
+#endif /* __FreeBSD__ */
+ return localtime_tzset(timep, p_tm, true);
}
struct tm *
@@ -1729,42 +1772,44 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
struct tm *
gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
{
- _once(&gmt_once, gmtcheck);
- return gmtsub(gmtptr, timep, 0, tmp);
+ gmtcheck();
+ return gmtsub(gmtptr, timep, 0, tmp);
}
+#ifdef __FreeBSD__
static void
gmtime_key_init(void)
{
-
- gmtime_key_error = _pthread_key_create(&gmtime_key, free);
+ gmtime_key_error = _pthread_key_create(&gmtime_key, free);
}
-
+#endif /* __FreeBSD__ */
struct tm *
gmtime(const time_t *timep)
{
#if !SUPPORT_C89
- static struct tm tm;
+ static struct tm tm;
#endif
- struct tm *p_tm = &tm;
-
- if (__isthreaded != 0) {
- _pthread_once(&gmtime_once, gmtime_key_init);
- if (gmtime_key_error != 0) {
- errno = gmtime_key_error;
- return (NULL);
- }
- if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
- if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
- return (NULL);
- }
- if (_pthread_setspecific(gmtime_key, p_tm) != 0) {
- free(p_tm);
- return (NULL);
- }
- }
- }
- return gmtime_r(timep, p_tm);
+#ifdef __FreeBSD__
+ struct tm *p_tm = &tm;
+
+ if (__isthreaded != 0) {
+ _pthread_once(&gmtime_once, gmtime_key_init);
+ if (gmtime_key_error != 0) {
+ errno = gmtime_key_error;
+ return (NULL);
+ }
+ if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
+ if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
+ return (NULL);
+ }
+ if (_pthread_setspecific(gmtime_key, p_tm) != 0) {
+ free(p_tm);
+ return (NULL);
+ }
+ }
+ }
+#endif /* __FreeBSD__ */
+ return gmtime_r(timep, p_tm);
}
#if STD_INSPIRED
@@ -1775,42 +1820,44 @@ gmtime(const time_t *timep)
struct tm *
offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp)
{
- _once(&gmt_once, gmtcheck);
- return gmtsub(gmtptr, timep, offset, tmp);
+ gmtcheck();
+ return gmtsub(gmtptr, timep, offset, tmp);
}
+#ifdef __FreeBSD__
static void
offtime_key_init(void)
{
-
- offtime_key_error = _pthread_key_create(&offtime_key, free);
+ offtime_key_error = _pthread_key_create(&offtime_key, free);
}
-
+#endif /* __FreeBSD__ */
struct tm *
offtime(const time_t *timep, long offset)
{
#if !SUPPORT_C89
- static struct tm tm;
+ static struct tm tm;
#endif
- struct tm *p_tm = &tm;
-
- if (__isthreaded != 0) {
- _pthread_once(&offtime_once, offtime_key_init);
- if (offtime_key_error != 0) {
- errno = offtime_key_error;
- return (NULL);
- }
- if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) {
- if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
- return (NULL);
- }
- if (_pthread_setspecific(offtime_key, p_tm) != 0) {
- free(p_tm);
- return (NULL);
- }
- }
- }
- return offtime_r(timep, offset, p_tm);
+#ifdef __FreeBSD__
+ struct tm *p_tm = &tm;
+
+ if (__isthreaded != 0) {
+ _pthread_once(&offtime_once, offtime_key_init);
+ if (offtime_key_error != 0) {
+ errno = offtime_key_error;
+ return (NULL);
+ }
+ if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) {
+ if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
+ return (NULL);
+ }
+ if (_pthread_setspecific(offtime_key, p_tm) != 0) {
+ free(p_tm);
+ return (NULL);
+ }
+ }
+ }
+#endif
+ return offtime_r(timep, offset, p_tm);
}
#endif
@@ -2323,7 +2370,6 @@ time1(struct tm *const tmp,
errno = EINVAL;
return WRONG;
}
-
if (tmp->tm_isdst > 1)
tmp->tm_isdst = 1;
t = time2(tmp, funcp, sp, offset, &okay);
@@ -2382,7 +2428,7 @@ mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
if (sp)
return time1(tmp, localsub, sp, setname);
else {
- _once(&gmt_once, gmtcheck);
+ gmtcheck();
return time1(tmp, gmtsub, gmtptr, 0);
}
}
@@ -2438,7 +2484,7 @@ timeoff(struct tm *tmp, long offset)
{
if (tmp)
tmp->tm_isdst = 0;
- _once(&gmt_once, gmtcheck);
+ gmtcheck();
return time1(tmp, gmtsub, gmtptr, offset);
}
@@ -2508,7 +2554,7 @@ time2posix(time_t t)
}
#ifndef DETECT_TZ_CHANGES
if (!lcl_is_set)
-#endif
+#endif /* DETECT_TZ_CHANGES */
tzset_unlocked();
if (lclptr)
t = time2posix_z(lclptr, t);
@@ -2555,7 +2601,7 @@ posix2time(time_t t)
}
#ifndef DETECT_TZ_CHANGES
if (!lcl_is_set)
-#endif
+#endif /* DETECT_TZ_CHANGES */
tzset_unlocked();
if (lclptr)
t = posix2time_z(lclptr, t);