/* direvent - directory content watcher daemon
Copyright (C) 2012-2014 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 "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "gettext.h"
#define _(s) gettext(s)
#define N_(s) s
/* Generic (system-independent) event codes */
#define GENEV_CREATE 0x01
#define GENEV_WRITE 0x02
#define GENEV_ATTRIB 0x04
#define GENEV_DELETE 0x08
/* Handler flags. */
#define HF_NOWAIT 0x01 /* Don't wait for termination */
#define HF_STDOUT 0x02 /* Capture stdout */
#define HF_STDERR 0x04 /* Capture stderr */
#ifndef DEFAULT_TIMEOUT
# define DEFAULT_TIMEOUT 5
#endif
typedef struct {
int gen_mask; /* Generic event mask */
int sys_mask; /* System event mask */
} event_mask;
/* Event description */
struct transtab {
char *name;
int tok;
};
#define PAT_GLOB 0
#define PAT_REGEX 1
struct filename_pattern {
int type;
int neg;
union {
regex_t re;
char *glob;
} v;
};
/* Handler structure */
struct handler {
struct handler *next;
event_mask ev_mask; /* Event mask */
struct grecs_list *fnames; /* File name patterns */
int flags; /* Handler flags */
const char *prog; /* Handler program (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 */
};
/* A directory watcher is described by the following structure */
struct dirwatcher {
int refcnt;
int wd; /* Watch descriptor */
struct dirwatcher *parent; /* Points to the parent watcher.
NULL for top-level watchers */
char *dirname; /* Pathname being watched */
struct handler *handler_list; /* List of handlers */
struct handler *handler_tail; /* Tail of the handler list */
int depth; /* Recursion depth */
char *split_p; /* Points to the deleted directory
separator in dirname (see
split_pathname,
unsplit_pathname */
#if USE_IFACE == IFACE_KQUEUE
mode_t file_mode;
time_t file_ctime;
#endif
};
#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)
extern int foreground;
extern int debug_level;
extern int facility;
extern char *tag;
extern int syslog_include_prio;
extern char *pidfile;
extern char *user;
extern unsigned opt_timeout;
extern unsigned opt_flags;
extern int signo;
extern int stop;
extern pid_t self_test_pid;
extern int exit_code;
void *emalloc(size_t size);
void *ecalloc(size_t nmemb, size_t size);
void *erealloc(void *ptr, size_t size);
char *estrdup(const char *str);
char *mkfilename(const char *dir, const char *file);
void diag(int prio, const char *fmt, ...);
void debugprt(const char *fmt, ...);
#define debug(l, c) do { if (debug_level>=(l)) debugprt c; } while(0)
void signal_setup(void (*sf) (int));
int detach(void (*)(void));
int sysev_filemask(struct dirwatcher *dp);
void sysev_init(void);
int sysev_add_watch(struct dirwatcher *dwp, event_mask mask);
void sysev_rm_watch(struct dirwatcher *dwp);
int sysev_select(void);
int sysev_name_to_code(const char *name);
const char *sysev_code_to_name(int code);
int defevt(const char *name, event_mask *mask, int line);
int getevt(const char *name, event_mask *mask);
int evtnullp(event_mask *mask);
event_mask *event_mask_init(event_mask *m, int fflags, event_mask const *);
void evtsetall(event_mask *m);
/* Translate generic events to system ones and vice-versa */
extern event_mask genev_xlat[];
/* Translate generic event codes to symbolic names and vice-versa */
extern struct transtab genev_transtab[];
/* Translate system event codes to symbolic names and vice-versa */
extern struct transtab sysev_transtab[];
int trans_strtotok(struct transtab *tab, const char *str, int *ret);
char *trans_toktostr(struct transtab *tab, int tok);
char *trans_tokfirst(struct transtab *tab, int tok, int *next);
char *trans_toknext(struct transtab *tab, int tok, int *next);
struct hashtab;
struct hashent {
int used;
};
int hashtab_replace(struct hashtab *st, void *ent, void **old_ent);
const char *hashtab_strerror(int rc);
int hashtab_remove(struct hashtab *st, void *elt);
int hashtab_get_index(unsigned *idx, struct hashtab *st, void *key,
int *install);
void *hashtab_lookup_or_install(struct hashtab *st, void *key, int *install);
void hashtab_clear(struct hashtab *st);
struct hashtab *hashtab_create(size_t elsize,
unsigned (*hash_fun)(void *, unsigned long),
int (*cmp_fun)(const void *, const void *),
int (*copy_fun)(void *, void *),
void *(*alloc_fun)(size_t),
void (*free_fun)(void *));
void hashtab_free(struct hashtab *st);
size_t hashtab_count_entries(struct hashtab *st);
typedef int (*hashtab_enumerator_t) (struct hashent *, void *);
int hashtab_foreach(struct hashtab *st, hashtab_enumerator_t fun,
void *data);
size_t hashtab_count(struct hashtab *st);
unsigned hash_string(const char *name, unsigned long hashsize);
struct pathent {
long depth;
size_t len;
char path[1];
};
void config_help(void);
struct grecs_node;
void config_finish(struct grecs_node *tree);
void config_parse(const char *file);
int get_facility(const char *arg);
int get_priority(const char *arg);
void setup_watchers(void);
struct dirwatcher *dirwatcher_lookup(const char *dirname);
struct dirwatcher *dirwatcher_lookup_wd(int wd);
int check_new_watcher(const char *dir, const char *name);
struct dirwatcher *dirwatcher_install(const char *path, int *pnew);
void dirwatcher_destroy(struct dirwatcher *dwp);
int watch_pathname(struct dirwatcher *parent, const char *dirname, int isdir, int notify);
char *split_pathname(struct dirwatcher *dp, char **dirname);
void unsplit_pathname(struct dirwatcher *dp);
void ev_log(int flags, struct dirwatcher *dp);
void deliver_ev_create(struct dirwatcher *dp, const char *name);
int subwatcher_create(struct dirwatcher *parent, const char *dirname,
int isdir, int notify);
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,
const char *dir, const char *file);
char **environ_setup(char **hint, char **kve);
#define NITEMS(a) ((sizeof(a)/sizeof((a)[0])))
struct sigtab {
int signo;
void (*sigfun)(int);
};
int sigv_set_action(int sigc, int *sigv, struct sigaction *sa);
int sigv_set_all(void (*handler)(int), int sigc, int *sigv,
struct sigaction *retsa);
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);