summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2016-08-22 12:31:05 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2016-08-25 19:29:47 (GMT)
commitcccafb5ff305978b2b7a41fd68ade359aa27007b (patch) (side-by-side diff)
tree8a4078fd13afc5f50eea985fc6f5fa53cac32e94
parent55f74d88c076061d03391689269641d141393187 (diff)
downloaddirevent-cccafb5ff305978b2b7a41fd68ade359aa27007b.tar.gz
direvent-cccafb5ff305978b2b7a41fd68ade359aa27007b.tar.bz2
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.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/Makefile.am1
-rw-r--r--src/config.c182
-rw-r--r--src/direvent.h42
-rw-r--r--src/ev_inotify.c22
-rw-r--r--src/ev_kqueue.c8
-rw-r--r--src/handler.c288
-rw-r--r--src/hashtab.c10
-rw-r--r--src/progman.c12
-rw-r--r--src/watcher.c68
9 files changed, 403 insertions, 230 deletions
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
--- a/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 <http://www.gnu.org/licenses/>. */
+
+#include "direvent.h"
+#include <grecs.h>
+
+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;
}
@@ -114,6 +114,38 @@ dirwatcher_install(const char *path, int *pnew)
}
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)
{
struct dirwatcher dwkey;
@@ -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;
}

Return to:

Send suggestions and report system problems to the System administrator.