clean observances, fanotify without glibc support hack

This commit is contained in:
Axel Kittenberger 2010-11-28 09:15:54 +00:00
parent 91bad8bf46
commit cb3737f5e8
6 changed files with 254 additions and 142 deletions

View File

@ -14,6 +14,7 @@ AC_PROG_MAKE_SET
PKG_CHECK_MODULES(LIBLUA, lua5.1) PKG_CHECK_MODULES(LIBLUA, lua5.1)
# Checks for header files. # Checks for header files.
AC_CHECK_HEADERS([sys/inotify.h]) AC_CHECK_HEADERS([sys/inotify.h])
AC_CHECK_HEADERS([sys/fanotify.h])
### ###
# --with-runner option # --with-runner option

38
fanotify-syscall.h Normal file
View File

@ -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 <linux/types.h>
#undef __EXPORTED_HEADERS__
#include <unistd.h>
#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

View File

@ -10,11 +10,30 @@
* Interface to Linux' new filesystem monitor - fanotify. * Interface to Linux' new filesystem monitor - fanotify.
*/ */
#include "lsyncd.h" #include "lsyncd.h"
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <lua.h> #include <lua.h>
#include <lualib.h> #include <lualib.h>
#include <lauxlib.h> #include <lauxlib.h>
#ifdef HAVE_SYS_FANOTIFY_H
# include <sys/fanotify.h>
#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[] = { static const luaL_reg lfanotifylib[] = {
{NULL, NULL} {NULL, NULL}
}; };
@ -29,18 +48,42 @@ register_fanotify(lua_State *L) {
} }
/** /**
* opens and initalizes fsevents. * Called by function pointer from when the inotify file descriptor
* became ready. Reads it contents and forward all received events
* to the runner.
*/ */
extern void static void
open_fanotify(lua_State *L) { fanotify_ready(lua_State *L, struct observance *ob)
{
// TODO // TODO
} }
/** /**
* closes fsevents * closes fanoitfy
*/ */
extern void extern void
close_fanotify() { fanotify_tidy(struct observance *ob) {
// TODO 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) {
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);
} }

View File

@ -92,6 +92,9 @@ l_rmwatch(lua_State *L)
return 0; return 0;
} }
/**
* Cores inotify functions.
*/
static const luaL_reg linotfylib[] = { static const luaL_reg linotfylib[] = {
{"addwatch", l_addwatch }, {"addwatch", l_addwatch },
{"rmwatch", l_rmwatch }, {"rmwatch", l_rmwatch },
@ -316,6 +319,22 @@ register_inotify(lua_State *L) {
luaL_register(L, "inotify", linotfylib); 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. * opens and initalizes inotify.
*/ */
@ -331,23 +350,13 @@ open_inotify(lua_State *L) {
inotify_fd = inotify_init(); inotify_fd = inotify_init();
if (inotify_fd == -1) { if (inotify_fd == -1) {
printlogf(L, "Error", printlogf(L, "Error",
"Cannot create inotify instance! (%d:%s)", "Cannot access inotify monitor! (%d:%s)",
errno, strerror(errno)); errno, strerror(errno));
exit(-1); // ERRNO exit(-1); // ERRNO
} }
close_exec_fd(inotify_fd); close_exec_fd(inotify_fd);
non_block_fd(inotify_fd); non_block_fd(inotify_fd);
observe_fd(inotify_fd, inotify_ready, NULL, NULL); observe_fd(inotify_fd, inotify_ready, NULL, inotify_tidy, NULL);
}
/**
* closes inotify
*/
extern void
close_inotify() {
close(inotify_fd);
free(readbuf);
readbuf = NULL;
} }

217
lsyncd.c
View File

@ -391,26 +391,32 @@ struct pipemsg {
* writeable again * writeable again
*/ */
static void static void
pipe_writey(lua_State *L, int fd, void *extra) { pipe_writey(lua_State *L, struct observance *observance)
struct pipemsg *pm = (struct pipemsg *) extra; {
int fd = observance->fd;
struct pipemsg *pm = (struct pipemsg *) observance->extra;
int len = write(fd, pm->text + pm->pos, pm->tlen - pm->pos); int len = write(fd, pm->text + pm->pos, pm->tlen - pm->pos);
bool do_close = false;
pm->pos += len; pm->pos += len;
if (len < 0) { if (len < 0) {
logstring("Normal", "broken pipe."); logstring("Normal", "broken pipe.");
do_close = true; nonobserve_fd(fd);
} else if (pm->pos >= pm->tlen) { } else if (pm->pos >= pm->tlen) {
logstring("Debug", "finished pipe."); logstring("Debug", "finished pipe.");
do_close = true; nonobserve_fd(fd);
}
if (do_close) {
close(fd);
free(pm->text);
free(extra);
unobserve_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. * helper routines.
@ -447,7 +453,7 @@ non_block_fd(int fd)
logstring("Error", "cannot get status flags!"); logstring("Error", "cannot get status flags!");
exit(-1); // ERRNO exit(-1); // ERRNO
} }
flags |= O_NONBLOCK;; flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) == -1) { if (fcntl(fd, F_SETFL, flags) == -1) {
logstring("Error", "cannot set status flags!"); logstring("Error", "cannot set status flags!");
exit(-1); // ERRNO exit(-1); // ERRNO
@ -726,12 +732,12 @@ l_exec(lua_State *L)
logstring("Exec", "one-sweeped pipe"); logstring("Exec", "one-sweeped pipe");
} else { } else {
struct pipemsg *pm; struct pipemsg *pm;
logstring("Exec", "adding pipe observer"); logstring("Exec", "adding pipe observance");
pm = s_calloc(1, sizeof(struct pipemsg)); pm = s_calloc(1, sizeof(struct pipemsg));
pm->text = s_strdup(pipe_text); pm->text = s_strdup(pipe_text);
pm->tlen = tlen; pm->tlen = tlen;
pm->pos = len; pm->pos = len;
observe_fd(pipefd[1], NULL, pipe_writey, pm); observe_fd(pipefd[1], NULL, pipe_writey, pipe_tidy, pm);
} }
close(pipefd[0]); close(pipefd[0]);
} }
@ -999,54 +1005,27 @@ load_runner_func(lua_State *L,
lua_remove(L, -2); 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. * List of file descriptor watches.
*/ */
static struct observer * observers = NULL; static struct observance * observances = NULL;
static int observers_len = 0; static int observances_len = 0;
static int observers_size = 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 * 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. * actions that will be delayed.
*/ */
static int *unobservers = NULL; static int *nonobservances = NULL;
static int unobservers_len = 0; static int nonobservances_len = 0;
static int unobservers_size = 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, * Core watches a filedescriptor to become ready,
@ -1054,83 +1033,90 @@ static bool observer_action = false;
*/ */
extern void extern void
observe_fd(int fd, observe_fd(int fd,
void (*ready)(lua_State *L, int fd, void *extra), void (*ready) (lua_State *, struct observance *),
void (*writey)(lua_State *L, int fd, void *extra), void (*writey)(lua_State *, struct observance *),
void (*tidy) (struct observance *),
void *extra) void *extra)
{ {
int pos; int pos;
if (observer_action) { if (observance_action) {
// TODO // TODO
logstring("Error", logstring("Error",
"Adding observers in ready/writey handlers not yet supported"); "internal, New observances in ready/writey handlers not yet supported");
exit(-1); // ERRNO exit(-1); // ERRNO
} }
if (observers_len + 1 > observers_size) { if (!tidy) {
observers_size = observers_len + 1; logstring("Error",
observers = s_realloc(observers, "internal, tidy() in observe_fd() must not be NULL.");
observers_size * sizeof(struct observer)); exit(-1); // ERRNO
} }
for(pos = 0; pos < observers_len; pos++) { if (observances_len + 1 > observances_size) {
if (observers[pos].fd <= fd) { 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; break;
} }
} }
if (observers[pos].fd == fd) { if (observances[pos].fd == fd) {
logstring("Error", logstring("Error",
"Observing already an observed file descriptor."); "Observing already an observed file descriptor.");
exit(-1); // ERRNO exit(-1); // ERRNO
} }
memmove(observers + pos + 1, observers + pos, memmove(observances + pos + 1, observances + pos,
(observers_len - pos) * (sizeof(struct observer))); (observances_len - pos) * (sizeof(struct observance)));
observers_len++; observances_len++;
observers[pos].fd = fd; observances[pos].fd = fd;
observers[pos].ready = ready; observances[pos].ready = ready;
observers[pos].writey = writey; observances[pos].writey = writey;
observers[pos].extra = extra; observances[pos].tidy = tidy;
observances[pos].extra = extra;
} }
/** /**
* Makes core no longer watch fd. * Makes core no longer watch fd.
*/ */
extern void extern void
unobserve_fd(int fd) nonobserve_fd(int fd)
{ {
int pos; int pos;
if (observer_action) { if (observance_action) {
/* this function is called through a ready/writey handler /* 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 * it does not alter the list, but stores this actions
* on a stack * on a stack
*/ */
unobservers_len++; nonobservances_len++;
if (unobservers_len > unobservers_size) { if (nonobservances_len > nonobservances_size) {
unobservers_size = unobservers_len; nonobservances_size = nonobservances_len;
unobservers = s_realloc(unobservers, nonobservances = s_realloc(nonobservances,
unobservers_size * sizeof(int)); nonobservances_size * sizeof(int));
} }
unobservers[unobservers_len - 1] = fd; nonobservances[nonobservances_len - 1] = fd;
return; return;
} }
/* looks for the fd */ /* looks for the fd */
for(pos = 0; pos < observers_len; pos++) { for(pos = 0; pos < observances_len; pos++) {
if (observers[pos].fd == fd) { if (observances[pos].fd == fd) {
break; break;
} }
} }
if (pos >= observers_len) { if (pos >= observances_len) {
logstring("Error", logstring("Error",
"internal fail, not observer file descriptor in unobserve"); "internal fail, not observance file descriptor in nonobserve");
exit(-1); //ERRNO exit(-1); //ERRNO
} }
/* and moves the list down */ /* and moves the list down */
memmove(observers + pos, observers + pos + 1, memmove(observances + pos, observances + pos + 1,
(observers_len - pos) * (sizeof(struct observer))); (observances_len - pos) * (sizeof(struct observance)));
observers_len--; observances_len--;
} }
/** /**
@ -1194,52 +1180,52 @@ masterloop(lua_State *L)
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_ZERO(&wfds); FD_ZERO(&wfds);
for(pi = 0; pi < observers_len; pi++) { for(pi = 0; pi < observances_len; pi++) {
int fd = observers[pi].fd; int fd = observances[pi].fd;
if (observers[pi].ready) { if (observances[pi].ready) {
FD_SET(fd, &rfds); FD_SET(fd, &rfds);
} }
if (observers[pi].writey) { if (observances[pi].writey) {
FD_SET(fd, &wfds); FD_SET(fd, &wfds);
} }
} }
/* the great select */ /* the great select */
pr = pselect( pr = pselect(
observers[observers_len - 1].fd + 1, observances[observances_len - 1].fd + 1,
&rfds, &wfds, NULL, &rfds, &wfds, NULL,
have_alarm ? &tv : NULL, &sigset); have_alarm ? &tv : NULL, &sigset);
if (pr >= 0) { if (pr >= 0) {
/* walks through the observers calling ready/writey fds */ /* walks through the observances calling ready/writey */
observer_action = true; observance_action = true;
for(pi = 0; pi < observers_len; pi++) { for(pi = 0; pi < observances_len; pi++) {
int fd = observers[pi].fd; struct observance *obs = observances + pi;
void *extra = observers[pi].extra;
if (hup || term) { if (hup || term) {
break; break;
} }
if (observers[pi].ready && FD_ISSET(fd, &rfds)) { if (obs->ready && FD_ISSET(obs->fd, &rfds)) {
observers[pi].ready(L, fd, extra); obs->ready(L, obs);
} }
if (hup || term) { if (hup || term) {
break; break;
} }
if (unobservers_len > 0 && if (nonobservances_len > 0 &&
unobservers[unobservers_len - 1] == fd) { nonobservances[nonobservances_len-1] == obs->fd) {
/* ready() unobserved itself */ /* TODO breaks if more nonobserves */
/* ready() nonobserved itself */
continue; continue;
} }
if (observers[pi].writey && FD_ISSET(fd, &wfds)) { if (obs->writey && FD_ISSET(obs->fd, &wfds)) {
observers[pi].writey(L, fd, extra); obs->writey(L, obs);
} }
} }
observer_action = false; observance_action = false;
/* work through delayed unobserve_fd() calls */ /* work through delayed nonobserve_fd() calls */
for (pi = 0; pi < unobservers_len; pi++) { for (pi = 0; pi < nonobservances_len; pi++) {
unobserve_fd(unobservers[pi]); nonobserve_fd(nonobservances[pi]);
} }
unobservers_len = 0; nonobservances_len = 0;
} }
} }
} }
@ -1576,6 +1562,17 @@ main1(int argc, char *argv[])
masterloop(L); masterloop(L);
/* cleanup */ /* 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 */ /* frees logging categories */
int ci; int ci;
@ -1604,12 +1601,6 @@ main1(int argc, char *argv[])
settings.log_level = 0, settings.log_level = 0,
settings.nodaemon = false, settings.nodaemon = false,
#ifdef LSYNCD_WITH_INOTIFY
close_inotify();
#endif
#ifdef LSYNCD_WITH_FSEVENTS
close_fsevents();
#endif
lua_close(L); lua_close(L);
return 0; return 0;
} }

View File

@ -103,15 +103,39 @@ extern void non_block_fd(int fd);
/* Sets the close-on-exit flag for a file descriptor. */ /* Sets the close-on-exit flag for a file descriptor. */
extern void close_exec_fd(int fd); 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( extern void observe_fd(
int fd, int fd,
void (*ready)(lua_State *L, int fd, void *extra), void (*ready) (lua_State *, struct observance *),
void (*writey)(lua_State *L, int fd, void *extra), void (*writey)(lua_State *, struct observance *),
void *extra); void (*tidy) (struct observance *),
void *extra
);
/* stops the core to observe a file descriptor */ /* stops the core to observe a file descriptor */
extern void unobserve_fd(int fd); extern void nonobserve_fd(int fd);
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
* inotify * inotify
@ -119,7 +143,14 @@ extern void unobserve_fd(int fd);
#ifdef LSYNCD_WITH_INOTIFY #ifdef LSYNCD_WITH_INOTIFY
extern void register_inotify(lua_State *L); extern void register_inotify(lua_State *L);
extern void open_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 #endif
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
@ -128,7 +159,6 @@ extern void close_inotify();
#ifdef LSYNCD_WITH_FSEVENTS #ifdef LSYNCD_WITH_FSEVENTS
extern void register_fsevents(lua_State *L); extern void register_fsevents(lua_State *L);
extern void open_fsevents(lua_State *L); extern void open_fsevents(lua_State *L);
extern void close_fsevents();
#endif #endif