|
@@ -71,6 +71,28 @@
|
|
|
* TODO - Rework _time_mktime to remove the dependency on long long.
|
|
|
*/
|
|
|
|
|
|
+
|
|
|
+ *
|
|
|
+ * Fixed allowed char check for std and dst TZ fields.
|
|
|
+ *
|
|
|
+ * Added several options concerned with timezone support. The names will
|
|
|
+ * probably change once Erik gets the new config system in place.
|
|
|
+ *
|
|
|
+ * Defining __TIME_TZ_FILE causes tzset() to attempt to read the TZ value
|
|
|
+ * from the file /etc/TZ if the TZ env variable isn't set. The file contents
|
|
|
+ * must be the intended value of TZ, followed by a newline. No other chars,
|
|
|
+ * spacing, etc is allowed. As an example, an easy way for me to init
|
|
|
+ * /etc/TZ appropriately would be: echo CST6CDT > /etc/TZ
|
|
|
+ *
|
|
|
+ * Defining __TIME_TZ_FILE_ONCE will cause all further accesses of /etc/TZ
|
|
|
+ * to be skipped once a legal value has been read.
|
|
|
+ *
|
|
|
+ * Defining __TIME_TZ_OPT_SPEED will cause a tzset() to keep a copy of the
|
|
|
+ * last TZ setting string and do a "fast out" if the current string is the
|
|
|
+ * same.
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
#define _GNU_SOURCE
|
|
|
#define _STDIO_UTILITY
|
|
|
#include <stdio.h>
|
|
@@ -93,9 +115,30 @@
|
|
|
#define TZNAME_MAX _POSIX_TZNAME_MAX
|
|
|
#endif
|
|
|
|
|
|
+
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
|
+#define __TIME_TZ_FILE
|
|
|
+
|
|
|
+
|
|
|
+#define __TIME_TZ_OPT_SPEED
|
|
|
+
|
|
|
+#define TZ_BUFLEN (2*TZNAME_MAX + 56)
|
|
|
+
|
|
|
+#ifdef __TIME_TZ_FILE
|
|
|
+#include <sys/stat.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include <unistd.h>
|
|
|
+
|
|
|
+
|
|
|
+#else
|
|
|
+#undef __TIME_TZ_FILE_ONCE
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
extern struct tm __time_tm;
|
|
|
|
|
|
typedef struct {
|
|
@@ -1476,6 +1519,50 @@ static const char *getnumber(register const char *e, int *pn)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
+#ifdef __TIME_TZ_FILE
|
|
|
+
|
|
|
+#ifdef __TIME_TZ_FILE_ONCE
|
|
|
+static int TZ_file_read;
|
|
|
+#endif
|
|
|
+
|
|
|
+static char *read_TZ_file(char *buf)
|
|
|
+{
|
|
|
+ int fd;
|
|
|
+ ssize_t r;
|
|
|
+ size_t todo;
|
|
|
+ char *p = NULL;
|
|
|
+
|
|
|
+ if ((fd = open("/etc/TZ", O_RDONLY)) >= 0) {
|
|
|
+ todo = TZ_BUFLEN;
|
|
|
+ p = buf;
|
|
|
+ do {
|
|
|
+ if ((r = read(fd, p, todo)) < 0) {
|
|
|
+ goto ERROR;
|
|
|
+ }
|
|
|
+ if (r == 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ p += r;
|
|
|
+ todo -= r;
|
|
|
+ } while (todo);
|
|
|
+
|
|
|
+ if ((p > buf) && (p[-1] == '\n')) {
|
|
|
+ p[-1] = 0;
|
|
|
+ p = buf;
|
|
|
+#ifdef __TIME_TZ_FILE_ONCE
|
|
|
+ ++TZ_file_read;
|
|
|
+#endif
|
|
|
+ } else {
|
|
|
+ ERROR:
|
|
|
+ p = NULL;
|
|
|
+ }
|
|
|
+ close(fd);
|
|
|
+ }
|
|
|
+ return p;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
void tzset(void)
|
|
|
{
|
|
|
register const char *e;
|
|
@@ -1485,11 +1572,42 @@ void tzset(void)
|
|
|
rule_struct new_rules[2];
|
|
|
int n, count, f;
|
|
|
char c;
|
|
|
+#ifdef __TIME_TZ_FILE
|
|
|
+ char buf[TZ_BUFLEN];
|
|
|
+#endif
|
|
|
+#ifdef __TIME_TZ_OPT_SPEED
|
|
|
+ static char oldval[TZ_BUFLEN];
|
|
|
+#endif
|
|
|
|
|
|
TZLOCK;
|
|
|
|
|
|
- if (!(e = getenv(TZ)) || !*e) {
|
|
|
+ e = getenv(TZ);
|
|
|
+
|
|
|
+#ifdef __TIME_TZ_FILE_ONCE
|
|
|
+
|
|
|
+ * timezones being used in a threaded app. */
|
|
|
+
|
|
|
+ if (e != NULL) {
|
|
|
+ TZ_file_read = 0;
|
|
|
+ } else if (TZ_file_read > 0) {
|
|
|
+ goto FAST_DONE;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+ * potentially unsafe in a multi-threaded program since it is remotely
|
|
|
+ * possible that another thread could call setenv() for TZ and overwrite
|
|
|
+ * the string being parsed. So, don't do that... */
|
|
|
+
|
|
|
+ if ((!e
|
|
|
+#ifdef __TIME_TZ_FILE
|
|
|
+ && !(e = read_TZ_file(buf))
|
|
|
+#endif
|
|
|
+ ) || !*e) {
|
|
|
ILLEGAL:
|
|
|
+#ifdef __TIME_TZ_OPT_SPEED
|
|
|
+ *oldval = 0;
|
|
|
+#endif
|
|
|
s = _time_tzinfo[0].tzname;
|
|
|
*s = 'U';
|
|
|
*++s = 'T';
|
|
@@ -1500,10 +1618,19 @@ void tzset(void)
|
|
|
goto DONE;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
if (*e == ':') {
|
|
|
++e;
|
|
|
}
|
|
|
+
|
|
|
+#ifdef __TIME_TZ_OPT_SPEED
|
|
|
+ if (strcmp(e, oldval) == 0) {
|
|
|
+ goto FAST_DONE;
|
|
|
+ }
|
|
|
+
|
|
|
+ * it is too long, but it that case it will be illegal and will be reset
|
|
|
+ * to the empty string anyway. */
|
|
|
+ strncpy(oldval, e, TZ_BUFLEN);
|
|
|
+#endif
|
|
|
|
|
|
count = 0;
|
|
|
new_rules[1].tzname[0] = 0;
|
|
@@ -1518,8 +1645,9 @@ void tzset(void)
|
|
|
s = new_rules[count].tzname;
|
|
|
n = 0;
|
|
|
while (*e
|
|
|
+ && isascii(*e)
|
|
|
&& (isalpha(*e)
|
|
|
- || (c && (isdigit(*e) || (*e == '+') || (*e == '-'))))
|
|
|
+ || (c && (isalnum(*e) || (*e == '+') || (*e == '-'))))
|
|
|
) {
|
|
|
*s++ = *e++;
|
|
|
if (++n > TZNAME_MAX) {
|
|
@@ -1621,6 +1749,7 @@ void tzset(void)
|
|
|
daylight = !!new_rules[1].tzname[0];
|
|
|
timezone = new_rules[0].gmt_offset;
|
|
|
|
|
|
+ FAST_DONE:
|
|
|
TZUNLOCK;
|
|
|
}
|
|
|
|