diff --git a/configure.ac b/configure.ac index 2f52712..a517ece 100644 --- a/configure.ac +++ b/configure.ac @@ -14,6 +14,7 @@ AC_PROG_MAKE_SET PKG_CHECK_MODULES(LIBLUA, lua5.1) # Checks for header files. AC_CHECK_HEADERS([sys/inotify.h]) +AC_CHECK_HEADERS([sys/fanotify.h]) ### # --with-runner option diff --git a/fanotify-syscall.h b/fanotify-syscall.h new file mode 100644 index 0000000..76f2f94 --- /dev/null +++ b/fanotify-syscall.h @@ -0,0 +1,38 @@ +/** + * Hack for yet missing fanotify interface in glibc. + * Does the syscalls by itself. + * + * TODO: Delete this as soon a glibc release supports this. + */ +#ifndef FANOTIFY_SYSCALL +#define FANOTIFY_SYSCALL + +#define __EXPORTED_HEADERS__ +#include +#undef __EXPORTED_HEADERS__ + +#include + +#if defined(__x86_64__) +# define __NR_fanotify_init 300 +# define __NR_fanotify_mark 301 +#elif defined(__i386__) +# define __NR_fanotify_init 338 +# define __NR_fanotify_mark 339 +#else +# error "System call numbers not defined for this architecture" +#endif + +static int fanotify_init(unsigned int flags, unsigned int event_f_flags) +{ + return syscall(__NR_fanotify_init, flags, event_f_flags); +} + +static int fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + int dfd, const char *pathname) +{ + return syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, + dfd, pathname); +} + +#endif diff --git a/fanotify.c b/fanotify.c index 3fe6060..ccd578f 100644 --- a/fanotify.c +++ b/fanotify.c @@ -10,11 +10,30 @@ * Interface to Linux' new filesystem monitor - fanotify. */ #include "lsyncd.h" +#include +#include +#include #include #include #include + +#ifdef HAVE_SYS_FANOTIFY_H +# include +#else +# warning sys/fanotify.h not found, using own syscalls as workaround. +# include "fanotify-syscall.h" +#endif + +/** + * The fanotify file descriptor. + */ +static int fanotify_fd = -1; + +/** + * Cores fanotify functions. + */ static const luaL_reg lfanotifylib[] = { {NULL, NULL} }; @@ -28,19 +47,43 @@ register_fanotify(lua_State *L) { luaL_register(L, "fanotify", lfanotifylib); } +/** + * Called by function pointer from when the inotify file descriptor + * became ready. Reads it contents and forward all received events + * to the runner. + */ +static void +fanotify_ready(lua_State *L, struct observance *ob) +{ + // TODO +} + /** - * opens and initalizes fsevents. + * closes fanoitfy + */ +extern void +fanotify_tidy(struct observance *ob) { + if (ob->fd != fanotify_fd) { + logstring("Error", "Internal, fanotify_fd != ob->fd"); + exit(-1); // ERRNO + } + close(fanotify_fd); +} + + +/** + * opens and initalizes fanotify. */ extern void open_fanotify(lua_State *L) { - // TODO -} - -/** - * closes fsevents - */ -extern void -close_fanotify() { - // TODO + fanotify_fd = fanotify_init(O_CLOEXEC | O_NONBLOCK, O_RDONLY); + if (fanotify_fd < 0) { + printlogf(L, "Error", + "Cannot access fanotify monitor! (%d:%s)", + errno, strerror(errno)); + exit(-1); // ERRNO + } + + observe_fd(fanotify_fd, fanotify_ready, NULL, fanotify_tidy, NULL); } diff --git a/inotify.c b/inotify.c index 24b2206..73fbf31 100644 --- a/inotify.c +++ b/inotify.c @@ -92,6 +92,9 @@ l_rmwatch(lua_State *L) return 0; } +/** + * Cores inotify functions. + */ static const luaL_reg linotfylib[] = { {"addwatch", l_addwatch }, {"rmwatch", l_rmwatch }, @@ -316,6 +319,22 @@ register_inotify(lua_State *L) { luaL_register(L, "inotify", linotfylib); } +/** + * closes inotify + */ +static void +inotify_tidy(struct observance *ob) { + if (ob->fd != inotify_fd) { + logstring("Error", "Internal, inotify_fd != ob->fd"); + exit(-1); // ERRNO + } + close(inotify_fd); + free(readbuf); + readbuf = NULL; +} + + + /** * opens and initalizes inotify. */ @@ -331,23 +350,13 @@ open_inotify(lua_State *L) { inotify_fd = inotify_init(); if (inotify_fd == -1) { printlogf(L, "Error", - "Cannot create inotify instance! (%d:%s)", + "Cannot access inotify monitor! (%d:%s)", errno, strerror(errno)); exit(-1); // ERRNO } close_exec_fd(inotify_fd); non_block_fd(inotify_fd); - observe_fd(inotify_fd, inotify_ready, NULL, NULL); -} - -/** - * closes inotify - */ -extern void -close_inotify() { - close(inotify_fd); - free(readbuf); - readbuf = NULL; + observe_fd(inotify_fd, inotify_ready, NULL, inotify_tidy, NULL); } diff --git a/lsyncd.c b/lsyncd.c index 9922ca2..e244629 100644 --- a/lsyncd.c +++ b/lsyncd.c @@ -391,26 +391,32 @@ struct pipemsg { * writeable again */ static void -pipe_writey(lua_State *L, int fd, void *extra) { - struct pipemsg *pm = (struct pipemsg *) extra; +pipe_writey(lua_State *L, struct observance *observance) +{ + int fd = observance->fd; + struct pipemsg *pm = (struct pipemsg *) observance->extra; int len = write(fd, pm->text + pm->pos, pm->tlen - pm->pos); - bool do_close = false; pm->pos += len; if (len < 0) { logstring("Normal", "broken pipe."); - do_close = true; + nonobserve_fd(fd); } else if (pm->pos >= pm->tlen) { logstring("Debug", "finished pipe."); - do_close = true; - } - if (do_close) { - close(fd); - free(pm->text); - free(extra); - unobserve_fd(fd); + nonobserve_fd(fd); } } +/** + * Called when cleaning up a pipe + */ +static void +pipe_tidy(struct observance *observance) +{ + struct pipemsg *pm = (struct pipemsg *) observance->extra; + close(observance->fd); + free(pm->text); + free(pm); +} /***************************************************************************** * helper routines. @@ -447,7 +453,7 @@ non_block_fd(int fd) logstring("Error", "cannot get status flags!"); exit(-1); // ERRNO } - flags |= O_NONBLOCK;; + flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) == -1) { logstring("Error", "cannot set status flags!"); exit(-1); // ERRNO @@ -726,12 +732,12 @@ l_exec(lua_State *L) logstring("Exec", "one-sweeped pipe"); } else { struct pipemsg *pm; - logstring("Exec", "adding pipe observer"); + logstring("Exec", "adding pipe observance"); pm = s_calloc(1, sizeof(struct pipemsg)); pm->text = s_strdup(pipe_text); pm->tlen = tlen; pm->pos = len; - observe_fd(pipefd[1], NULL, pipe_writey, pm); + observe_fd(pipefd[1], NULL, pipe_writey, pipe_tidy, pm); } close(pipefd[0]); } @@ -999,54 +1005,27 @@ load_runner_func(lua_State *L, lua_remove(L, -2); } - -/** - * An observer to be called when a file descritor becomes - * read-ready or write-ready. - */ -struct observer { - /** - * The file descriptor to observe. - */ - int fd; - - /** - * Function to call when read becomes ready. - */ - void (*ready)(lua_State *L, int fd, void *extra); - - /** - * Function to call when write becomes ready. - */ - void (*writey)(lua_State *L, int fd, void *extra); - - /** - * Extra tokens to pass to the functions- - */ - void *extra; -}; - /** * List of file descriptor watches. */ -static struct observer * observers = NULL; -static int observers_len = 0; -static int observers_size = 0; +static struct observance * observances = NULL; +static int observances_len = 0; +static int observances_size = 0; /** - * List of file descriptors to unobserve. + * List of file descriptors to nonobserve. * While working for the oberver lists, it may - * not be altered, thus unobserve stores here the + * not be altered, thus nonobserve stores here the * actions that will be delayed. */ -static int *unobservers = NULL; -static int unobservers_len = 0; -static int unobservers_size = 0; +static int *nonobservances = NULL; +static int nonobservances_len = 0; +static int nonobservances_size = 0; /** - * true while the observers list is being handled. + * true while the observances list is being handled. */ -static bool observer_action = false; +static bool observance_action = false; /** * Core watches a filedescriptor to become ready, @@ -1054,83 +1033,90 @@ static bool observer_action = false; */ extern void observe_fd(int fd, - void (*ready)(lua_State *L, int fd, void *extra), - void (*writey)(lua_State *L, int fd, void *extra), + void (*ready) (lua_State *, struct observance *), + void (*writey)(lua_State *, struct observance *), + void (*tidy) (struct observance *), void *extra) { int pos; - if (observer_action) { + if (observance_action) { // TODO logstring("Error", - "Adding observers in ready/writey handlers not yet supported"); + "internal, New observances in ready/writey handlers not yet supported"); exit(-1); // ERRNO } - if (observers_len + 1 > observers_size) { - observers_size = observers_len + 1; - observers = s_realloc(observers, - observers_size * sizeof(struct observer)); + if (!tidy) { + logstring("Error", + "internal, tidy() in observe_fd() must not be NULL."); + exit(-1); // ERRNO } - for(pos = 0; pos < observers_len; pos++) { - if (observers[pos].fd <= fd) { + if (observances_len + 1 > observances_size) { + observances_size = observances_len + 1; + observances = s_realloc(observances, + observances_size * sizeof(struct observance)); + } + for(pos = 0; pos < observances_len; pos++) { + if (observances[pos].fd <= fd) { break; } } - if (observers[pos].fd == fd) { + if (observances[pos].fd == fd) { logstring("Error", "Observing already an observed file descriptor."); exit(-1); // ERRNO } - memmove(observers + pos + 1, observers + pos, - (observers_len - pos) * (sizeof(struct observer))); + memmove(observances + pos + 1, observances + pos, + (observances_len - pos) * (sizeof(struct observance))); - observers_len++; - observers[pos].fd = fd; - observers[pos].ready = ready; - observers[pos].writey = writey; - observers[pos].extra = extra; + observances_len++; + observances[pos].fd = fd; + observances[pos].ready = ready; + observances[pos].writey = writey; + observances[pos].tidy = tidy; + observances[pos].extra = extra; } /** * Makes core no longer watch fd. */ extern void -unobserve_fd(int fd) +nonobserve_fd(int fd) { int pos; - if (observer_action) { + if (observance_action) { /* this function is called through a ready/writey handler - * while the core works through the observer list, thus + * while the core works through the observance list, thus * it does not alter the list, but stores this actions * on a stack */ - unobservers_len++; - if (unobservers_len > unobservers_size) { - unobservers_size = unobservers_len; - unobservers = s_realloc(unobservers, - unobservers_size * sizeof(int)); + nonobservances_len++; + if (nonobservances_len > nonobservances_size) { + nonobservances_size = nonobservances_len; + nonobservances = s_realloc(nonobservances, + nonobservances_size * sizeof(int)); } - unobservers[unobservers_len - 1] = fd; + nonobservances[nonobservances_len - 1] = fd; return; } /* looks for the fd */ - for(pos = 0; pos < observers_len; pos++) { - if (observers[pos].fd == fd) { + for(pos = 0; pos < observances_len; pos++) { + if (observances[pos].fd == fd) { break; } } - if (pos >= observers_len) { + if (pos >= observances_len) { logstring("Error", - "internal fail, not observer file descriptor in unobserve"); + "internal fail, not observance file descriptor in nonobserve"); exit(-1); //ERRNO } /* and moves the list down */ - memmove(observers + pos, observers + pos + 1, - (observers_len - pos) * (sizeof(struct observer))); - observers_len--; + memmove(observances + pos, observances + pos + 1, + (observances_len - pos) * (sizeof(struct observance))); + observances_len--; } /** @@ -1194,52 +1180,52 @@ masterloop(lua_State *L) FD_ZERO(&rfds); FD_ZERO(&wfds); - for(pi = 0; pi < observers_len; pi++) { - int fd = observers[pi].fd; - if (observers[pi].ready) { + for(pi = 0; pi < observances_len; pi++) { + int fd = observances[pi].fd; + if (observances[pi].ready) { FD_SET(fd, &rfds); } - if (observers[pi].writey) { + if (observances[pi].writey) { FD_SET(fd, &wfds); } } /* the great select */ pr = pselect( - observers[observers_len - 1].fd + 1, + observances[observances_len - 1].fd + 1, &rfds, &wfds, NULL, have_alarm ? &tv : NULL, &sigset); if (pr >= 0) { - /* walks through the observers calling ready/writey fds */ - observer_action = true; - for(pi = 0; pi < observers_len; pi++) { - int fd = observers[pi].fd; - void *extra = observers[pi].extra; + /* walks through the observances calling ready/writey */ + observance_action = true; + for(pi = 0; pi < observances_len; pi++) { + struct observance *obs = observances + pi; if (hup || term) { break; } - if (observers[pi].ready && FD_ISSET(fd, &rfds)) { - observers[pi].ready(L, fd, extra); + if (obs->ready && FD_ISSET(obs->fd, &rfds)) { + obs->ready(L, obs); } if (hup || term) { break; } - if (unobservers_len > 0 && - unobservers[unobservers_len - 1] == fd) { - /* ready() unobserved itself */ + if (nonobservances_len > 0 && + nonobservances[nonobservances_len-1] == obs->fd) { + /* TODO breaks if more nonobserves */ + /* ready() nonobserved itself */ continue; } - if (observers[pi].writey && FD_ISSET(fd, &wfds)) { - observers[pi].writey(L, fd, extra); + if (obs->writey && FD_ISSET(obs->fd, &wfds)) { + obs->writey(L, obs); } } - observer_action = false; - /* work through delayed unobserve_fd() calls */ - for (pi = 0; pi < unobservers_len; pi++) { - unobserve_fd(unobservers[pi]); + observance_action = false; + /* work through delayed nonobserve_fd() calls */ + for (pi = 0; pi < nonobservances_len; pi++) { + nonobserve_fd(nonobservances[pi]); } - unobservers_len = 0; + nonobservances_len = 0; } } } @@ -1576,6 +1562,17 @@ main1(int argc, char *argv[]) masterloop(L); /* cleanup */ + { + /* tidies all observances */ + int i; + for(i = 0; i < observances_len; i++) { + struct observance *obs = observances + i; + obs->tidy(obs); + } + observances_len = 0; + nonobservances_len = 0; + } + { /* frees logging categories */ int ci; @@ -1604,12 +1601,6 @@ main1(int argc, char *argv[]) settings.log_level = 0, settings.nodaemon = false, -#ifdef LSYNCD_WITH_INOTIFY - close_inotify(); -#endif -#ifdef LSYNCD_WITH_FSEVENTS - close_fsevents(); -#endif lua_close(L); return 0; } diff --git a/lsyncd.h b/lsyncd.h index 80f40c8..4577eda 100644 --- a/lsyncd.h +++ b/lsyncd.h @@ -103,15 +103,39 @@ extern void non_block_fd(int fd); /* Sets the close-on-exit flag for a file descriptor. */ extern void close_exec_fd(int fd); -/* makes the core to observe a file descriptor */ + +/** + * An observance to be called when a file descritor becomes + * read-ready or write-ready. + */ +struct observance { + /* The file descriptor to observe. */ + int fd; + + /* Function to call when read becomes ready. */ + void (*ready)(lua_State *, struct observance *); + + /* Function to call when write becomes ready. */ + void (*writey)(lua_State *, struct observance *); + + /* Function to call to clean up */ + void (*tidy)(struct observance *); + + /* Extra tokens to pass to the functions- */ + void *extra; +}; + +/* makes the core observe a file descriptor */ extern void observe_fd( int fd, - void (*ready)(lua_State *L, int fd, void *extra), - void (*writey)(lua_State *L, int fd, void *extra), - void *extra); + void (*ready) (lua_State *, struct observance *), + void (*writey)(lua_State *, struct observance *), + void (*tidy) (struct observance *), + void *extra +); /* stops the core to observe a file descriptor */ -extern void unobserve_fd(int fd); +extern void nonobserve_fd(int fd); /*----------------------------------------------------------------------------- * inotify @@ -119,7 +143,14 @@ extern void unobserve_fd(int fd); #ifdef LSYNCD_WITH_INOTIFY extern void register_inotify(lua_State *L); extern void open_inotify(lua_State *L); -extern void close_inotify(); +#endif + +/*----------------------------------------------------------------------------- + * fanotify + */ +#ifdef LSYNCD_WITH_FANOTIFY +extern void register_fanotify(lua_State *L); +extern void open_fanotify(lua_State *L); #endif /*----------------------------------------------------------------------------- @@ -128,7 +159,6 @@ extern void close_inotify(); #ifdef LSYNCD_WITH_FSEVENTS extern void register_fsevents(lua_State *L); extern void open_fsevents(lua_State *L); -extern void close_fsevents(); #endif