aboutsummaryrefslogtreecommitdiffstats
path: root/main/stdtime
diff options
context:
space:
mode:
authortilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2009-02-25 19:24:44 +0000
committertilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2009-02-25 19:24:44 +0000
commit82a4dd2ed8d1efc9d6c68f158663beb96aeced65 (patch)
treecf55319fa2d5403fde6fba72ae8a4fd2b3ac5912 /main/stdtime
parenta9e3b506a0e9205fea98075119ea77575db78ce6 (diff)
Use notification when timezone files change and re-scan then.
(closes issue #14300) Reported by: jamessan Patches: 20090127__bug14300.diff.txt uploaded by tilghman (license 14) 20090224__bug14300.diff uploaded by jamessan (license 246) Tested by: jamessan Review: http://reviewboard.digium.com/r/136/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@178605 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main/stdtime')
-rw-r--r--main/stdtime/localtime.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/main/stdtime/localtime.c b/main/stdtime/localtime.c
index 389107cb7..e247a4de0 100644
--- a/main/stdtime/localtime.c
+++ b/main/stdtime/localtime.c
@@ -51,6 +51,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/stat.h>
#include <fcntl.h>
#include <float.h>
+#ifdef HAVE_INOTIFY
+#include <sys/inotify.h>
+#endif
#include "private.h"
#include "tzfile.h"
@@ -147,6 +150,11 @@ struct state {
char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
(2 * (MY_TZNAME_MAX + 1)))];
struct lsinfo lsis[TZ_MAX_LEAPS];
+#ifdef HAVE_INOTIFY
+ int wd[2];
+#else
+ time_t mtime[2];
+#endif
AST_LIST_ENTRY(state) list;
};
@@ -217,6 +225,156 @@ static AST_LIST_HEAD_STATIC(zonelist, state);
#define TZ_STRLEN_MAX 255
#endif /* !defined TZ_STRLEN_MAX */
+static pthread_t inotify_thread = AST_PTHREADT_NULL;
+static ast_cond_t initialization;
+static ast_mutex_t initialization_lock;
+#ifdef HAVE_INOTIFY
+static int inotify_fd = -1;
+
+static void *inotify_daemon(void *data)
+{
+ struct {
+ struct inotify_event iev;
+ char name[FILENAME_MAX + 1];
+ } buf;
+ ssize_t res;
+ struct state *cur;
+
+ inotify_fd = inotify_init();
+
+ ast_mutex_lock(&initialization_lock);
+ ast_cond_signal(&initialization);
+ ast_mutex_unlock(&initialization_lock);
+
+ if (inotify_fd < 0) {
+ ast_log(LOG_ERROR, "Cannot initialize file notification service: %s (%d)\n", strerror(errno), errno);
+ inotify_thread = AST_PTHREADT_NULL;
+ return NULL;
+ }
+
+ for (;/*ever*/;) {
+ /* This read should block, most of the time. */
+ if ((res = read(inotify_fd, &buf, sizeof(buf))) < sizeof(buf.iev) && res > 0) {
+ /* This should never happen */
+ ast_log(LOG_ERROR, "Inotify read less than a full event (%d < %d)?!!\n", res, sizeof(buf.iev));
+ break;
+ } else if (res < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ /* If read fails, then wait a bit, then continue */
+ poll(NULL, 0, 10000);
+ continue;
+ }
+ /* Sanity check -- this should never happen, either */
+ ast_log(LOG_ERROR, "Inotify failed: %s\n", strerror(errno));
+ break;
+ }
+ AST_LIST_LOCK(&zonelist);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
+ if (cur->wd[0] == buf.iev.wd || cur->wd[1] == buf.iev.wd) {
+ AST_LIST_REMOVE_CURRENT(list);
+ ast_free(cur);
+ break;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END
+ AST_LIST_UNLOCK(&zonelist);
+ }
+ close(inotify_fd);
+ inotify_thread = AST_PTHREADT_NULL;
+ return NULL;
+}
+
+static void add_notify(struct state *sp, const char *path)
+{
+ if (inotify_thread == AST_PTHREADT_NULL) {
+ ast_cond_init(&initialization, NULL);
+ ast_mutex_init(&initialization_lock);
+ ast_mutex_lock(&initialization_lock);
+ if (!(ast_pthread_create_background(&inotify_thread, NULL, inotify_daemon, NULL))) {
+ /* Give the thread a chance to initialize */
+ ast_cond_wait(&initialization, &initialization_lock);
+ } else {
+ ast_log(LOG_ERROR, "Unable to start notification thread\n");
+ ast_mutex_unlock(&initialization_lock);
+ return;
+ }
+ ast_mutex_unlock(&initialization_lock);
+ }
+
+ if (inotify_fd > -1) {
+ char fullpath[FILENAME_MAX + 1] = "";
+ if (readlink(path, fullpath, sizeof(fullpath) - 1) != -1) {
+ /* If file the symlink points to changes */
+ sp->wd[1] = inotify_add_watch(inotify_fd, fullpath, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE );
+ } else {
+ sp->wd[1] = -1;
+ }
+ /* or if the symlink itself changes (or the real file is here, if path is not a symlink) */
+ sp->wd[0] = inotify_add_watch(inotify_fd, path, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE | IN_DONT_FOLLOW);
+ }
+}
+#else
+static void *notify_daemon(void *data)
+{
+ struct stat st, lst;
+ struct state *cur;
+
+ ast_mutex_lock(&initialization_lock);
+ ast_cond_signal(&initialization);
+ ast_mutex_unlock(&initialization_lock);
+
+ for (;/*ever*/;) {
+ char fullname[FILENAME_MAX + 1];
+
+ poll(NULL, 0, 60000);
+ AST_LIST_LOCK(&zonelist);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
+ char *name = cur->name;
+
+ if (name[0] == ':')
+ ++name;
+ if (name[0] != '/') {
+ (void) strcpy(fullname, TZDIR "/");
+ (void) strcat(fullname, name);
+ name = fullname;
+ }
+ stat(name, &st);
+ lstat(name, &lst);
+ if (st.st_mtime > cur->mtime[0] || lst.st_mtime > cur->mtime[1]) {
+ AST_LIST_REMOVE_CURRENT(list);
+ ast_free(cur);
+ continue;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END
+ AST_LIST_UNLOCK(&zonelist);
+ }
+ inotify_thread = AST_PTHREADT_NULL;
+ return NULL;
+}
+
+static void add_notify(struct state *sp, const char *path)
+{
+ struct stat st;
+
+ if (inotify_thread == AST_PTHREADT_NULL) {
+ ast_cond_init(&initialization, NULL);
+ ast_mutex_init(&initialization_lock);
+ ast_mutex_lock(&initialization_lock);
+ if (!(ast_pthread_create_background(&inotify_thread, NULL, notify_daemon, NULL))) {
+ /* Give the thread a chance to initialize */
+ ast_cond_wait(&initialization, &initialization_lock);
+ }
+ ast_mutex_unlock(&initialization_lock);
+ }
+
+ stat(path, &st);
+ sp->mtime[0] = st.st_mtime;
+ lstat(path, &st);
+ sp->mtime[1] = st.st_mtime;
+}
+#endif
+
/*! \note
** Section 4.12.3 of X3.159-1989 requires that
** Except for the strftime function, these functions [asctime,
@@ -305,6 +463,7 @@ static int tzload(const char *name, struct state * const sp, const int doextend)
return -1;
if ((fid = open(name, OPEN_MODE)) == -1)
return -1;
+ add_notify(sp, name);
}
nread = read(fid, u.buf, sizeof u.buf);
if (close(fid) < 0 || nread <= 0)