blob: c6d5d9032cad2660cffab2093d4ae4e88aba1aff [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001--- a/src/time/__tz.c
2+++ b/src/time/__tz.c
3@@ -5,6 +5,10 @@
4 #include <string.h>
5 #include <sys/mman.h>
6 #include <ctype.h>
7+#include <unistd.h>
8+#include <sys/types.h>
9+#include <sys/stat.h>
10+#include <fcntl.h>
11 #include "libc.h"
12 #include "lock.h"
13 #include "fork_impl.h"
14@@ -123,6 +127,67 @@ static size_t zi_dotprod(const unsigned
15 return y;
16 }
17
18+#define TZ_BUFLEN (2*TZNAME_MAX + 56)
19+static char *read_TZ_file(char *buf)
20+{
21+ int r;
22+ int fd;
23+ char *p = NULL;
24+
25+ fd = open("/etc/TZ", O_RDONLY);
26+ if (fd >= 0) {
27+ /* Shorter, and does one fewer read syscall */
28+ r = read(fd, buf, TZ_BUFLEN);
29+ if (r < 0)
30+ goto ERROR;
31+ p = buf + r;
32+
33+ if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline */
34+ p[-1] = 0;
35+ p = buf;
36+ } else {
37+ERROR:
38+ p = NULL;
39+ }
40+ close(fd);
41+ } else {
42+ fd = open("/etc/localtime", O_RDONLY);
43+ if (fd >= 0) {
44+ r = read(fd, buf, TZ_BUFLEN);
45+ if (r != TZ_BUFLEN
46+ || strncmp(buf, "TZif", 4) != 0
47+ || (unsigned char)buf[4] < 2
48+ || lseek(fd, -TZ_BUFLEN, SEEK_END) < 0
49+ ) {
50+ goto ERROR;
51+ }
52+ /* tzfile.h from tzcode database says about TZif2+ files:
53+ **
54+ ** If tzh_version is '2' or greater, the above is followed by a second instance
55+ ** of tzhead and a second instance of the data in which each coded transition
56+ ** time uses 8 rather than 4 chars,
57+ ** then a POSIX-TZ-environment-variable-style string for use in handling
58+ ** instants after the last transition time stored in the file
59+ ** (with nothing between the newlines if there is no POSIX representation for
60+ ** such instants).
61+ */
62+ r = read(fd, buf, TZ_BUFLEN);
63+ if (r <= 0 || buf[--r] != '\n')
64+ goto ERROR;
65+ buf[r] = 0;
66+ while (r != 0) {
67+ if (buf[--r] == '\n') {
68+ p = buf + r + 1;
69+ break;
70+ }
71+ } /* else ('\n' not found): p remains NULL */
72+ close(fd);
73+ }
74+ }
75+
76+ return p;
77+}
78+
79 static void do_tzset()
80 {
81 char buf[NAME_MAX+25], *pathname=buf+24;
82@@ -131,8 +196,15 @@ static void do_tzset()
83 size_t i;
84 static const char search[] =
85 "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0";
86+ char tzbuf[TZ_BUFLEN];
87
88 s = getenv("TZ");
89+
90+ /* if TZ is empty try to read it from /etc/TZ */
91+ if (!s || !*s) {
92+ s = read_TZ_file(tzbuf);
93+ }
94+
95 if (!s) s = "/etc/localtime";
96 if (!*s) s = __utc;
97