Asterisk - The Open Source Telephony Project GIT-master-67613d1
localtime.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2010, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * Most of this code is in the public domain, so clarified as of
9 * June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov).
10 *
11 * All modifications to this code to abstract timezones away from
12 * the environment are by Tilghman Lesher, <tlesher@vcch.com>, with
13 * the copyright assigned to Digium.
14 *
15 * See http://www.asterisk.org for more information about
16 * the Asterisk project. Please do not directly contact
17 * any of the maintainers of this project for assistance;
18 * the project provides a web site, mailing lists and IRC
19 * channels for your use.
20 *
21 * This program is free software, distributed under the terms of
22 * the GNU General Public License Version 2. See the LICENSE file
23 * at the top of the source tree.
24 */
25
26/*! \file
27 *
28 * Multi-timezone Localtime code
29 *
30 * The original source from this file may be obtained from ftp://elsie.nci.nih.gov/pub/
31 */
32
33/*
34** This file is in the public domain, so clarified as of
35** 1996-06-05 by Arthur David Olson.
36*/
37
38/*
39** Leap second handling from Bradley White.
40** POSIX-style TZ environment variable handling from Guy Harris.
41*/
42
43/* #define DEBUG */
44
45/*LINTLIBRARY*/
46
47/*** MODULEINFO
48 <support_level>core</support_level>
49 ***/
50
51#include "asterisk.h"
52
53#include <signal.h>
54#include <sys/stat.h>
55#include <fcntl.h>
56#include <float.h>
57#include <stdlib.h>
58#ifdef HAVE_INOTIFY
59#include <sys/inotify.h>
60#elif defined(HAVE_KQUEUE)
61#include <sys/types.h>
62#include <sys/time.h>
63#include <sys/event.h>
64#include <dirent.h>
65#include <sys/stat.h>
66#include <fcntl.h>
67#endif
68
69#include "private.h"
70#include "tzfile.h"
71
72#include "asterisk/_private.h"
73#include "asterisk/lock.h"
74#include "asterisk/localtime.h"
75#include "asterisk/strings.h"
77#include "asterisk/utils.h"
78#include "asterisk/test.h"
79
80#ifndef lint
81#ifndef NOID
82static char __attribute__((unused)) elsieid[] = "@(#)localtime.c 8.5";
83#endif /* !defined NOID */
84#endif /* !defined lint */
85
86#ifndef TZ_ABBR_MAX_LEN
87#define TZ_ABBR_MAX_LEN 16
88#endif /* !defined TZ_ABBR_MAX_LEN */
89
90#ifndef TZ_ABBR_CHAR_SET
91#define TZ_ABBR_CHAR_SET \
92 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
93#endif /* !defined TZ_ABBR_CHAR_SET */
94
95#ifndef TZ_ABBR_ERR_CHAR
96#define TZ_ABBR_ERR_CHAR '_'
97#endif /* !defined TZ_ABBR_ERR_CHAR */
98
99/*
100** SunOS 4.1.1 headers lack O_BINARY.
101*/
102
103#ifdef O_BINARY
104#define OPEN_MODE (O_RDONLY | O_BINARY)
105#endif /* defined O_BINARY */
106#ifndef O_BINARY
107#define OPEN_MODE O_RDONLY
108#endif /* !defined O_BINARY */
109
110static const char gmt[] = "GMT";
111static const struct timeval WRONG = { 0, 0 };
112
113#ifdef TEST_FRAMEWORK
114/* Protected from multiple threads by the zonelist lock */
115static struct ast_test *test = NULL;
116#else
117struct ast_test;
118#endif
119
120/*! \note
121 * The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
122 * We default to US rules as of 1999-08-17.
123 * POSIX 1003.1 section 8.1.1 says that the default DST rules are
124 * implementation dependent; for historical reasons, US rules are a
125 * common default.
126 */
127#ifndef TZDEFRULESTRING
128#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
129#endif /* !defined TZDEFDST */
130
131/*!< \brief time type information */
132struct ttinfo { /* time type information */
133 long tt_gmtoff; /* UTC offset in seconds */
134 int tt_isdst; /* used to set tm_isdst */
135 int tt_abbrind; /* abbreviation list index */
136 int tt_ttisstd; /* TRUE if transition is std time */
137 int tt_ttisgmt; /* TRUE if transition is UTC */
138};
139
140/*! \brief leap second information */
141struct lsinfo { /* leap second information */
142 time_t ls_trans; /* transition time */
143 long ls_corr; /* correction to apply */
144};
145
146#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
147
148#ifdef TZNAME_MAX
149#define MY_TZNAME_MAX TZNAME_MAX
150#endif /* defined TZNAME_MAX */
151#ifndef TZNAME_MAX
152#define MY_TZNAME_MAX 255
153#endif /* !defined TZNAME_MAX */
154#ifndef TZ_STRLEN_MAX
155#define TZ_STRLEN_MAX 255
156#endif /* !defined TZ_STRLEN_MAX */
157
158struct state {
159 /*! Name of the file that this references */
168 unsigned char types[TZ_MAX_TIMES];
171 (2 * (MY_TZNAME_MAX + 1)))];
173#ifdef HAVE_INOTIFY
174 int wd[2];
175#elif defined(HAVE_KQUEUE)
176 int fd;
177# ifdef HAVE_O_SYMLINK
178 int fds;
179# else
180 DIR *dir;
181# endif /* defined(HAVE_O_SYMLINK) */
182#else
183 time_t mtime[2];
184#endif
186};
187
188/* extra initialisation for sstate_alloc() */
189#define SP_STACK_FLAG INT_MIN
190#ifdef HAVE_INOTIFY
191# define SP_STACK_INIT(sp) do { \
192 (sp).wd[0] = SP_STACK_FLAG; \
193 } while (0)
194# define SP_STACK_CHECK(sp) ((sp)->wd[0] == SP_STACK_FLAG)
195# define SP_HEAP_INIT(sp) do { \
196 (sp)->wd[0] = -1; \
197 (sp)->wd[1] = -1; \
198 } while (0)
199# define SP_HEAP_FREE(sp) do {} while (0)
200
201#elif defined(HAVE_KQUEUE)
202# define SP_STACK_INIT(sp) do { \
203 (sp).fd = SP_STACK_FLAG; \
204 } while (0)
205# define SP_STACK_CHECK(sp) ((sp)->fd == SP_STACK_FLAG)
206#ifdef HAVE_O_SYMLINK
207# define SP_HEAP_INIT(sp) do { \
208 (sp)->fd = -1; \
209 (sp)->fds = -1; \
210 } while (0)
211# define SP_HEAP_FREE(sp) do { \
212 if ( (sp) ) { \
213 kqueue_daemon_freestate(sp); \
214 if ((sp)->fd > -1) { close((sp)->fd); (sp)->fd = -1; } \
215 if ((sp)->fds > -1) { close((sp)->fds); (sp)->fds = -1; } \
216 } \
217 } while (0)
218
219#else /* HAVE_O_SYMLINK */
220# define SP_HEAP_INIT(sp) do { \
221 (sp)->fd = -1; \
222 (sp)->dir = NULL; \
223 } while (0)
224# define SP_HEAP_FREE(sp) do { \
225 if ( (sp) ) { \
226 kqueue_daemon_freestate(sp); \
227 if ((sp)->fd > -1) { close((sp)->fd); (sp)->fd = -1; } \
228 if ((sp)->dir != NULL) { closedir((sp)->dir); (sp)->dir = NULL; } \
229 } \
230 } while (0)
231
232#endif /* HAVE_O_SYMLINK */
233
234#else /* defined(HAVE_KQUEUE) */
235# define SP_STACK_INIT(sp) do {} while (0)
236# define SP_STACK_CHECK(sp) (0)
237# define SP_HEAP_INIT(sp) do {} while (0)
238# define SP_HEAP_FREE(sp) do {} while (0)
239
240#endif
241
245 char name[0];
246};
247
248struct rule {
249 int r_type; /* type of rule--see below */
250 int r_day; /* day number of rule */
251 int r_week; /* week number of rule */
252 int r_mon; /* month number of rule */
253 long r_time; /* transition time of rule */
254};
255
256#define JULIAN_DAY 0 /* Jn - Julian day */
257#define DAY_OF_YEAR 1 /* n - day of year */
258#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
259
260/*
261** Prototypes for static functions.
262*/
263
264static long detzcode P((const char * codep));
265static time_t detzcode64 P((const char * codep));
266static int differ_by_repeat P((time_t t1, time_t t0));
267static const char * getzname P((const char * strp));
268static const char * getqzname P((const char * strp, const int delim));
269static const char * getnum P((const char * strp, int * nump, int min,
270 int max));
271static const char * getsecs P((const char * strp, long * secsp));
272static const char * getoffset P((const char * strp, long * offsetp));
273static const char * getrule P((const char * strp, struct rule * rulep));
274static int gmtload P((struct state * sp));
275static struct ast_tm * gmtsub P((const struct timeval * timep, long offset,
276 struct ast_tm * tmp));
277static struct ast_tm * localsub P((const struct timeval * timep, long offset,
278 struct ast_tm * tmp, const struct state *sp));
279static int increment_overflow P((int * number, int delta));
280static int leaps_thru_end_of P((int y));
281static int long_increment_overflow P((long * number, int delta));
282static int long_normalize_overflow P((long * tensptr,
283 int * unitsptr, const int base));
284static int normalize_overflow P((int * tensptr, int * unitsptr,
285 const int base));
286static struct timeval time1 P((struct ast_tm * tmp,
287 struct ast_tm * (*funcp) P((const struct timeval *,
288 long, struct ast_tm *, const struct state *sp)),
289 long offset, const struct state *sp));
290static struct timeval time2 P((struct ast_tm *tmp,
291 struct ast_tm * (*funcp) P((const struct timeval *,
292 long, struct ast_tm*, const struct state *sp)),
293 long offset, int * okayp, const struct state *sp));
294static struct timeval time2sub P((struct ast_tm *tmp,
295 struct ast_tm * (*funcp) (const struct timeval *,
296 long, struct ast_tm*, const struct state *sp),
297 long offset, int * okayp, int do_norm_secs, const struct state *sp));
298static struct ast_tm * timesub P((const struct timeval * timep, long offset,
299 const struct state * sp, struct ast_tm * tmp));
300static int tmcomp P((const struct ast_tm * atmp,
301 const struct ast_tm * btmp));
302static time_t transtime P((time_t janfirst, int year,
303 const struct rule * rulep, long offset));
304static int tzload P((const char * name, struct state * sp,
305 int doextend));
306static int tzparse P((const char * name, struct state * sp,
307 int lastditch));
308/* struct state allocator with additional setup as needed */
309static struct state * sstate_alloc(void);
310static void sstate_free(struct state *p);
311
313#if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE)
315#endif
316
317#ifndef TZ_STRLEN_MAX
318#define TZ_STRLEN_MAX 255
319#endif /* !defined TZ_STRLEN_MAX */
320
324
325static void add_notify(struct state *sp, const char *path);
326
327/*! Start a notification for every entry already in the list. */
328static void common_startup(void) {
329 struct state *sp;
332 /* ensure sp->name is not relative -- it
333 * often is -- otherwise add_notify() fails
334 */
335 char name[FILENAME_MAX + 1];
336
337 if (sp->name[0] == '/') {
338 snprintf(name, sizeof(name), "%s", sp->name);
339 } else if (!strcmp(sp->name, TZDEFAULT)) {
340 snprintf(name, sizeof(name), "/etc/%s", sp->name);
341 } else {
342 snprintf(name, sizeof(name), "%s/%s", TZDIR, sp->name);
343 }
344
345 add_notify(sp, name);
346 }
348}
349
350#ifdef HAVE_INOTIFY
351static int inotify_fd = -1;
352
353static void *inotify_daemon(void *data)
354{
355 /* inotify_event is dynamically sized */
356 struct inotify_event *iev;
357 size_t real_sizeof_iev = sizeof(*iev) + FILENAME_MAX + 1;
358 ssize_t res;
359 struct state *cur;
360
361 inotify_fd = inotify_init();
362
366
367 if (inotify_fd < 0) {
368 ast_log(LOG_ERROR, "Cannot initialize file notification service: %s (%d)\n", strerror(errno), errno);
370 return NULL;
371 }
372 iev = ast_alloca(real_sizeof_iev);
373
375
376 for (;/*ever*/;) {
377 /* This read should block, most of the time. */
378 if ((res = read(inotify_fd, iev, real_sizeof_iev)) < sizeof(*iev) && res > 0) {
379 /* This should never happen */
380 ast_log(LOG_ERROR, "Inotify read less than a full event (%zd < %zu)?!!\n", res, sizeof(*iev));
381 break;
382 } else if (res < 0) {
383 if (errno == EINTR || errno == EAGAIN) {
384 /* If read fails, try again */
388 continue;
389 }
390 /* Sanity check -- this should never happen, either */
391 ast_log(LOG_ERROR, "Inotify failed: %s\n", strerror(errno));
392 break;
393 }
396 if (cur->wd[0] == iev->wd || cur->wd[1] == iev->wd) {
398 sstate_free(cur);
399 break;
400 }
401 }
405 }
406 close(inotify_fd);
408 return NULL;
409}
410
411static void add_notify(struct state *sp, const char *path)
412{
413 /* watch for flag indicating stack automatic sp,
414 * should not be added to watch
415 */
416 if (SP_STACK_CHECK(sp)) {
417 return;
418 }
419
425 /* Give the thread a chance to initialize */
427 } else {
428 fprintf(stderr, "Unable to start notification thread\n");
430 return;
431 }
433 }
434
435 if (inotify_fd > -1) {
436 char fullpath[FILENAME_MAX + 1] = "";
437 if (readlink(path, fullpath, sizeof(fullpath) - 1) != -1) {
438 /* If file the symlink points to changes */
439 sp->wd[1] = inotify_add_watch(inotify_fd, fullpath, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE );
440 } else {
441 sp->wd[1] = -1;
442 }
443 /* or if the symlink itself changes (or the real file is here, if path is not a symlink) */
444 sp->wd[0] = inotify_add_watch(inotify_fd, path, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE
445#ifdef IN_DONT_FOLLOW /* Only defined in glibc 2.5 and above */
446 | IN_DONT_FOLLOW
447#endif
448 );
449 }
450}
451#elif defined(HAVE_KQUEUE)
452static int queue_fd = -1;
453
454/*
455 * static struct state *psx_sp and associated code will guard against
456 * add_notify() called repeatedly for /usr/share/zoneinfo/posixrules
457 * without zonelist check as a result of some errors
458 * (any code where tzparse() is called if tzload() fails --
459 * tzparse() re-calls tzload() for /usr/share/zoneinfo/posixrules)
460 * the pointer itself is guarded by the zonelist lock
461 */
462static struct state *psx_sp = NULL;
463
464/* collect EVFILT_VNODE fflags in macro;
465 */
466#ifdef NOTE_TRUNCATE
467# define EVVN_NOTES_BITS \
468 (NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_REVOKE|NOTE_ATTRIB \
469 |NOTE_RENAME|NOTE_LINK|NOTE_TRUNCATE)
470#else
471# define EVVN_NOTES_BITS \
472 (NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_REVOKE|NOTE_ATTRIB \
473 |NOTE_RENAME|NOTE_LINK)
474#endif
475
476static void *kqueue_daemon(void *data)
477{
478 struct kevent kev;
479 struct state *sp;
480
482 if (queue_fd < 0 && (queue_fd = kqueue()) < 0) {
483 /* ast_log uses us to format messages, so if we called ast_log, we'd be
484 * in for a nasty loop (seen already in testing) */
485 fprintf(stderr, "Unable to initialize kqueue(): %s\n", strerror(errno));
487
488 /* Okay to proceed */
491 return NULL;
492 }
493
496
498
499 for (;/*ever*/;) {
500 if (kevent(queue_fd, NULL, 0, &kev, 1, NULL) < 0) {
504 continue;
505 }
506
507 sp = (struct state *) kev.udata;
508
510 /* see comment near psx_sp in add_notify() */
511 if (sp == psx_sp) {
512 psx_sp = NULL;
513
514 sstate_free(sp);
515
516 while ((sp = AST_LIST_REMOVE_HEAD(&zonelist, list))) {
517 sstate_free(sp);
518 }
519 } else {
521 sstate_free(sp);
522 }
523
524 /* Just in case the signal was sent late */
527 }
528
530 return NULL;
531}
532
533static void kqueue_daemon_freestate(struct state *sp)
534{
535 struct kevent kev;
536 struct timespec no_wait = { 0, 1 };
537
538 /*!\note
539 * If the file event fired, then the file was removed, so we'll need
540 * to reparse the entry. The directory event is a bit more
541 * interesting. Unfortunately, the queue doesn't contain information
542 * about the file that changed (only the directory itself), so unless
543 * we kept a record of the directory state before, it's not really
544 * possible to know what change occurred. But if we act paranoid and
545 * just purge the associated file, then it will get reparsed, and
546 * everything works fine. It may be more work, but it's a vast
547 * improvement over the alternative implementation, which is to stat
548 * the file repeatedly in what is essentially a busy loop. */
549
550 if (sp->fd > -1) {
551 /* If the directory event fired, remove the file event */
552 EV_SET(&kev, sp->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
553 kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
554 }
555
556#ifdef HAVE_O_SYMLINK
557 if (sp->fds > -1) {
558 /* If the file event fired, remove the symlink event */
559 EV_SET(&kev, sp->fds, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
560 kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
561 }
562#else
563 if (sp->dir) {
564 /* If the file event fired, remove the directory event */
565 EV_SET(&kev, dirfd(sp->dir), EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
566 kevent(queue_fd, &kev, 1, NULL, 0, &no_wait);
567 }
568#endif
569}
570
571static void add_notify(struct state *sp, const char *path)
572{
573 struct kevent kev;
574 struct timespec no_wait = { 0, 1 };
575 char watchdir[PATH_MAX + 1] = "";
576
577 /* watch for flag indicating stack automatic sp,
578 * should not be added to watch
579 */
580 if (SP_STACK_CHECK(sp) || sp->fd != -1) {
581 return;
582 }
583
584 /* some errors might cause repeated calls to tzload()
585 * for TZDEFRULES more than once if errors repeat,
586 * so psx_sp is used to keep just one
587 */
588 if (!strcmp(path, TZDEFRULES) ||
589 !strcmp(path, TZDIR "/" TZDEFRULES)) {
590 int lckgot = AST_LIST_TRYLOCK(&zonelist);
591
592 if (lckgot) {
593 return;
594 }
595
596 if (psx_sp != NULL ||
597 (psx_sp = sstate_alloc()) == NULL) {
599 return;
600 }
601
603 sizeof(psx_sp->name));
604 sp = psx_sp;
606 }
607
612 if (!(ast_pthread_create_background(&inotify_thread, NULL, kqueue_daemon, NULL))) {
613 /* Give the thread a chance to initialize */
615 }
617 }
618
619 if (queue_fd < 0) {
620 /* Error already sent */
621 return;
622 }
623
624#ifdef HAVE_O_SYMLINK
625 if (readlink(path, watchdir, sizeof(watchdir) - 1) != -1 && (sp->fds = open(path, O_RDONLY | O_SYMLINK
626# ifdef HAVE_O_EVTONLY
627 | O_EVTONLY
628# endif
629 )) >= 0) {
630 EV_SET(&kev, sp->fds, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, EVVN_NOTES_BITS, 0, sp);
631 errno = 0;
632 if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
633 /* According to the API docs, we may get -1 return value, due to the
634 * NULL space for a returned event, but errno should be 0 unless
635 * there's a real error. Otherwise, kevent will return 0 to indicate
636 * that the time limit expired. */
637 fprintf(stderr, "Unable to watch '%s': %s\n", path, strerror(errno));
638 close(sp->fds);
639 sp->fds = -1;
640 }
641 }
642#else
643 if (readlink(path, watchdir, sizeof(watchdir) - 1) != -1) {
644 /* Special -- watch the directory for changes, because we cannot directly watch a symlink */
645 char *slash;
646
647 ast_copy_string(watchdir, path, sizeof(watchdir));
648
649 if ((slash = strrchr(watchdir, '/'))) {
650 *slash = '\0';
651 }
652 if (!(sp->dir = opendir(watchdir))) {
653 fprintf(stderr, "Unable to watch directory with symlink '%s': %s\n", path, strerror(errno));
654 goto watch_file;
655 }
656
657 /*!\note
658 * You may be wondering about whether there is a potential conflict
659 * with the kqueue interface, because we might be watching the same
660 * directory for multiple zones. The answer is no, because kqueue
661 * looks at the descriptor to know if there's a duplicate. Since we
662 * (may) have opened the directory multiple times, each represents a
663 * different event, so no replacement of an existing event will occur.
664 * Likewise, there's no potential leak of a descriptor.
665 */
666 EV_SET(&kev, dirfd(sp->dir), EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
667 EVVN_NOTES_BITS, 0, sp);
668 errno = 0;
669 if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
670 fprintf(stderr, "Unable to watch '%s': %s\n", watchdir, strerror(errno));
671 closedir(sp->dir);
672 sp->dir = NULL;
673 }
674 }
675
676watch_file:
677#endif
678
679 if ((sp->fd = open(path, O_RDONLY
680# ifdef HAVE_O_EVTONLY
681 | O_EVTONLY
682# endif
683 )) < 0) {
684 fprintf(stderr, "Unable to watch '%s' for changes: %s\n", path, strerror(errno));
685 return;
686 }
687
688 EV_SET(&kev, sp->fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, EVVN_NOTES_BITS, 0, sp);
689 errno = 0;
690 if (kevent(queue_fd, &kev, 1, NULL, 0, &no_wait) < 0 && errno != 0) {
691 /* According to the API docs, we may get -1 return value, due to the
692 * NULL space for a returned event, but errno should be 0 unless
693 * there's a real error. Otherwise, kevent will return 0 to indicate
694 * that the time limit expired. */
695 fprintf(stderr, "Unable to watch '%s': %s\n", path, strerror(errno));
696 close(sp->fd);
697 sp->fd = -1;
698 }
699}
700#else
701
702static void *notify_daemon(void *data)
703{
704 struct stat st, lst;
705 struct state *cur;
706 struct timespec sixty_seconds = { 60, 0 };
707
711
713
714 for (;/*ever*/;) {
715 char fullname[FILENAME_MAX + 1];
716
717 nanosleep(&sixty_seconds, NULL);
720 char *name = cur->name;
721
722 if (name[0] == ':')
723 ++name;
724 if (name[0] != '/') {
725 (void) strcpy(fullname, TZDIR "/");
726 (void) strcat(fullname, name);
727 name = fullname;
728 }
729 stat(name, &st);
730 lstat(name, &lst);
731 if (st.st_mtime > cur->mtime[0] || lst.st_mtime > cur->mtime[1]) {
732#ifdef TEST_FRAMEWORK
733 if (test) {
734 ast_test_status_update(test, "Removing cached TZ entry '%s' because underlying file changed. (%ld != %ld) or (%ld != %ld)\n", name, st.st_mtime, cur->mtime[0], lst.st_mtime, cur->mtime[1]);
735 } else
736#endif
737 {
738 ast_log(LOG_NOTICE, "Removing cached TZ entry '%s' because underlying file changed.\n", name);
739 }
741 sstate_free(cur);
742 continue;
743 }
744 }
748 }
750 return NULL;
751}
752
753static void add_notify(struct state *sp, const char *path)
754{
755 struct stat st;
756
761 if (!(ast_pthread_create_background(&inotify_thread, NULL, notify_daemon, NULL))) {
762 /* Give the thread a chance to initialize */
764 }
766 }
767
768 stat(path, &st);
769 sp->mtime[0] = st.st_mtime;
770 lstat(path, &st);
771 sp->mtime[1] = st.st_mtime;
772}
773#endif
774
775/*
776 * struct state allocator with additional setup as needed
777 */
778static struct state *sstate_alloc(void)
779{
780 struct state *p = ast_calloc(1, sizeof(*p));
781
782 if (p != NULL) {
783 SP_HEAP_INIT(p);
784 }
785
786 return p;
787}
788
789static void sstate_free(struct state *p)
790{
791 SP_HEAP_FREE(p);
792 ast_free(p);
793}
794
795void ast_localtime_wakeup_monitor(struct ast_test *info)
796{
797 struct timeval wait_now = ast_tvnow();
798 struct timespec wait_time = { .tv_sec = wait_now.tv_sec + 2, .tv_nsec = wait_now.tv_usec * 1000 };
799
802#ifdef TEST_FRAMEWORK
803 test = info;
804#endif
805 pthread_kill(inotify_thread, SIGURG);
807#ifdef TEST_FRAMEWORK
808 test = NULL;
809#endif
811 }
812}
813
814/*! \note
815** Section 4.12.3 of X3.159-1989 requires that
816** Except for the strftime function, these functions [asctime,
817** ctime, gmtime, localtime] return values in one of two static
818** objects: a broken-down time structure and an array of char.
819** Thanks to Paul Eggert for noting this.
820*/
821
822static long detzcode(const char * const codep)
823{
824 long result;
825 int i;
826
827 result = (codep[0] & 0x80) ? ~0L : 0;
828 for (i = 0; i < 4; ++i)
829 result = (result << 8) | (codep[i] & 0xff);
830 return result;
831}
832
833static time_t detzcode64(const char * const codep)
834{
835 time_t result;
836 int i;
837
838 result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0;
839 for (i = 0; i < 8; ++i)
840 result = result * 256 + (codep[i] & 0xff);
841 return result;
842}
843
844static int differ_by_repeat(const time_t t1, const time_t t0)
845{
846 const long long at1 = t1, at0 = t0;
847 if (TYPE_INTEGRAL(time_t) &&
848 TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
849 return 0;
850 return at1 - at0 == SECSPERREPEAT;
851}
852
853static int tzload(const char *name, struct state * const sp, const int doextend)
854{
855 const char * p;
856 int i;
857 int fid;
858 int stored;
859 int nread;
860 union {
861 struct tzhead tzhead;
862 char buf[2 * sizeof(struct tzhead) +
863 2 * sizeof *sp +
864 4 * TZ_MAX_TIMES];
865 } u;
866
867 if (name == NULL && (name = TZDEFAULT) == NULL)
868 return -1;
869 {
870 int doaccess;
871 /*
872 ** Section 4.9.1 of the C standard says that
873 ** "FILENAME_MAX expands to an integral constant expression
874 ** that is the size needed for an array of char large enough
875 ** to hold the longest file name string that the implementation
876 ** guarantees can be opened."
877 */
878 char fullname[FILENAME_MAX + 1];
879
880 if (name[0] == ':')
881 ++name;
882 doaccess = name[0] == '/';
883 if (!doaccess) {
884 if ((p = TZDIR) == NULL)
885 return -1;
886 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
887 return -1;
888 (void) strcpy(fullname, p);
889 (void) strcat(fullname, "/");
890 (void) strcat(fullname, name);
891 /*
892 ** Set doaccess if '.' (as in "../") shows up in name.
893 */
894 if (strchr(name, '.') != NULL)
895 doaccess = TRUE;
896 name = fullname;
897 }
898 if (doaccess && access(name, R_OK) != 0)
899 return -1;
900 if ((fid = open(name, OPEN_MODE)) == -1)
901 return -1;
902 if (ast_fully_booted) {
903 /* If we don't wait until Asterisk is fully booted, it's possible
904 * that the watcher thread gets started in the parent process,
905 * before daemon(3) is called, and the thread won't propagate to
906 * the child. Given that bootup only takes a few seconds, it's
907 * reasonable to only start the watcher later. */
908 add_notify(sp, name);
909 }
910 }
911 nread = read(fid, u.buf, sizeof u.buf);
912 /* comp nread < sizeof u.tzhead against unexpected short files */
913 if (close(fid) < 0 || nread < sizeof u.tzhead)
914 return -1;
915 for (stored = 4; stored <= 8; stored *= 2) {
916 int ttisstdcnt;
917 int ttisgmtcnt;
918
919 ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
920 ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
921 sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
922 sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
923 sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
924 sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
925 p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
926 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
927 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
928 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
929 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
930 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
931 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
932 return -1;
933 if (nread - (p - u.buf) <
934 sp->timecnt * stored + /* ats */
935 sp->timecnt + /* types */
936 sp->typecnt * 6 + /* ttinfos */
937 sp->charcnt + /* chars */
938 sp->leapcnt * (stored + 4) + /* lsinfos */
939 ttisstdcnt + /* ttisstds */
940 ttisgmtcnt) /* ttisgmts */
941 return -1;
942 for (i = 0; i < sp->timecnt; ++i) {
943 sp->ats[i] = (stored == 4) ?
944 detzcode(p) : detzcode64(p);
945 p += stored;
946 }
947 for (i = 0; i < sp->timecnt; ++i) {
948 sp->types[i] = (unsigned char) *p++;
949 if (sp->types[i] >= sp->typecnt)
950 return -1;
951 }
952 for (i = 0; i < sp->typecnt; ++i) {
953 struct ttinfo * ttisp;
954
955 ttisp = &sp->ttis[i];
956 ttisp->tt_gmtoff = detzcode(p);
957 p += 4;
958 ttisp->tt_isdst = (unsigned char) *p++;
959 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
960 return -1;
961 ttisp->tt_abbrind = (unsigned char) *p++;
962 if (ttisp->tt_abbrind < 0 ||
963 ttisp->tt_abbrind > sp->charcnt)
964 return -1;
965 }
966 for (i = 0; i < sp->charcnt; ++i)
967 sp->chars[i] = *p++;
968 sp->chars[i] = '\0'; /* ensure '\0' at end */
969 for (i = 0; i < sp->leapcnt; ++i) {
970 struct lsinfo * lsisp;
971
972 lsisp = &sp->lsis[i];
973 lsisp->ls_trans = (stored == 4) ?
974 detzcode(p) : detzcode64(p);
975 p += stored;
976 lsisp->ls_corr = detzcode(p);
977 p += 4;
978 }
979 for (i = 0; i < sp->typecnt; ++i) {
980 struct ttinfo * ttisp;
981
982 ttisp = &sp->ttis[i];
983 if (ttisstdcnt == 0)
984 ttisp->tt_ttisstd = FALSE;
985 else {
986 ttisp->tt_ttisstd = *p++;
987 if (ttisp->tt_ttisstd != TRUE &&
988 ttisp->tt_ttisstd != FALSE)
989 return -1;
990 }
991 }
992 for (i = 0; i < sp->typecnt; ++i) {
993 struct ttinfo * ttisp;
994
995 ttisp = &sp->ttis[i];
996 if (ttisgmtcnt == 0)
997 ttisp->tt_ttisgmt = FALSE;
998 else {
999 ttisp->tt_ttisgmt = *p++;
1000 if (ttisp->tt_ttisgmt != TRUE &&
1001 ttisp->tt_ttisgmt != FALSE)
1002 return -1;
1003 }
1004 }
1005 /*
1006 ** Out-of-sort ats should mean we're running on a
1007 ** signed time_t system but using a data file with
1008 ** unsigned values (or vice versa).
1009 */
1010 for (i = 0; i < sp->timecnt - 2; ++i)
1011 if (sp->ats[i] > sp->ats[i + 1]) {
1012 ++i;
1013 if (TYPE_SIGNED(time_t)) {
1014 /*
1015 ** Ignore the end (easy).
1016 */
1017 sp->timecnt = i;
1018 } else {
1019 /*
1020 ** Ignore the beginning (harder).
1021 */
1022 int j;
1023
1024 for (j = 0; j + i < sp->timecnt; ++j) {
1025 sp->ats[j] = sp->ats[j + i];
1026 sp->types[j] = sp->types[j + i];
1027 }
1028 sp->timecnt = j;
1029 }
1030 break;
1031 }
1032 /*
1033 ** If this is an old file, we're done.
1034 */
1035 if (u.tzhead.tzh_version[0] == '\0')
1036 break;
1037 nread -= p - u.buf;
1038 for (i = 0; i < nread; ++i)
1039 u.buf[i] = p[i];
1040 /* next loop iter. will assume at least
1041 sizeof(struct tzhead) bytes */
1042 if (nread < sizeof(u.tzhead)) {
1043 break;
1044 }
1045 /*
1046 ** If this is a narrow integer time_t system, we're done.
1047 */
1048 if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
1049 break;
1050 }
1051 if (doextend && nread > 2 &&
1052 u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
1053 sp->typecnt + 2 <= TZ_MAX_TYPES) {
1054 struct state ts;
1055 int result;
1056
1057 /* for temporary struct state --
1058 * macro flags the struct as a stack temp.
1059 * to prevent use within add_notify()
1060 */
1061 SP_STACK_INIT(ts);
1062
1063 u.buf[nread - 1] = '\0';
1064 result = tzparse(&u.buf[1], &ts, FALSE);
1065 if (result == 0 && ts.typecnt == 2 &&
1066 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
1067 for (i = 0; i < 2; ++i)
1068 ts.ttis[i].tt_abbrind +=
1069 sp->charcnt;
1070 for (i = 0; i < ts.charcnt; ++i)
1071 sp->chars[sp->charcnt++] =
1072 ts.chars[i];
1073 i = 0;
1074 while (i < ts.timecnt &&
1075 ts.ats[i] <=
1076 sp->ats[sp->timecnt - 1])
1077 ++i;
1078 while (i < ts.timecnt &&
1079 sp->timecnt < TZ_MAX_TIMES) {
1080 sp->ats[sp->timecnt] =
1081 ts.ats[i];
1082 sp->types[sp->timecnt] =
1083 sp->typecnt +
1084 ts.types[i];
1085 ++sp->timecnt;
1086 ++i;
1087 }
1088 sp->ttis[sp->typecnt++] = ts.ttis[0];
1089 sp->ttis[sp->typecnt++] = ts.ttis[1];
1090 }
1091 }
1092 i = 2 * YEARSPERREPEAT;
1093 sp->goback = sp->goahead = sp->timecnt > i;
1094 sp->goback = sp->goback && sp->types[i] == sp->types[0] &&
1095 differ_by_repeat(sp->ats[i], sp->ats[0]);
1096 sp->goahead = sp->goahead &&
1097 sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
1098 differ_by_repeat(sp->ats[sp->timecnt - 1],
1099 sp->ats[sp->timecnt - 1 - i]);
1100 return 0;
1101}
1102
1103static const int mon_lengths[2][MONSPERYEAR] = {
1104 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
1105 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
1106};
1107
1108static const int year_lengths[2] = {
1110};
1111
1112/*! \brief
1113** Given a pointer into a time zone string, scan until a character that is not
1114** a valid character in a zone name is found. Return a pointer to that
1115** character.
1116*/
1117
1118static const char * getzname(const char *strp)
1119{
1120 char c;
1121
1122 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
1123 c != '+')
1124 ++strp;
1125 return strp;
1126}
1127
1128/*! \brief
1129** Given a pointer into an extended time zone string, scan until the ending
1130** delimiter of the zone name is located. Return a pointer to the delimiter.
1131**
1132** As with getzname above, the legal character set is actually quite
1133** restricted, with other characters producing undefined results.
1134** We don't do any checking here; checking is done later in common-case code.
1135*/
1136
1137static const char * getqzname(const char *strp, const int delim)
1138{
1139 int c;
1140
1141 while ((c = *strp) != '\0' && c != delim)
1142 ++strp;
1143 return strp;
1144}
1145
1146/*! \brief
1147** Given a pointer into a time zone string, extract a number from that string.
1148** Check that the number is within a specified range; if it is not, return
1149** NULL.
1150** Otherwise, return a pointer to the first character not part of the number.
1151*/
1152
1153static const char *getnum(const char *strp, int *nump, const int min, const int max)
1154{
1155 char c;
1156 int num;
1157
1158 if (strp == NULL || !is_digit(c = *strp))
1159 return NULL;
1160 num = 0;
1161 do {
1162 num = num * 10 + (c - '0');
1163 if (num > max)
1164 return NULL; /* illegal value */
1165 c = *++strp;
1166 } while (is_digit(c));
1167 if (num < min)
1168 return NULL; /* illegal value */
1169 *nump = num;
1170 return strp;
1171}
1172
1173/*! \brief
1174** Given a pointer into a time zone string, extract a number of seconds,
1175** in hh[:mm[:ss]] form, from the string.
1176** If any error occurs, return NULL.
1177** Otherwise, return a pointer to the first character not part of the number
1178** of seconds.
1179*/
1180
1181static const char *getsecs(const char *strp, long * const secsp)
1182{
1183 int num;
1184
1185 /*
1186 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
1187 ** "M10.4.6/26", which does not conform to Posix,
1188 ** but which specifies the equivalent of
1189 ** ``02:00 on the first Sunday on or after 23 Oct''.
1190 */
1191 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
1192 if (strp == NULL)
1193 return NULL;
1194 *secsp = num * (long) SECSPERHOUR;
1195 if (*strp == ':') {
1196 ++strp;
1197 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
1198 if (strp == NULL)
1199 return NULL;
1200 *secsp += num * SECSPERMIN;
1201 if (*strp == ':') {
1202 ++strp;
1203 /* `SECSPERMIN' allows for leap seconds. */
1204 strp = getnum(strp, &num, 0, SECSPERMIN);
1205 if (strp == NULL)
1206 return NULL;
1207 *secsp += num;
1208 }
1209 }
1210 return strp;
1211}
1212
1213/*! \brief
1214** Given a pointer into a time zone string, extract an offset, in
1215** [+-]hh[:mm[:ss]] form, from the string.
1216** If any error occurs, return NULL.
1217** Otherwise, return a pointer to the first character not part of the time.
1218*/
1219
1220static const char *getoffset(const char *strp, long *offsetp)
1221{
1222 int neg = 0;
1223
1224 if (*strp == '-') {
1225 neg = 1;
1226 ++strp;
1227 } else if (*strp == '+')
1228 ++strp;
1229 strp = getsecs(strp, offsetp);
1230 if (strp == NULL)
1231 return NULL; /* illegal time */
1232 if (neg)
1233 *offsetp = -*offsetp;
1234 return strp;
1235}
1236
1237/*! \brief
1238** Given a pointer into a time zone string, extract a rule in the form
1239** date[/time]. See POSIX section 8 for the format of "date" and "time".
1240** If a valid rule is not found, return NULL.
1241** Otherwise, return a pointer to the first character not part of the rule.
1242*/
1243
1244static const char *getrule(const char *strp, struct rule *rulep)
1245{
1246 if (*strp == 'J') {
1247 /*
1248 ** Julian day.
1249 */
1250 rulep->r_type = JULIAN_DAY;
1251 ++strp;
1252 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
1253 } else if (*strp == 'M') {
1254 /*
1255 ** Month, week, day.
1256 */
1258 ++strp;
1259 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
1260 if (strp == NULL)
1261 return NULL;
1262 if (*strp++ != '.')
1263 return NULL;
1264 strp = getnum(strp, &rulep->r_week, 1, 5);
1265 if (strp == NULL)
1266 return NULL;
1267 if (*strp++ != '.')
1268 return NULL;
1269 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
1270 } else if (is_digit(*strp)) {
1271 /*
1272 ** Day of year.
1273 */
1274 rulep->r_type = DAY_OF_YEAR;
1275 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
1276 } else return NULL; /* invalid format */
1277 if (strp == NULL)
1278 return NULL;
1279 if (*strp == '/') {
1280 /*
1281 ** Time specified.
1282 */
1283 ++strp;
1284 strp = getsecs(strp, &rulep->r_time);
1285 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
1286 return strp;
1287}
1288
1289/*! \brief
1290** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
1291** year, a rule, and the offset from UTC at the time that rule takes effect,
1292** calculate the Epoch-relative time that rule takes effect.
1293*/
1294
1295static time_t transtime(const time_t janfirst, const int year, const struct rule *rulep, const long offset)
1296{
1297 int leapyear;
1298 time_t value;
1299 int i;
1300 int d, m1, yy0, yy1, yy2, dow;
1301
1303 leapyear = isleap(year);
1304 switch (rulep->r_type) {
1305
1306 case JULIAN_DAY:
1307 /*
1308 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
1309 ** years.
1310 ** In non-leap years, or if the day number is 59 or less, just
1311 ** add SECSPERDAY times the day number-1 to the time of
1312 ** January 1, midnight, to get the day.
1313 */
1314 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
1315 if (leapyear && rulep->r_day >= 60)
1316 value += SECSPERDAY;
1317 break;
1318
1319 case DAY_OF_YEAR:
1320 /*
1321 ** n - day of year.
1322 ** Just add SECSPERDAY times the day number to the time of
1323 ** January 1, midnight, to get the day.
1324 */
1325 value = janfirst + rulep->r_day * SECSPERDAY;
1326 break;
1327
1329 /*
1330 ** Mm.n.d - nth "dth day" of month m.
1331 */
1332 value = janfirst;
1333 for (i = 0; i < rulep->r_mon - 1; ++i)
1334 value += mon_lengths[leapyear][i] * SECSPERDAY;
1335
1336 /*
1337 ** Use Zeller's Congruence to get day-of-week of first day of
1338 ** month.
1339 */
1340 m1 = (rulep->r_mon + 9) % 12 + 1;
1341 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
1342 yy1 = yy0 / 100;
1343 yy2 = yy0 % 100;
1344 dow = ((26 * m1 - 2) / 10 +
1345 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
1346 if (dow < 0)
1347 dow += DAYSPERWEEK;
1348
1349 /*
1350 ** "dow" is the day-of-week of the first day of the month. Get
1351 ** the day-of-month (zero-origin) of the first "dow" day of the
1352 ** month.
1353 */
1354 d = rulep->r_day - dow;
1355 if (d < 0)
1356 d += DAYSPERWEEK;
1357 for (i = 1; i < rulep->r_week; ++i) {
1358 if (d + DAYSPERWEEK >=
1359 mon_lengths[leapyear][rulep->r_mon - 1])
1360 break;
1361 d += DAYSPERWEEK;
1362 }
1363
1364 /*
1365 ** "d" is the day-of-month (zero-origin) of the day we want.
1366 */
1367 value += d * SECSPERDAY;
1368 break;
1369 }
1370
1371 /*
1372 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
1373 ** question. To get the Epoch-relative time of the specified local
1374 ** time on that day, add the transition time and the current offset
1375 ** from UTC.
1376 */
1377 return value + rulep->r_time + offset;
1378}
1379
1380/*! \note
1381** Given a POSIX section 8-style TZ string, fill in the rule tables as
1382** appropriate.
1383*/
1384
1385static int tzparse(const char *name, struct state *sp, const int lastditch)
1386{
1387 const char * stdname;
1388 const char * dstname;
1389 size_t stdlen;
1390 size_t dstlen;
1391 long stdoffset;
1392 long dstoffset;
1393 time_t * atp;
1394 unsigned char * typep;
1395 char * cp;
1396 int load_result;
1397
1398 INITIALIZE(dstname);
1399 stdname = name;
1400 if (lastditch) {
1401 stdlen = strlen(name); /* length of standard zone name */
1402 name += stdlen;
1403 if (stdlen >= sizeof sp->chars)
1404 stdlen = (sizeof sp->chars) - 1;
1405 stdoffset = 0;
1406 } else {
1407 if (*name == '<') {
1408 name++;
1409 stdname = name;
1410 name = getqzname(name, '>');
1411 if (*name != '>')
1412 return -1;
1413 stdlen = name - stdname;
1414 name++;
1415 } else {
1416 name = getzname(name);
1417 stdlen = name - stdname;
1418 }
1419 if (*name == '\0')
1420 return -1;
1421 name = getoffset(name, &stdoffset);
1422 if (name == NULL)
1423 return -1;
1424 }
1425 load_result = tzload(TZDEFRULES, sp, FALSE);
1426 if (load_result != 0)
1427 sp->leapcnt = 0; /* so, we're off a little */
1428 if (*name != '\0') {
1429 if (*name == '<') {
1430 dstname = ++name;
1431 name = getqzname(name, '>');
1432 if (*name != '>')
1433 return -1;
1434 dstlen = name - dstname;
1435 name++;
1436 } else {
1437 dstname = name;
1438 name = getzname(name);
1439 dstlen = name - dstname; /* length of DST zone name */
1440 }
1441 if (*name != '\0' && *name != ',' && *name != ';') {
1442 name = getoffset(name, &dstoffset);
1443 if (name == NULL)
1444 return -1;
1445 } else dstoffset = stdoffset - SECSPERHOUR;
1446 if (*name == '\0' && load_result != 0)
1448 if (*name == ',' || *name == ';') {
1449 struct rule start;
1450 struct rule end;
1451 int year;
1452 time_t janfirst;
1453 time_t starttime;
1454 time_t endtime;
1455
1456 ++name;
1457 if ((name = getrule(name, &start)) == NULL)
1458 return -1;
1459 if (*name++ != ',')
1460 return -1;
1461 if ((name = getrule(name, &end)) == NULL)
1462 return -1;
1463 if (*name != '\0')
1464 return -1;
1465 sp->typecnt = 2; /* standard time and DST */
1466 /*
1467 ** Two transitions per year, from EPOCH_YEAR forward.
1468 */
1469 sp->ttis[0].tt_gmtoff = -dstoffset;
1470 sp->ttis[0].tt_isdst = 1;
1471 sp->ttis[0].tt_abbrind = stdlen + 1;
1472 sp->ttis[1].tt_gmtoff = -stdoffset;
1473 sp->ttis[1].tt_isdst = 0;
1474 sp->ttis[1].tt_abbrind = 0;
1475 atp = sp->ats;
1476 typep = sp->types;
1477 janfirst = 0;
1478 sp->timecnt = 0;
1479 for (year = EPOCH_YEAR;
1480 sp->timecnt + 2 <= TZ_MAX_TIMES;
1481 ++year) {
1482 time_t newfirst;
1483
1484 starttime = transtime(janfirst, year, &start,
1485 stdoffset);
1486 endtime = transtime(janfirst, year, &end,
1487 dstoffset);
1488 if (starttime > endtime) {
1489 *atp++ = endtime;
1490 *typep++ = 1; /* DST ends */
1491 *atp++ = starttime;
1492 *typep++ = 0; /* DST begins */
1493 } else {
1494 *atp++ = starttime;
1495 *typep++ = 0; /* DST begins */
1496 *atp++ = endtime;
1497 *typep++ = 1; /* DST ends */
1498 }
1499 sp->timecnt += 2;
1500 newfirst = janfirst;
1501 newfirst += year_lengths[isleap(year)] *
1502 SECSPERDAY;
1503 if (newfirst <= janfirst)
1504 break;
1505 janfirst = newfirst;
1506 }
1507 } else {
1508 long theirstdoffset;
1509 long theiroffset;
1510 int i;
1511 int j;
1512
1513 if (*name != '\0')
1514 return -1;
1515 /*
1516 ** Initial values of theirstdoffset.
1517 */
1518 theirstdoffset = 0;
1519 for (i = 0; i < sp->timecnt; ++i) {
1520 j = sp->types[i];
1521 if (!sp->ttis[j].tt_isdst) {
1522 theirstdoffset =
1523 -sp->ttis[j].tt_gmtoff;
1524 break;
1525 }
1526 }
1527 theiroffset = theirstdoffset;
1528 /*
1529 ** Now juggle transition times and types
1530 ** tracking offsets as you do.
1531 */
1532 for (i = 0; i < sp->timecnt; ++i) {
1533 j = sp->types[i];
1534 sp->types[i] = sp->ttis[j].tt_isdst;
1535 if (sp->ttis[j].tt_ttisgmt) {
1536 /* No adjustment to transition time */
1537 } else {
1538 /* Add the standard time offset to the transition time. */
1539 sp->ats[i] += stdoffset - theirstdoffset;
1540 }
1541 theiroffset = -sp->ttis[j].tt_gmtoff;
1542 if (!sp->ttis[j].tt_isdst) {
1543 theirstdoffset = theiroffset;
1544 }
1545 }
1546 /*
1547 ** Finally, fill in ttis.
1548 ** ttisstd and ttisgmt need not be handled.
1549 */
1550 sp->ttis[0].tt_gmtoff = -stdoffset;
1551 sp->ttis[0].tt_isdst = FALSE;
1552 sp->ttis[0].tt_abbrind = 0;
1553 sp->ttis[1].tt_gmtoff = -dstoffset;
1554 sp->ttis[1].tt_isdst = TRUE;
1555 sp->ttis[1].tt_abbrind = stdlen + 1;
1556 sp->typecnt = 2;
1557 }
1558 } else {
1559 dstlen = 0;
1560 sp->typecnt = 1; /* only standard time */
1561 sp->timecnt = 0;
1562 sp->ttis[0].tt_gmtoff = -stdoffset;
1563 sp->ttis[0].tt_isdst = 0;
1564 sp->ttis[0].tt_abbrind = 0;
1565 }
1566 sp->charcnt = stdlen + 1;
1567 if (dstlen != 0)
1568 sp->charcnt += dstlen + 1;
1569 if ((size_t) sp->charcnt > sizeof sp->chars)
1570 return -1;
1571 cp = sp->chars;
1572 (void) strncpy(cp, stdname, stdlen);
1573 cp += stdlen;
1574 *cp++ = '\0';
1575 if (dstlen != 0) {
1576 (void) strncpy(cp, dstname, dstlen);
1577 *(cp + dstlen) = '\0';
1578 }
1579 return 0;
1580}
1581
1582static int gmtload(struct state *sp)
1583{
1584 if (tzload(gmt, sp, TRUE) != 0)
1585 return tzparse(gmt, sp, TRUE);
1586 else
1587 return -1;
1588}
1589
1591{
1592 struct state *sp;
1593
1595 while ((sp = AST_LIST_REMOVE_HEAD(&zonelist, list))) {
1596 sstate_free(sp);
1597 }
1599}
1600
1601static const struct state *ast_tzset(const char *zone)
1602{
1603 struct state *sp;
1604
1605 if (ast_strlen_zero(zone)) {
1606#ifdef SOLARIS
1607 zone = getenv("TZ");
1608 if (ast_strlen_zero(zone)) {
1609 zone = "GMT";
1610 }
1611#else
1612 zone = "/etc/localtime";
1613#endif
1614 }
1615
1618 if (!strcmp(sp->name, zone)) {
1620 return sp;
1621 }
1622 }
1623
1624 if (!(sp = sstate_alloc())) {
1626 return NULL;
1627 }
1628
1629 if (tzload(zone, sp, TRUE) != 0) {
1630 if (zone[0] == ':' || tzparse(zone, sp, FALSE) != 0)
1631 (void) gmtload(sp);
1632 }
1633 ast_copy_string(sp->name, zone, sizeof(sp->name));
1636 return sp;
1637}
1638
1639/*! \note
1640** The easy way to behave "as if no library function calls" localtime
1641** is to not call it--so we drop its guts into "localsub", which can be
1642** freely called. (And no, the PANS doesn't require the above behavior--
1643** but it *is* desirable.)
1644**
1645** The unused offset argument is for the benefit of mktime variants.
1646*/
1647
1648static struct ast_tm *localsub(const struct timeval *timep, const long offset, struct ast_tm *tmp, const struct state *sp)
1649{
1650 const struct ttinfo * ttisp;
1651 int i;
1652 struct ast_tm * result;
1653 struct timeval t;
1654 memcpy(&t, timep, sizeof(t));
1655
1656 if (sp == NULL)
1657 return gmtsub(timep, offset, tmp);
1658 if ((sp->goback && t.tv_sec < sp->ats[0]) ||
1659 (sp->goahead && t.tv_sec > sp->ats[sp->timecnt - 1])) {
1660 struct timeval newt = t;
1661 time_t seconds;
1662 time_t tcycles;
1663 int_fast64_t icycles;
1664
1665 if (t.tv_sec < sp->ats[0])
1666 seconds = sp->ats[0] - t.tv_sec;
1667 else seconds = t.tv_sec - sp->ats[sp->timecnt - 1];
1668 --seconds;
1669 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1670 ++tcycles;
1671 icycles = tcycles;
1672 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1673 return NULL;
1674 seconds = icycles;
1675 seconds *= YEARSPERREPEAT;
1676 seconds *= AVGSECSPERYEAR;
1677 if (t.tv_sec < sp->ats[0])
1678 newt.tv_sec += seconds;
1679 else newt.tv_sec -= seconds;
1680 if (newt.tv_sec < sp->ats[0] ||
1681 newt.tv_sec > sp->ats[sp->timecnt - 1])
1682 return NULL; /* "cannot happen" */
1683 result = localsub(&newt, offset, tmp, sp);
1684 if (result == tmp) {
1685 time_t newy;
1686
1687 newy = tmp->tm_year;
1688 if (t.tv_sec < sp->ats[0])
1689 newy -= icycles * YEARSPERREPEAT;
1690 else
1691 newy += icycles * YEARSPERREPEAT;
1692 tmp->tm_year = newy;
1693 if (tmp->tm_year != newy)
1694 return NULL;
1695 }
1696 return result;
1697 }
1698 if (sp->timecnt == 0 || t.tv_sec < sp->ats[0]) {
1699 i = 0;
1700 while (sp->ttis[i].tt_isdst) {
1701 if (++i >= sp->typecnt) {
1702 i = 0;
1703 break;
1704 }
1705 }
1706 } else {
1707 int lo = 1;
1708 int hi = sp->timecnt;
1709
1710 while (lo < hi) {
1711 int mid = (lo + hi) >> 1;
1712
1713 if (t.tv_sec < sp->ats[mid])
1714 hi = mid;
1715 else
1716 lo = mid + 1;
1717 }
1718 i = (int) sp->types[lo - 1];
1719 }
1720 ttisp = &sp->ttis[i];
1721 /*
1722 ** To get (wrong) behavior that's compatible with System V Release 2.0
1723 ** you'd replace the statement below with
1724 ** t += ttisp->tt_gmtoff;
1725 ** timesub(&t, 0L, sp, tmp);
1726 */
1727 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1728 tmp->tm_isdst = ttisp->tt_isdst;
1729#ifndef SOLARIS /* Solaris doesn't have this element */
1730 tmp->tm_gmtoff = ttisp->tt_gmtoff;
1731#endif
1732#ifdef TM_ZONE
1733 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
1734#endif /* defined TM_ZONE */
1735 tmp->tm_usec = timep->tv_usec;
1736 return result;
1737}
1738
1739struct ast_tm *ast_localtime(const struct timeval *timep, struct ast_tm *tmp, const char *zone)
1740{
1741 const struct state *sp = ast_tzset(zone);
1742 memset(tmp, 0, sizeof(*tmp));
1743 return sp ? localsub(timep, 0L, tmp, sp) : NULL;
1744}
1745
1746/*
1747** This function provides informaton about daylight savings time
1748** for the given timezone. This includes whether it can determine
1749** if daylight savings is used for this timezone, the UTC times for
1750** when daylight savings transitions, and the offset in seconds from
1751** UTC.
1752*/
1753
1754void ast_get_dst_info(const time_t * const timep, int *dst_enabled, time_t *dst_start, time_t *dst_end, int *gmt_off, const char * const zone)
1755{
1756 int i;
1757 int transition1 = -1;
1758 int transition2 = -1;
1759 time_t seconds;
1760 int bounds_exceeded = 0;
1761 time_t t = *timep;
1762 const struct state *sp;
1763
1764 if (NULL == dst_enabled)
1765 return;
1766 *dst_enabled = 0;
1767
1768 if (NULL == dst_start || NULL == dst_end || NULL == gmt_off)
1769 return;
1770
1771 *gmt_off = 0;
1772
1773 sp = ast_tzset(zone);
1774 if (NULL == sp)
1775 return;
1776
1777 /* If the desired time exceeds the bounds of the defined time transitions
1778 * then give up on determining DST info and simply look for gmt offset
1779 * This requires that I adjust the given time using increments of Gregorian
1780 * repeats to place the time within the defined time transitions in the
1781 * timezone structure.
1782 */
1783 if ((sp->goback && t < sp->ats[0]) ||
1784 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1785 time_t tcycles;
1786 int_fast64_t icycles;
1787
1788 if (t < sp->ats[0])
1789 seconds = sp->ats[0] - t;
1790 else seconds = t - sp->ats[sp->timecnt - 1];
1791 --seconds;
1792 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1793 ++tcycles;
1794 icycles = tcycles;
1795 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1796 return;
1797 seconds = icycles;
1798 seconds *= YEARSPERREPEAT;
1799 seconds *= AVGSECSPERYEAR;
1800 if (t < sp->ats[0])
1801 t += seconds;
1802 else
1803 t -= seconds;
1804
1805 if (t < sp->ats[0] || t > sp->ats[sp->timecnt - 1])
1806 return; /* "cannot happen" */
1807
1808 bounds_exceeded = 1;
1809 }
1810
1811 if (sp->timecnt == 0 || t < sp->ats[0]) {
1812 /* I have no transition times or I'm before time */
1813 *dst_enabled = 0;
1814 /* Find where I can get gmtoff */
1815 i = 0;
1816 while (sp->ttis[i].tt_isdst) {
1817 if (++i >= sp->typecnt) {
1818 i = 0;
1819 break;
1820 }
1821 }
1822 *gmt_off = sp->ttis[i].tt_gmtoff;
1823 return;
1824 }
1825
1826 for (i = 1; i < sp->timecnt; ++i) {
1827 if (t < sp->ats[i]) {
1828 transition1 = sp->types[i - 1];
1829 transition2 = sp->types[i];
1830 break;
1831 }
1832 }
1833 /* if I found transition times that do not bounded the given time and these correspond to
1834 or the bounding zones do not reflect a changes in day light savings, then I do not have dst active */
1835 if (i >= sp->timecnt || 0 > transition1 || 0 > transition2 ||
1836 (sp->ttis[transition1].tt_isdst == sp->ttis[transition2].tt_isdst)) {
1837 *dst_enabled = 0;
1838 *gmt_off = sp->ttis[sp->types[sp->timecnt -1]].tt_gmtoff;
1839 } else {
1840 /* I have valid daylight savings information. */
1841 if(sp->ttis[transition2].tt_isdst)
1842 *gmt_off = sp->ttis[transition1].tt_gmtoff;
1843 else
1844 *gmt_off = sp->ttis[transition2].tt_gmtoff;
1845
1846 /* If I adjusted the time earlier, indicate that the dst is invalid */
1847 if (!bounds_exceeded) {
1848 *dst_enabled = 1;
1849 /* Determine which of the bounds is the start of daylight savings and which is the end */
1850 if(sp->ttis[transition2].tt_isdst) {
1851 *dst_start = sp->ats[i];
1852 *dst_end = sp->ats[i -1];
1853 } else {
1854 *dst_start = sp->ats[i -1];
1855 *dst_end = sp->ats[i];
1856 }
1857 }
1858 }
1859 return;
1860}
1861
1862/*
1863** gmtsub is to gmtime as localsub is to localtime.
1864*/
1865
1866static struct ast_tm *gmtsub(const struct timeval *timep, const long offset, struct ast_tm *tmp)
1867{
1868 struct ast_tm * result;
1869 struct state *sp;
1870
1873 if (!strcmp(sp->name, "UTC"))
1874 break;
1875 }
1876
1877 if (!sp) {
1878 if (!(sp = sstate_alloc())) {
1880 return NULL;
1881 }
1882 gmtload(sp);
1884 }
1886
1887 result = timesub(timep, offset, sp, tmp);
1888#ifdef TM_ZONE
1889 /*
1890 ** Could get fancy here and deliver something such as
1891 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
1892 ** but this is no time for a treasure hunt.
1893 */
1894 if (offset != 0)
1895 tmp->TM_ZONE = " ";
1896 else
1897 tmp->TM_ZONE = sp->chars;
1898#endif /* defined TM_ZONE */
1899 return result;
1900}
1901
1902/*! \brief
1903** Return the number of leap years through the end of the given year
1904** where, to make the math easy, the answer for year zero is defined as zero.
1905*/
1906
1907static int leaps_thru_end_of(const int y)
1908{
1909 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1910 -(leaps_thru_end_of(-(y + 1)) + 1);
1911}
1912
1913static struct ast_tm *timesub(const struct timeval *timep, const long offset, const struct state *sp, struct ast_tm *tmp)
1914{
1915 const struct lsinfo * lp;
1916 time_t tdays;
1917 int idays; /* unsigned would be so 2003 */
1918 long rem;
1919 int y;
1920 const int * ip;
1921 long corr;
1922 int hit;
1923 int i;
1924 long seconds;
1925
1926
1927 corr = 0;
1928 hit = 0;
1929 i = (sp == NULL) ? 0 : sp->leapcnt;
1930 while (--i >= 0) {
1931 lp = &sp->lsis[i];
1932 if (timep->tv_sec >= lp->ls_trans) {
1933 if (timep->tv_sec == lp->ls_trans) {
1934 hit = ((i == 0 && lp->ls_corr > 0) ||
1935 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1936 if (hit)
1937 while (i > 0 &&
1938 sp->lsis[i].ls_trans ==
1939 sp->lsis[i - 1].ls_trans + 1 &&
1940 sp->lsis[i].ls_corr ==
1941 sp->lsis[i - 1].ls_corr + 1) {
1942 ++hit;
1943 --i;
1944 }
1945 }
1946 corr = lp->ls_corr;
1947 break;
1948 }
1949 }
1950 y = EPOCH_YEAR;
1951 tdays = timep->tv_sec / SECSPERDAY;
1952 rem = timep->tv_sec - tdays * SECSPERDAY;
1953 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1954 int newy;
1955 time_t tdelta;
1956 int idelta;
1957 int leapdays;
1958
1959 tdelta = tdays / DAYSPERLYEAR;
1960 idelta = tdelta;
1961 if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1962 return NULL;
1963 if (idelta == 0)
1964 idelta = (tdays < 0) ? -1 : 1;
1965 newy = y;
1966 if (increment_overflow(&newy, idelta))
1967 return NULL;
1968 leapdays = leaps_thru_end_of(newy - 1) -
1969 leaps_thru_end_of(y - 1);
1970 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1971 tdays -= leapdays;
1972 y = newy;
1973 }
1974
1975 seconds = tdays * SECSPERDAY + 0.5;
1976 tdays = seconds / SECSPERDAY;
1977 rem += seconds - tdays * SECSPERDAY;
1978
1979 /*
1980 ** Given the range, we can now fearlessly cast...
1981 */
1982 idays = tdays;
1983 rem += offset - corr;
1984 while (rem < 0) {
1985 rem += SECSPERDAY;
1986 --idays;
1987 }
1988 while (rem >= SECSPERDAY) {
1989 rem -= SECSPERDAY;
1990 ++idays;
1991 }
1992 while (idays < 0) {
1993 if (increment_overflow(&y, -1))
1994 return NULL;
1995 idays += year_lengths[isleap(y)];
1996 }
1997 while (idays >= year_lengths[isleap(y)]) {
1998 idays -= year_lengths[isleap(y)];
1999 if (increment_overflow(&y, 1))
2000 return NULL;
2001 }
2002 tmp->tm_year = y;
2003 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
2004 return NULL;
2005 tmp->tm_yday = idays;
2006 /*
2007 ** The "extra" mods below avoid overflow problems.
2008 */
2009 tmp->tm_wday = EPOCH_WDAY +
2010 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
2012 leaps_thru_end_of(y - 1) -
2014 idays;
2015 tmp->tm_wday %= DAYSPERWEEK;
2016 if (tmp->tm_wday < 0)
2017 tmp->tm_wday += DAYSPERWEEK;
2018 tmp->tm_hour = (int) (rem / SECSPERHOUR);
2019 rem %= SECSPERHOUR;
2020 tmp->tm_min = (int) (rem / SECSPERMIN);
2021 /*
2022 ** A positive leap second requires a special
2023 ** representation. This uses "... ??:59:60" et seq.
2024 */
2025 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
2026 ip = mon_lengths[isleap(y)];
2027 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
2028 idays -= ip[tmp->tm_mon];
2029 tmp->tm_mday = (int) (idays + 1);
2030 tmp->tm_isdst = 0;
2031#ifdef TM_GMTOFF
2032 tmp->TM_GMTOFF = offset;
2033#endif /* defined TM_GMTOFF */
2034 tmp->tm_usec = timep->tv_usec;
2035 return tmp;
2036}
2037
2038/*! \note
2039** Adapted from code provided by Robert Elz, who writes:
2040** The "best" way to do mktime I think is based on an idea of Bob
2041** Kridle's (so its said...) from a long time ago.
2042** It does a binary search of the time_t space. Since time_t's are
2043** just 32 bits, its a max of 32 iterations (even at 64 bits it
2044** would still be very reasonable).
2045*/
2046
2047/*! \brief
2048** Simplified normalize logic courtesy Paul Eggert.
2049*/
2050
2051static int increment_overflow(int *number, int delta)
2052{
2053 int number0;
2054
2055 number0 = *number;
2056 *number += delta;
2057 return (*number < number0) != (delta < 0);
2058}
2059
2060static int long_increment_overflow(long *number, int delta)
2061{
2062 long number0;
2063
2064 number0 = *number;
2065 *number += delta;
2066 return (*number < number0) != (delta < 0);
2067}
2068
2069static int normalize_overflow(int *tensptr, int *unitsptr, const int base)
2070{
2071 int tensdelta;
2072
2073 tensdelta = (*unitsptr >= 0) ?
2074 (*unitsptr / base) :
2075 (-1 - (-1 - *unitsptr) / base);
2076 *unitsptr -= tensdelta * base;
2077 return increment_overflow(tensptr, tensdelta);
2078}
2079
2080static int long_normalize_overflow(long *tensptr, int *unitsptr, const int base)
2081{
2082 int tensdelta;
2083
2084 tensdelta = (*unitsptr >= 0) ?
2085 (*unitsptr / base) :
2086 (-1 - (-1 - *unitsptr) / base);
2087 *unitsptr -= tensdelta * base;
2088 return long_increment_overflow(tensptr, tensdelta);
2089}
2090
2091static int tmcomp(const struct ast_tm *atmp, const struct ast_tm *btmp)
2092{
2093 int result;
2094
2095 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
2096 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
2097 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
2098 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
2099 (result = (atmp->tm_min - btmp->tm_min)) == 0 &&
2100 (result = (atmp->tm_sec - btmp->tm_sec)) == 0)
2101 result = atmp->tm_usec - btmp->tm_usec;
2102 return result;
2103}
2104
2105static struct timeval time2sub(struct ast_tm *tmp, struct ast_tm * (* const funcp) (const struct timeval *, long, struct ast_tm *, const struct state *), const long offset, int *okayp, const int do_norm_secs, const struct state *sp)
2106{
2107 int dir;
2108 int i, j;
2109 int saved_seconds;
2110 long li;
2111 time_t lo;
2112 time_t hi;
2113 long y;
2114 struct timeval newt = { 0, 0 };
2115 struct timeval t = { 0, 0 };
2116 struct ast_tm yourtm, mytm;
2117
2118 *okayp = FALSE;
2119 yourtm = *tmp;
2120 if (do_norm_secs) {
2121 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
2122 SECSPERMIN))
2123 return WRONG;
2124 }
2125 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
2126 return WRONG;
2127 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
2128 return WRONG;
2129 y = yourtm.tm_year;
2130 if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
2131 return WRONG;
2132 /*
2133 ** Turn y into an actual year number for now.
2134 ** It is converted back to an offset from TM_YEAR_BASE later.
2135 */
2137 return WRONG;
2138 while (yourtm.tm_mday <= 0) {
2139 if (long_increment_overflow(&y, -1))
2140 return WRONG;
2141 li = y + (1 < yourtm.tm_mon);
2142 yourtm.tm_mday += year_lengths[isleap(li)];
2143 }
2144 while (yourtm.tm_mday > DAYSPERLYEAR) {
2145 li = y + (1 < yourtm.tm_mon);
2146 yourtm.tm_mday -= year_lengths[isleap(li)];
2147 if (long_increment_overflow(&y, 1))
2148 return WRONG;
2149 }
2150 for ( ; ; ) {
2151 i = mon_lengths[isleap(y)][yourtm.tm_mon];
2152 if (yourtm.tm_mday <= i)
2153 break;
2154 yourtm.tm_mday -= i;
2155 if (++yourtm.tm_mon >= MONSPERYEAR) {
2156 yourtm.tm_mon = 0;
2157 if (long_increment_overflow(&y, 1))
2158 return WRONG;
2159 }
2160 }
2162 return WRONG;
2163 yourtm.tm_year = y;
2164 if (yourtm.tm_year != y)
2165 return WRONG;
2166 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
2167 saved_seconds = 0;
2168 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
2169 /*
2170 ** We can't set tm_sec to 0, because that might push the
2171 ** time below the minimum representable time.
2172 ** Set tm_sec to 59 instead.
2173 ** This assumes that the minimum representable time is
2174 ** not in the same minute that a leap second was deleted from,
2175 ** which is a safer assumption than using 58 would be.
2176 */
2177 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
2178 return WRONG;
2179 saved_seconds = yourtm.tm_sec;
2180 yourtm.tm_sec = SECSPERMIN - 1;
2181 } else {
2182 saved_seconds = yourtm.tm_sec;
2183 yourtm.tm_sec = 0;
2184 }
2185 /*
2186 ** Do a binary search (this works whatever time_t's type is).
2187 */
2188 if (!TYPE_SIGNED(time_t)) {
2189 lo = 0;
2190 hi = lo - 1;
2191 } else if (!TYPE_INTEGRAL(time_t)) {
2192 if (sizeof(time_t) > sizeof(float))
2193 hi = (time_t) DBL_MAX;
2194 else hi = (time_t) FLT_MAX;
2195 lo = -hi;
2196 } else {
2197 lo = 1;
2198 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
2199 lo *= 2;
2200 hi = -(lo + 1);
2201 }
2202 for ( ; ; ) {
2203 t.tv_sec = lo / 2 + hi / 2;
2204 if (t.tv_sec < lo)
2205 t.tv_sec = lo;
2206 else if (t.tv_sec > hi)
2207 t.tv_sec = hi;
2208 if ((*funcp)(&t, offset, &mytm, sp) == NULL) {
2209 /*
2210 ** Assume that t is too extreme to be represented in
2211 ** a struct ast_tm; arrange things so that it is less
2212 ** extreme on the next pass.
2213 */
2214 dir = (t.tv_sec > 0) ? 1 : -1;
2215 } else dir = tmcomp(&mytm, &yourtm);
2216 if (dir != 0) {
2217 if (t.tv_sec == lo) {
2218 ++t.tv_sec;
2219 if (t.tv_sec <= lo)
2220 return WRONG;
2221 ++lo;
2222 } else if (t.tv_sec == hi) {
2223 --t.tv_sec;
2224 if (t.tv_sec >= hi)
2225 return WRONG;
2226 --hi;
2227 }
2228 if (lo > hi)
2229 return WRONG;
2230 if (dir > 0)
2231 hi = t.tv_sec;
2232 else lo = t.tv_sec;
2233 continue;
2234 }
2235 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
2236 break;
2237 /*
2238 ** Right time, wrong type.
2239 ** Hunt for right time, right type.
2240 ** It's okay to guess wrong since the guess
2241 ** gets checked.
2242 */
2243 /*
2244 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
2245 */
2246 for (i = sp->typecnt - 1; i >= 0; --i) {
2247 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
2248 continue;
2249 for (j = sp->typecnt - 1; j >= 0; --j) {
2250 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
2251 continue;
2252 newt.tv_sec = t.tv_sec + sp->ttis[j].tt_gmtoff -
2253 sp->ttis[i].tt_gmtoff;
2254 if ((*funcp)(&newt, offset, &mytm, sp) == NULL)
2255 continue;
2256 if (tmcomp(&mytm, &yourtm) != 0)
2257 continue;
2258 if (mytm.tm_isdst != yourtm.tm_isdst)
2259 continue;
2260 /*
2261 ** We have a match.
2262 */
2263 t = newt;
2264 goto label;
2265 }
2266 }
2267 return WRONG;
2268 }
2269label:
2270 newt.tv_sec = t.tv_sec + saved_seconds;
2271 if ((newt.tv_sec < t.tv_sec) != (saved_seconds < 0))
2272 return WRONG;
2273 t.tv_sec = newt.tv_sec;
2274 if ((*funcp)(&t, offset, tmp, sp))
2275 *okayp = TRUE;
2276 return t;
2277}
2278
2279static struct timeval time2(struct ast_tm *tmp, struct ast_tm * (* const funcp) (const struct timeval *, long, struct ast_tm*, const struct state *sp), const long offset, int *okayp, const struct state *sp)
2280{
2281 struct timeval t;
2282
2283 /*! \note
2284 ** First try without normalization of seconds
2285 ** (in case tm_sec contains a value associated with a leap second).
2286 ** If that fails, try with normalization of seconds.
2287 */
2288 t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
2289 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
2290}
2291
2292static struct timeval time1(struct ast_tm *tmp, struct ast_tm * (* const funcp) (const struct timeval *, long, struct ast_tm *, const struct state *), const long offset, const struct state *sp)
2293{
2294 struct timeval t;
2295 int samei, otheri;
2296 int sameind, otherind;
2297 int i;
2298 int nseen;
2299 int seen[TZ_MAX_TYPES];
2300 int types[TZ_MAX_TYPES];
2301 int okay;
2302
2303 if (tmp->tm_isdst > 1)
2304 tmp->tm_isdst = 1;
2305 t = time2(tmp, funcp, offset, &okay, sp);
2306#ifdef PCTS
2307 /*
2308 ** PCTS code courtesy Grant Sullivan.
2309 */
2310 if (okay)
2311 return t;
2312 if (tmp->tm_isdst < 0)
2313 tmp->tm_isdst = 0; /* reset to std and try again */
2314#endif /* defined PCTS */
2315#ifndef PCTS
2316 if (okay || tmp->tm_isdst < 0)
2317 return t;
2318#endif /* !defined PCTS */
2319 /*
2320 ** We're supposed to assume that somebody took a time of one type
2321 ** and did some math on it that yielded a "struct ast_tm" that's bad.
2322 ** We try to divine the type they started from and adjust to the
2323 ** type they need.
2324 */
2325 if (sp == NULL)
2326 return WRONG;
2327 for (i = 0; i < sp->typecnt; ++i)
2328 seen[i] = FALSE;
2329 nseen = 0;
2330 for (i = sp->timecnt - 1; i >= 0; --i)
2331 if (!seen[sp->types[i]]) {
2332 seen[sp->types[i]] = TRUE;
2333 types[nseen++] = sp->types[i];
2334 }
2335 for (sameind = 0; sameind < nseen; ++sameind) {
2336 samei = types[sameind];
2337 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2338 continue;
2339 for (otherind = 0; otherind < nseen; ++otherind) {
2340 otheri = types[otherind];
2341 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2342 continue;
2343 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
2344 sp->ttis[samei].tt_gmtoff;
2345 tmp->tm_isdst = !tmp->tm_isdst;
2346 t = time2(tmp, funcp, offset, &okay, sp);
2347 if (okay)
2348 return t;
2349 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
2350 sp->ttis[samei].tt_gmtoff;
2351 tmp->tm_isdst = !tmp->tm_isdst;
2352 }
2353 }
2354 return WRONG;
2355}
2356
2357struct timeval ast_mktime(struct ast_tm *tmp, const char *zone)
2358{
2359 const struct state *sp;
2360 if (!(sp = ast_tzset(zone)))
2361 return WRONG;
2362 return time1(tmp, localsub, 0L, sp);
2363}
2364
2365#if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE)
2367{
2368 struct locale_entry *cur;
2370 if (locale == cur->locale) {
2371 return cur;
2372 }
2373 }
2374 return NULL;
2375}
2376
2377static struct locale_entry *find_by_name(const char *name)
2378{
2379 struct locale_entry *cur;
2381 if (strcmp(name, cur->name) == 0) {
2382 return cur;
2383 }
2384 }
2385 return NULL;
2386}
2387
2388static const char *store_by_locale(locale_t prevlocale)
2389{
2390 struct locale_entry *cur;
2391 if (prevlocale == LC_GLOBAL_LOCALE) {
2392 return NULL;
2393 } else {
2394 /* Get a handle for this entry, if any */
2395 if ((cur = find_by_locale(prevlocale))) {
2396 return cur->name;
2397 } else {
2398 /* Create an entry, so it can be restored later */
2399 int x;
2400 cur = NULL;
2402 for (x = 0; x < 10000; x++) {
2403 char name[6];
2404 snprintf(name, sizeof(name), "%04d", x);
2405 if (!find_by_name(name)) {
2406 if ((cur = ast_calloc(1, sizeof(*cur) + strlen(name) + 1))) {
2407 cur->locale = prevlocale;
2408 strcpy(cur->name, name); /* SAFE */
2410 }
2411 break;
2412 }
2413 }
2415 return cur ? cur->name : NULL;
2416 }
2417 }
2418}
2419
2420const char *ast_setlocale(const char *locale)
2421{
2422 struct locale_entry *cur;
2423 locale_t prevlocale = LC_GLOBAL_LOCALE;
2424
2425 if (locale == NULL) {
2426 return store_by_locale(uselocale(LC_GLOBAL_LOCALE));
2427 }
2428
2430 if ((cur = find_by_name(locale))) {
2431 prevlocale = uselocale(cur->locale);
2432 }
2433
2434 if (!cur) {
2435 if ((cur = ast_calloc(1, sizeof(*cur) + strlen(locale) + 1))) {
2436 cur->locale = newlocale(LC_ALL_MASK, locale, NULL);
2437 strcpy(cur->name, locale); /* SAFE */
2439 prevlocale = uselocale(cur->locale);
2440 }
2441 }
2443 return store_by_locale(prevlocale);
2444}
2445#else
2446const char *ast_setlocale(const char *unused)
2447{
2448 return NULL;
2449}
2450#endif
2451
2452int ast_strftime_locale(char *buf, size_t len, const char *tmp, const struct ast_tm *tm, const char *locale)
2453{
2454 size_t fmtlen = strlen(tmp) + 1;
2455 char *format = ast_calloc(1, fmtlen), *fptr = format, *newfmt;
2456 int decimals = -1, i, res;
2457 long fraction;
2458 const char *prevlocale;
2459
2460 buf[0] = '\0';/* Ensure the buffer is initialized. */
2461 if (!format) {
2462 return -1;
2463 }
2464 for (; *tmp; tmp++) {
2465 if (*tmp == '%') {
2466 switch (tmp[1]) {
2467 case '1':
2468 case '2':
2469 case '3':
2470 case '4':
2471 case '5':
2472 case '6':
2473 if (tmp[2] != 'q') {
2474 goto defcase;
2475 }
2476 decimals = tmp[1] - '0';
2477 tmp++;
2478 /* Fall through */
2479 case 'q': /* Milliseconds */
2480 if (decimals == -1) {
2481 decimals = 3;
2482 }
2483
2484 /* Juggle some memory to fit the item */
2485 newfmt = ast_realloc(format, fmtlen + decimals);
2486 if (!newfmt) {
2487 ast_free(format);
2488 return -1;
2489 }
2490 fptr = fptr - format + newfmt;
2491 format = newfmt;
2492 fmtlen += decimals;
2493
2494 /* Reduce the fraction of time to the accuracy needed */
2495 for (i = 6, fraction = tm->tm_usec; i > decimals; i--) {
2496 fraction /= 10;
2497 }
2498 fptr += sprintf(fptr, "%0*ld", decimals, fraction);
2499
2500 /* Reset, in case more than one 'q' specifier exists */
2501 decimals = -1;
2502 tmp++;
2503 break;
2504 default:
2505 goto defcase;
2506 }
2507 } else {
2508defcase: *fptr++ = *tmp;
2509 }
2510 }
2511 *fptr = '\0';
2512#undef strftime
2513 if (locale) {
2514 prevlocale = ast_setlocale(locale);
2515 }
2516 res = (int)strftime(buf, len, format, (struct tm *)tm);
2517 if (locale) {
2518 ast_setlocale(prevlocale);
2519 }
2520 ast_free(format);
2521 return res;
2522}
2523
2524int ast_strftime(char *buf, size_t len, const char *tmp, const struct ast_tm *tm)
2525{
2526 return ast_strftime_locale(buf, len, tmp, tm, NULL);
2527}
2528
2529char *ast_strptime_locale(const char *s, const char *format, struct ast_tm *tm, const char *locale)
2530{
2531 struct tm tm2 = { 0, };
2532 char *res;
2533 const char *prevlocale;
2534
2535 prevlocale = ast_setlocale(locale);
2536 res = strptime(s, format, &tm2);
2537 ast_setlocale(prevlocale);
2538 /* ast_time and tm are not the same size - tm is a subset of
2539 * ast_time. Hence, the size of tm needs to be used for the
2540 * memcpy
2541 */
2542 memcpy(tm, &tm2, sizeof(tm2));
2543 tm->tm_usec = 0;
2544 /* strptime(3) doesn't set .tm_isdst correctly, so to force ast_mktime(3)
2545 * to deal with it correctly, we set it to -1. */
2546 tm->tm_isdst = -1;
2547 return res;
2548}
2549
2550char *ast_strptime(const char *s, const char *format, struct ast_tm *tm)
2551{
2552 return ast_strptime_locale(s, format, tm, NULL);
2553}
Prototypes for public functions only of internal interest,.
#define TRUE
Definition: app_minivm.c:524
#define FALSE
Definition: app_minivm.c:527
ast_mutex_t lock
Definition: app_sla.c:331
static char locale[20]
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
while(1)
Definition: ast_expr2f.c:880
Asterisk main include file. File version handling, generic pbx functions.
#define PATH_MAX
Definition: asterisk.h:40
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
#define ast_realloc(p, len)
A wrapper for realloc()
Definition: astmm.h:226
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
static int tmp()
Definition: bt_open.c:389
static PGresult * result
Definition: cel_pgsql.c:84
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define min(a, b)
Definition: f2c.h:197
#define max(a, b)
Definition: f2c.h:198
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define LOG_ERROR
#define LOG_NOTICE
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:291
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_TRYLOCK(head)
Locks a list, without blocking if the list is locked.
Definition: linkedlists.h:105
static long detzcode P((const char *codep))
static const char * getqzname(const char *strp, const int delim)
Given a pointer into an extended time zone string, scan until the ending delimiter of the zone name i...
Definition: localtime.c:1137
static int leaps_thru_end_of(const int y)
Return the number of leap years through the end of the given year where, to make the math easy,...
Definition: localtime.c:1907
static void common_startup(void)
Definition: localtime.c:328
static const char * getsecs(const char *strp, long *const secsp)
Given a pointer into a time zone string, extract a number of seconds, in hh[:mm[:ss]] form,...
Definition: localtime.c:1181
static int tzload(const char *name, struct state *const sp, const int doextend)
Definition: localtime.c:853
static const struct timeval WRONG
Definition: localtime.c:111
static int differ_by_repeat(const time_t t1, const time_t t0)
Definition: localtime.c:844
static const struct state * ast_tzset(const char *zone)
Definition: localtime.c:1601
#define SP_HEAP_FREE(sp)
Definition: localtime.c:199
static struct state * sstate_alloc(void)
Definition: localtime.c:778
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *tmp, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
static ast_cond_t initialization
Definition: localtime.c:322
static void * inotify_daemon(void *data)
Definition: localtime.c:353
static struct locale_entry * find_by_name(const char *name)
Definition: localtime.c:2377
const char * ast_setlocale(const char *locale)
Set the thread-local representation of the current locale.
Definition: localtime.c:2420
static const char * getnum(const char *strp, int *nump, const int min, const int max)
Given a pointer into a time zone string, extract a number from that string. Check that the number is ...
Definition: localtime.c:1153
#define TZ_STRLEN_MAX
Definition: localtime.c:155
#define SP_STACK_CHECK(sp)
Definition: localtime.c:194
static void sstate_free(struct state *p)
Definition: localtime.c:789
#define DAY_OF_YEAR
Definition: localtime.c:257
static int long_increment_overflow(long *number, int delta)
Definition: localtime.c:2060
int ast_strftime_locale(char *buf, size_t len, const char *tmp, const struct ast_tm *tm, const char *locale)
Definition: localtime.c:2452
#define TZDEFRULESTRING
Definition: localtime.c:128
#define BIGGEST(a, b)
Definition: localtime.c:146
static void add_notify(struct state *sp, const char *path)
Definition: localtime.c:411
void ast_localtime_wakeup_monitor(struct ast_test *info)
Definition: localtime.c:795
static int increment_overflow(int *number, int delta)
Simplified normalize logic courtesy Paul Eggert.
Definition: localtime.c:2051
struct timeval ast_mktime(struct ast_tm *tmp, const char *zone)
Timezone-independent version of mktime(3).
Definition: localtime.c:2357
static struct ast_tm * timesub(const struct timeval *timep, const long offset, const struct state *sp, struct ast_tm *tmp)
Definition: localtime.c:1913
static int long_normalize_overflow(long *tensptr, int *unitsptr, const int base)
Definition: localtime.c:2080
#define JULIAN_DAY
Definition: localtime.c:256
static const char * store_by_locale(locale_t prevlocale)
Definition: localtime.c:2388
int ast_strftime(char *buf, size_t len, const char *tmp, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
void clean_time_zones(void)
Definition: localtime.c:1590
static int tzparse(const char *name, struct state *sp, const int lastditch)
Definition: localtime.c:1385
static ast_mutex_t initialization_lock
Definition: localtime.c:323
static struct locale_entry * find_by_locale(locale_t locale)
Definition: localtime.c:2366
static int normalize_overflow(int *tensptr, int *unitsptr, const int base)
Definition: localtime.c:2069
static const char * getrule(const char *strp, struct rule *rulep)
Given a pointer into a time zone string, extract a rule in the form date[/time]. See POSIX section 8 ...
Definition: localtime.c:1244
#define MY_TZNAME_MAX
Definition: localtime.c:152
static int gmtload(struct state *sp)
Definition: localtime.c:1582
char * ast_strptime_locale(const char *s, const char *format, struct ast_tm *tm, const char *locale)
Definition: localtime.c:2529
void ast_get_dst_info(const time_t *const timep, int *dst_enabled, time_t *dst_start, time_t *dst_end, int *gmt_off, const char *const zone)
Definition: localtime.c:1754
static long detzcode(const char *const codep)
Definition: localtime.c:822
static pthread_t inotify_thread
Definition: localtime.c:321
static time_t transtime(const time_t janfirst, const int year, const struct rule *rulep, const long offset)
Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the year, a rule,...
Definition: localtime.c:1295
static struct timeval time2(struct ast_tm *tmp, struct ast_tm *(*const funcp)(const struct timeval *, long, struct ast_tm *, const struct state *sp), const long offset, int *okayp, const struct state *sp)
Definition: localtime.c:2279
static const char * getzname(const char *strp)
Given a pointer into a time zone string, scan until a character that is not a valid character in a zo...
Definition: localtime.c:1118
static const char gmt[]
Definition: localtime.c:110
static struct ast_tm * localsub(const struct timeval *timep, const long offset, struct ast_tm *tmp, const struct state *sp)
Definition: localtime.c:1648
#define OPEN_MODE
Definition: localtime.c:107
#define MONTH_NTH_DAY_OF_WEEK
Definition: localtime.c:258
static struct ast_tm * gmtsub(const struct timeval *timep, const long offset, struct ast_tm *tmp)
Definition: localtime.c:1866
static const char * getoffset(const char *strp, long *offsetp)
Given a pointer into a time zone string, extract an offset, in [+-]hh[:mm[:ss]] form,...
Definition: localtime.c:1220
static int tmcomp(const struct ast_tm *atmp, const struct ast_tm *btmp)
Definition: localtime.c:2091
#define SP_STACK_INIT(sp)
Definition: localtime.c:191
static char elsieid[]
Definition: localtime.c:82
static const int year_lengths[2]
Definition: localtime.c:1108
static int inotify_fd
Definition: localtime.c:351
static const int mon_lengths[2][MONSPERYEAR]
Definition: localtime.c:1103
static struct timeval time2sub(struct ast_tm *tmp, struct ast_tm *(*const funcp)(const struct timeval *, long, struct ast_tm *, const struct state *), const long offset, int *okayp, const int do_norm_secs, const struct state *sp)
Definition: localtime.c:2105
#define SP_HEAP_INIT(sp)
Definition: localtime.c:195
static struct timeval time1(struct ast_tm *tmp, struct ast_tm *(*const funcp)(const struct timeval *, long, struct ast_tm *, const struct state *), const long offset, const struct state *sp)
Definition: localtime.c:2292
char * ast_strptime(const char *s, const char *format, struct ast_tm *tm)
Special version of strptime(3) which places the answer in the common structure ast_tm....
Definition: localtime.c:2550
static time_t detzcode64(const char *const codep)
Definition: localtime.c:833
Custom localtime functions for multiple timezones.
void * locale_t
Definition: localtime.h:32
Asterisk locking-related definitions:
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:206
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_cond_broadcast(cond)
Definition: lock.h:204
pthread_cond_t ast_cond_t
Definition: lock.h:178
#define ast_mutex_lock(a)
Definition: lock.h:189
#define ast_cond_signal(cond)
Definition: lock.h:203
#define is_digit(c)
#define SECSPERREPEAT
#define AVGSECSPERYEAR
#define TYPE_INTEGRAL(type)
you may need to compile with DHAVE_STDINT_H typedef long int_fast64_t
#define FILENAME_MAX
#define INITIALIZE(x)
#define YEARSPERREPEAT
int errno
#define SECSPERREPEAT_BITS
#define TYPE_BIT(type)
#define TYPE_SIGNED(type)
def info(msg)
#define ast_fully_booted
Definition: options.h:117
#define NULL
Definition: resample.c:96
String manipulation functions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Structure for mutex and tracking information.
Definition: lock.h:135
int tm_mday
Definition: localtime.h:39
int tm_sec
Definition: localtime.h:36
int tm_hour
Definition: localtime.h:38
int tm_isdst
Definition: localtime.h:44
int tm_min
Definition: localtime.h:37
int tm_year
Definition: localtime.h:41
int tm_mon
Definition: localtime.h:40
int tm_usec
Definition: localtime.h:48
Definition: localtime.c:242
locale_t locale
Definition: localtime.c:244
struct locale_entry::@401 list
char name[0]
Definition: localtime.c:245
leap second information
Definition: localtime.c:141
long ls_corr
Definition: localtime.c:143
time_t ls_trans
Definition: localtime.c:142
Number structure.
Definition: app_followme.c:154
int r_mon
Definition: localtime.c:252
long r_time
Definition: localtime.c:253
int r_day
Definition: localtime.c:250
int r_week
Definition: localtime.c:251
int r_type
Definition: localtime.c:249
int typecnt
Definition: localtime.c:163
int goback
Definition: localtime.c:165
time_t ats[TZ_MAX_TIMES]
Definition: localtime.c:167
char name[TZ_STRLEN_MAX+1]
Definition: localtime.c:160
struct lsinfo lsis[TZ_MAX_LEAPS]
Definition: localtime.c:172
int timecnt
Definition: localtime.c:162
int wd[2]
Definition: localtime.c:174
int charcnt
Definition: localtime.c:164
struct ttinfo ttis[TZ_MAX_TYPES]
Definition: localtime.c:169
unsigned char types[TZ_MAX_TIMES]
Definition: localtime.c:168
int leapcnt
Definition: localtime.c:161
struct state::@400 list
int goahead
Definition: localtime.c:166
char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS+1, sizeof gmt),(2 *(MY_TZNAME_MAX+1)))]
Definition: localtime.c:171
time type information
Definition: localtime.c:132
int tt_ttisgmt
Definition: localtime.c:137
int tt_ttisstd
Definition: localtime.c:136
int tt_abbrind
Definition: localtime.c:135
int tt_isdst
Definition: localtime.c:134
long tt_gmtoff
Definition: localtime.c:133
Definition: tzfile.h:54
int value
Definition: syslog.c:37
Test Framework API.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static struct test_val d
static struct test_val c
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
#define SECSPERDAY
Definition: tzfile.h:139
#define TM_YEAR_BASE
Definition: tzfile.h:163
#define SECSPERHOUR
Definition: tzfile.h:138
#define DAYSPERNYEAR
Definition: tzfile.h:136
#define SECSPERMIN
Definition: tzfile.h:132
#define EPOCH_WDAY
Definition: tzfile.h:166
#define MONSPERYEAR
Definition: tzfile.h:140
#define TZ_MAX_CHARS
Definition: tzfile.h:124
#define HOURSPERDAY
Definition: tzfile.h:134
#define isleap(y)
Definition: tzfile.h:168
#define DAYSPERWEEK
Definition: tzfile.h:135
#define EPOCH_YEAR
Definition: tzfile.h:165
#define TZ_MAX_TYPES
Definition: tzfile.h:112
#define TZDIR
Definition: tzfile.h:36
#define TZDEFRULES
Definition: tzfile.h:45
#define MINSPERHOUR
Definition: tzfile.h:133
#define TZ_MAX_TIMES
Definition: tzfile.h:107
#define DAYSPERLYEAR
Definition: tzfile.h:137
#define TZ_MAX_LEAPS
Definition: tzfile.h:129
#define TZDEFAULT
Definition: tzfile.h:41
Utility functions.
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592