]>
Commit | Line | Data |
---|---|---|
1f2f436a A |
1 | --- localtime.c.orig 2011-05-02 23:14:13.000000000 -0700 |
2 | +++ localtime.c 2011-05-03 17:12:02.000000000 -0700 | |
34e8f829 | 3 | @@ -22,8 +22,22 @@ __FBSDID("$FreeBSD: src/lib/libc/stdtime |
224c7076 A |
4 | #include "namespace.h" |
5 | #include <sys/types.h> | |
9385eb3d | 6 | #include <sys/stat.h> |
224c7076 | 7 | +#include <time.h> |
9385eb3d A |
8 | #include <fcntl.h> |
9 | #include <pthread.h> | |
224c7076 | 10 | +#include <errno.h> |
9385eb3d A |
11 | +#ifdef NOTIFY_TZ |
12 | +//#define NOTIFY_TZ_DEBUG | |
13 | +//#define NOTIFY_TZ_DEBUG_FILE "/var/log/localtime.debug" | |
14 | +//#define NOTIFY_TZ_LOG "/var/log/localtime.log" | |
15 | +/* force ALL_STATE if NOTIFY_TZ is set */ | |
16 | +#ifndef ALL_STATE | |
17 | +#define ALL_STATE | |
18 | +#endif /* ALL_STATE */ | |
19 | +#include <mach/mach_init.h> | |
20 | +#include <notify.h> | |
21 | +#include <alloca.h> | |
22 | +#endif /* NOTIFY_TZ */ | |
23 | #include "private.h" | |
24 | #include "un-namespace.h" | |
25 | ||
1f2f436a | 26 | @@ -150,40 +164,94 @@ struct rule { |
9385eb3d A |
27 | #define DAY_OF_YEAR 1 /* n - day of year */ |
28 | #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ | |
29 | ||
30 | +#ifdef NOTIFY_TZ | |
31 | +typedef struct { | |
32 | + int token; | |
33 | + int notify_was_off; | |
34 | + int is_set; | |
35 | +} notify_tz_t; | |
36 | + | |
37 | +#define NOTIFY_TZ_NAME "com.apple.system.timezone" | |
38 | +#endif /* NOTIFY_TZ */ | |
39 | + | |
40 | /* | |
41 | ** Prototypes for static functions. | |
42 | */ | |
224c7076 A |
43 | +#define localsub _st_localsub |
44 | +#define time1 _st_time1 | |
45 | +#define tzset_basic _st_tzset_basic | |
46 | +__private_extern__ | |
47 | +#ifdef __LP64__ | |
48 | +struct tm * localsub(const time_t * timep, long offset, | |
49 | + struct tm * tmp); | |
50 | +#else /* !__LP64__ */ | |
51 | +void localsub(const time_t * timep, long offset, | |
52 | + struct tm * tmp); | |
53 | +#endif /* __LP64__ */ | |
54 | +__private_extern__ | |
55 | +time_t time1(struct tm * tmp, | |
56 | +#ifdef __LP64__ | |
57 | + struct tm *(*funcp) (const time_t *, | |
58 | + long, struct tm *), | |
59 | +#else /* !__LP64__ */ | |
60 | + void(*funcp) (const time_t *, | |
61 | + long, struct tm *), | |
62 | +#endif /* __LP64__ */ | |
63 | + long offset, | |
64 | + int unix03); | |
65 | +__private_extern__ | |
1f2f436a | 66 | +void tzset_basic(int); |
224c7076 A |
67 | |
68 | +#if !BUILDING_VARIANT | |
69 | static long detzcode(const char * codep); | |
70 | -static const char * getzname(const char * strp); | |
71 | +static const char * getzname(const char * strp, char **name, size_t *len); | |
72 | static const char * getnum(const char * strp, int * nump, int min, | |
73 | int max); | |
74 | static const char * getsecs(const char * strp, long * secsp); | |
75 | static const char * getoffset(const char * strp, long * offsetp); | |
76 | static const char * getrule(const char * strp, struct rule * rulep); | |
77 | static void gmtload(struct state * sp); | |
78 | -static void gmtsub(const time_t * timep, long offset, | |
79 | +#ifdef __LP64__ | |
80 | +static struct tm * gmtsub(const time_t * timep, long offset, | |
81 | struct tm * tmp); | |
82 | -static void localsub(const time_t * timep, long offset, | |
83 | +#else /* !__LP64__ */ | |
84 | +static void gmtsub(const time_t * timep, long offset, | |
85 | struct tm * tmp); | |
86 | +#endif /* __LP64__ */ | |
9385eb3d A |
87 | static int increment_overflow(int * number, int delta); |
88 | static int normalize_overflow(int * tensptr, int * unitsptr, | |
89 | int base); | |
90 | +#ifdef NOTIFY_TZ | |
91 | +static void notify_check_tz(notify_tz_t *p); | |
92 | +static void notify_register_tz(char *file, notify_tz_t *p); | |
93 | +#endif /* NOTIFY_TZ */ | |
94 | static void settzname(void); | |
224c7076 A |
95 | -static time_t time1(struct tm * tmp, |
96 | - void(*funcp) (const time_t *, | |
97 | - long, struct tm *), | |
98 | - long offset); | |
99 | static time_t time2(struct tm *tmp, | |
100 | +#ifdef __LP64__ | |
101 | + struct tm *(*funcp) (const time_t *, | |
102 | + long, struct tm*), | |
103 | +#else /* !__LP64__ */ | |
104 | void(*funcp) (const time_t *, | |
105 | long, struct tm*), | |
106 | - long offset, int * okayp); | |
107 | +#endif /* __LP64__ */ | |
108 | + long offset, int * okayp, int unix03); | |
109 | static time_t time2sub(struct tm *tmp, | |
110 | +#ifdef __LP64__ | |
111 | + struct tm *(*funcp) (const time_t *, | |
112 | + long, struct tm*), | |
113 | +#else /* !__LP64__ */ | |
9385eb3d | 114 | void(*funcp) (const time_t *, |
224c7076 A |
115 | long, struct tm*), |
116 | - long offset, int * okayp, int do_norm_secs); | |
117 | +#endif /* __LP64__ */ | |
118 | + long offset, int * okayp, int do_norm_secs, | |
119 | + int unix03); | |
120 | +#ifdef __LP64__ | |
121 | +static struct tm * timesub(const time_t * timep, long offset, | |
122 | + const struct state * sp, struct tm * tmp); | |
123 | +#else /* !__LP64__ */ | |
124 | static void timesub(const time_t * timep, long offset, | |
125 | const struct state * sp, struct tm * tmp); | |
126 | +#endif /* __LP64__ */ | |
127 | static int tmcomp(const struct tm * atmp, | |
128 | const struct tm * btmp); | |
129 | static time_t transtime(time_t janfirst, int year, | |
1f2f436a | 130 | @@ -209,9 +277,14 @@ static struct state gmtmem; |
9385eb3d A |
131 | #endif /* !defined TZ_STRLEN_MAX */ |
132 | ||
133 | static char lcl_TZname[TZ_STRLEN_MAX + 1]; | |
134 | +#ifdef NOTIFY_TZ | |
1f2f436a A |
135 | +#define lcl_is_set (lcl_notify.is_set) |
136 | +#define gmt_is_set (gmt_notify.is_set) | |
9385eb3d A |
137 | +#else /* ! NOTIFY_TZ */ |
138 | static int lcl_is_set; | |
139 | static int gmt_is_set; | |
1f2f436a | 140 | -static pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; |
9385eb3d | 141 | +#endif /* NOTIFY_TZ */ |
1f2f436a A |
142 | +__private_extern__ pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; |
143 | static pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER; | |
9385eb3d | 144 | |
224c7076 | 145 | char * tzname[2] = { |
1f2f436a | 146 | @@ -229,15 +302,62 @@ char * tzname[2] = { |
3d9156a7 A |
147 | |
148 | static struct tm tm; | |
149 | ||
150 | +#define USG_COMPAT | |
151 | +#define ALTZONE | |
152 | #ifdef USG_COMPAT | |
153 | -time_t timezone = 0; | |
154 | int daylight = 0; | |
155 | +__private_extern__ void _st_set_timezone(long); | |
156 | #endif /* defined USG_COMPAT */ | |
157 | ||
158 | #ifdef ALTZONE | |
159 | -time_t altzone = 0; | |
160 | +__private_extern__ long __darwin_altzone = 0; | |
161 | +#define altzone __darwin_altzone | |
9385eb3d A |
162 | #endif /* defined ALTZONE */ |
163 | ||
164 | +#ifdef NOTIFY_TZ | |
165 | +#ifdef NOTIFY_TZ_DEBUG | |
166 | +#ifdef NOTIFY_TZ_DEBUG_FILE | |
167 | +#define NOTIFY_TZ_PRINTF(fmt, args...) \ | |
168 | +{ \ | |
169 | + FILE *_notify_tz_fp_; \ | |
170 | + if((_notify_tz_fp_ = fopen(NOTIFY_TZ_DEBUG_FILE, "a")) != NULL) { \ | |
171 | + fprintf(_notify_tz_fp_, "%d: " fmt, getpid(), ## args); \ | |
172 | + fclose(_notify_tz_fp_); \ | |
173 | + } \ | |
174 | +} | |
175 | +#else /* ! NOTIFY_TZ_DEBUG_FILE */ | |
176 | +#define NOTIFY_TZ_PRINTF(args...) fprintf(stdout, ## args) | |
177 | +#endif /* NOTIFY_TZ_DEBUG_FILE */ | |
178 | +#endif /* NOTIFY_TZ_DEBUG */ | |
179 | +#ifdef NOTIFY_TZ_LOG | |
180 | +#define NOTIFY_LOG(fmt, args...) \ | |
181 | +{ \ | |
182 | + FILE *_notify_log_fp_; \ | |
183 | + if((_notify_log_fp_ = fopen(NOTIFY_TZ_LOG, "a")) != NULL) { \ | |
184 | + fprintf(_notify_log_fp_, "%d: " fmt, getpid(), ## args); \ | |
185 | + fclose(_notify_log_fp_); \ | |
186 | + } \ | |
187 | +} | |
188 | +#endif /* NOTIFY_TZ_LOG */ | |
189 | +/*-------------------------------------------------------------------- | |
190 | + * __notify_78945668_info__ is a global variable (defined in Libnotify) | |
191 | + * that can be used to disable the notify mechanism. Set to a negative | |
192 | + * value to disable. It can then be set back to zero to re-enable. | |
193 | + *-------------------------------------------------------------------- */ | |
194 | +extern int __notify_78945668_info__; | |
195 | + | |
196 | +/*-------------------------------------------------------------------- | |
197 | + * fullname is used to pass the actual path of the timezone file to the | |
198 | + * notify routines. If it is a nil string, that means no timezone file | |
199 | + * is being used. | |
200 | + *-------------------------------------------------------------------- */ | |
201 | +static char * fullname = NULL; | |
202 | + | |
203 | +static notify_tz_t gmt_notify = {-1, 0, 0}; | |
204 | +static notify_tz_t lcl_notify = {-1, 0, 0}; | |
205 | +static char notify_tz_name[] = NOTIFY_TZ_NAME; | |
206 | +#endif /* NOTIFY_TZ */ | |
207 | + | |
208 | static long | |
209 | detzcode(codep) | |
210 | const char * const codep; | |
1f2f436a A |
211 | @@ -255,51 +375,203 @@ static void |
212 | settzname(void) | |
213 | { | |
214 | struct state * sp = lclptr; | |
215 | - int i; | |
216 | + int i, need; | |
217 | + unsigned char * types; | |
218 | +#define NEED_STD 1 | |
219 | +#define NEED_DST 2 | |
220 | +#define NEED_DAYLIGHT 4 | |
221 | +#define NEED_ALL (NEED_STD | NEED_DST | NEED_DAYLIGHT) | |
222 | ||
223 | tzname[0] = wildabbr; | |
3d9156a7 A |
224 | tzname[1] = wildabbr; |
225 | #ifdef USG_COMPAT | |
226 | daylight = 0; | |
227 | - timezone = 0; | |
228 | + _st_set_timezone(0); | |
229 | #endif /* defined USG_COMPAT */ | |
230 | #ifdef ALTZONE | |
231 | altzone = 0; | |
9385eb3d A |
232 | #endif /* defined ALTZONE */ |
233 | #ifdef ALL_STATE | |
234 | if (sp == NULL) { | |
235 | - tzname[0] = tzname[1] = gmt; | |
236 | + tzname[0] = tzname[1] = (char *)gmt; | |
237 | return; | |
238 | } | |
239 | #endif /* defined ALL_STATE */ | |
1f2f436a A |
240 | - for (i = 0; i < sp->typecnt; ++i) { |
241 | - const struct ttinfo * const ttisp = &sp->ttis[i]; | |
242 | + /* | |
243 | + * PR-3765457: The original settzname went sequentially through the ttis | |
244 | + * array, rather than correctly indexing via the types array, to get | |
245 | + * the real order of the timezone changes. In addition, as a speed up, | |
246 | + * we start at the end of the changes, and work back, so that most of | |
247 | + * the time, we don't have to look through the entire array. | |
248 | + */ | |
249 | + if (sp->timecnt == 0 && sp->typecnt == 1) { | |
250 | + /* | |
251 | + * Unfortunately, there is an edge case when typecnt == 1 and | |
252 | + * timecnt == 0, which would cause the loop to never run. So | |
253 | + * in that case, we fudge things up so that it is as if | |
254 | + * timecnt == 1. | |
255 | + */ | |
256 | + i = 0; | |
257 | + types = (unsigned char *)""; /* we use the null as index */ | |
258 | + } else { | |
259 | + /* the usual case */ | |
260 | + i = sp->timecnt - 1; | |
261 | + types = sp->types; | |
262 | + } | |
263 | + need = NEED_ALL; | |
264 | + for (; i >= 0 && need; --i) { | |
265 | + const struct ttinfo * const ttisp = &sp->ttis[types[i]]; | |
266 | ||
267 | - tzname[ttisp->tt_isdst] = | |
268 | - &sp->chars[ttisp->tt_abbrind]; | |
269 | #ifdef USG_COMPAT | |
270 | - if (ttisp->tt_isdst) | |
271 | + if ((need & NEED_DAYLIGHT) && ttisp->tt_isdst) { | |
272 | + need &= ~NEED_DAYLIGHT; | |
3d9156a7 | 273 | daylight = 1; |
1f2f436a | 274 | - if (i == 0 || !ttisp->tt_isdst) |
3d9156a7 | 275 | - timezone = -(ttisp->tt_gmtoff); |
1f2f436a | 276 | + } |
3d9156a7 | 277 | #endif /* defined USG_COMPAT */ |
1f2f436a A |
278 | + if (ttisp->tt_isdst) { |
279 | + if (need & NEED_DST) { | |
280 | + need &= ~NEED_DST; | |
281 | + tzname[1] = &sp->chars[ttisp->tt_abbrind]; | |
3d9156a7 | 282 | #ifdef ALTZONE |
1f2f436a A |
283 | - if (i == 0 || ttisp->tt_isdst) |
284 | - altzone = -(ttisp->tt_gmtoff); | |
285 | + altzone = -(ttisp->tt_gmtoff); | |
286 | #endif /* defined ALTZONE */ | |
287 | + } | |
288 | + } else if (need & NEED_STD) { | |
289 | + need &= ~NEED_STD; | |
290 | + tzname[0] = &sp->chars[ttisp->tt_abbrind]; | |
291 | +#ifdef USG_COMPAT | |
292 | + _st_set_timezone(-(ttisp->tt_gmtoff)); | |
293 | +#endif /* defined USG_COMPAT */ | |
294 | + } | |
295 | +#if defined(ALTZONE) || defined(USG_COMPAT) | |
296 | + if (i == 0) { | |
297 | +#endif /* defined(ALTZONE) || defined(USG_COMPAT) */ | |
298 | +#ifdef ALTZONE | |
299 | + if (need & NEED_DST) | |
300 | + altzone = -(ttisp->tt_gmtoff); | |
301 | +#endif /* defined ALTZONE */ | |
302 | +#ifdef USG_COMPAT | |
303 | + if (need & NEED_STD) | |
304 | + _st_set_timezone(-(ttisp->tt_gmtoff)); | |
305 | +#endif /* defined USG_COMPAT */ | |
306 | +#if defined(ALTZONE) || defined(USG_COMPAT) | |
307 | + } | |
308 | +#endif /* defined(ALTZONE) || defined(USG_COMPAT) */ | |
9385eb3d | 309 | } |
1f2f436a A |
310 | - /* |
311 | - ** And to get the latest zone names into tzname. . . | |
312 | - */ | |
313 | - for (i = 0; i < sp->timecnt; ++i) { | |
314 | - const struct ttinfo * const ttisp = | |
315 | - &sp->ttis[ | |
316 | - sp->types[i]]; | |
317 | +} | |
318 | + | |
9385eb3d A |
319 | +#ifdef NOTIFY_TZ |
320 | +static void | |
321 | +notify_check_tz(notify_tz_t *p) | |
322 | +{ | |
323 | + unsigned int nstat; | |
324 | + int ncheck; | |
325 | + | |
326 | + if (__notify_78945668_info__ < 0) { | |
327 | +#ifdef NOTIFY_TZ_DEBUG | |
328 | + if(!p->notify_was_off) NOTIFY_TZ_PRINTF("notify_check_tz: setting %s_notify->notify_was_off\n", (p == &lcl_notify ? "lcl" : "gmt")); | |
329 | +#endif /* NOTIFY_TZ_DEBUG */ | |
330 | + p->notify_was_off = 1; | |
331 | + return; | |
332 | + } | |
333 | + /* force rereading the timezone file if notify was off */ | |
334 | + if (p->notify_was_off) { | |
335 | +#ifdef NOTIFY_TZ_DEBUG | |
336 | + NOTIFY_TZ_PRINTF("notify_check_tz: saw %s_notify->notify_was_off\n", (p == &lcl_notify ? "lcl" : "gmt")); | |
337 | +#endif /* NOTIFY_TZ_DEBUG */ | |
338 | + p->is_set = 0; | |
339 | + p->notify_was_off = 0; | |
340 | + return; | |
341 | + } | |
342 | + if (p->token < 0) | |
343 | + return; | |
344 | + nstat = notify_check(p->token, &ncheck); | |
345 | + if (nstat || ncheck) { | |
346 | + p->is_set = 0; | |
347 | +#ifdef NOTIFY_TZ_DEBUG | |
348 | + NOTIFY_TZ_PRINTF("notify_check_tz: %s changed\n", (p == &lcl_notify) ? "lcl" : "gmt"); | |
349 | +#endif /* NOTIFY_TZ_DEBUG */ | |
350 | + } | |
351 | +#ifdef NOTIFY_TZ_DEBUG | |
352 | + NOTIFY_TZ_PRINTF("notify_check_tz: %s unchanged\n", (p == &lcl_notify) ? "lcl" : "gmt"); | |
353 | +#endif /* NOTIFY_TZ_DEBUG */ | |
354 | +} | |
355 | + | |
224c7076 A |
356 | +extern uint32_t notify_monitor_file(int token, char *path, int flags); |
357 | + | |
9385eb3d A |
358 | +static void |
359 | +notify_register_tz(char *file, notify_tz_t *p) | |
360 | +{ | |
361 | + char *name; | |
362 | + unsigned int nstat; | |
363 | + int ncheck; | |
1f2f436a A |
364 | |
365 | - tzname[ttisp->tt_isdst] = | |
366 | - &sp->chars[ttisp->tt_abbrind]; | |
9385eb3d A |
367 | + if (__notify_78945668_info__ < 0) |
368 | + return; | |
369 | + /*---------------------------------------------------------------- | |
370 | + * Since we don't record the last time zone filename, just cancel | |
371 | + * (which should remove the file monitor) and setup from scratch | |
372 | + *----------------------------------------------------------------*/ | |
373 | + if (p->token >= 0) | |
374 | + notify_cancel(p->token); | |
59e0d9fe | 375 | + if (!file || *file == 0) { |
9385eb3d A |
376 | + /* no time zone file to monitor */ |
377 | + p->token = -1; | |
378 | + return; | |
379 | + } | |
380 | + /*---------------------------------------------------------------- | |
381 | + * Just use com.apple.system.timezone if the path is /etc/localtime. | |
382 | + * Otherwise use com.apple.system.timezone.<fullpath> | |
383 | + *----------------------------------------------------------------*/ | |
384 | + if (TZDEFAULT && strcmp(file, TZDEFAULT) == 0) | |
385 | + name = notify_tz_name; | |
386 | + else { | |
387 | + name = alloca(sizeof(notify_tz_name) + strlen(file) + 1); | |
388 | + if (name == NULL) { | |
389 | + p->token = -1; | |
390 | + return; | |
391 | + } | |
392 | + strcpy(name, notify_tz_name); | |
393 | + strcat(name, "."); | |
394 | + strcat(name, file); | |
395 | + } | |
396 | +#ifdef NOTIFY_TZ_DEBUG | |
397 | + NOTIFY_TZ_PRINTF("notify_register_tz: file=%s name=%s\n", file, name); | |
398 | +#endif /* NOTIFY_TZ_DEBUG */ | |
399 | + nstat = notify_register_check(name, &p->token); | |
400 | + if (nstat != 0) { | |
401 | + p->token = -1; | |
402 | + p->is_set = 0; | |
403 | +#ifdef NOTIFY_TZ_DEBUG | |
404 | + NOTIFY_TZ_PRINTF("***notify_register_tz: notify_register_check failed: %u\n", nstat); | |
405 | +#endif /* NOTIFY_TZ_DEBUG */ | |
406 | +#ifdef NOTIFY_TZ_LOG | |
407 | + NOTIFY_LOG("notify_register_check(%s) failed: %u\n", name, nstat); | |
408 | +#endif /* NOTIFY_TZ_LOG */ | |
409 | + return; | |
410 | + } | |
411 | + /* don't need to request monitoring /etc/localtime */ | |
412 | + if (name != notify_tz_name) { | |
413 | +#ifdef NOTIFY_TZ_DEBUG | |
414 | + NOTIFY_TZ_PRINTF("notify_register_tz: monitor %s\n", file); | |
415 | +#endif /* NOTIFY_TZ_DEBUG */ | |
416 | + nstat = notify_monitor_file(p->token, file, 0); | |
417 | + if (nstat != 0) { | |
418 | + notify_cancel(p->token); | |
419 | + p->token = -1; | |
420 | + p->is_set = 0; | |
421 | +#ifdef NOTIFY_TZ_DEBUG | |
422 | + NOTIFY_TZ_PRINTF("***notify_register_tz: notify_monitor_file failed: %u\n", nstat); | |
423 | +#endif /* NOTIFY_TZ_DEBUG */ | |
424 | +#ifdef NOTIFY_TZ_LOG | |
425 | + NOTIFY_LOG("notify_monitor_file(%s) failed: %u\n", file, nstat); | |
426 | +#endif /* NOTIFY_TZ_LOG */ | |
427 | + return; | |
428 | + } | |
1f2f436a | 429 | } |
9385eb3d | 430 | + notify_check(p->token, &ncheck); /* this always returns true */ |
1f2f436a | 431 | } |
9385eb3d | 432 | +#endif /* NOTIFY_TZ */ |
1f2f436a | 433 | |
9385eb3d A |
434 | static int |
435 | tzload(name, sp) | |
1f2f436a | 436 | @@ -310,6 +582,9 @@ struct state * const sp; |
9385eb3d A |
437 | int i; |
438 | int fid; | |
439 | ||
440 | +#ifdef NOTIFY_TZ_DEBUG | |
441 | + NOTIFY_TZ_PRINTF("tzload: name=%s\n", name); | |
442 | +#endif /* NOTIFY_TZ_DEBUG */ | |
443 | /* XXX The following is from OpenBSD, and I'm not sure it is correct */ | |
444 | if (name != NULL && issetugid() != 0) | |
445 | if ((name[0] == ':' && name[1] == '/') || | |
1f2f436a | 446 | @@ -327,7 +602,15 @@ struct state * const sp; |
9385eb3d A |
447 | ** to hold the longest file name string that the implementation |
448 | ** guarantees can be opened." | |
449 | */ | |
450 | +#ifdef NOTIFY_TZ | |
451 | + if (!fullname) { | |
452 | + fullname = malloc(FILENAME_MAX + 1); | |
453 | + if (!fullname) | |
454 | + return -1; | |
455 | + } | |
456 | +#else /* ! NOTIFY_TZ */ | |
457 | char fullname[FILENAME_MAX + 1]; | |
458 | +#endif /* NOTIFY_TZ */ | |
459 | ||
460 | if (name[0] == ':') | |
461 | ++name; | |
1f2f436a | 462 | @@ -335,7 +618,11 @@ struct state * const sp; |
9385eb3d A |
463 | if (!doaccess) { |
464 | if ((p = TZDIR) == NULL) | |
465 | return -1; | |
466 | +#ifdef NOTIFY_TZ | |
467 | + if ((strlen(p) + 1 + strlen(name) + 1) >= (FILENAME_MAX + 1)) | |
468 | +#else /* ! NOTIFY_TZ */ | |
469 | if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname) | |
470 | +#endif /* NOTIFY_TZ */ | |
471 | return -1; | |
472 | (void) strcpy(fullname, p); | |
473 | (void) strcat(fullname, "/"); | |
1f2f436a | 474 | @@ -347,6 +634,10 @@ struct state * const sp; |
9385eb3d A |
475 | doaccess = TRUE; |
476 | name = fullname; | |
477 | } | |
478 | +#ifdef NOTIFY_TZ | |
479 | + else | |
480 | + strcpy(fullname, name); | |
481 | +#endif /* NOTIFY_TZ */ | |
482 | if (doaccess && access(name, R_OK) != 0) | |
483 | return -1; | |
484 | if ((fid = _open(name, OPEN_MODE)) == -1) | |
1f2f436a | 485 | @@ -365,6 +656,9 @@ struct state * const sp; |
9385eb3d A |
486 | int ttisstdcnt; |
487 | int ttisgmtcnt; | |
488 | ||
489 | +#ifdef NOTIFY_TZ_DEBUG | |
490 | + NOTIFY_TZ_PRINTF("tzload: reading %s\n", name); | |
491 | +#endif /* NOTIFY_TZ_DEBUG */ | |
3d9156a7 | 492 | i = _read(fid, u.buf, sizeof u.buf); |
9385eb3d A |
493 | if (_close(fid) != 0) |
494 | return -1; | |
1f2f436a | 495 | @@ -471,14 +765,24 @@ static const int year_lengths[2] = { |
224c7076 A |
496 | */ |
497 | ||
498 | static const char * | |
499 | -getzname(strp) | |
500 | +getzname(strp, name, len) | |
501 | const char * strp; | |
502 | +char ** name; | |
503 | +size_t * len; | |
504 | { | |
505 | char c; | |
506 | + char * ket; | |
507 | ||
508 | + if (*strp == '<' && (ket = strchr(strp, '>')) != NULL) { | |
509 | + *name = (char *)(strp + 1); | |
510 | + *len = ket - strp - 1; | |
511 | + return ket + 1; | |
512 | + } | |
513 | + *name = (char *)strp; | |
514 | while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && | |
515 | c != '+') | |
516 | ++strp; | |
517 | + *len = strp - *name; | |
518 | return strp; | |
519 | } | |
520 | ||
1f2f436a | 521 | @@ -758,16 +1062,15 @@ const int lastditch; |
224c7076 A |
522 | int load_result; |
523 | ||
524 | INITIALIZE(dstname); | |
525 | - stdname = name; | |
526 | if (lastditch) { | |
527 | + stdname = name; | |
528 | stdlen = strlen(name); /* length of standard zone name */ | |
529 | name += stdlen; | |
530 | if (stdlen >= sizeof sp->chars) | |
531 | stdlen = (sizeof sp->chars) - 1; | |
532 | stdoffset = 0; | |
533 | } else { | |
534 | - name = getzname(name); | |
535 | - stdlen = name - stdname; | |
536 | + name = getzname(name, (char **)&stdname, &stdlen); | |
537 | if (stdlen < 3) | |
538 | return -1; | |
539 | if (*name == '\0') | |
1f2f436a | 540 | @@ -779,12 +1082,14 @@ const int lastditch; |
9385eb3d A |
541 | } |
542 | } | |
543 | load_result = tzload(TZDEFRULES, sp); | |
544 | +#ifdef NOTIFY_TZ | |
545 | + *fullname = 0; /* mark fullname as invalid */ | |
546 | +#endif /* NOTIFY_TZ */ | |
547 | if (load_result != 0) | |
548 | sp->leapcnt = 0; /* so, we're off a little */ | |
549 | if (*name != '\0') { | |
224c7076 A |
550 | dstname = name; |
551 | - name = getzname(name); | |
552 | - dstlen = name - dstname; /* length of DST zone name */ | |
553 | + name = getzname(name, (char **)&dstname, &dstlen); | |
554 | if (dstlen < 3) | |
555 | return -1; | |
556 | if (*name != '\0' && *name != ',' && *name != ';') { | |
1f2f436a | 557 | @@ -966,13 +1271,37 @@ struct state * const sp; |
9385eb3d | 558 | static void |
1f2f436a | 559 | tzsetwall_basic(int rdlocked) |
9385eb3d A |
560 | { |
561 | +#ifdef NOTIFY_TZ | |
562 | + notify_check_tz(&lcl_notify); | |
1f2f436a A |
563 | +#else |
564 | + if (TZDEFAULT) { | |
565 | + static struct timespec last_mtimespec = {0, 0}; | |
566 | + struct stat statbuf; | |
567 | + | |
568 | + if (lstat(TZDEFAULT, &statbuf) == 0) { | |
569 | + if (statbuf.st_mtimespec.tv_sec > last_mtimespec.tv_sec || | |
570 | + (statbuf.st_mtimespec.tv_sec == last_mtimespec.tv_sec && | |
571 | + statbuf.st_mtimespec.tv_nsec > last_mtimespec.tv_nsec)) { | |
572 | + /* Trigger resetting the local TZ */ | |
573 | + lcl_is_set = 0; | |
574 | + } | |
575 | + last_mtimespec = statbuf.st_mtimespec; | |
576 | + } | |
577 | + } | |
9385eb3d | 578 | +#endif /* NOTIFY_TZ */ |
1f2f436a A |
579 | if (!rdlocked) |
580 | _RWLOCK_RDLOCK(&lcl_rwlock); | |
581 | if (lcl_is_set < 0) { | |
9385eb3d | 582 | +#ifdef NOTIFY_TZ_DEBUG |
9385eb3d | 583 | + NOTIFY_TZ_PRINTF("tzsetwall_basic lcl_is_set < 0\n"); |
1f2f436a A |
584 | +#endif |
585 | if (!rdlocked) | |
586 | _RWLOCK_UNLOCK(&lcl_rwlock); | |
9385eb3d | 587 | return; |
1f2f436a A |
588 | } |
589 | +#ifdef NOTIFY_TZ_DEBUG | |
590 | + NOTIFY_TZ_PRINTF("tzsetwall_basic not set\n"); | |
591 | +#endif | |
592 | _RWLOCK_UNLOCK(&lcl_rwlock); | |
9385eb3d | 593 | |
1f2f436a A |
594 | _RWLOCK_WRLOCK(&lcl_rwlock); |
595 | @@ -992,6 +1321,9 @@ tzsetwall_basic(int rdlocked) | |
9385eb3d A |
596 | #endif /* defined ALL_STATE */ |
597 | if (tzload((char *) NULL, lclptr) != 0) | |
598 | gmtload(lclptr); | |
599 | +#ifdef NOTIFY_TZ | |
600 | + notify_register_tz(fullname, &lcl_notify); | |
601 | +#endif /* NOTIFY_TZ */ | |
602 | settzname(); | |
1f2f436a | 603 | _RWLOCK_UNLOCK(&lcl_rwlock); |
9385eb3d | 604 | |
1f2f436a | 605 | @@ -1002,10 +1334,13 @@ tzsetwall_basic(int rdlocked) |
9385eb3d A |
606 | void |
607 | tzsetwall(void) | |
608 | { | |
609 | +#ifdef NOTIFY_TZ_DEBUG | |
610 | + NOTIFY_TZ_PRINTF("tzsetwall called\n"); | |
611 | +#endif /* NOTIFY_TZ_DEBUG */ | |
1f2f436a | 612 | tzsetwall_basic(0); |
224c7076 A |
613 | } |
614 | ||
615 | -static void | |
616 | +__private_extern__ void | |
1f2f436a | 617 | tzset_basic(int rdlocked) |
224c7076 A |
618 | { |
619 | const char * name; | |
1f2f436a | 620 | @@ -1016,11 +1351,17 @@ tzset_basic(int rdlocked) |
9385eb3d A |
621 | return; |
622 | } | |
623 | ||
624 | +#ifdef NOTIFY_TZ | |
625 | + notify_check_tz(&lcl_notify); | |
626 | +#endif /* NOTIFY_TZ */ | |
1f2f436a A |
627 | if (!rdlocked) |
628 | _RWLOCK_RDLOCK(&lcl_rwlock); | |
629 | if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) { | |
630 | if (!rdlocked) | |
631 | _RWLOCK_UNLOCK(&lcl_rwlock); | |
9385eb3d | 632 | +#ifdef NOTIFY_TZ_DEBUG |
9385eb3d | 633 | + NOTIFY_TZ_PRINTF("tzset_basic matched %s\n", lcl_TZname); |
1f2f436a | 634 | +#endif |
9385eb3d | 635 | return; |
1f2f436a A |
636 | } |
637 | _RWLOCK_UNLOCK(&lcl_rwlock); | |
638 | @@ -1053,9 +1394,16 @@ tzset_basic(int rdlocked) | |
9385eb3d A |
639 | lclptr->ttis[0].tt_gmtoff = 0; |
640 | lclptr->ttis[0].tt_abbrind = 0; | |
641 | (void) strcpy(lclptr->chars, gmt); | |
642 | +#ifdef NOTIFY_TZ | |
59e0d9fe A |
643 | + if (fullname) |
644 | + *fullname = 0; | |
9385eb3d A |
645 | +#endif /* NOTIFY_TZ */ |
646 | } else if (tzload(name, lclptr) != 0) | |
647 | if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) | |
648 | (void) gmtload(lclptr); | |
649 | +#ifdef NOTIFY_TZ | |
650 | + notify_register_tz(fullname, &lcl_notify); | |
651 | +#endif /* NOTIFY_TZ */ | |
652 | settzname(); | |
1f2f436a | 653 | _RWLOCK_UNLOCK(&lcl_rwlock); |
9385eb3d | 654 | |
1f2f436a | 655 | @@ -1066,6 +1414,9 @@ tzset_basic(int rdlocked) |
9385eb3d A |
656 | void |
657 | tzset(void) | |
658 | { | |
659 | +#ifdef NOTIFY_TZ_DEBUG | |
660 | + NOTIFY_TZ_PRINTF("tzset called TZ=%s\n", getenv("TZ")); | |
661 | +#endif /* NOTIFY_TZ_DEBUG */ | |
1f2f436a A |
662 | tzset_basic(0); |
663 | } | |
664 | ||
665 | @@ -1079,7 +1430,11 @@ tzset(void) | |
224c7076 A |
666 | */ |
667 | ||
668 | /*ARGSUSED*/ | |
669 | -static void | |
670 | +#ifdef __LP64__ | |
671 | +__private_extern__ struct tm * | |
672 | +#else /* !__LP64__ */ | |
673 | +__private_extern__ void | |
674 | +#endif /* __LP64__ */ | |
675 | localsub(timep, offset, tmp) | |
676 | const time_t * const timep; | |
677 | const long offset; | |
1f2f436a | 678 | @@ -1090,11 +1445,18 @@ struct tm * const tmp; |
9385eb3d A |
679 | int i; |
680 | const time_t t = *timep; | |
681 | ||
682 | +#ifdef NOTIFY_TZ_DEBUG | |
683 | + NOTIFY_TZ_PRINTF("localsub called\n"); | |
684 | +#endif /* NOTIFY_TZ_DEBUG */ | |
685 | sp = lclptr; | |
686 | #ifdef ALL_STATE | |
687 | if (sp == NULL) { | |
224c7076 A |
688 | +#ifdef __LP64__ |
689 | + return gmtsub(timep, offset, tmp); | |
690 | +#else /* !__LP64__ */ | |
691 | gmtsub(timep, offset, tmp); | |
692 | return; | |
693 | +#endif /* __LP64__ */ | |
694 | } | |
695 | #endif /* defined ALL_STATE */ | |
696 | if (sp->timecnt == 0 || t < sp->ats[0]) { | |
1f2f436a | 697 | @@ -1117,12 +1479,20 @@ struct tm * const tmp; |
224c7076 A |
698 | ** t += ttisp->tt_gmtoff; |
699 | ** timesub(&t, 0L, sp, tmp); | |
700 | */ | |
701 | +#ifdef __LP64__ | |
702 | + if (timesub(&t, ttisp->tt_gmtoff, sp, tmp) == NULL) | |
703 | + return NULL; | |
704 | +#else /* !__LP64__ */ | |
705 | timesub(&t, ttisp->tt_gmtoff, sp, tmp); | |
706 | +#endif /* __LP64__ */ | |
707 | tmp->tm_isdst = ttisp->tt_isdst; | |
708 | tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; | |
709 | #ifdef TM_ZONE | |
710 | tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; | |
711 | #endif /* defined TM_ZONE */ | |
712 | +#ifdef __LP64__ | |
713 | + return tmp; | |
714 | +#endif /* __LP64__ */ | |
715 | } | |
716 | ||
717 | struct tm * | |
1f2f436a A |
718 | @@ -1134,10 +1504,11 @@ const time_t * const timep; |
719 | struct tm *p_tm; | |
9385eb3d A |
720 | |
721 | if (__isthreaded != 0) { | |
9385eb3d A |
722 | - if (localtime_key < 0) { |
723 | + if (localtime_key == (pthread_key_t)-1) { | |
1f2f436a A |
724 | _pthread_mutex_lock(&localtime_mutex); |
725 | - if (localtime_key < 0) { | |
726 | - if (_pthread_key_create(&localtime_key, free) < 0) { | |
727 | + if (localtime_key == (pthread_key_t)-1) { | |
728 | + localtime_key = __LIBC_PTHREAD_KEY_LOCALTIME; | |
729 | + if (pthread_key_init_np(localtime_key, free) < 0) { | |
730 | _pthread_mutex_unlock(&localtime_mutex); | |
731 | return(NULL); | |
732 | } | |
733 | @@ -1153,13 +1524,21 @@ const time_t * const timep; | |
224c7076 | 734 | } |
1f2f436a A |
735 | _RWLOCK_RDLOCK(&lcl_rwlock); |
736 | tzset_basic(1); | |
224c7076 A |
737 | +#ifdef __LP64__ |
738 | + p_tm = localsub(timep, 0L, p_tm); | |
739 | +#else /* !__LP64__ */ | |
740 | localsub(timep, 0L, p_tm); | |
741 | +#endif /* __LP64__ */ | |
1f2f436a | 742 | _RWLOCK_UNLOCK(&lcl_rwlock); |
224c7076 A |
743 | return(p_tm); |
744 | } else { | |
1f2f436a | 745 | tzset_basic(0); |
224c7076 A |
746 | +#ifdef __LP64__ |
747 | + return localsub(timep, 0L, &tm); | |
748 | +#else /* !__LP64__ */ | |
749 | localsub(timep, 0L, &tm); | |
750 | return(&tm); | |
751 | +#endif /* __LP64__ */ | |
752 | } | |
753 | } | |
754 | ||
1f2f436a | 755 | @@ -1168,13 +1547,15 @@ const time_t * const timep; |
224c7076 A |
756 | */ |
757 | ||
758 | struct tm * | |
759 | -localtime_r(timep, tm) | |
760 | -const time_t * const timep; | |
761 | -struct tm * tm; | |
762 | +localtime_r(const time_t * const __restrict timep, struct tm * __restrict tm) | |
763 | { | |
1f2f436a A |
764 | _RWLOCK_RDLOCK(&lcl_rwlock); |
765 | tzset_basic(1); | |
224c7076 A |
766 | +#ifdef __LP64__ |
767 | + tm = localsub(timep, 0L, tm); | |
768 | +#else /* !__LP64__ */ | |
769 | localsub(timep, 0L, tm); | |
770 | +#endif /* __LP64__ */ | |
1f2f436a | 771 | _RWLOCK_UNLOCK(&lcl_rwlock); |
224c7076 A |
772 | return tm; |
773 | } | |
1f2f436a | 774 | @@ -1183,25 +1564,52 @@ struct tm * tm; |
224c7076 A |
775 | ** gmtsub is to gmtime as localsub is to localtime. |
776 | */ | |
777 | ||
778 | +#ifdef __LP64__ | |
779 | +static struct tm * | |
780 | +#else /* !__LP64__ */ | |
781 | static void | |
782 | +#endif /* __LP64__ */ | |
783 | gmtsub(timep, offset, tmp) | |
784 | const time_t * const timep; | |
9385eb3d A |
785 | const long offset; |
786 | struct tm * const tmp; | |
787 | { | |
788 | +#ifdef NOTIFY_TZ_DEBUG | |
789 | + NOTIFY_TZ_PRINTF("gmtsub called\n"); | |
790 | +#endif /* NOTIFY_TZ_DEBUG */ | |
9385eb3d A |
791 | +#ifdef NOTIFY_TZ |
792 | + notify_check_tz(&gmt_notify); | |
793 | +#endif /* NOTIFY_TZ */ | |
794 | if (!gmt_is_set) { | |
1f2f436a A |
795 | _MUTEX_LOCK(&gmt_mutex); |
796 | if (!gmt_is_set) { | |
9385eb3d | 797 | #ifdef ALL_STATE |
1f2f436a | 798 | - gmtptr = (struct state *) malloc(sizeof *gmtptr); |
9385eb3d | 799 | +#ifdef NOTIFY_TZ |
1f2f436a | 800 | + if (gmtptr == NULL) |
9385eb3d | 801 | +#endif /* NOTIFY_TZ */ |
1f2f436a A |
802 | + gmtptr = (struct state *) malloc(sizeof *gmtptr); |
803 | if (gmtptr != NULL) | |
9385eb3d | 804 | +#ifdef NOTIFY_TZ |
1f2f436a | 805 | + { |
9385eb3d A |
806 | +#endif /* NOTIFY_TZ */ |
807 | #endif /* defined ALL_STATE */ | |
1f2f436a | 808 | gmtload(gmtptr); |
9385eb3d | 809 | +#ifdef NOTIFY_TZ |
1f2f436a A |
810 | + notify_register_tz(fullname, &gmt_notify); |
811 | +#ifdef ALL_STATE | |
812 | + } | |
813 | +#endif | |
9385eb3d | 814 | +#endif /* NOTIFY_TZ */ |
1f2f436a A |
815 | gmt_is_set = TRUE; |
816 | } | |
817 | _MUTEX_UNLOCK(&gmt_mutex); | |
9385eb3d | 818 | } |
224c7076 A |
819 | +#ifdef __LP64__ |
820 | + if(timesub(timep, offset, gmtptr, tmp) == NULL) | |
821 | + return NULL; | |
822 | +#else /* !__LP64__ */ | |
9385eb3d | 823 | timesub(timep, offset, gmtptr, tmp); |
224c7076 A |
824 | +#endif /* __LP64__ */ |
825 | #ifdef TM_ZONE | |
826 | /* | |
827 | ** Could get fancy here and deliver something such as | |
1f2f436a | 828 | @@ -1213,7 +1621,7 @@ struct tm * const tmp; |
9385eb3d A |
829 | else { |
830 | #ifdef ALL_STATE | |
831 | if (gmtptr == NULL) | |
832 | - tmp->TM_ZONE = gmt; | |
833 | + tmp->TM_ZONE = (char *)gmt; | |
834 | else tmp->TM_ZONE = gmtptr->chars; | |
835 | #endif /* defined ALL_STATE */ | |
836 | #ifndef ALL_STATE | |
1f2f436a | 837 | @@ -1221,6 +1629,9 @@ struct tm * const tmp; |
224c7076 A |
838 | #endif /* State Farm */ |
839 | } | |
840 | #endif /* defined TM_ZONE */ | |
841 | +#ifdef __LP64__ | |
842 | + return tmp; | |
843 | +#endif /* __LP64__ */ | |
844 | } | |
9385eb3d | 845 | |
224c7076 | 846 | struct tm * |
1f2f436a | 847 | @@ -1232,10 +1643,11 @@ const time_t * const timep; |
224c7076 A |
848 | struct tm *p_tm; |
849 | ||
9385eb3d | 850 | if (__isthreaded != 0) { |
9385eb3d A |
851 | - if (gmtime_key < 0) { |
852 | + if (gmtime_key == (pthread_key_t)-1) { | |
1f2f436a A |
853 | _pthread_mutex_lock(&gmtime_mutex); |
854 | - if (gmtime_key < 0) { | |
855 | - if (_pthread_key_create(&gmtime_key, free) < 0) { | |
856 | + if (gmtime_key == (pthread_key_t)-1) { | |
857 | + gmtime_key = __LIBC_PTHREAD_KEY_GMTIME; | |
858 | + if (pthread_key_init_np(gmtime_key, free) < 0) { | |
859 | _pthread_mutex_unlock(&gmtime_mutex); | |
860 | return(NULL); | |
861 | } | |
862 | @@ -1253,12 +1665,20 @@ const time_t * const timep; | |
224c7076 A |
863 | } |
864 | _pthread_setspecific(gmtime_key, p_tm); | |
865 | } | |
866 | +#ifdef __LP64__ | |
867 | + return gmtsub(timep, 0L, p_tm); | |
868 | +#else /* !__LP64__ */ | |
869 | gmtsub(timep, 0L, p_tm); | |
870 | return(p_tm); | |
871 | +#endif /* __LP64__ */ | |
872 | } | |
873 | else { | |
874 | +#ifdef __LP64__ | |
875 | + return gmtsub(timep, 0L, &tm); | |
876 | +#else /* !__LP64__ */ | |
877 | gmtsub(timep, 0L, &tm); | |
878 | return(&tm); | |
879 | +#endif /* __LP64__ */ | |
880 | } | |
881 | } | |
882 | ||
1f2f436a | 883 | @@ -1271,8 +1691,13 @@ gmtime_r(timep, tm) |
224c7076 A |
884 | const time_t * const timep; |
885 | struct tm * tm; | |
886 | { | |
887 | + | |
888 | +#ifdef __LP64__ | |
889 | + return gmtsub(timep, 0L, tm); | |
890 | +#else /* !__LP64__ */ | |
891 | gmtsub(timep, 0L, tm); | |
892 | return tm; | |
893 | +#endif /* __LP64__ */ | |
894 | } | |
895 | ||
896 | #ifdef STD_INSPIRED | |
1f2f436a | 897 | @@ -1282,13 +1707,21 @@ offtime(timep, offset) |
224c7076 A |
898 | const time_t * const timep; |
899 | const long offset; | |
900 | { | |
901 | +#ifdef __LP64__ | |
902 | + return gmtsub(timep, offset, &tm); | |
903 | +#else /* !__LP64__ */ | |
904 | gmtsub(timep, offset, &tm); | |
905 | return &tm; | |
906 | +#endif /* __LP64__ */ | |
907 | } | |
908 | ||
909 | #endif /* defined STD_INSPIRED */ | |
910 | ||
911 | +#ifdef __LP64__ | |
912 | +static struct tm * | |
913 | +#else /* !__LP64__ */ | |
914 | static void | |
915 | +#endif /* __LP64__ */ | |
916 | timesub(timep, offset, sp, tmp) | |
917 | const time_t * const timep; | |
918 | const long offset; | |
1f2f436a A |
919 | @@ -1365,7 +1798,12 @@ struct tm * const tmp; |
920 | if (tmp->tm_wday < 0) | |
921 | tmp->tm_wday += DAYSPERWEEK; | |
922 | y = EPOCH_YEAR; | |
923 | -#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) | |
924 | +#define _LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) | |
925 | +#ifdef __LP64__ | |
926 | +#define LEAPS_THRU_END_OF(y) ((y) >= 0 ? _LEAPS_THRU_END_OF(y) : _LEAPS_THRU_END_OF((y) + 1) - 1) | |
927 | +#else /* !__LP64__ */ | |
928 | +#define LEAPS_THRU_END_OF(y) _LEAPS_THRU_END_OF(y) | |
929 | +#endif /* __LP64__ */ | |
930 | while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { | |
931 | long newy; | |
932 | ||
933 | @@ -1377,7 +1815,16 @@ struct tm * const tmp; | |
224c7076 A |
934 | LEAPS_THRU_END_OF(y - 1); |
935 | y = newy; | |
936 | } | |
937 | +#ifdef __LP64__ | |
938 | + y -= TM_YEAR_BASE; | |
939 | + if (y < INT_MIN || y > INT_MAX) { | |
940 | + errno = EOVERFLOW; | |
941 | + return NULL; | |
942 | + } | |
943 | + tmp->tm_year = y; | |
944 | +#else /* !__LP64__ */ | |
945 | tmp->tm_year = y - TM_YEAR_BASE; | |
946 | +#endif /* __LP64__ */ | |
947 | tmp->tm_yday = (int) days; | |
948 | ip = mon_lengths[yleap]; | |
949 | for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) | |
1f2f436a | 950 | @@ -1387,6 +1834,9 @@ struct tm * const tmp; |
224c7076 A |
951 | #ifdef TM_GMTOFF |
952 | tmp->TM_GMTOFF = offset; | |
953 | #endif /* defined TM_GMTOFF */ | |
954 | +#ifdef __LP64__ | |
955 | + return tmp; | |
956 | +#endif /* __LP64__ */ | |
957 | } | |
958 | ||
959 | char * | |
1f2f436a | 960 | @@ -1399,7 +1849,20 @@ const time_t * const timep; |
34e8f829 A |
961 | ** to local time in the form of a string. It is equivalent to |
962 | ** asctime(localtime(timer)) | |
963 | */ | |
964 | +#ifdef __LP64__ | |
965 | + /* | |
966 | + * In 64-bit, the timep value may produce a time value with a year | |
967 | + * that exceeds 32-bits in size (won't fit in struct tm), so localtime | |
968 | + * will return NULL. | |
969 | + */ | |
970 | + struct tm *tm = localtime(timep); | |
971 | + | |
972 | + if (tm == NULL) | |
973 | + return NULL; | |
974 | + return asctime(tm); | |
975 | +#else /* !__LP64__ */ | |
976 | return asctime(localtime(timep)); | |
977 | +#endif /* __LP64__ */ | |
978 | } | |
979 | ||
980 | char * | |
1f2f436a | 981 | @@ -1409,7 +1872,18 @@ char * buf; |
34e8f829 A |
982 | { |
983 | struct tm tm; | |
984 | ||
985 | +#ifdef __LP64__ | |
986 | + /* | |
987 | + * In 64-bit, the timep value may produce a time value with a year | |
988 | + * that exceeds 32-bits in size (won't fit in struct tm), so localtime_r | |
989 | + * will return NULL. | |
990 | + */ | |
991 | + if (localtime_r(timep, &tm) == NULL) | |
992 | + return NULL; | |
993 | + return asctime_r(&tm, buf); | |
994 | +#else /* !__LP64__ */ | |
995 | return asctime_r(localtime_r(timep, &tm), buf); | |
996 | +#endif /* __LP64__ */ | |
997 | } | |
998 | ||
999 | /* | |
1f2f436a A |
1000 | @@ -1464,8 +1938,14 @@ const struct tm * const btmp; |
1001 | { | |
1002 | int result; | |
1003 | ||
1004 | - if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && | |
1005 | - (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && | |
1006 | + /* | |
1007 | + * Assume that atmp and btmp point to normalized tm strutures. | |
1008 | + * So only arithmetic with tm_year could overflow in 64-bit. | |
1009 | + */ | |
1010 | + if (atmp->tm_year != btmp->tm_year) { | |
1011 | + return (atmp->tm_year > btmp->tm_year ? 1 : -1); | |
1012 | + } | |
1013 | + if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 && | |
1014 | (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && | |
1015 | (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && | |
1016 | (result = (atmp->tm_min - btmp->tm_min)) == 0) | |
1017 | @@ -1474,12 +1954,17 @@ const struct tm * const btmp; | |
224c7076 A |
1018 | } |
1019 | ||
1020 | static time_t | |
1021 | -time2sub(tmp, funcp, offset, okayp, do_norm_secs) | |
1022 | +time2sub(tmp, funcp, offset, okayp, do_norm_secs, unix03) | |
1023 | struct tm * const tmp; | |
1024 | +#ifdef __LP64__ | |
1025 | +struct tm *(* const funcp)(const time_t*, long, struct tm*); | |
1026 | +#else /* !__LP64__ */ | |
1027 | void (* const funcp)(const time_t*, long, struct tm*); | |
1028 | +#endif /* __LP64__ */ | |
1029 | const long offset; | |
1030 | int * const okayp; | |
1031 | const int do_norm_secs; | |
1032 | +int unix03; | |
1033 | { | |
1034 | const struct state * sp; | |
1035 | int dir; | |
1f2f436a | 1036 | @@ -1489,6 +1974,9 @@ const int do_norm_secs; |
224c7076 A |
1037 | time_t newt; |
1038 | time_t t; | |
1039 | struct tm yourtm, mytm; | |
1040 | +#ifdef __LP64__ | |
1041 | + long year, il; | |
1042 | +#endif /* __LP64__ */ | |
1043 | ||
1044 | *okayp = FALSE; | |
1045 | yourtm = *tmp; | |
1f2f436a | 1046 | @@ -1507,33 +1995,64 @@ const int do_norm_secs; |
224c7076 A |
1047 | ** Turn yourtm.tm_year into an actual year number for now. |
1048 | ** It is converted back to an offset from TM_YEAR_BASE later. | |
1049 | */ | |
1050 | +#ifdef __LP64__ | |
1051 | + year = (long)yourtm.tm_year + TM_YEAR_BASE; | |
1052 | +#else /* !__LP64__ */ | |
1053 | if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) | |
1054 | return WRONG; | |
1055 | +#endif /* __LP64__ */ | |
1056 | while (yourtm.tm_mday <= 0) { | |
1057 | +#ifdef __LP64__ | |
1058 | + year--; | |
1059 | + il = year + (1 < yourtm.tm_mon); | |
1060 | + yourtm.tm_mday += year_lengths[isleap(il)]; | |
1061 | +#else /* !__LP64__ */ | |
1062 | if (increment_overflow(&yourtm.tm_year, -1)) | |
1063 | return WRONG; | |
1064 | i = yourtm.tm_year + (1 < yourtm.tm_mon); | |
1065 | yourtm.tm_mday += year_lengths[isleap(i)]; | |
1066 | +#endif /* __LP64__ */ | |
1067 | } | |
1068 | while (yourtm.tm_mday > DAYSPERLYEAR) { | |
1069 | +#ifdef __LP64__ | |
1070 | + il = year + (1 < yourtm.tm_mon); | |
1071 | + yourtm.tm_mday -= year_lengths[isleap(il)]; | |
1072 | + year++; | |
1073 | +#else /* !__LP64__ */ | |
1074 | i = yourtm.tm_year + (1 < yourtm.tm_mon); | |
1075 | yourtm.tm_mday -= year_lengths[isleap(i)]; | |
1076 | if (increment_overflow(&yourtm.tm_year, 1)) | |
1077 | return WRONG; | |
1078 | +#endif /* __LP64__ */ | |
1079 | } | |
1080 | for ( ; ; ) { | |
1081 | +#ifdef __LP64__ | |
1082 | + i = mon_lengths[isleap(year)][yourtm.tm_mon]; | |
1083 | +#else /* !__LP64__ */ | |
1084 | i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; | |
1085 | +#endif /* __LP64__ */ | |
1086 | if (yourtm.tm_mday <= i) | |
1087 | break; | |
1088 | yourtm.tm_mday -= i; | |
1089 | if (++yourtm.tm_mon >= MONSPERYEAR) { | |
1090 | yourtm.tm_mon = 0; | |
1091 | +#ifdef __LP64__ | |
1092 | + year++; | |
1093 | +#else /* !__LP64__ */ | |
1094 | if (increment_overflow(&yourtm.tm_year, 1)) | |
1095 | return WRONG; | |
1096 | +#endif /* __LP64__ */ | |
1097 | } | |
1098 | } | |
1099 | +#ifdef __LP64__ | |
1100 | + year -= TM_YEAR_BASE; | |
1101 | + if (year > INT_MAX || year < INT_MIN) | |
1102 | + return WRONG; | |
1103 | + yourtm.tm_year = year; | |
1104 | +#else /* !__LP64__ */ | |
1105 | if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) | |
1106 | return WRONG; | |
1107 | +#endif /* __LP64__ */ | |
1108 | /* Don't go below 1900 for POLA */ | |
1109 | if (yourtm.tm_year < 0) | |
1110 | return WRONG; | |
1f2f436a | 1111 | @@ -1560,13 +2079,21 @@ const int do_norm_secs; |
34e8f829 A |
1112 | ** Divide the search space in half |
1113 | ** (this works whether time_t is signed or unsigned). | |
1114 | */ | |
1115 | +#ifdef __LP64__ | |
1116 | + /* optimization: see if the value is 31-bit (signed) */ | |
1117 | + t = (((time_t) 1) << (TYPE_BIT(int) - 1)) - 1; | |
1118 | + bits = ((*funcp)(&t, offset, &mytm) == NULL || tmcomp(&mytm, &yourtm) < 0) ? TYPE_BIT(time_t) - 1 : TYPE_BIT(int) - 1; | |
1119 | +#else /* !__LP64__ */ | |
1120 | bits = TYPE_BIT(time_t) - 1; | |
1121 | +#endif /* __LP64__ */ | |
1122 | /* | |
1f2f436a A |
1123 | - ** If we have more than this, we will overflow tm_year for tmcomp(). |
1124 | - ** We should really return an error if we cannot represent it. | |
1125 | + ** In 64-bit, we now return an error if we cannot represent the | |
1126 | + ** struct tm value in a time_t. And tmcomp() is fixed to avoid | |
1127 | + ** overflow in tm_year. So we only put a cap on bits because time_t | |
1128 | + ** can't be larger that 56 bit (when tm_year == INT_MAX). | |
1129 | */ | |
1130 | - if (bits > 48) | |
1131 | - bits = 48; | |
1132 | + if (bits > 56) | |
1133 | + bits = 56; | |
1134 | /* | |
1135 | ** If time_t is signed, then 0 is just above the median, | |
1136 | ** assuming two's complement arithmetic. | |
1137 | @@ -1574,8 +2101,19 @@ const int do_norm_secs; | |
224c7076 A |
1138 | */ |
1139 | t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); | |
1140 | for ( ; ; ) { | |
1141 | +#ifdef __LP64__ | |
1142 | + if ((*funcp)(&t, offset, &mytm) == NULL) { | |
1143 | + /* we overflowed, so t is too big */ | |
1144 | + dir = 1; | |
1145 | + goto skip_tmcomp; | |
1146 | + } | |
1147 | +#else /* !__LP64__ */ | |
1148 | (*funcp)(&t, offset, &mytm); | |
1149 | +#endif /* __LP64__ */ | |
1150 | dir = tmcomp(&mytm, &yourtm); | |
1151 | +#ifdef __LP64__ | |
1152 | +skip_tmcomp: | |
1153 | +#endif /* __LP64__ */ | |
1154 | if (dir != 0) { | |
1155 | if (bits-- < 0) | |
1156 | return WRONG; | |
1f2f436a | 1157 | @@ -1586,6 +2124,9 @@ const int do_norm_secs; |
224c7076 A |
1158 | else t += ((time_t) 1) << bits; |
1159 | continue; | |
1160 | } | |
1161 | + sp = (funcp == localsub) ? lclptr : gmtptr; | |
1162 | + if (unix03 && sp->typecnt == 1 && yourtm.tm_isdst > 0) | |
1163 | + yourtm.tm_isdst = 0; /* alternative time does not apply */ | |
1164 | if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) | |
1165 | break; | |
1166 | /* | |
1f2f436a | 1167 | @@ -1594,7 +2135,6 @@ const int do_norm_secs; |
224c7076 A |
1168 | ** It's okay to guess wrong since the guess |
1169 | ** gets checked. | |
1170 | */ | |
1171 | - sp = (funcp == localsub) ? lclptr : gmtptr; | |
1172 | #ifdef ALL_STATE | |
1173 | if (sp == NULL) | |
1174 | return WRONG; | |
1f2f436a | 1175 | @@ -1607,7 +2147,12 @@ const int do_norm_secs; |
224c7076 A |
1176 | continue; |
1177 | newt = t + sp->ttis[j].tt_gmtoff - | |
1178 | sp->ttis[i].tt_gmtoff; | |
1179 | +#ifdef __LP64__ | |
1180 | + if ((*funcp)(&newt, offset, &mytm) == NULL) | |
1181 | + return WRONG; | |
1182 | +#else /* !__LP64__ */ | |
1183 | (*funcp)(&newt, offset, &mytm); | |
1184 | +#endif /* __LP64__ */ | |
1185 | if (tmcomp(&mytm, &yourtm) != 0) | |
1186 | continue; | |
1187 | if (mytm.tm_isdst != yourtm.tm_isdst) | |
1f2f436a | 1188 | @@ -1626,17 +2171,27 @@ label: |
224c7076 A |
1189 | if ((newt < t) != (saved_seconds < 0)) |
1190 | return WRONG; | |
1191 | t = newt; | |
1192 | +#ifdef __LP64__ | |
1193 | + if ((*funcp)(&t, offset, tmp) == NULL) | |
1194 | + return WRONG; | |
1195 | +#else /* !__LP64__ */ | |
1196 | (*funcp)(&t, offset, tmp); | |
1197 | +#endif /* __LP64__ */ | |
1198 | *okayp = TRUE; | |
1199 | return t; | |
1200 | } | |
1201 | ||
1202 | static time_t | |
1203 | -time2(tmp, funcp, offset, okayp) | |
1204 | +time2(tmp, funcp, offset, okayp, unix03) | |
1205 | struct tm * const tmp; | |
1206 | +#ifdef __LP64__ | |
1207 | +struct tm *(* const funcp)(const time_t*, long, struct tm*); | |
1208 | +#else /* !__LP64__ */ | |
1209 | void (* const funcp)(const time_t*, long, struct tm*); | |
1210 | +#endif /* __LP64__ */ | |
1211 | const long offset; | |
1212 | int * const okayp; | |
1213 | +int unix03; | |
1214 | { | |
1215 | time_t t; | |
1216 | ||
1f2f436a | 1217 | @@ -1645,15 +2200,20 @@ int * const okayp; |
224c7076 A |
1218 | ** (in case tm_sec contains a value associated with a leap second). |
1219 | ** If that fails, try with normalization of seconds. | |
1220 | */ | |
1221 | - t = time2sub(tmp, funcp, offset, okayp, FALSE); | |
1222 | - return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); | |
1223 | + t = time2sub(tmp, funcp, offset, okayp, FALSE, unix03); | |
1224 | + return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, unix03); | |
1225 | } | |
1226 | ||
1227 | -static time_t | |
1228 | -time1(tmp, funcp, offset) | |
1229 | +__private_extern__ time_t | |
1230 | +time1(tmp, funcp, offset, unix03) | |
1231 | struct tm * const tmp; | |
1232 | +#ifdef __LP64__ | |
1233 | +struct tm *(* const funcp)(const time_t *, long, struct tm *); | |
1234 | +#else /* !__LP64__ */ | |
1235 | void (* const funcp)(const time_t *, long, struct tm *); | |
1236 | +#endif /* __LP64__ */ | |
1237 | const long offset; | |
1238 | +int unix03; | |
1239 | { | |
1240 | time_t t; | |
1241 | const struct state * sp; | |
1f2f436a | 1242 | @@ -1667,7 +2227,7 @@ const long offset; |
224c7076 A |
1243 | |
1244 | if (tmp->tm_isdst > 1) | |
1245 | tmp->tm_isdst = 1; | |
1246 | - t = time2(tmp, funcp, offset, &okay); | |
1247 | + t = time2(tmp, funcp, offset, &okay, unix03); | |
1248 | #ifdef PCTS | |
1249 | /* | |
1250 | ** PCTS code courtesy Grant Sullivan (grant@osf.org). | |
1f2f436a | 1251 | @@ -1711,7 +2271,7 @@ const long offset; |
224c7076 A |
1252 | tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - |
1253 | sp->ttis[samei].tt_gmtoff; | |
1254 | tmp->tm_isdst = !tmp->tm_isdst; | |
1255 | - t = time2(tmp, funcp, offset, &okay); | |
1256 | + t = time2(tmp, funcp, offset, &okay, unix03); | |
1257 | if (okay) | |
1258 | return t; | |
1259 | tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - | |
1f2f436a | 1260 | @@ -1721,19 +2281,25 @@ const long offset; |
224c7076 A |
1261 | } |
1262 | return WRONG; | |
1263 | } | |
1264 | +#else /* BUILDING_VARIANT */ | |
1f2f436a | 1265 | +__private_extern__ pthread_rwlock_t lcl_rwlock; |
224c7076 A |
1266 | +#endif /* BUILDING_VARIANT */ |
1267 | ||
1268 | time_t | |
1269 | mktime(tmp) | |
1270 | struct tm * const tmp; | |
1271 | { | |
1272 | time_t mktime_return_value; | |
1273 | + int serrno = errno; | |
1f2f436a A |
1274 | _RWLOCK_RDLOCK(&lcl_rwlock); |
1275 | tzset_basic(1); | |
224c7076 A |
1276 | - mktime_return_value = time1(tmp, localsub, 0L); |
1277 | + mktime_return_value = time1(tmp, localsub, 0L, __DARWIN_UNIX03); | |
1f2f436a | 1278 | _RWLOCK_UNLOCK(&lcl_rwlock); |
224c7076 A |
1279 | + errno = serrno; |
1280 | return(mktime_return_value); | |
1281 | } | |
1282 | ||
1283 | +#if !BUILDING_VARIANT | |
1284 | #ifdef STD_INSPIRED | |
1285 | ||
1286 | time_t | |
1f2f436a | 1287 | @@ -1749,7 +2315,7 @@ timegm(tmp) |
224c7076 A |
1288 | struct tm * const tmp; |
1289 | { | |
1290 | tmp->tm_isdst = 0; | |
1291 | - return time1(tmp, gmtsub, 0L); | |
1292 | + return time1(tmp, gmtsub, 0L, __DARWIN_UNIX03); | |
1293 | } | |
1294 | ||
1295 | time_t | |
1f2f436a | 1296 | @@ -1758,7 +2324,7 @@ struct tm * const tmp; |
224c7076 A |
1297 | const long offset; |
1298 | { | |
1299 | tmp->tm_isdst = 0; | |
1300 | - return time1(tmp, gmtsub, offset); | |
1301 | + return time1(tmp, gmtsub, offset, __DARWIN_UNIX03); | |
1302 | } | |
1303 | ||
1304 | #endif /* defined STD_INSPIRED */ | |
1f2f436a | 1305 | @@ -1858,3 +2424,4 @@ time_t t; |
224c7076 A |
1306 | } |
1307 | ||
1308 | #endif /* defined STD_INSPIRED */ | |
1309 | +#endif /* !BUILDING_VARIANT */ |