From cccafb5ff305978b2b7a41fd68ade359aa27007b Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Mon, 22 Aug 2016 15:31:05 +0300 Subject: Implement sentinel handlers. Sentinel handlers wait for a creation of a directory. When the target directory is created, the sentinel handler installs the actual handler for that directory and destroys itself. Thus, basically sentinel handlers provide a way to defer setting a watchpoint on a directory until it is created. * src/handler.c: New source. * src/Makefile.am (direvent_SOURCES): Add handler.c * src/config.c: Move handler-specific stuff to handler.c * src/direvent.h: Rename direvent_handler_ to handler_ (handler_free, handler_copy) (handler_envrealloc) (dirwatcher_init,dirwatcher_gc): New protos. (dirwatcher_install_ptr) (dirwatcher_install_sentinel): New protos. * src/ev_inotify.c (process_event): Special handling for IN_IGNORED. (sysev_select): Ignore signo==0. * src/hashtab.c (hashtab_remove): Add missing return statement. (hashtab_foreach): Break out of look instead of returning from it. * src/progman.c (run_sentinel): Implement. * src/watcher.c (+dirwatcher_install_ptr): New function. (dirwatcher_gc): New function. --- src/Makefile.am | 1 + src/config.c | 182 +---------------------------------- src/direvent.h | 42 +++++--- src/ev_inotify.c | 22 +++-- src/ev_kqueue.c | 8 +- src/handler.c | 288 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/hashtab.c | 10 +- src/progman.c | 12 ++- src/watcher.c | 68 ++++++++++--- 9 files changed, 403 insertions(+), 230 deletions(-) create mode 100644 src/handler.c diff --git a/src/Makefile.am b/src/Makefile.am index e64c90f..bc13509 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,6 +23,7 @@ direvent_SOURCES=\ environ.c\ event.c\ fnpat.c\ + handler.c\ hashtab.c\ watcher.c\ progman.c\ diff --git a/src/config.c b/src/config.c index 3a4878c..a11e629 100644 --- a/src/config.c +++ b/src/config.c @@ -146,165 +146,6 @@ static struct grecs_keyword syslog_kw[] = { { NULL }, }; -struct handler * -handler_alloc(enum handler_type type) -{ - struct handler *hp = ecalloc(1, sizeof(*hp)); - hp->type = type; - hp->refcnt = 0; - return hp; -} - -static struct handler * -handler_copy(struct handler *orig) -{ - struct handler *hp = emalloc(sizeof(*hp)); - *hp = *orig; - hp->refcnt = 0; - return hp; -} - -static void -handler_ref(struct handler *hp) -{ - ++hp->refcnt; -} - -static void -envfree(char **env) -{ - int i; - - if (!env) - return; - for (i = 0; env[i]; i++) - free(env[i]); - free(env); -} - -/* Reallocate environment of handler HP to accomodate COUNT more - entries (not bytes) plus a final NULL entry. - - Return offset of the first unused entry. -*/ -static size_t -handler_envrealloc(struct handler *hp, size_t count) -{ - size_t i; - - if (!hp->prog_env) { - hp->prog_env = ecalloc(count + 1, sizeof(hp->prog_env[0])); - i = 0; - } else { - for (i = 0; hp->prog_env[i]; i++) - ; - hp->prog_env = erealloc(hp->prog_env, - (i + count + 1) * sizeof(hp->prog_env[0])); - memset(hp->prog_env + i, 0, (count + 1) * sizeof(hp->prog_env[0])); - } - return i; -} - -static void -handler_free(struct handler *hp) -{ - grecs_list_free(hp->fnames); - switch (hp->type) { - case HANDLER_EXTERN: - free(hp->prog_command); - free(hp->prog_gidv); - envfree(hp->prog_env); - break; - case HANDLER_SENTINEL: - dirwatcher_unref(hp->sentinel_watcher); - } -} - -static void -handler_unref(struct handler *hp) -{ - if (hp && --hp->refcnt) { - handler_free(hp); - free(hp); - } -} - -static void -handler_listent_free(void *p) -{ - struct handler *hp = p; - handler_unref(hp); -} - -struct direvent_handler_list { - size_t refcnt; - grecs_list_ptr_t list; -}; - -struct handler * -direvent_handler_first(struct dirwatcher *dwp, - direvent_handler_iterator_t *itr) -{ - if (!dwp->handler_list) - return NULL; - *itr = dwp->handler_list->list->head; - return direvent_handler_current(*itr); -} - -struct handler * -direvent_handler_next(direvent_handler_iterator_t *itr) -{ - if (!itr || !*itr) - return NULL; - *itr = (*itr)->next; - return direvent_handler_current(*itr); -} - -struct handler * -direvent_handler_current(direvent_handler_iterator_t itr) -{ - if (!itr) - return NULL; - return itr ? itr->data : NULL; -} - -direvent_handler_list_t -direvent_handler_list_create(void) -{ - direvent_handler_list_t hlist = emalloc(sizeof(*hlist)); - hlist->list = grecs_list_create(); - hlist->list->free_entry = handler_listent_free; - hlist->refcnt = 1; - return hlist; -} - -direvent_handler_list_t -direvent_handler_list_copy(direvent_handler_list_t orig) -{ - if (!orig) - return direvent_handler_list_create(); - ++orig->refcnt; - return orig; -} - -void -direvent_handler_list_unref(direvent_handler_list_t hlist) -{ - if (hlist) { - if (--hlist->refcnt == 0) { - grecs_list_free(hlist->list); - free(hlist); - } - } -} - -void -direvent_handler_list_append(direvent_handler_list_t hlist, struct handler *hp) -{ - handler_ref(hp); - grecs_list_append(hlist->list, hp); -} - struct eventconf { struct grecs_list *pathlist; struct handler handler; @@ -346,7 +187,7 @@ eventconf_flush(grecs_locus_t *loc) _("%s: recursion depth does not match previous definition"), pe->path); dwp->depth = pe->depth; - direvent_handler_list_append(dwp->handler_list, hp); + handler_list_append(dwp->handler_list, hp); } grecs_list_free(eventconf.pathlist); eventconf_init(); @@ -704,27 +545,6 @@ cb_environ(enum grecs_callback_command cmd, grecs_node_t *node, return 0; } -void -handler_add_pattern(struct handler *hp, struct filename_pattern *pat) -{ - if (!hp->fnames) { - hp->fnames = grecs_list_create(); - hp->fnames->free_entry = filename_pattern_free; - } - grecs_list_append(hp->fnames, pat); -} - -void -handler_add_exact_filename(struct handler *hp, const char *filename) -{ - struct filename_pattern *pat; - pat = emalloc(sizeof(*pat)); - pat->neg = 0; - pat->type = PAT_EXACT; - pat->v.glob = estrdup(filename); - handler_add_pattern(hp, pat); -} - static int is_glob(char const *str) { diff --git a/src/direvent.h b/src/direvent.h index 75f3708..bc5bb46 100644 --- a/src/direvent.h +++ b/src/direvent.h @@ -108,8 +108,8 @@ struct handler { #define sentinel_watcher v.sentinel.watcher }; -typedef struct direvent_handler_list *direvent_handler_list_t; -typedef struct grecs_list_entry *direvent_handler_iterator_t; +typedef struct handler_list *handler_list_t; +typedef struct handler_iterator *handler_iterator_t; /* A directory watcher is described by the following structure */ struct dirwatcher { @@ -118,7 +118,7 @@ struct dirwatcher { struct dirwatcher *parent; /* Points to the parent watcher. NULL for top-level watchers */ char *dirname; /* Pathname being watched */ - direvent_handler_list_t handler_list;/* List of handlers */ + handler_list_t handler_list; /* List of handlers */ int depth; /* Recursion depth */ char *split_p; /* Points to the deleted directory separator in dirname (see @@ -136,6 +136,10 @@ struct dirwatcher { filename_pattern_match((h)->fnames, n) == 0) struct handler *handler_alloc(enum handler_type type); +void handler_free(struct handler *hp); +struct handler *handler_copy(struct handler *orig); +size_t handler_envrealloc(struct handler *hp, size_t count); + void handler_add_pattern(struct handler *hp, struct filename_pattern *pat); void handler_add_exact_filename(struct handler *hp, const char *filename); @@ -236,8 +240,10 @@ void config_parse(const char *file); int get_facility(const char *arg); int get_priority(const char *arg); +int dirwatcher_init(struct dirwatcher *dwp); void dirwatcher_ref(struct dirwatcher *dw); void dirwatcher_unref(struct dirwatcher *dw); +void dirwatcher_gc(void); int dirwatcher_pattern_match(struct dirwatcher *dwp, const char *file_name); @@ -247,7 +253,11 @@ void shutdown_watchers(void); struct dirwatcher *dirwatcher_lookup(const char *dirname); int check_new_watcher(const char *dir, const char *name); struct dirwatcher *dirwatcher_install(const char *path, int *pnew); +struct dirwatcher *dirwatcher_install_ptr(struct dirwatcher *dw); +void dirwatcher_suspend(struct dirwatcher *dwp); void dirwatcher_destroy(struct dirwatcher *dwp); +struct dirwatcher *dirwatcher_install_sentinel(struct dirwatcher *dwp); + int watch_pathname(struct dirwatcher *parent, const char *dirname, int isdir, int notify); char *split_pathname(struct dirwatcher *dp, char **dirname); @@ -258,28 +268,30 @@ void deliver_ev_create(struct dirwatcher *dp, const char *name); int subwatcher_create(struct dirwatcher *parent, const char *dirname, int isdir, int notify); -struct handler *direvent_handler_first(struct dirwatcher *dp, - direvent_handler_iterator_t *itr); -struct handler *direvent_handler_next(direvent_handler_iterator_t *itr); -struct handler *direvent_handler_current(direvent_handler_iterator_t itr); +struct handler *handler_itr_first(struct dirwatcher *dp, + handler_iterator_t *itr); +struct handler *handler_itr_next(handler_iterator_t *itr); +struct handler *handler_itr_current(handler_iterator_t itr); #define for_each_handler(d,i,h) \ - for (h = direvent_handler_first(d, &(i)); \ + for (h = handler_itr_first(d, &(i)); \ h; \ - h = direvent_handler_next(&(i))) + h = handler_itr_next(&(i))) -direvent_handler_list_t direvent_handler_list_create(void); -direvent_handler_list_t direvent_handler_list_copy(direvent_handler_list_t); -void direvent_handler_list_unref(direvent_handler_list_t hlist); -void direvent_handler_list_append(direvent_handler_list_t hlist, +handler_list_t handler_list_create(void); +handler_list_t handler_list_copy(handler_list_t); +void handler_list_unref(handler_list_t hlist); +void handler_list_append(handler_list_t hlist, struct handler *hp); - +void handler_list_remove(handler_list_t hlist, + struct handler *hp); +size_t handler_list_size(handler_list_t hlist); struct process *process_lookup(pid_t pid); void process_cleanup(int expect_term); void process_timeouts(void); -int run_handler(struct handler *hp, event_mask *event, +int run_handler(struct dirwatcher *dp, struct handler *hp, event_mask *event, const char *dir, const char *file); char **environ_setup(char **hint, char **kve); diff --git a/src/ev_inotify.c b/src/ev_inotify.c index 8db7bb8..6d4c03a 100644 --- a/src/ev_inotify.c +++ b/src/ev_inotify.c @@ -152,7 +152,7 @@ remove_watcher(const char *dir, const char *name) dwp = dirwatcher_lookup(fullname); free(fullname); if (dwp) - dirwatcher_destroy(dwp); + dirwatcher_suspend(dwp); } static void @@ -160,18 +160,23 @@ process_event(struct inotify_event *ep) { struct dirwatcher *dp; struct handler *h; - direvent_handler_iterator_t itr; + handler_iterator_t itr; event_mask m; char *dirname, *filename; dp = dwget(ep->wd); if (!dp) { - diag(LOG_NOTICE, _("watcher not found: %d"), ep->wd); + if (!(ep->mask & IN_IGNORED)) + diag(LOG_NOTICE, _("watcher not found: %d (%s)"), + ep->wd, ep->name); return; } - if (ep->mask & IN_IGNORED) - ep->mask = IN_DELETE; + if (ep->mask & IN_IGNORED) { + diag(LOG_NOTICE, _("%s deleted"), dp->dirname); + dirwatcher_suspend(dp); + return; + } if (ep->mask & IN_Q_OVERFLOW) { diag(LOG_NOTICE, @@ -210,9 +215,8 @@ process_event(struct inotify_event *ep) } for_each_handler(dp, itr, h) { if (handler_matches_event(h, sys, ep->mask, filename)) - run_handler(h, event_mask_init(&m, - ep->mask, - &h->ev_mask), + run_handler(dp, h, + event_mask_init(&m, ep->mask, &h->ev_mask), dirname, filename); } unsplit_pathname(dp); @@ -234,7 +238,7 @@ sysev_select() rdbytes = read(ifd, buffer, sizeof(buffer)); if (rdbytes == -1) { if (errno == EINTR) { - if (signo == SIGCHLD || signo == SIGALRM) + if (!signo || signo == SIGCHLD || signo == SIGALRM) return 0; diag(LOG_NOTICE, "got signal %d", signo); return 1; diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c index 63663ea..a9921c6 100644 --- a/src/ev_kqueue.c +++ b/src/ev_kqueue.c @@ -63,7 +63,7 @@ int sysev_filemask(struct dirwatcher *dp) { struct handler *h; - direvent_handler_iterator_t itr; + handler_iterator_t itr; for_each_handler(dp, itr, h) { if (h->ev_mask.sys_mask) @@ -187,7 +187,7 @@ process_event(struct kevent *ep) { struct dirwatcher *dp = ep->udata; struct handler *h; - direvent_handler_iterator_t itr; + handler_iterator_t itr; event_mask m; char *filename, *dirname; @@ -208,7 +208,7 @@ process_event(struct kevent *ep) filename = split_pathname(dp, &dirname); for_each_handler(dp, itr, h) { if (handler_matches_event(h, sys, ep->fflags, filename)) { - run_handler(h, + run_handler(dp, h, event_mask_init(&m, ep->fflags, &h->ev_mask), dirname, filename); } @@ -217,7 +217,7 @@ process_event(struct kevent *ep) if (ep->fflags & (NOTE_DELETE|NOTE_RENAME)) { debug(1, ("%s deleted", dp->dirname)); - dirwatcher_destroy(dp); + dirwatcher_suspend(dp); return; } } diff --git a/src/handler.c b/src/handler.c new file mode 100644 index 0000000..0e86a44 --- /dev/null +++ b/src/handler.c @@ -0,0 +1,288 @@ +/* direvent - directory content watcher daemon + Copyright (C) 2012-2016 Sergey Poznyakoff + + Direvent is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + Direvent is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with direvent. If not, see . */ + +#include "direvent.h" +#include + +struct handler * +handler_alloc(enum handler_type type) +{ + struct handler *hp = ecalloc(1, sizeof(*hp)); + hp->type = type; + hp->refcnt = 0; + return hp; +} + +struct handler * +handler_copy(struct handler *orig) +{ + struct handler *hp = emalloc(sizeof(*hp)); + *hp = *orig; + hp->refcnt = 0; + return hp; +} + +/* Reallocate environment of handler HP to accomodate COUNT more + entries (not bytes) plus a final NULL entry. + + Return offset of the first unused entry. +*/ +size_t +handler_envrealloc(struct handler *hp, size_t count) +{ + size_t i; + + if (!hp->prog_env) { + hp->prog_env = ecalloc(count + 1, sizeof(hp->prog_env[0])); + i = 0; + } else { + for (i = 0; hp->prog_env[i]; i++) + ; + hp->prog_env = erealloc(hp->prog_env, + (i + count + 1) * sizeof(hp->prog_env[0])); + memset(hp->prog_env + i, 0, (count + 1) * sizeof(hp->prog_env[0])); + } + return i; +} + +void +handler_add_pattern(struct handler *hp, struct filename_pattern *pat) +{ + if (!hp->fnames) { + hp->fnames = grecs_list_create(); + hp->fnames->free_entry = filename_pattern_free; + } + grecs_list_append(hp->fnames, pat); +} + +void +handler_add_exact_filename(struct handler *hp, const char *filename) +{ + struct filename_pattern *pat; + pat = emalloc(sizeof(*pat)); + pat->neg = 0; + pat->type = PAT_EXACT; + pat->v.glob = estrdup(filename); + handler_add_pattern(hp, pat); +} + +static void +handler_ref(struct handler *hp) +{ + ++hp->refcnt; +} + +static void +envfree(char **env) +{ + int i; + + if (!env) + return; + for (i = 0; env[i]; i++) + free(env[i]); + free(env); +} + +void +handler_free(struct handler *hp) +{ + grecs_list_free(hp->fnames); + switch (hp->type) { + case HANDLER_EXTERN: + free(hp->prog_command); + free(hp->prog_gidv); + envfree(hp->prog_env); + break; + case HANDLER_SENTINEL: + dirwatcher_unref(hp->sentinel_watcher); + } +} + +static void +handler_unref(struct handler *hp) +{ + if (hp && --hp->refcnt) { + handler_free(hp); + free(hp); + } +} + +/* Handler lists */ + +static void +handler_listent_free(void *p) +{ + struct handler *hp = p; + handler_unref(hp); +} + +struct handler_list { + size_t refcnt; + grecs_list_ptr_t list; + struct handler_iterator *itr_chain; +}; + +struct handler_iterator { + struct handler_iterator *prev, *next; + handler_list_t hlist; + struct grecs_list_entry *ent; + int advanced; +}; + +static struct handler_iterator *itr_avail; + +struct handler * +handler_itr_first(struct dirwatcher *dwp, handler_iterator_t *ret_itr) +{ + struct handler_iterator *itr; + + if (!dwp->handler_list) + return NULL; + + if (itr_avail) { + itr = itr_avail; + itr_avail = itr->next; + if (itr_avail) + itr_avail->prev = NULL; + } else + itr = emalloc(sizeof *itr); + + itr->prev = NULL; + itr->next = dwp->handler_list->itr_chain; + itr->hlist = dwp->handler_list; + if (dwp->handler_list->itr_chain) + dwp->handler_list->itr_chain->prev = itr; + dwp->handler_list->itr_chain = itr; + + itr->ent = dwp->handler_list->list->head; + itr->advanced = 0; + *ret_itr = itr; + return handler_itr_current(itr); +} + +struct handler * +handler_itr_next(handler_iterator_t *pitr) +{ + struct handler_iterator *itr; + + if (!pitr || (itr = *pitr) == NULL) + return NULL; + if (itr->advanced) + itr->advanced = 0; + else + itr->ent = itr->ent->next; + + if (!itr->ent) { + /* Remove from iterator chain */ + struct handler_iterator *p; + if ((p = itr->prev) != NULL) + p->next = itr->next; + else + itr->hlist->itr_chain = itr->next; + if ((p = itr->next) != NULL) + p->prev = itr->prev; + + /* Add to the available chain */ + if (itr_avail) + itr_avail->prev = itr; + itr->prev = NULL; + itr->next = itr_avail; + itr->hlist = NULL; + itr_avail = itr; + *pitr = NULL; + return NULL; + } + return handler_itr_current(itr); +} + +struct handler * +handler_itr_current(handler_iterator_t itr) +{ + if (!itr) + return NULL; + return itr->ent ? itr->ent->data : NULL; +} + +handler_list_t +handler_list_create(void) +{ + handler_list_t hlist = emalloc(sizeof(*hlist)); + hlist->list = grecs_list_create(); + hlist->list->free_entry = handler_listent_free; + hlist->refcnt = 1; + hlist->itr_chain = NULL; + return hlist; +} + +size_t +handler_list_size(handler_list_t hlist) +{ + return grecs_list_size(hlist->list); +} + +handler_list_t +handler_list_copy(handler_list_t orig) +{ + if (!orig) + return handler_list_create(); + ++orig->refcnt; + return orig; +} + +void +handler_list_unref(handler_list_t hlist) +{ + if (hlist) { + if (--hlist->refcnt == 0) { + grecs_list_free(hlist->list); + free(hlist); + } + } +} + +void +handler_list_append(handler_list_t hlist, struct handler *hp) +{ + handler_ref(hp); + grecs_list_append(hlist->list, hp); +} + +void +handler_list_remove(handler_list_t hlist, struct handler *hp) +{ + struct grecs_list_entry *ep; + for (ep = hlist->list->head; ep; ep = ep->next) + if (ep->data == hp) + break; + if (!ep) + abort(); + + if (hlist->itr_chain) { + struct handler_iterator *itr; + + for (itr = hlist->itr_chain; itr; itr = itr->next) + if (itr->ent == ep) { + itr->ent = ep->next; + itr->advanced = 1; + } + } + + grecs_list_remove_entry(hlist->list, ep); + if (grecs_list_size(hlist->list) == 0) + /* Remove watchers that don't have handlers */ + dirwatcher_gc(); +} diff --git a/src/hashtab.c b/src/hashtab.c index f7cb0aa..f7eaf18 100644 --- a/src/hashtab.c +++ b/src/hashtab.c @@ -247,6 +247,7 @@ hashtab_remove(struct hashtab *st, void *elt) if (hashent_list_append(&st->list_del, entry)) return ENOMEM; entry->used = 0; + return 0; } hashent_free(st, entry); @@ -413,7 +414,8 @@ int hashtab_foreach(struct hashtab *st, hashtab_enumerator_t fun, void *data) { unsigned i; - + int rc = 0; + if (!st) return 0; @@ -425,9 +427,9 @@ hashtab_foreach(struct hashtab *st, hashtab_enumerator_t fun, void *data) for (i = 0; i < hash_size[st->hash_num]; i++) { struct hashent *ep = st->tab[i]; if (ep) { - int rc = fun(ep, data); + rc = fun(ep, data); if (rc) - return rc; + break; } } @@ -450,7 +452,7 @@ hashtab_foreach(struct hashtab *st, hashtab_enumerator_t fun, void *data) } } - return 0; + return rc; } size_t diff --git a/src/progman.c b/src/progman.c index 3b78874..823d51c 100644 --- a/src/progman.c +++ b/src/progman.c @@ -541,14 +541,16 @@ run_handler_prog(struct handler *hp, event_mask *event, } static int -run_sentinel(struct handler *hp) +run_sentinel(struct dirwatcher *dp, struct handler *hp) { - return dirwatcher_init(hp->sentinel_watcher); - //FIXME: Remove watcher + dirwatcher_init(hp->sentinel_watcher); + dirwatcher_install_ptr(hp->sentinel_watcher); + handler_list_remove(dp->handler_list, hp); + return 0; } int -run_handler(struct handler *hp, event_mask *event, +run_handler(struct dirwatcher *dp, struct handler *hp, event_mask *event, const char *dirname, const char *file) { int rc; @@ -557,7 +559,7 @@ run_handler(struct handler *hp, event_mask *event, rc = run_handler_prog(hp, event, dirname, file); break; case HANDLER_SENTINEL: - rc = run_sentinel(hp); + rc = run_sentinel(dp, hp); break; default: abort(); diff --git a/src/watcher.c b/src/watcher.c index 8f79562..b625276 100644 --- a/src/watcher.c +++ b/src/watcher.c @@ -30,7 +30,7 @@ dirwatcher_unref(struct dirwatcher *dw) if (--dw->refcnt) return; free(dw->dirname); - direvent_handler_list_unref(dw->handler_list); + handler_list_unref(dw->handler_list); free(dw); } @@ -102,7 +102,7 @@ dirwatcher_install(const char *path, int *pnew) dw = ecalloc(1, sizeof(*dw)); dw->dirname = estrdup(path); dw->wd = -1; - dw->handler_list = direvent_handler_list_create(); + dw->handler_list = handler_list_create(); dw->refcnt++; ent->dw = dw; } @@ -113,6 +113,38 @@ dirwatcher_install(const char *path, int *pnew) return ent->dw; } +struct dirwatcher * +dirwatcher_install_ptr(struct dirwatcher *dw) +{ + struct dwref key; + int install = 1; + key.dw = dw; + + if (!hashtab_lookup_or_install(nametab, &key, &install)) { + diag(LOG_CRIT, _("not enough memory")); + exit(1); + } + dirwatcher_ref(dw); + return dw; +} + +static int +dwref_gc(struct hashent *ent, void *data) +{ + struct dwref *dwref = (struct dwref *) ent; + struct dirwatcher *dwp = dwref->dw; + + if (handler_list_size(dwp->handler_list) == 0) + dirwatcher_destroy(dwp); + return 0; +} + +void +dirwatcher_gc(void) +{ + hashtab_foreach(nametab, dwref_gc, NULL); +} + struct dirwatcher * dirwatcher_lookup(const char *dirname) { @@ -149,6 +181,15 @@ dirwatcher_destroy(struct dirwatcher *dwp) debug(1, (_("removing watcher %s"), dwp->dirname)); sysev_rm_watch(dwp); dirwatcher_remove(dwp->dirname); +} + +// FIXME: Perhaps the check for count is not needed after all +void +dirwatcher_suspend(struct dirwatcher *dwp) +{ + struct dirwatcher *sent = dirwatcher_install_sentinel(dwp); + dirwatcher_init(sent);//FIXME: error checking + dirwatcher_destroy(dwp); if (hashtab_count(nametab) == 0) { diag(LOG_CRIT, _("no watchers left; exiting now")); stop = 1; @@ -162,7 +203,7 @@ convert_watcher(struct dirwatcher *dwp) char *filename; char *new_dirname; struct handler *hp; - direvent_handler_iterator_t itr; + handler_iterator_t itr; for_each_handler(dwp, itr, hp) { if (hp->fnames) { @@ -200,10 +241,10 @@ dirwatcher_install_sentinel(struct dirwatcher *dwp) hp->sentinel_watcher = dwp; dirwatcher_ref(dwp); handler_add_exact_filename(hp, filename); - direvent_handler_list_append(sent->handler_list, hp); - + handler_list_append(sent->handler_list, hp); unsplit_pathname(dwp); diag(LOG_NOTICE, _("installing CREATE sentinel for %s"), dwp->dirname); + dirwatcher_init(sent); return sent; } @@ -213,7 +254,7 @@ dirwatcher_init(struct dirwatcher *dwp) struct stat st; event_mask mask = { 0, 0 }; struct handler *hp; - direvent_handler_iterator_t itr; + handler_iterator_t itr; int wd; debug(1, (_("creating watcher %s"), dwp->dirname)); @@ -221,6 +262,7 @@ dirwatcher_init(struct dirwatcher *dwp) if (stat(dwp->dirname, &st)) { if (errno == ENOENT) { dwp = dirwatcher_install_sentinel(dwp); + return 0; } else { diag(LOG_ERR, _("cannot set watcher on %s: %s"), dwp->dirname, strerror(errno)); @@ -261,7 +303,7 @@ subwatcher_create(struct dirwatcher *parent, const char *dirname, if (!inst) return -1; - dwp->handler_list = direvent_handler_list_copy(parent->handler_list); + dwp->handler_list = handler_list_copy(parent->handler_list); dwp->parent = parent; if (parent->depth == -1) @@ -285,11 +327,11 @@ deliver_ev_create(struct dirwatcher *dp, const char *name) { event_mask m = { GENEV_CREATE, 0 }; struct handler *h; - direvent_handler_iterator_t itr; + handler_iterator_t itr; for_each_handler(dp, itr, h) { if (handler_matches_event(h, gen, GENEV_CREATE, name)) - run_handler(h, &m, dp->dirname, name); + run_handler(dp, h, &m, dp->dirname, name); } } @@ -342,7 +384,7 @@ int dirwatcher_pattern_match(struct dirwatcher *dwp, const char *file_name) { struct handler *hp; - direvent_handler_iterator_t itr; + handler_iterator_t itr; for_each_handler(dwp, itr, hp) { if (filename_pattern_match(hp->fnames, file_name) == 0) @@ -450,8 +492,10 @@ stopwatcher(struct hashent *ent, void *data) { struct dwref *dwref = (struct dwref *) ent; struct dirwatcher *dwp = dwref->dw; - debug(1, (_("removing watcher %s"), dwp->dirname)); - sysev_rm_watch(dwp); + if (dwp->wd != -1) { + debug(1, (_("removing watcher %s"), dwp->dirname)); + sysev_rm_watch(dwp); + } return 0; } -- cgit v1.2.1