aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2016-08-23 08:36:01 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2016-08-23 08:36:01 +0300
commit7566e5322fb2f057da9f36a1587956f5034fd740 (patch)
tree5e115b267348aa71cb271a56ddd8e03f8265b303
parent3547d5c623a6dac4cae24d4b21f14a40d8e2d1b6 (diff)
downloaddirevent-7566e5322fb2f057da9f36a1587956f5034fd740.tar.gz
direvent-7566e5322fb2f057da9f36a1587956f5034fd740.tar.bz2
Further modify struct handler.
Instead of accomodating two types of functionality, the new struct handler has a pointer to the function that is responsible for handling the event, and a pointer to data for that function (closure). Additionally, a pointer to deallocator function is also provided. Existing functionality is reimplemented using this new struct. New types of handlers can easily be added. * src/config.c (eventconf)<ev_mask,fpat,prog_handler>: New members <handler>: Remove. All uses changed. * src/direvent.h (filpatlist_t) (event_handler_fn, handler_free_fn): New data types. (handler): Remove union and type. Add two pointer to functions that are to implement the functionality (run and free) and a pointer to data for them. (prog_handler): New struct. (prog_handler_alloc,prog_handler_free) (prog_handler_envrealloc) (watchpoint_run_handlers): New protos. (run_handler,filename_pattern_free) (filename_pattern_match): Remove (filpatlist_add, filpatlist_add_exact) (filpatlist_destroy, filpatlist_match): New protos. * src/ev_inotify.c (process_event): Use watchpoint_run_handlers * src/ev_kqueue.c: Likewise. * src/fnpat.c: Major rewrite. * src/handler.c (handler_copy) (handler_envrealloc,handler_add_pattern) (handler_add_exact_filename): Remove (handler_alloc): Change arguments. (watchpoint_run_handlers): New function. * src/progman.c (prog_handler_alloc) (prog_handler_envrealloc): New functions. * src/watcher.c: Reimplement sentinel watchers.
-rw-r--r--src/config.c141
-rw-r--r--src/direvent.h89
-rw-r--r--src/ev_inotify.c40
-rw-r--r--src/ev_kqueue.c10
-rw-r--r--src/fnpat.c111
-rw-r--r--src/handler.c90
-rw-r--r--src/progman.c133
-rw-r--r--src/watcher.c69
8 files changed, 370 insertions, 313 deletions
diff --git a/src/config.c b/src/config.c
index 1f8d26e..6ad3016 100644
--- a/src/config.c
+++ b/src/config.c
@@ -148,7 +148,9 @@ static struct grecs_keyword syslog_kw[] = {
struct eventconf {
struct grecs_list *pathlist;
- struct handler handler;
+ event_mask ev_mask;
+ filpatlist_t fpat;
+ struct prog_handler prog_handler;
};
static struct eventconf eventconf;
@@ -156,24 +158,26 @@ static struct eventconf eventconf;
static void
eventconf_init(void)
{
- memset(&eventconf, 0, sizeof eventconf);
- eventconf.handler.type = HANDLER_EXTERN;
- eventconf.handler.prog_timeout = DEFAULT_TIMEOUT;
+ memset(&eventconf, 0, sizeof eventconf);
+ eventconf.prog_handler.timeout = DEFAULT_TIMEOUT;
}
static void
eventconf_free(void)
{
grecs_list_free(eventconf.pathlist);
- handler_free(&eventconf.handler);
+ prog_handler_free(&eventconf.prog_handler);
+ filpatlist_destroy(&eventconf.fpat);
}
void
eventconf_flush(grecs_locus_t *loc)
{
struct grecs_list_entry *ep;
- struct handler *hp = handler_copy(&eventconf.handler);
-
+ struct handler *hp = prog_handler_alloc(eventconf.ev_mask,
+ eventconf.fpat,
+ &eventconf.prog_handler);
+
for (ep = eventconf.pathlist->head; ep; ep = ep->next) {
struct pathent *pe = ep->data;
struct watchpoint *wpt;
@@ -208,13 +212,13 @@ cb_watcher(enum grecs_callback_command cmd, grecs_node_t *node,
grecs_error(&node->locus, 0, _("no paths configured"));
++err;
}
- if (!eventconf.handler.prog_command) {
+ if (!eventconf.prog_handler.command) {
grecs_error(&node->locus, 0,
_("no command configured"));
++err;
}
- if (evtnullp(&eventconf.handler.ev_mask))
- evtsetall(&eventconf.handler.ev_mask);
+ if (evtnullp(&eventconf.ev_mask))
+ evtsetall(&eventconf.ev_mask);
if (err == 0)
eventconf_flush(&node->locus);
else
@@ -459,9 +463,9 @@ cb_user(enum grecs_callback_command cmd, grecs_node_t *node,
} else
gid = pw->pw_gid;
- eventconf.handler.prog_uid = pw->pw_uid;
+ eventconf.prog_handler.uid = pw->pw_uid;
get_user_groups(uv->v.string, gid,
- &eventconf.handler.prog_gidc, &eventconf.handler.prog_gidv);
+ &eventconf.prog_handler.gidc, &eventconf.prog_handler.gidv);
return 0;
}
@@ -484,15 +488,15 @@ cb_option(enum grecs_callback_command cmd, grecs_node_t *node,
GRECS_TYPE_STRING))
return 1;
if (strcmp(vp->v.string, "nowait") == 0)
- eventconf.handler.prog_flags |= HF_NOWAIT;
+ eventconf.prog_handler.flags |= HF_NOWAIT;
else if (strcmp(vp->v.string, "wait") == 0)
- eventconf.handler.prog_flags &= ~HF_NOWAIT;
+ eventconf.prog_handler.flags &= ~HF_NOWAIT;
else if (strcmp(vp->v.string, "stdout") == 0)
- eventconf.handler.prog_flags |= HF_STDOUT;
+ eventconf.prog_handler.flags |= HF_STDOUT;
else if (strcmp(vp->v.string, "stderr") == 0)
- eventconf.handler.prog_flags |= HF_STDERR;
+ eventconf.prog_handler.flags |= HF_STDERR;
else if (strcmp(vp->v.string, "shell") == 0)
- eventconf.handler.prog_flags |= HF_SHELL;
+ eventconf.prog_handler.flags |= HF_SHELL;
else
grecs_error(&vp->locus, 0, _("unrecognized option"));
}
@@ -514,107 +518,44 @@ cb_environ(enum grecs_callback_command cmd, grecs_node_t *node,
if (assert_grecs_value_type(&val->locus, val,
GRECS_TYPE_STRING))
return 1;
- i = handler_envrealloc(&eventconf.handler, 1);
- eventconf.handler.prog_env[i] = estrdup(val->v.string);
- eventconf.handler.prog_env[i+1] = NULL;
+ i = prog_handler_envrealloc(&eventconf.prog_handler, 1);
+ eventconf.prog_handler.env[i] = estrdup(val->v.string);
+ eventconf.prog_handler.env[i+1] = NULL;
break;
case GRECS_TYPE_ARRAY:
- j = handler_envrealloc(&eventconf.handler, val->v.arg.c);
+ j = prog_handler_envrealloc(&eventconf.prog_handler, val->v.arg.c);
for (i = 0; i < val->v.arg.c; i++, j++) {
if (assert_grecs_value_type(&val->v.arg.v[i]->locus,
val->v.arg.v[i],
GRECS_TYPE_STRING))
return 1;
- eventconf.handler.prog_env[j] = estrdup(val->v.arg.v[i]->v.string);
+ eventconf.prog_handler.env[j] = estrdup(val->v.arg.v[i]->v.string);
}
- eventconf.handler.prog_env[j] = NULL;
+ eventconf.prog_handler.env[j] = NULL;
break;
case GRECS_TYPE_LIST:
- j = handler_envrealloc(&eventconf.handler, val->v.list->count);
+ j = prog_handler_envrealloc(&eventconf.prog_handler,
+ val->v.list->count);
for (ep = val->v.list->head; ep; ep = ep->next, j++) {
grecs_value_t *vp = ep->data;
if (assert_grecs_value_type(&vp->locus, vp,
GRECS_TYPE_STRING))
return 1;
- eventconf.handler.prog_env[j] = estrdup(vp->v.string);
+ eventconf.prog_handler.env[j] = estrdup(vp->v.string);
}
- eventconf.handler.prog_env[j] = NULL;
+ eventconf.prog_handler.env[j] = NULL;
}
return 0;
}
static int
-is_glob(char const *str)
+file_name_pattern(filpatlist_t *fptr, grecs_value_t *val)
{
- return strcspn(str, "[]*?") < strlen(str);
-}
-
-static int
-file_name_pattern(struct handler *handler, grecs_value_t *val)
-{
- char *arg;
- int rc;
- int flags = REG_EXTENDED|REG_NOSUB;
- struct filename_pattern *pat;
-
if (assert_grecs_value_type(&val->locus, val, GRECS_TYPE_STRING))
return 1;
- arg = val->v.string;
-
- pat = emalloc(sizeof(*pat));
- if (*arg == '!') {
- pat->neg = 1;
- ++arg;
- } else
- pat->neg = 0;
- if (arg[0] == '/') {
- char *q, *p;
-
- pat->type = PAT_REGEX;
-
- p = strchr(arg+1, '/');
- if (!p) {
- grecs_error(&val->locus, 0, _("unterminated regexp"));
- free(pat);
- return 1;
- }
- for (q = p + 1; *q; q++) {
- switch (*q) {
- case 'b':
- flags &= ~REG_EXTENDED;
- break;
- case 'i':
- flags |= REG_ICASE;
- break;
- default:
- grecs_error(&val->locus, 0,
- _("unrecognized flag: %c"), *q);
- free(pat);
- return 1;
- }
- }
-
- *p = 0;
- rc = regcomp(&pat->v.re, arg + 1, flags);
- *p = '/';
-
- if (rc) {
- char errbuf[128];
- regerror(rc, &pat->v.re, errbuf, sizeof(errbuf));
- grecs_error(&val->locus, 0, "%s", errbuf);
- filename_pattern_free(pat);
- return 1;
- }
- } else {
- pat->type = is_glob(arg) ? PAT_GLOB : PAT_EXACT;
- pat->v.glob = estrdup(arg);
- }
-
- handler_add_pattern(handler, pat);
-
- return 0;
+ return filpatlist_add(fptr, val->v.string, &val->locus);
}
static int
@@ -622,7 +563,7 @@ cb_file_pattern(enum grecs_callback_command cmd, grecs_node_t *node,
void *varptr, void *cb_data)
{
grecs_value_t *val = node->v.value;
- struct handler *handler = varptr;
+ filpatlist_t *fpat = varptr;
struct grecs_list_entry *ep;
int i;
@@ -630,18 +571,18 @@ cb_file_pattern(enum grecs_callback_command cmd, grecs_node_t *node,
switch (val->type) {
case GRECS_TYPE_STRING:
- file_name_pattern(handler, val);
+ file_name_pattern(fpat, val);
break;
case GRECS_TYPE_ARRAY:
for (i = 0; i < val->v.arg.c; i++)
- if (file_name_pattern(handler, val->v.arg.v[i]))
+ if (file_name_pattern(fpat, val->v.arg.v[i]))
break;
break;
case GRECS_TYPE_LIST:
for (ep = val->v.list->head; ep; ep = ep->next)
- if (file_name_pattern(handler,
+ if (file_name_pattern(fpat,
(grecs_value_t *) ep->data))
break;
break;
@@ -655,18 +596,18 @@ static struct grecs_keyword watcher_kw[] = {
grecs_type_string, GRECS_DFLT, &eventconf.pathlist, 0,
cb_path },
{ "event", NULL, N_("Events to watch for"),
- grecs_type_string, GRECS_LIST, &eventconf.handler.ev_mask, 0,
+ grecs_type_string, GRECS_LIST, &eventconf.ev_mask, 0,
cb_eventlist },
{ "file", N_("regexp"), N_("Files to watch for"),
- grecs_type_string, GRECS_LIST, &eventconf.handler, 0,
+ grecs_type_string, GRECS_LIST, &eventconf.fpat, 0,
cb_file_pattern },
{ "command", NULL, N_("Command to execute on event"),
- grecs_type_string, GRECS_DFLT, &eventconf.handler.prog_command },
+ grecs_type_string, GRECS_DFLT, &eventconf.prog_handler.command },
{ "user", N_("name"), N_("Run command as this user"),
grecs_type_string, GRECS_DFLT, NULL, 0,
cb_user },
{ "timeout", N_("seconds"), N_("Timeout for the command"),
- grecs_type_uint, GRECS_DFLT, &eventconf.handler.prog_timeout },
+ grecs_type_uint, GRECS_DFLT, &eventconf.prog_handler.timeout },
{ "option", NULL, N_("List of additional options"),
grecs_type_string, GRECS_LIST, NULL, 0,
cb_option },
diff --git a/src/direvent.h b/src/direvent.h
index faa1657..d69fa34 100644
--- a/src/direvent.h
+++ b/src/direvent.h
@@ -72,40 +72,25 @@ struct filename_pattern {
} v;
};
-enum handler_type {
- HANDLER_EXTERN,
- HANDLER_SENTINEL
-};
+typedef struct filpatlist *filpatlist_t;
+
+struct watchpoint;
+
+typedef int (*event_handler_fn) (struct watchpoint *wp,
+ event_mask *event,
+ const char *dir,
+ const char *file,
+ void *data);
+typedef void (*handler_free_fn) (void *data);
/* Handler structure */
struct handler {
- size_t refcnt; /* Reference counter */
- event_mask ev_mask; /* Event mask */
- struct grecs_list *fnames; /* File name patterns */
- enum handler_type type;
- union {
- struct {
- int flags; /* Handler flags */
- char *command; /* Handler command (with eventual
- arguments) */
- uid_t uid; /* Run as this user (unless 0) */
- gid_t *gidv; /* Run with these groups' privileges */
- size_t gidc; /* Number of elements in gidv */
- unsigned timeout; /* Handler timeout */
- char **env; /* Environment */
- } prog;
- struct {
- struct watchpoint *watchpoint;
- } sentinel;
- } v;
-#define prog_flags v.prog.flags
-#define prog_command v.prog.command
-#define prog_uid v.prog.uid
-#define prog_gidv v.prog.gidv
-#define prog_gidc v.prog.gidc
-#define prog_timeout v.prog.timeout
-#define prog_env v.prog.env
-#define sentinel_watchpoint v.sentinel.watchpoint
+ size_t refcnt; /* Reference counter */
+ event_mask ev_mask; /* Event mask */
+ filpatlist_t fnames; /* File name patterns */
+ event_handler_fn run;
+ handler_free_fn free;
+ void *data;
};
typedef struct handler_list *handler_list_t;
@@ -133,16 +118,27 @@ struct watchpoint {
#define __cat2__(a,b) a ## b
#define handler_matches_event(h,m,f,n) \
- (((h)->ev_mask.__cat2__(m,_mask) & (f)) && \
- filename_pattern_match((h)->fnames, n) == 0)
+ (((h)->ev_mask.__cat2__(m,_mask) & (f)) && \
+ filpatlist_match((h)->fnames, n) == 0)
-struct handler *handler_alloc(enum handler_type type);
+struct handler *handler_alloc(event_mask ev_mask);
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);
+
+struct prog_handler {
+ int flags; /* Handler flags */
+ char *command; /* Handler command (with eventual arguments) */
+ uid_t uid; /* Run as this user (unless 0) */
+ gid_t *gidv; /* Run with these groups' privileges */
+ size_t gidc; /* Number of elements in gidv */
+ unsigned timeout; /* Handler timeout */
+ char **env; /* Environment */
+};
+
+struct handler *prog_handler_alloc(event_mask ev_mask, filpatlist_t fpat,
+ struct prog_handler *p);
+void prog_handler_free(struct prog_handler *);
+size_t prog_handler_envrealloc(struct prog_handler *hp, size_t count);
+
extern int foreground;
extern int debug_level;
@@ -248,6 +244,10 @@ void watchpoint_gc(void);
int watchpoint_pattern_match(struct watchpoint *dwp, const char *file_name);
+void watchpoint_run_handlers(struct watchpoint *wp, int evflags,
+ const char *dirname, const char *filename);
+
+
void setup_watchers(void);
void shutdown_watchers(void);
@@ -257,7 +257,7 @@ struct watchpoint *watchpoint_install(const char *path, int *pnew);
struct watchpoint *watchpoint_install_ptr(struct watchpoint *dw);
void watchpoint_suspend(struct watchpoint *dwp);
void watchpoint_destroy(struct watchpoint *dwp);
-struct watchpoint *watchpoint_install_sentinel(struct watchpoint *dwp);
+int watchpoint_install_sentinel(struct watchpoint *dwp);
int watch_pathname(struct watchpoint *parent, const char *dirname, int isdir, int notify);
@@ -292,8 +292,6 @@ 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 watchpoint *dp, struct handler *hp, event_mask *event,
- const char *dir, const char *file);
char **environ_setup(char **hint, char **kve);
#define NITEMS(a) ((sizeof(a)/sizeof((a)[0])))
@@ -308,6 +306,9 @@ int sigv_set_all(void (*handler)(int), int sigc, int *sigv,
int sigv_set_tab(int sigc, struct sigtab *sigtab, struct sigaction *retsa);
int sigv_set_action_tab(int sigc, struct sigtab *sigtab, struct sigaction *sa);
-void filename_pattern_free(void *p);
-int filename_pattern_match(struct grecs_list *lp, const char *name);
+struct grecs_locus;
+int filpatlist_add(filpatlist_t *fptr, char const *arg, struct grecs_locus *loc);
+void filpatlist_add_exact(filpatlist_t *fptr, char const *arg);
+void filpatlist_destroy(filpatlist_t *fptr);
+int filpatlist_match(filpatlist_t fp, const char *name);
diff --git a/src/ev_inotify.c b/src/ev_inotify.c
index 7b2ee1d..d79b5f0 100644
--- a/src/ev_inotify.c
+++ b/src/ev_inotify.c
@@ -158,14 +158,11 @@ remove_watcher(const char *dir, const char *name)
static void
process_event(struct inotify_event *ep)
{
- struct watchpoint *dp;
- struct handler *h;
- handler_iterator_t itr;
- event_mask m;
+ struct watchpoint *wpt;
char *dirname, *filename;
- dp = wpget(ep->wd);
- if (!dp) {
+ wpt = wpget(ep->wd);
+ if (!wpt) {
if (!(ep->mask & IN_IGNORED))
diag(LOG_NOTICE, _("watcher not found: %d (%s)"),
ep->wd, ep->name);
@@ -173,8 +170,8 @@ process_event(struct inotify_event *ep)
}
if (ep->mask & IN_IGNORED) {
- diag(LOG_NOTICE, _("%s deleted"), dp->dirname);
- watchpoint_suspend(dp);
+ diag(LOG_NOTICE, _("%s deleted"), wpt->dirname);
+ watchpoint_suspend(wpt);
return;
}
@@ -189,7 +186,7 @@ process_event(struct inotify_event *ep)
were located under the mountpoint
*/
return;
- } else if (!dp) {
+ } else if (!wpt) {
if (ep->name)
diag(LOG_NOTICE, "unrecognized event %x"
"for %s", ep->mask, ep->name);
@@ -199,31 +196,28 @@ process_event(struct inotify_event *ep)
return;
}
- ev_log(ep->mask, dp);
+ ev_log(ep->mask, wpt);
if (ep->mask & IN_CREATE) {
- debug(1, ("%s/%s created", dp->dirname, ep->name));
- if (check_new_watcher(dp->dirname, ep->name) > 0)
+ debug(1, ("%s/%s created", wpt->dirname, ep->name));
+ if (check_new_watcher(wpt->dirname, ep->name) > 0)
return;
}
if (ep->len == 0)
- filename = split_pathname(dp, &dirname);
+ filename = split_pathname(wpt, &dirname);
else {
- dirname = dp->dirname;
+ dirname = wpt->dirname;
filename = ep->name;
}
- for_each_handler(dp, itr, h) {
- if (handler_matches_event(h, sys, ep->mask, filename))
- run_handler(dp, h,
- event_mask_init(&m, ep->mask, &h->ev_mask),
- dirname, filename);
- }
- unsplit_pathname(dp);
+
+ watchpoint_run_handlers(wpt, ep->mask, dirname, filename);
+
+ unsplit_pathname(wpt);
if (ep->mask & (IN_DELETE|IN_MOVED_FROM)) {
- debug(1, ("%s/%s deleted", dp->dirname, ep->name));
- remove_watcher(dp->dirname, ep->name);
+ debug(1, ("%s/%s deleted", wpt->dirname, ep->name));
+ remove_watcher(wpt->dirname, ep->name);
}
}
diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c
index 680fb42..a002182 100644
--- a/src/ev_kqueue.c
+++ b/src/ev_kqueue.c
@@ -206,13 +206,9 @@ 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(dp, h,
- event_mask_init(&m, ep->fflags, &h->ev_mask),
- dirname, filename);
- }
- }
+
+ watchpoint_run_handlers(dp, ep->fflags, dirname, filename);
+
unsplit_pathname(dp);
if (ep->fflags & (NOTE_DELETE|NOTE_RENAME)) {
diff --git a/src/fnpat.c b/src/fnpat.c
index 775a558..5a98053 100644
--- a/src/fnpat.c
+++ b/src/fnpat.c
@@ -18,7 +18,7 @@
#include <fnmatch.h>
#include <grecs.h>
-void
+static void
filename_pattern_free(void *p)
{
struct filename_pattern *pat = p;
@@ -33,14 +33,117 @@ filename_pattern_free(void *p)
free(pat);
}
+struct filpatlist {
+ grecs_list_ptr_t list;
+};
+
+static int
+is_glob(char const *str)
+{
+ return strcspn(str, "[]*?") < strlen(str);
+}
+
+void
+filpatlist_add_pattern(filpatlist_t *fptr, struct filename_pattern *pat)
+{
+ grecs_list_ptr_t list;
+ if (!*fptr) {
+ *fptr = emalloc(sizeof(*fptr));
+ (*fptr)->list = grecs_list_create();
+ (*fptr)->list->free_entry = filename_pattern_free;
+ }
+ list = (*fptr)->list;
+ grecs_list_append(list, pat);
+}
+
+void
+filpatlist_add_exact(filpatlist_t *fptr, char const *arg)
+{
+ struct filename_pattern *pat = emalloc(sizeof(*pat));
+
+ pat->neg = 0;
+ pat->type = PAT_EXACT;
+ pat->v.glob = estrdup(arg);
+ filpatlist_add_pattern(fptr, pat);
+}
+
+int
+filpatlist_add(filpatlist_t *fptr, char const *arg, grecs_locus_t *loc)
+{
+ int flags = REG_EXTENDED|REG_NOSUB;
+ struct filename_pattern *pat;
+
+ pat = emalloc(sizeof(*pat));
+ if (*arg == '!') {
+ pat->neg = 1;
+ ++arg;
+ } else
+ pat->neg = 0;
+ if (arg[0] == '/') {
+ int rc;
+ char *q, *p;
+
+ pat->type = PAT_REGEX;
+
+ p = strchr(arg+1, '/');
+ if (!p) {
+ grecs_error(loc, 0, _("unterminated regexp"));
+ free(pat);
+ return 1;
+ }
+ for (q = p + 1; *q; q++) {
+ switch (*q) {
+ case 'b':
+ flags &= ~REG_EXTENDED;
+ break;
+ case 'i':
+ flags |= REG_ICASE;
+ break;
+ default:
+ grecs_error(loc, 0,
+ _("unrecognized flag: %c"), *q);
+ free(pat);
+ return 1;
+ }
+ }
+
+ *p = 0;
+ rc = regcomp(&pat->v.re, arg + 1, flags);
+ *p = '/';
+
+ if (rc) {
+ char errbuf[128];
+ regerror(rc, &pat->v.re, errbuf, sizeof(errbuf));
+ grecs_error(loc, 0, "%s", errbuf);
+ filename_pattern_free(pat);
+ return 1;
+ }
+ } else {
+ pat->type = is_glob(arg) ? PAT_GLOB : PAT_EXACT;
+ pat->v.glob = estrdup(arg);
+ }
+ filpatlist_add_pattern(fptr, pat);
+ return 0;
+}
+
+void
+filpatlist_destroy(filpatlist_t *fptr)
+{
+ if (fptr && *fptr) {
+ grecs_list_free((*fptr)->list);
+ free(*fptr);
+ *fptr = NULL;
+ }
+}
+
int
-filename_pattern_match(struct grecs_list *lp, const char *name)
+filpatlist_match(filpatlist_t fp, const char *name)
{
struct grecs_list_entry *ep;
- if (!lp)
+ if (!fp || !fp->list)
return 0;
- for (ep = lp->head; ep; ep = ep->next) {
+ for (ep = fp->list->head; ep; ep = ep->next) {
struct filename_pattern *pat = ep->data;
int rc;
diff --git a/src/handler.c b/src/handler.c
index 2d27824..f016829 100644
--- a/src/handler.c
+++ b/src/handler.c
@@ -18,65 +18,27 @@
#include <grecs.h>
struct handler *
-handler_alloc(enum handler_type type)
+handler_alloc(event_mask ev_mask)
{
struct handler *hp = ecalloc(1, sizeof(*hp));
- hp->type = type;
hp->refcnt = 0;
+ hp->ev_mask = ev_mask;
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)
+watchpoint_run_handlers(struct watchpoint *wp, int evflags,
+ const char *dirname, const char *filename)
{
- if (!hp->fnames) {
- hp->fnames = grecs_list_create();
- hp->fnames->free_entry = filename_pattern_free;
- }
- grecs_list_append(hp->fnames, pat);
-}
+ handler_iterator_t itr;
+ struct handler *hp;
+ event_mask m;
-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);
+ for_each_handler(wp, itr, hp) {
+ if (handler_matches_event(hp, sys, evflags, filename))
+ hp->run(wp, event_mask_init(&m, evflags, &hp->ev_mask),
+ dirname, filename, hp->data);
+ }
}
static void
@@ -85,31 +47,12 @@ 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:
- watchpoint_unref(hp->sentinel_watchpoint);
- }
+ filpatlist_destroy(&hp->fnames);
+ if (hp->free)
+ hp->free(hp->data);
}
static void
@@ -286,3 +229,4 @@ handler_list_remove(handler_list_t hlist, struct handler *hp)
/* Remove watchers that don't have handlers */
watchpoint_gc();
}
+
diff --git a/src/progman.c b/src/progman.c
index 134deaf..10b014a 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -246,27 +246,27 @@ process_timeouts()
}
int
-switchpriv(struct handler *hp)
+switchpriv(struct prog_handler *hp)
{
- if (hp->prog_uid == 0 || hp->prog_uid == getuid())
+ if (hp->uid == 0 || hp->uid == getuid())
return 0;
- if (setgroups(hp->prog_gidc, hp->prog_gidv) < 0) {
+ if (setgroups(hp->gidc, hp->gidv) < 0) {
diag(LOG_CRIT, "setgroups: %s",
strerror(errno));
return 1;
}
- if (setregid(hp->prog_gidv[0], hp->prog_gidv[0]) < 0) {
+ if (setregid(hp->gidv[0], hp->gidv[0]) < 0) {
diag(LOG_CRIT, "setregid(%lu,%lu): %s",
- (unsigned long) hp->prog_gidv[0],
- (unsigned long) hp->prog_gidv[0],
+ (unsigned long) hp->gidv[0],
+ (unsigned long) hp->gidv[0],
strerror(errno));
return 1;
}
- if (setreuid(hp->prog_uid, hp->prog_uid) < 0) {
+ if (setreuid(hp->uid, hp->uid) < 0) {
diag(LOG_CRIT, "setreuid(%lu,%lu): %s",
- (unsigned long) hp->prog_uid,
- (unsigned long) hp->prog_uid,
+ (unsigned long) hp->uid,
+ (unsigned long) hp->uid,
strerror(errno));
return 1;
}
@@ -440,23 +440,25 @@ runcmd(const char *cmd, char **envhint, event_mask *event, const char *file,
}
static int
-run_handler_prog(struct handler *hp, event_mask *event,
- const char *dirname, const char *file)
+prog_handler_run(struct watchpoint *wp, event_mask *event,
+ const char *dirname, const char *file, void *data)
{
pid_t pid;
int redir_fd[2] = { -1, -1 };
struct process *redir_proc[2] = { NULL, NULL };
struct process *p;
+ struct prog_handler *hp = data;
- if (!hp->prog_command)
+ if (!hp->command)
return 0;
- debug(1, (_("starting %s, dir=%s, file=%s"), hp->prog_command, dirname, file));
- if (hp->prog_flags & HF_STDERR)
- redir_fd[REDIR_ERR] = open_redirector(hp->prog_command, LOG_ERR,
+ debug(1, (_("starting %s, dir=%s, file=%s"),
+ hp->command, dirname, file));
+ if (hp->flags & HF_STDERR)
+ redir_fd[REDIR_ERR] = open_redirector(hp->command, LOG_ERR,
&redir_proc[REDIR_ERR]);
- if (hp->prog_flags & HF_STDOUT)
- redir_fd[REDIR_OUT] = open_redirector(hp->prog_command, LOG_INFO,
+ if (hp->flags & HF_STDOUT)
+ redir_fd[REDIR_OUT] = open_redirector(hp->command, LOG_INFO,
&redir_proc[REDIR_OUT]);
pid = fork();
@@ -503,34 +505,34 @@ run_handler_prog(struct handler *hp, event_mask *event,
close_fds(fdset);
alarm(0);
signal_setup(SIG_DFL);
- runcmd(hp->prog_command, hp->prog_env, event, file, hp->prog_flags & HF_SHELL);
+ runcmd(hp->command, hp->env, event, file, hp->flags & HF_SHELL);
}
/* master */
debug(1, (_("%s running; dir=%s, file=%s, pid=%lu"),
- hp->prog_command, dirname, file, (unsigned long)pid));
+ hp->command, dirname, file, (unsigned long)pid));
- p = register_process(PROC_HANDLER, pid, time(NULL), hp->prog_timeout);
+ p = register_process(PROC_HANDLER, pid, time(NULL), hp->timeout);
if (redir_proc[REDIR_OUT]) {
redir_proc[REDIR_OUT]->v.master = p;
- redir_proc[REDIR_OUT]->timeout = hp->prog_timeout;
+ redir_proc[REDIR_OUT]->timeout = hp->timeout;
}
if (redir_proc[REDIR_ERR]) {
redir_proc[REDIR_ERR]->v.master = p;
- redir_proc[REDIR_ERR]->timeout = hp->prog_timeout;
+ redir_proc[REDIR_ERR]->timeout = hp->timeout;
}
memcpy(p->v.redir, redir_proc, sizeof(p->v.redir));
close(redir_fd[REDIR_OUT]);
close(redir_fd[REDIR_ERR]);
- if (hp->prog_flags & HF_NOWAIT) {
+ if (hp->flags & HF_NOWAIT) {
return 0;
}
debug(1, (_("waiting for %s (%lu) to terminate"),
- hp->prog_command, (unsigned long)pid));
+ hp->command, (unsigned long)pid));
while (time(NULL) - p->start < 2 * p->timeout) {
sleep(1);
process_cleanup(1);
@@ -540,30 +542,73 @@ run_handler_prog(struct handler *hp, event_mask *event,
return 0;
}
-static int
-run_sentinel(struct watchpoint *dp, struct handler *hp)
+static void
+envfree(char **env)
{
- watchpoint_init(hp->sentinel_watchpoint);
- watchpoint_install_ptr(hp->sentinel_watchpoint);
- handler_list_remove(dp->handler_list, hp);
- return 0;
+ int i;
+
+ if (!env)
+ return;
+ for (i = 0; env[i]; i++)
+ free(env[i]);
+ free(env);
}
-int
-run_handler(struct watchpoint *dp, struct handler *hp, event_mask *event,
- const char *dirname, const char *file)
+void
+prog_handler_free(struct prog_handler *hp)
{
- int rc;
- switch (hp->type) {
- case HANDLER_EXTERN:
- rc = run_handler_prog(hp, event, dirname, file);
- break;
- case HANDLER_SENTINEL:
- rc = run_sentinel(dp, hp);
- break;
- default:
- abort();
+ free(hp->command);
+ free(hp->gidv);
+ envfree(hp->env);
+}
+
+static void
+prog_handler_free_data(void *ptr)
+{
+ prog_handler_free((struct prog_handler *)ptr);
+}
+
+struct handler *
+prog_handler_alloc(event_mask ev_mask, filpatlist_t fpat,
+ struct prog_handler *p)
+{
+ struct handler *hp = handler_alloc(ev_mask);
+ struct prog_handler *mem;
+
+ hp->fnames = fpat;
+ hp->run = prog_handler_run;
+ hp->free = prog_handler_free_data;
+ mem = emalloc(sizeof(*mem));
+ *mem = *p;
+ hp->data = mem;
+ memset(p, 0, sizeof(*p));
+ 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
+prog_handler_envrealloc(struct prog_handler *hp, size_t count)
+{
+ size_t i;
+
+ if (!hp->env) {
+ hp->env = ecalloc(count + 1, sizeof(hp->env[0]));
+ i = 0;
+ } else {
+ for (i = 0; hp->env[i]; i++)
+ ;
+ hp->env = erealloc(hp->env,
+ (i + count + 1) * sizeof(hp->env[0]));
+ memset(hp->env + i, 0, (count + 1) * sizeof(hp->env[0]));
}
- return rc;
+ return i;
}
+
+
+
+
diff --git a/src/watcher.c b/src/watcher.c
index e0b4950..7ac3d86 100644
--- a/src/watcher.c
+++ b/src/watcher.c
@@ -187,8 +187,7 @@ watchpoint_destroy(struct watchpoint *wpt)
void
watchpoint_suspend(struct watchpoint *wpt)
{
- struct watchpoint *sent = watchpoint_install_sentinel(wpt);
- watchpoint_init(sent);//FIXME: error checking
+ watchpoint_install_sentinel(wpt);//FIXME: error checking
watchpoint_destroy(wpt);
if (hashtab_count(nametab) == 0) {
diag(LOG_CRIT, _("no watchers left; exiting now"));
@@ -214,7 +213,7 @@ convert_watcher(struct watchpoint *wpt)
filename = split_pathname(wpt, &dirname);
for_each_handler(wpt, itr, hp)
- handler_add_exact_filename(hp, filename);
+ filpatlist_add_exact(&hp->fnames, filename);
new_dirname = estrdup(dirname);
unsplit_pathname(wpt);
@@ -225,27 +224,62 @@ convert_watcher(struct watchpoint *wpt)
wpt->dirname = new_dirname;
return 0;
}
+
+struct sentinel {
+ struct handler *hp;
+ struct watchpoint *watchpoint;
+};
-struct watchpoint *
+static int
+sentinel_handler_run(struct watchpoint *wp, event_mask *event,
+ const char *dirname, const char *file, void *data)
+{
+ struct sentinel *sentinel = data;
+
+ watchpoint_init(sentinel->watchpoint);
+ watchpoint_install_ptr(sentinel->watchpoint);
+ handler_list_remove(wp->handler_list, sentinel->hp);
+ return 0;
+}
+
+static void
+sentinel_handler_free(void *ptr)
+{
+ struct sentinel *sentinel = ptr;
+ watchpoint_unref(sentinel->watchpoint);
+ free(sentinel);
+}
+
+int
watchpoint_install_sentinel(struct watchpoint *wpt)
{
struct watchpoint *sent;
char *dirname;
char *filename;
struct handler *hp;
+ event_mask ev_mask;
+ struct sentinel *sentinel;
filename = split_pathname(wpt, &dirname);
sent = watchpoint_install(dirname, NULL);
- hp = handler_alloc(HANDLER_SENTINEL);
- getevt("CREATE", &hp->ev_mask);