From a60dcd92df15705bb84f644c99fd166e101dc681 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 23 Aug 2016 08:36:01 +0300 Subject: 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): New members : 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. --- src/config.c | 141 ++++++++++++++++--------------------------------------- src/direvent.h | 89 ++++++++++++++++++----------------- src/ev_inotify.c | 40 +++++++--------- src/ev_kqueue.c | 10 ++-- src/fnpat.c | 111 +++++++++++++++++++++++++++++++++++++++++-- src/handler.c | 90 +++++++---------------------------- src/progman.c | 133 ++++++++++++++++++++++++++++++++++----------------- src/watcher.c | 69 ++++++++++++++++++++------- 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 #include -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 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); - hp->sentinel_watchpoint = wpt; + + getevt("CREATE", &ev_mask); + hp = handler_alloc(ev_mask); + hp->run = sentinel_handler_run; + hp->free = sentinel_handler_free; + + sentinel = emalloc(sizeof(*sentinel)); + sentinel->watchpoint = wpt; + sentinel->hp = hp; watchpoint_ref(wpt); - handler_add_exact_filename(hp, filename); + + hp->data = sentinel; + + filpatlist_add_exact(&hp->fnames, filename); handler_list_append(sent->handler_list, hp); unsplit_pathname(wpt); diag(LOG_NOTICE, _("installing CREATE sentinel for %s"), wpt->dirname); - watchpoint_init(sent); - return sent; + return watchpoint_init(sent); } int @@ -261,8 +295,7 @@ watchpoint_init(struct watchpoint *wpt) if (stat(wpt->dirname, &st)) { if (errno == ENOENT) { - wpt = watchpoint_install_sentinel(wpt); - return 0; + return watchpoint_install_sentinel(wpt); } else { diag(LOG_ERR, _("cannot set watcher on %s: %s"), wpt->dirname, strerror(errno)); @@ -323,15 +356,15 @@ subwatcher_create(struct watchpoint *parent, const char *dirname, /* Deliver GENEV_CREATE event */ void -deliver_ev_create(struct watchpoint *dp, const char *name) +deliver_ev_create(struct watchpoint *wp, const char *name) { event_mask m = { GENEV_CREATE, 0 }; - struct handler *h; + struct handler *hp; handler_iterator_t itr; - for_each_handler(dp, itr, h) { - if (handler_matches_event(h, gen, GENEV_CREATE, name)) - run_handler(dp, h, &m, dp->dirname, name); + for_each_handler(wp, itr, hp) { + if (handler_matches_event(hp, gen, GENEV_CREATE, name)) + hp->run(wp, &m, wp->dirname, name, hp->data); } } @@ -387,7 +420,7 @@ watchpoint_pattern_match(struct watchpoint *wpt, const char *file_name) handler_iterator_t itr; for_each_handler(wpt, itr, hp) { - if (filename_pattern_match(hp->fnames, file_name) == 0) + if (filpatlist_match(hp->fnames, file_name) == 0) return 0; } return 1; -- cgit v1.2.1