1*c9945492SAndroid Build Coastguard Worker #include "time_impl.h"
2*c9945492SAndroid Build Coastguard Worker #include <stdint.h>
3*c9945492SAndroid Build Coastguard Worker #include <limits.h>
4*c9945492SAndroid Build Coastguard Worker #include <stdlib.h>
5*c9945492SAndroid Build Coastguard Worker #include <string.h>
6*c9945492SAndroid Build Coastguard Worker #include <sys/mman.h>
7*c9945492SAndroid Build Coastguard Worker #include <ctype.h>
8*c9945492SAndroid Build Coastguard Worker #include "libc.h"
9*c9945492SAndroid Build Coastguard Worker #include "lock.h"
10*c9945492SAndroid Build Coastguard Worker #include "fork_impl.h"
11*c9945492SAndroid Build Coastguard Worker
12*c9945492SAndroid Build Coastguard Worker #define malloc __libc_malloc
13*c9945492SAndroid Build Coastguard Worker #define calloc undef
14*c9945492SAndroid Build Coastguard Worker #define realloc undef
15*c9945492SAndroid Build Coastguard Worker #define free undef
16*c9945492SAndroid Build Coastguard Worker
17*c9945492SAndroid Build Coastguard Worker long __timezone = 0;
18*c9945492SAndroid Build Coastguard Worker int __daylight = 0;
19*c9945492SAndroid Build Coastguard Worker char *__tzname[2] = { 0, 0 };
20*c9945492SAndroid Build Coastguard Worker
21*c9945492SAndroid Build Coastguard Worker weak_alias(__timezone, timezone);
22*c9945492SAndroid Build Coastguard Worker weak_alias(__daylight, daylight);
23*c9945492SAndroid Build Coastguard Worker weak_alias(__tzname, tzname);
24*c9945492SAndroid Build Coastguard Worker
25*c9945492SAndroid Build Coastguard Worker static char std_name[TZNAME_MAX+1];
26*c9945492SAndroid Build Coastguard Worker static char dst_name[TZNAME_MAX+1];
27*c9945492SAndroid Build Coastguard Worker const char __utc[] = "UTC";
28*c9945492SAndroid Build Coastguard Worker
29*c9945492SAndroid Build Coastguard Worker static int dst_off;
30*c9945492SAndroid Build Coastguard Worker static int r0[5], r1[5];
31*c9945492SAndroid Build Coastguard Worker
32*c9945492SAndroid Build Coastguard Worker static const unsigned char *zi, *trans, *index, *types, *abbrevs, *abbrevs_end;
33*c9945492SAndroid Build Coastguard Worker static size_t map_size;
34*c9945492SAndroid Build Coastguard Worker
35*c9945492SAndroid Build Coastguard Worker static char old_tz_buf[32];
36*c9945492SAndroid Build Coastguard Worker static char *old_tz = old_tz_buf;
37*c9945492SAndroid Build Coastguard Worker static size_t old_tz_size = sizeof old_tz_buf;
38*c9945492SAndroid Build Coastguard Worker
39*c9945492SAndroid Build Coastguard Worker static volatile int lock[1];
40*c9945492SAndroid Build Coastguard Worker volatile int *const __timezone_lockptr = lock;
41*c9945492SAndroid Build Coastguard Worker
getint(const char ** p)42*c9945492SAndroid Build Coastguard Worker static int getint(const char **p)
43*c9945492SAndroid Build Coastguard Worker {
44*c9945492SAndroid Build Coastguard Worker unsigned x;
45*c9945492SAndroid Build Coastguard Worker for (x=0; **p-'0'<10U; (*p)++) x = **p-'0' + 10*x;
46*c9945492SAndroid Build Coastguard Worker return x;
47*c9945492SAndroid Build Coastguard Worker }
48*c9945492SAndroid Build Coastguard Worker
getoff(const char ** p)49*c9945492SAndroid Build Coastguard Worker static int getoff(const char **p)
50*c9945492SAndroid Build Coastguard Worker {
51*c9945492SAndroid Build Coastguard Worker int neg = 0;
52*c9945492SAndroid Build Coastguard Worker if (**p == '-') {
53*c9945492SAndroid Build Coastguard Worker ++*p;
54*c9945492SAndroid Build Coastguard Worker neg = 1;
55*c9945492SAndroid Build Coastguard Worker } else if (**p == '+') {
56*c9945492SAndroid Build Coastguard Worker ++*p;
57*c9945492SAndroid Build Coastguard Worker }
58*c9945492SAndroid Build Coastguard Worker int off = 3600*getint(p);
59*c9945492SAndroid Build Coastguard Worker if (**p == ':') {
60*c9945492SAndroid Build Coastguard Worker ++*p;
61*c9945492SAndroid Build Coastguard Worker off += 60*getint(p);
62*c9945492SAndroid Build Coastguard Worker if (**p == ':') {
63*c9945492SAndroid Build Coastguard Worker ++*p;
64*c9945492SAndroid Build Coastguard Worker off += getint(p);
65*c9945492SAndroid Build Coastguard Worker }
66*c9945492SAndroid Build Coastguard Worker }
67*c9945492SAndroid Build Coastguard Worker return neg ? -off : off;
68*c9945492SAndroid Build Coastguard Worker }
69*c9945492SAndroid Build Coastguard Worker
getrule(const char ** p,int rule[5])70*c9945492SAndroid Build Coastguard Worker static void getrule(const char **p, int rule[5])
71*c9945492SAndroid Build Coastguard Worker {
72*c9945492SAndroid Build Coastguard Worker int r = rule[0] = **p;
73*c9945492SAndroid Build Coastguard Worker
74*c9945492SAndroid Build Coastguard Worker if (r!='M') {
75*c9945492SAndroid Build Coastguard Worker if (r=='J') ++*p;
76*c9945492SAndroid Build Coastguard Worker else rule[0] = 0;
77*c9945492SAndroid Build Coastguard Worker rule[1] = getint(p);
78*c9945492SAndroid Build Coastguard Worker } else {
79*c9945492SAndroid Build Coastguard Worker ++*p; rule[1] = getint(p);
80*c9945492SAndroid Build Coastguard Worker ++*p; rule[2] = getint(p);
81*c9945492SAndroid Build Coastguard Worker ++*p; rule[3] = getint(p);
82*c9945492SAndroid Build Coastguard Worker }
83*c9945492SAndroid Build Coastguard Worker
84*c9945492SAndroid Build Coastguard Worker if (**p=='/') {
85*c9945492SAndroid Build Coastguard Worker ++*p;
86*c9945492SAndroid Build Coastguard Worker rule[4] = getoff(p);
87*c9945492SAndroid Build Coastguard Worker } else {
88*c9945492SAndroid Build Coastguard Worker rule[4] = 7200;
89*c9945492SAndroid Build Coastguard Worker }
90*c9945492SAndroid Build Coastguard Worker }
91*c9945492SAndroid Build Coastguard Worker
getname(char * d,const char ** p)92*c9945492SAndroid Build Coastguard Worker static void getname(char *d, const char **p)
93*c9945492SAndroid Build Coastguard Worker {
94*c9945492SAndroid Build Coastguard Worker int i;
95*c9945492SAndroid Build Coastguard Worker if (**p == '<') {
96*c9945492SAndroid Build Coastguard Worker ++*p;
97*c9945492SAndroid Build Coastguard Worker for (i=0; (*p)[i] && (*p)[i]!='>'; i++)
98*c9945492SAndroid Build Coastguard Worker if (i<TZNAME_MAX) d[i] = (*p)[i];
99*c9945492SAndroid Build Coastguard Worker if ((*p)[i]) ++*p;
100*c9945492SAndroid Build Coastguard Worker } else {
101*c9945492SAndroid Build Coastguard Worker for (i=0; ((*p)[i]|32)-'a'<26U; i++)
102*c9945492SAndroid Build Coastguard Worker if (i<TZNAME_MAX) d[i] = (*p)[i];
103*c9945492SAndroid Build Coastguard Worker }
104*c9945492SAndroid Build Coastguard Worker *p += i;
105*c9945492SAndroid Build Coastguard Worker d[i<TZNAME_MAX?i:TZNAME_MAX] = 0;
106*c9945492SAndroid Build Coastguard Worker }
107*c9945492SAndroid Build Coastguard Worker
108*c9945492SAndroid Build Coastguard Worker #define VEC(...) ((const unsigned char[]){__VA_ARGS__})
109*c9945492SAndroid Build Coastguard Worker
zi_read32(const unsigned char * z)110*c9945492SAndroid Build Coastguard Worker static uint32_t zi_read32(const unsigned char *z)
111*c9945492SAndroid Build Coastguard Worker {
112*c9945492SAndroid Build Coastguard Worker return (unsigned)z[0]<<24 | z[1]<<16 | z[2]<<8 | z[3];
113*c9945492SAndroid Build Coastguard Worker }
114*c9945492SAndroid Build Coastguard Worker
zi_dotprod(const unsigned char * z,const unsigned char * v,size_t n)115*c9945492SAndroid Build Coastguard Worker static size_t zi_dotprod(const unsigned char *z, const unsigned char *v, size_t n)
116*c9945492SAndroid Build Coastguard Worker {
117*c9945492SAndroid Build Coastguard Worker size_t y;
118*c9945492SAndroid Build Coastguard Worker uint32_t x;
119*c9945492SAndroid Build Coastguard Worker for (y=0; n; n--, z+=4, v++) {
120*c9945492SAndroid Build Coastguard Worker x = zi_read32(z);
121*c9945492SAndroid Build Coastguard Worker y += x * *v;
122*c9945492SAndroid Build Coastguard Worker }
123*c9945492SAndroid Build Coastguard Worker return y;
124*c9945492SAndroid Build Coastguard Worker }
125*c9945492SAndroid Build Coastguard Worker
do_tzset()126*c9945492SAndroid Build Coastguard Worker static void do_tzset()
127*c9945492SAndroid Build Coastguard Worker {
128*c9945492SAndroid Build Coastguard Worker char buf[NAME_MAX+25], *pathname=buf+24;
129*c9945492SAndroid Build Coastguard Worker const char *try, *s, *p;
130*c9945492SAndroid Build Coastguard Worker const unsigned char *map = 0;
131*c9945492SAndroid Build Coastguard Worker size_t i;
132*c9945492SAndroid Build Coastguard Worker static const char search[] =
133*c9945492SAndroid Build Coastguard Worker "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0";
134*c9945492SAndroid Build Coastguard Worker
135*c9945492SAndroid Build Coastguard Worker s = getenv("TZ");
136*c9945492SAndroid Build Coastguard Worker if (!s) s = "/etc/localtime";
137*c9945492SAndroid Build Coastguard Worker if (!*s) s = __utc;
138*c9945492SAndroid Build Coastguard Worker
139*c9945492SAndroid Build Coastguard Worker if (old_tz && !strcmp(s, old_tz)) return;
140*c9945492SAndroid Build Coastguard Worker
141*c9945492SAndroid Build Coastguard Worker for (i=0; i<5; i++) r0[i] = r1[i] = 0;
142*c9945492SAndroid Build Coastguard Worker
143*c9945492SAndroid Build Coastguard Worker if (zi) __munmap((void *)zi, map_size);
144*c9945492SAndroid Build Coastguard Worker
145*c9945492SAndroid Build Coastguard Worker /* Cache the old value of TZ to check if it has changed. Avoid
146*c9945492SAndroid Build Coastguard Worker * free so as not to pull it into static programs. Growth
147*c9945492SAndroid Build Coastguard Worker * strategy makes it so free would have minimal benefit anyway. */
148*c9945492SAndroid Build Coastguard Worker i = strlen(s);
149*c9945492SAndroid Build Coastguard Worker if (i > PATH_MAX+1) s = __utc, i = 3;
150*c9945492SAndroid Build Coastguard Worker if (i >= old_tz_size) {
151*c9945492SAndroid Build Coastguard Worker old_tz_size *= 2;
152*c9945492SAndroid Build Coastguard Worker if (i >= old_tz_size) old_tz_size = i+1;
153*c9945492SAndroid Build Coastguard Worker if (old_tz_size > PATH_MAX+2) old_tz_size = PATH_MAX+2;
154*c9945492SAndroid Build Coastguard Worker old_tz = malloc(old_tz_size);
155*c9945492SAndroid Build Coastguard Worker }
156*c9945492SAndroid Build Coastguard Worker if (old_tz) memcpy(old_tz, s, i+1);
157*c9945492SAndroid Build Coastguard Worker
158*c9945492SAndroid Build Coastguard Worker int posix_form = 0;
159*c9945492SAndroid Build Coastguard Worker if (*s != ':') {
160*c9945492SAndroid Build Coastguard Worker p = s;
161*c9945492SAndroid Build Coastguard Worker char dummy_name[TZNAME_MAX+1];
162*c9945492SAndroid Build Coastguard Worker getname(dummy_name, &p);
163*c9945492SAndroid Build Coastguard Worker if (p!=s && (*p == '+' || *p == '-' || isdigit(*p)
164*c9945492SAndroid Build Coastguard Worker || !strcmp(dummy_name, "UTC")
165*c9945492SAndroid Build Coastguard Worker || !strcmp(dummy_name, "GMT")))
166*c9945492SAndroid Build Coastguard Worker posix_form = 1;
167*c9945492SAndroid Build Coastguard Worker }
168*c9945492SAndroid Build Coastguard Worker
169*c9945492SAndroid Build Coastguard Worker /* Non-suid can use an absolute tzfile pathname or a relative
170*c9945492SAndroid Build Coastguard Worker * pathame beginning with "."; in secure mode, only the
171*c9945492SAndroid Build Coastguard Worker * standard path will be searched. */
172*c9945492SAndroid Build Coastguard Worker if (!posix_form) {
173*c9945492SAndroid Build Coastguard Worker if (*s == ':') s++;
174*c9945492SAndroid Build Coastguard Worker if (*s == '/' || *s == '.') {
175*c9945492SAndroid Build Coastguard Worker if (!libc.secure || !strcmp(s, "/etc/localtime"))
176*c9945492SAndroid Build Coastguard Worker map = __map_file(s, &map_size);
177*c9945492SAndroid Build Coastguard Worker } else {
178*c9945492SAndroid Build Coastguard Worker size_t l = strlen(s);
179*c9945492SAndroid Build Coastguard Worker if (l <= NAME_MAX && !strchr(s, '.')) {
180*c9945492SAndroid Build Coastguard Worker memcpy(pathname, s, l+1);
181*c9945492SAndroid Build Coastguard Worker pathname[l] = 0;
182*c9945492SAndroid Build Coastguard Worker for (try=search; !map && *try; try+=l+1) {
183*c9945492SAndroid Build Coastguard Worker l = strlen(try);
184*c9945492SAndroid Build Coastguard Worker memcpy(pathname-l, try, l);
185*c9945492SAndroid Build Coastguard Worker map = __map_file(pathname-l, &map_size);
186*c9945492SAndroid Build Coastguard Worker }
187*c9945492SAndroid Build Coastguard Worker }
188*c9945492SAndroid Build Coastguard Worker }
189*c9945492SAndroid Build Coastguard Worker if (!map) s = __utc;
190*c9945492SAndroid Build Coastguard Worker }
191*c9945492SAndroid Build Coastguard Worker if (map && (map_size < 44 || memcmp(map, "TZif", 4))) {
192*c9945492SAndroid Build Coastguard Worker __munmap((void *)map, map_size);
193*c9945492SAndroid Build Coastguard Worker map = 0;
194*c9945492SAndroid Build Coastguard Worker s = __utc;
195*c9945492SAndroid Build Coastguard Worker }
196*c9945492SAndroid Build Coastguard Worker
197*c9945492SAndroid Build Coastguard Worker zi = map;
198*c9945492SAndroid Build Coastguard Worker if (map) {
199*c9945492SAndroid Build Coastguard Worker int scale = 2;
200*c9945492SAndroid Build Coastguard Worker if (map[4]!='1') {
201*c9945492SAndroid Build Coastguard Worker size_t skip = zi_dotprod(zi+20, VEC(1,1,8,5,6,1), 6);
202*c9945492SAndroid Build Coastguard Worker trans = zi+skip+44+44;
203*c9945492SAndroid Build Coastguard Worker scale++;
204*c9945492SAndroid Build Coastguard Worker } else {
205*c9945492SAndroid Build Coastguard Worker trans = zi+44;
206*c9945492SAndroid Build Coastguard Worker }
207*c9945492SAndroid Build Coastguard Worker index = trans + (zi_read32(trans-12) << scale);
208*c9945492SAndroid Build Coastguard Worker types = index + zi_read32(trans-12);
209*c9945492SAndroid Build Coastguard Worker abbrevs = types + 6*zi_read32(trans-8);
210*c9945492SAndroid Build Coastguard Worker abbrevs_end = abbrevs + zi_read32(trans-4);
211*c9945492SAndroid Build Coastguard Worker if (zi[map_size-1] == '\n') {
212*c9945492SAndroid Build Coastguard Worker for (s = (const char *)zi+map_size-2; *s!='\n'; s--);
213*c9945492SAndroid Build Coastguard Worker s++;
214*c9945492SAndroid Build Coastguard Worker } else {
215*c9945492SAndroid Build Coastguard Worker const unsigned char *p;
216*c9945492SAndroid Build Coastguard Worker __tzname[0] = __tzname[1] = 0;
217*c9945492SAndroid Build Coastguard Worker __daylight = __timezone = dst_off = 0;
218*c9945492SAndroid Build Coastguard Worker for (p=types; p<abbrevs; p+=6) {
219*c9945492SAndroid Build Coastguard Worker if (!p[4] && !__tzname[0]) {
220*c9945492SAndroid Build Coastguard Worker __tzname[0] = (char *)abbrevs + p[5];
221*c9945492SAndroid Build Coastguard Worker __timezone = -zi_read32(p);
222*c9945492SAndroid Build Coastguard Worker }
223*c9945492SAndroid Build Coastguard Worker if (p[4] && !__tzname[1]) {
224*c9945492SAndroid Build Coastguard Worker __tzname[1] = (char *)abbrevs + p[5];
225*c9945492SAndroid Build Coastguard Worker dst_off = -zi_read32(p);
226*c9945492SAndroid Build Coastguard Worker __daylight = 1;
227*c9945492SAndroid Build Coastguard Worker }
228*c9945492SAndroid Build Coastguard Worker }
229*c9945492SAndroid Build Coastguard Worker if (!__tzname[0]) __tzname[0] = __tzname[1];
230*c9945492SAndroid Build Coastguard Worker if (!__tzname[0]) __tzname[0] = (char *)__utc;
231*c9945492SAndroid Build Coastguard Worker if (!__daylight) {
232*c9945492SAndroid Build Coastguard Worker __tzname[1] = __tzname[0];
233*c9945492SAndroid Build Coastguard Worker dst_off = __timezone;
234*c9945492SAndroid Build Coastguard Worker }
235*c9945492SAndroid Build Coastguard Worker return;
236*c9945492SAndroid Build Coastguard Worker }
237*c9945492SAndroid Build Coastguard Worker }
238*c9945492SAndroid Build Coastguard Worker
239*c9945492SAndroid Build Coastguard Worker if (!s) s = __utc;
240*c9945492SAndroid Build Coastguard Worker getname(std_name, &s);
241*c9945492SAndroid Build Coastguard Worker __tzname[0] = std_name;
242*c9945492SAndroid Build Coastguard Worker __timezone = getoff(&s);
243*c9945492SAndroid Build Coastguard Worker getname(dst_name, &s);
244*c9945492SAndroid Build Coastguard Worker __tzname[1] = dst_name;
245*c9945492SAndroid Build Coastguard Worker if (dst_name[0]) {
246*c9945492SAndroid Build Coastguard Worker __daylight = 1;
247*c9945492SAndroid Build Coastguard Worker if (*s == '+' || *s=='-' || *s-'0'<10U)
248*c9945492SAndroid Build Coastguard Worker dst_off = getoff(&s);
249*c9945492SAndroid Build Coastguard Worker else
250*c9945492SAndroid Build Coastguard Worker dst_off = __timezone - 3600;
251*c9945492SAndroid Build Coastguard Worker } else {
252*c9945492SAndroid Build Coastguard Worker __daylight = 0;
253*c9945492SAndroid Build Coastguard Worker dst_off = __timezone;
254*c9945492SAndroid Build Coastguard Worker }
255*c9945492SAndroid Build Coastguard Worker
256*c9945492SAndroid Build Coastguard Worker if (*s == ',') s++, getrule(&s, r0);
257*c9945492SAndroid Build Coastguard Worker if (*s == ',') s++, getrule(&s, r1);
258*c9945492SAndroid Build Coastguard Worker }
259*c9945492SAndroid Build Coastguard Worker
260*c9945492SAndroid Build Coastguard Worker /* Search zoneinfo rules to find the one that applies to the given time,
261*c9945492SAndroid Build Coastguard Worker * and determine alternate opposite-DST-status rule that may be needed. */
262*c9945492SAndroid Build Coastguard Worker
scan_trans(long long t,int local,size_t * alt)263*c9945492SAndroid Build Coastguard Worker static size_t scan_trans(long long t, int local, size_t *alt)
264*c9945492SAndroid Build Coastguard Worker {
265*c9945492SAndroid Build Coastguard Worker int scale = 3 - (trans == zi+44);
266*c9945492SAndroid Build Coastguard Worker uint64_t x;
267*c9945492SAndroid Build Coastguard Worker int off = 0;
268*c9945492SAndroid Build Coastguard Worker
269*c9945492SAndroid Build Coastguard Worker size_t a = 0, n = (index-trans)>>scale, m;
270*c9945492SAndroid Build Coastguard Worker
271*c9945492SAndroid Build Coastguard Worker if (!n) {
272*c9945492SAndroid Build Coastguard Worker if (alt) *alt = 0;
273*c9945492SAndroid Build Coastguard Worker return 0;
274*c9945492SAndroid Build Coastguard Worker }
275*c9945492SAndroid Build Coastguard Worker
276*c9945492SAndroid Build Coastguard Worker /* Binary search for 'most-recent rule before t'. */
277*c9945492SAndroid Build Coastguard Worker while (n > 1) {
278*c9945492SAndroid Build Coastguard Worker m = a + n/2;
279*c9945492SAndroid Build Coastguard Worker x = zi_read32(trans + (m<<scale));
280*c9945492SAndroid Build Coastguard Worker if (scale == 3) x = x<<32 | zi_read32(trans + (m<<scale) + 4);
281*c9945492SAndroid Build Coastguard Worker else x = (int32_t)x;
282*c9945492SAndroid Build Coastguard Worker if (local) off = (int32_t)zi_read32(types + 6 * index[m-1]);
283*c9945492SAndroid Build Coastguard Worker if (t - off < (int64_t)x) {
284*c9945492SAndroid Build Coastguard Worker n /= 2;
285*c9945492SAndroid Build Coastguard Worker } else {
286*c9945492SAndroid Build Coastguard Worker a = m;
287*c9945492SAndroid Build Coastguard Worker n -= n/2;
288*c9945492SAndroid Build Coastguard Worker }
289*c9945492SAndroid Build Coastguard Worker }
290*c9945492SAndroid Build Coastguard Worker
291*c9945492SAndroid Build Coastguard Worker /* First and last entry are special. First means to use lowest-index
292*c9945492SAndroid Build Coastguard Worker * non-DST type. Last means to apply POSIX-style rule if available. */
293*c9945492SAndroid Build Coastguard Worker n = (index-trans)>>scale;
294*c9945492SAndroid Build Coastguard Worker if (a == n-1) return -1;
295*c9945492SAndroid Build Coastguard Worker if (a == 0) {
296*c9945492SAndroid Build Coastguard Worker x = zi_read32(trans);
297*c9945492SAndroid Build Coastguard Worker if (scale == 3) x = x<<32 | zi_read32(trans + 4);
298*c9945492SAndroid Build Coastguard Worker else x = (int32_t)x;
299*c9945492SAndroid Build Coastguard Worker /* Find the lowest non-DST type, or 0 if none. */
300*c9945492SAndroid Build Coastguard Worker size_t j = 0;
301*c9945492SAndroid Build Coastguard Worker for (size_t i=abbrevs-types; i; i-=6) {
302*c9945492SAndroid Build Coastguard Worker if (!types[i-6+4]) j = i-6;
303*c9945492SAndroid Build Coastguard Worker }
304*c9945492SAndroid Build Coastguard Worker if (local) off = (int32_t)zi_read32(types + j);
305*c9945492SAndroid Build Coastguard Worker /* If t is before first transition, use the above-found type
306*c9945492SAndroid Build Coastguard Worker * and the index-zero (after transition) type as the alt. */
307*c9945492SAndroid Build Coastguard Worker if (t - off < (int64_t)x) {
308*c9945492SAndroid Build Coastguard Worker if (alt) *alt = index[0];
309*c9945492SAndroid Build Coastguard Worker return j/6;
310*c9945492SAndroid Build Coastguard Worker }
311*c9945492SAndroid Build Coastguard Worker }
312*c9945492SAndroid Build Coastguard Worker
313*c9945492SAndroid Build Coastguard Worker /* Try to find a neighboring opposite-DST-status rule. */
314*c9945492SAndroid Build Coastguard Worker if (alt) {
315*c9945492SAndroid Build Coastguard Worker if (a && types[6*index[a-1]+4] != types[6*index[a]+4])
316*c9945492SAndroid Build Coastguard Worker *alt = index[a-1];
317*c9945492SAndroid Build Coastguard Worker else if (a+1<n && types[6*index[a+1]+4] != types[6*index[a]+4])
318*c9945492SAndroid Build Coastguard Worker *alt = index[a+1];
319*c9945492SAndroid Build Coastguard Worker else
320*c9945492SAndroid Build Coastguard Worker *alt = index[a];
321*c9945492SAndroid Build Coastguard Worker }
322*c9945492SAndroid Build Coastguard Worker
323*c9945492SAndroid Build Coastguard Worker return index[a];
324*c9945492SAndroid Build Coastguard Worker }
325*c9945492SAndroid Build Coastguard Worker
days_in_month(int m,int is_leap)326*c9945492SAndroid Build Coastguard Worker static int days_in_month(int m, int is_leap)
327*c9945492SAndroid Build Coastguard Worker {
328*c9945492SAndroid Build Coastguard Worker if (m==2) return 28+is_leap;
329*c9945492SAndroid Build Coastguard Worker else return 30+((0xad5>>(m-1))&1);
330*c9945492SAndroid Build Coastguard Worker }
331*c9945492SAndroid Build Coastguard Worker
332*c9945492SAndroid Build Coastguard Worker /* Convert a POSIX DST rule plus year to seconds since epoch. */
333*c9945492SAndroid Build Coastguard Worker
rule_to_secs(const int * rule,int year)334*c9945492SAndroid Build Coastguard Worker static long long rule_to_secs(const int *rule, int year)
335*c9945492SAndroid Build Coastguard Worker {
336*c9945492SAndroid Build Coastguard Worker int is_leap;
337*c9945492SAndroid Build Coastguard Worker long long t = __year_to_secs(year, &is_leap);
338*c9945492SAndroid Build Coastguard Worker int x, m, n, d;
339*c9945492SAndroid Build Coastguard Worker if (rule[0]!='M') {
340*c9945492SAndroid Build Coastguard Worker x = rule[1];
341*c9945492SAndroid Build Coastguard Worker if (rule[0]=='J' && (x < 60 || !is_leap)) x--;
342*c9945492SAndroid Build Coastguard Worker t += 86400 * x;
343*c9945492SAndroid Build Coastguard Worker } else {
344*c9945492SAndroid Build Coastguard Worker m = rule[1];
345*c9945492SAndroid Build Coastguard Worker n = rule[2];
346*c9945492SAndroid Build Coastguard Worker d = rule[3];
347*c9945492SAndroid Build Coastguard Worker t += __month_to_secs(m-1, is_leap);
348*c9945492SAndroid Build Coastguard Worker int wday = (int)((t + 4*86400) % (7*86400)) / 86400;
349*c9945492SAndroid Build Coastguard Worker int days = d - wday;
350*c9945492SAndroid Build Coastguard Worker if (days < 0) days += 7;
351*c9945492SAndroid Build Coastguard Worker if (n == 5 && days+28 >= days_in_month(m, is_leap)) n = 4;
352*c9945492SAndroid Build Coastguard Worker t += 86400 * (days + 7*(n-1));
353*c9945492SAndroid Build Coastguard Worker }
354*c9945492SAndroid Build Coastguard Worker t += rule[4];
355*c9945492SAndroid Build Coastguard Worker return t;
356*c9945492SAndroid Build Coastguard Worker }
357*c9945492SAndroid Build Coastguard Worker
358*c9945492SAndroid Build Coastguard Worker /* Determine the time zone in effect for a given time in seconds since the
359*c9945492SAndroid Build Coastguard Worker * epoch. It can be given in local or universal time. The results will
360*c9945492SAndroid Build Coastguard Worker * indicate whether DST is in effect at the queried time, and will give both
361*c9945492SAndroid Build Coastguard Worker * the GMT offset for the active zone/DST rule and the opposite DST. This
362*c9945492SAndroid Build Coastguard Worker * enables a caller to efficiently adjust for the case where an explicit
363*c9945492SAndroid Build Coastguard Worker * DST specification mismatches what would be in effect at the time. */
364*c9945492SAndroid Build Coastguard Worker
__secs_to_zone(long long t,int local,int * isdst,long * offset,long * oppoff,const char ** zonename)365*c9945492SAndroid Build Coastguard Worker void __secs_to_zone(long long t, int local, int *isdst, long *offset, long *oppoff, const char **zonename)
366*c9945492SAndroid Build Coastguard Worker {
367*c9945492SAndroid Build Coastguard Worker LOCK(lock);
368*c9945492SAndroid Build Coastguard Worker
369*c9945492SAndroid Build Coastguard Worker do_tzset();
370*c9945492SAndroid Build Coastguard Worker
371*c9945492SAndroid Build Coastguard Worker if (zi) {
372*c9945492SAndroid Build Coastguard Worker size_t alt, i = scan_trans(t, local, &alt);
373*c9945492SAndroid Build Coastguard Worker if (i != -1) {
374*c9945492SAndroid Build Coastguard Worker *isdst = types[6*i+4];
375*c9945492SAndroid Build Coastguard Worker *offset = (int32_t)zi_read32(types+6*i);
376*c9945492SAndroid Build Coastguard Worker *zonename = (const char *)abbrevs + types[6*i+5];
377*c9945492SAndroid Build Coastguard Worker if (oppoff) *oppoff = (int32_t)zi_read32(types+6*alt);
378*c9945492SAndroid Build Coastguard Worker UNLOCK(lock);
379*c9945492SAndroid Build Coastguard Worker return;
380*c9945492SAndroid Build Coastguard Worker }
381*c9945492SAndroid Build Coastguard Worker }
382*c9945492SAndroid Build Coastguard Worker
383*c9945492SAndroid Build Coastguard Worker if (!__daylight) goto std;
384*c9945492SAndroid Build Coastguard Worker
385*c9945492SAndroid Build Coastguard Worker /* FIXME: may be broken if DST changes right at year boundary?
386*c9945492SAndroid Build Coastguard Worker * Also, this could be more efficient.*/
387*c9945492SAndroid Build Coastguard Worker long long y = t / 31556952 + 70;
388*c9945492SAndroid Build Coastguard Worker while (__year_to_secs(y, 0) > t) y--;
389*c9945492SAndroid Build Coastguard Worker while (__year_to_secs(y+1, 0) < t) y++;
390*c9945492SAndroid Build Coastguard Worker
391*c9945492SAndroid Build Coastguard Worker long long t0 = rule_to_secs(r0, y);
392*c9945492SAndroid Build Coastguard Worker long long t1 = rule_to_secs(r1, y);
393*c9945492SAndroid Build Coastguard Worker
394*c9945492SAndroid Build Coastguard Worker if (!local) {
395*c9945492SAndroid Build Coastguard Worker t0 += __timezone;
396*c9945492SAndroid Build Coastguard Worker t1 += dst_off;
397*c9945492SAndroid Build Coastguard Worker }
398*c9945492SAndroid Build Coastguard Worker if (t0 < t1) {
399*c9945492SAndroid Build Coastguard Worker if (t >= t0 && t < t1) goto dst;
400*c9945492SAndroid Build Coastguard Worker goto std;
401*c9945492SAndroid Build Coastguard Worker } else {
402*c9945492SAndroid Build Coastguard Worker if (t >= t1 && t < t0) goto std;
403*c9945492SAndroid Build Coastguard Worker goto dst;
404*c9945492SAndroid Build Coastguard Worker }
405*c9945492SAndroid Build Coastguard Worker std:
406*c9945492SAndroid Build Coastguard Worker *isdst = 0;
407*c9945492SAndroid Build Coastguard Worker *offset = -__timezone;
408*c9945492SAndroid Build Coastguard Worker if (oppoff) *oppoff = -dst_off;
409*c9945492SAndroid Build Coastguard Worker *zonename = __tzname[0];
410*c9945492SAndroid Build Coastguard Worker UNLOCK(lock);
411*c9945492SAndroid Build Coastguard Worker return;
412*c9945492SAndroid Build Coastguard Worker dst:
413*c9945492SAndroid Build Coastguard Worker *isdst = 1;
414*c9945492SAndroid Build Coastguard Worker *offset = -dst_off;
415*c9945492SAndroid Build Coastguard Worker if (oppoff) *oppoff = -__timezone;
416*c9945492SAndroid Build Coastguard Worker *zonename = __tzname[1];
417*c9945492SAndroid Build Coastguard Worker UNLOCK(lock);
418*c9945492SAndroid Build Coastguard Worker }
419*c9945492SAndroid Build Coastguard Worker
__tzset()420*c9945492SAndroid Build Coastguard Worker static void __tzset()
421*c9945492SAndroid Build Coastguard Worker {
422*c9945492SAndroid Build Coastguard Worker LOCK(lock);
423*c9945492SAndroid Build Coastguard Worker do_tzset();
424*c9945492SAndroid Build Coastguard Worker UNLOCK(lock);
425*c9945492SAndroid Build Coastguard Worker }
426*c9945492SAndroid Build Coastguard Worker
427*c9945492SAndroid Build Coastguard Worker weak_alias(__tzset, tzset);
428*c9945492SAndroid Build Coastguard Worker
__tm_to_tzname(const struct tm * tm)429*c9945492SAndroid Build Coastguard Worker const char *__tm_to_tzname(const struct tm *tm)
430*c9945492SAndroid Build Coastguard Worker {
431*c9945492SAndroid Build Coastguard Worker const void *p = tm->__tm_zone;
432*c9945492SAndroid Build Coastguard Worker LOCK(lock);
433*c9945492SAndroid Build Coastguard Worker do_tzset();
434*c9945492SAndroid Build Coastguard Worker if (p != __utc && p != __tzname[0] && p != __tzname[1] &&
435*c9945492SAndroid Build Coastguard Worker (!zi || (uintptr_t)p-(uintptr_t)abbrevs >= abbrevs_end - abbrevs))
436*c9945492SAndroid Build Coastguard Worker p = "";
437*c9945492SAndroid Build Coastguard Worker UNLOCK(lock);
438*c9945492SAndroid Build Coastguard Worker return p;
439*c9945492SAndroid Build Coastguard Worker }
440