splitted inotify into own c-file to be optional later.

This commit is contained in:
Axel Kittenberger 2010-11-22 20:09:52 +00:00
parent ea0fce13e3
commit 45c7f3665f
5 changed files with 546 additions and 358 deletions

View File

@ -1,7 +1,7 @@
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
CFLAGS = -Wall $(LIBLUA_CFLAGS) CFLAGS = -Wall $(LIBLUA_CFLAGS)
bin_PROGRAMS = lsyncd bin_PROGRAMS = lsyncd
lsyncd_SOURCES = lsyncd.c lsyncd.lua lsyncd_SOURCES = lsyncd.c lsyncd.lua inotify.c
lsyncd_LDADD = $(LIBLUA_LIBS) lsyncd_LDADD = $(LIBLUA_LIBS)
exampledir = $(datarootdir)/doc/@PACKAGE@ exampledir = $(datarootdir)/doc/@PACKAGE@
dist_example_DATA = \ dist_example_DATA = \
@ -23,7 +23,8 @@ runner_DATA = lsyncd.lua
else else
# or compiles it into the binary # or compiles it into the binary
lsyncd: luac.o $(lsyncd_LDADD)
lsyncd_LDADD += luac.o
objarch: | lsyncd.o objarch: | lsyncd.o
objdump -f lsyncd.o | grep architecture | \ objdump -f lsyncd.o | grep architecture | \

View File

@ -2,8 +2,8 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
#AC_PREREQ(2.60) #AC_PREREQ(2.60)
AC_INIT(lsyncd, 2.0beta2, axkibe@gmail.com) AC_INIT(lsyncd, 2.0beta2, axkibe@gmail.com)
AC_CONFIG_SRCDIR([lsyncd.c],[lsyncd.lua]) AC_CONFIG_SRCDIR([lsyncd.c],[lsyncd.lua],[inotify.c])
AC_CONFIG_HEADER([config.h]) AC_CONFIG_HEADER([config.h],[lsyncd.h])
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
# Checks for programs. # Checks for programs.
AC_PROG_CC AC_PROG_CC

324
inotify.c Normal file
View File

@ -0,0 +1,324 @@
/**
* lsyncd.c Live (Mirror) Syncing Demon
*
* License: GPLv2 (see COPYING) or any later version
*
* Authors: Axel Kittenberger <axkibe@gmail.com>
*
* Event interface for Lsyncd to Linux´ inotify.
*/
#include "lsyncd.h"
#ifndef HAVE_SYS_INOTIFY_H
# error Missing <sys/inotify.h>; supply kernel-headers and rerun configure.
#endif
#include <sys/stat.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/inotify.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
/**
* The inotify file descriptor.
*/
static int inotify_fd;
/**
* TODO allow configure.
*/
static const uint32_t standard_event_mask =
IN_ATTRIB | IN_CLOSE_WRITE | IN_CREATE |
IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM |
IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR;
/**
* Adds an inotify watch
*
* @param dir (Lua stack) path to directory
* @return (Lua stack) numeric watch descriptor
*/
static int
l_addwatch(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
lua_Integer wd = inotify_add_watch(inotify_fd, path, standard_event_mask);
lua_pushinteger(L, wd);
return 1;
}
/**
* Removes an inotify watch
*
* @param dir (Lua stack) numeric watch descriptor
* @return nil
*/
static int
l_rmwatch(lua_State *L)
{
lua_Integer wd = luaL_checkinteger(L, 1);
inotify_rm_watch(inotify_fd, wd);
return 0;
}
static const luaL_reg linotfylib[] = {
{"addwatch", l_addwatch },
{"rmwatch", l_rmwatch },
{NULL, NULL}
};
/**
* Buffer for MOVE_FROM events.
* Lsyncd buffers MOVE_FROM events to check if
*/
static struct inotify_event * move_event_buf = NULL;
/**
* Memory allocated for move_event_buf
*/
static size_t move_event_buf_size = 0;
/**
* true if the buffer is used.
*/
static bool move_event = false;
/**
* Handles an inotify event.
*/
static void
handle_event(lua_State *L,
struct inotify_event *event)
{
int event_type;
/* used to execute two events in case of unmatched MOVE_FROM buffer */
struct inotify_event *after_buf = NULL;
if (event && (IN_Q_OVERFLOW & event->mask)) {
/* and overflow happened, tells the runner */
load_runner_func(L, "overflow");
if (lua_pcall(L, 0, 0, -2)) {
exit(-1); // ERRNO
}
lua_pop(L, 1);
hup = 1;
return;
}
/* cancel on ignored or resetting */
if (event && (IN_IGNORED & event->mask)) {
return;
}
if (event && event->len == 0) {
/* sometimes inotify sends such strange events,
* (e.g. when touching a dir */
return;
}
if (event == NULL) {
/* a buffered MOVE_FROM is not followed by anything,
thus it is unary */
event = move_event_buf;
event_type = DELETE;
move_event = false;
} else if (move_event &&
( !(IN_MOVED_TO & event->mask) ||
event->cookie != move_event_buf->cookie) ) {
/* there is a MOVE_FROM event in the buffer and this is not the match
* continue in this function iteration to handler the buffer instead */
after_buf = event;
event = move_event_buf;
event_type = DELETE;
move_event = false;
} else if ( move_event &&
(IN_MOVED_TO & event->mask) &&
event->cookie == move_event_buf->cookie ) {
/* this is indeed a matched move */
event_type = MOVE;
move_event = false;
} else if (IN_MOVED_FROM & event->mask) {
/* just the MOVE_FROM, buffers this event, and wait if next event is
* a matching MOVED_TO of this was an unary move out of the watched
* tree. */
size_t el = sizeof(struct inotify_event) + event->len;
if (move_event_buf_size < el) {
move_event_buf_size = el;
move_event_buf = s_realloc(move_event_buf, el);
}
memcpy(move_event_buf, event, el);
move_event = true;
return;
} else if (IN_MOVED_TO & event->mask) {
/* must be an unary move-to */
event_type = CREATE;
} else if (IN_MOVED_FROM & event->mask) {
/* must be an unary move-from */
event_type = DELETE;
} else if (IN_ATTRIB & event->mask) {
/* just attrib change */
event_type = ATTRIB;
} else if (IN_CLOSE_WRITE & event->mask) {
/* closed after written something */
event_type = MODIFY;
} else if (IN_CREATE & event->mask) {
/* a new file */
event_type = CREATE;
} else if (IN_DELETE & event->mask) {
/* rm'ed */
event_type = DELETE;
} else {
logstring("Inotify", "skipped some inotify event.");
return;
}
/* and hands over to runner */
load_runner_func(L, "inotifyEvent");
switch(event_type) {
case ATTRIB : lua_pushstring(L, "Attrib"); break;
case MODIFY : lua_pushstring(L, "Modify"); break;
case CREATE : lua_pushstring(L, "Create"); break;
case DELETE : lua_pushstring(L, "Delete"); break;
case MOVE : lua_pushstring(L, "Move"); break;
default :
logstring("Error", "Internal: unknown event in handle_event()");
exit(-1); // ERRNO
}
if (event_type != MOVE) {
lua_pushnumber(L, event->wd);
} else {
lua_pushnumber(L, move_event_buf->wd);
}
lua_pushboolean(L, (event->mask & IN_ISDIR) != 0);
lua_pushinteger(L, times(NULL));
if (event_type == MOVE) {
lua_pushstring(L, move_event_buf->name);
lua_pushnumber(L, event->wd);
lua_pushstring(L, event->name);
} else {
lua_pushstring(L, event->name);
lua_pushnil(L);
lua_pushnil(L);
}
if (lua_pcall(L, 7, 0, -9)) {
exit(-1); // ERRNO
}
lua_pop(L, 1);
/* if there is a buffered event executes it */
if (after_buf) {
logstring("Inotify", "handling buffered event.");
handle_event(L, after_buf);
}
}
size_t readbuf_size = 2048;
char *readbuf = NULL;
/**
* inotify file descriptor became ready.
*/
static void
inotify_ready(lua_State *L, int fd, void *extra)
{
size_t len;
while(true) {
int i = 0;
do {
len = read (inotify_fd, readbuf, readbuf_size);
if (len < 0 && errno == EINVAL) {
/* kernel > 2.6.21 indicates that way that way that
* the buffer was too small to fit a filename.
* double its size and try again. When using a lower
* kernel and a filename > 2KB appears lsyncd
* will fail. (but does a 2KB filename really happen?)
*/
readbuf_size *= 2;
readbuf = s_realloc(readbuf, readbuf_size);
continue;
}
} while(0);
if (len == 0) {
/* nothing more inotify */
break;
}
if (len < 0) {
if (errno == EAGAIN) {
/* nothing more inotify */
break;
} else {
printlogf(L, "Error", "Read fail on inotify");
exit(-1); // ERRNO
}
}
while (i < len && !hup && !term) {
struct inotify_event *event =
(struct inotify_event *) &readbuf[i];
handle_event(L, event);
i += sizeof(struct inotify_event) + event->len;
}
if (!move_event) {
/* give it a pause if not endangering splitting a move */
break;
}
}
/* checks if there is an unary MOVE_FROM left in the buffer */
if (move_event) {
logstring("Inotify", "handling unary move from.");
handle_event(L, NULL);
}
}
/**
* registers inotify functions.
*/
extern void
register_inotify(lua_State *L) {
lua_pushstring(L, "inotify");
luaL_register(L, "inotify", linotfylib);
}
/**
* opens and initalizes inotify.
*/
extern void
open_inotify(lua_State *L) {
readbuf = s_malloc(readbuf_size);
inotify_fd = inotify_init();
if (inotify_fd == -1) {
printlogf(L, "Error",
"Cannot create inotify instance! (%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);
}

567
lsyncd.c
View File

@ -11,12 +11,6 @@
*/ */
#include "lsyncd.h" #include "lsyncd.h"
#ifdef HAVE_SYS_INOTIFY_H
# include <sys/inotify.h>
#else
# error Missing <sys/inotify.h>; supply kernel-headers and rerun configure.
#endif
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/times.h> #include <sys/times.h>
#include <sys/types.h> #include <sys/types.h>
@ -47,50 +41,10 @@ extern char _binary_luac_out_start;
extern char _binary_luac_out_end; extern char _binary_luac_out_end;
#endif #endif
/**
* The inotify file descriptor.
*/
static int inotify_fd;
/**
* TODO allow configure.
*/
static const uint32_t standard_event_mask =
IN_ATTRIB | IN_CLOSE_WRITE | IN_CREATE |
IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM |
IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR;
/** /**
* configuration parameters * configuration parameters
*/ */
static struct settings { struct settings settings = {
/**
* If not NULL Lsyncd logs into this file.
*/
char * log_file;
/**
* If true Lsyncd sends log messages to syslog
*/
bool log_syslog;
/**
* -1 logs everything, 0 normal mode,
* LOG_ERROR logs errors only.
*/
int log_level;
/**
* True if Lsyncd shall not daemonize.
*/
bool nodaemon;
/**
* If not NULL Lsyncd writes its pid into this file.
*/
char * pidfile;
} settings = {
.log_file = NULL, .log_file = NULL,
.log_syslog = false, .log_syslog = false,
.log_level = 0, .log_level = 0,
@ -113,8 +67,8 @@ static bool running = false;
/** /**
* Set to TERM or HUP in signal handler, when lsyncd should end or reset ASAP. * Set to TERM or HUP in signal handler, when lsyncd should end or reset ASAP.
*/ */
static volatile sig_atomic_t hup = 0; volatile sig_atomic_t hup = 0;
static volatile sig_atomic_t term = 0; volatile sig_atomic_t term = 0;
/** /**
* The kernels clock ticks per second. * The kernels clock ticks per second.
@ -168,7 +122,7 @@ static struct logcat *logcats[26] = {0,};
* Returns the positive priority if category is configured to be logged. * Returns the positive priority if category is configured to be logged.
* or -1 * or -1
*/ */
static int extern int
check_logcat(const char *name) check_logcat(const char *name)
{ {
struct logcat *lc; struct logcat *lc;
@ -323,7 +277,6 @@ printlogf0(lua_State *L,
/***************************************************************************** /*****************************************************************************
* Simple memory management * Simple memory management
*
* TODO: call the garbace collector in case of out of memory. * TODO: call the garbace collector in case of out of memory.
****************************************************************************/ ****************************************************************************/
@ -393,9 +346,6 @@ s_strdup(const char *src)
* write() can manage. * write() can manage.
*/ */
struct pipemsg { struct pipemsg {
/* pipe file descriptor */
int fd;
/* message to send */ /* message to send */
char *text; char *text;
@ -407,19 +357,29 @@ struct pipemsg {
}; };
/** /**
* All pipes currently active. * Called by the core whenever a pipe becomes
* writeable again
*/ */
static struct pipemsg *pipes = NULL; static void
pipe_writey(lua_State *L, int fd, void *extra) {
/** struct pipemsg *pm = (struct pipemsg *) extra;
* amount of pipes allocated. int len = write(fd, pm->text + pm->pos, pm->tlen - pm->pos);
*/ bool do_close = false;
size_t pipes_size = 0; pm->pos += len;
if (len < 0) {
/** logstring("Normal", "broken pipe.");
* number of pipes used. do_close = true;
*/ } else if (pm->pos >= pm->tlen) {
size_t pipes_len = 0; logstring("Debug", "finished pipe.");
do_close = true;
}
if (do_close) {
close(fd);
free(pm->text);
free(extra);
unobserve_fd(fd);
}
}
/***************************************************************************** /*****************************************************************************
@ -489,35 +449,6 @@ write_pidfile(lua_State *L, const char *pidfile) {
static int l_stackdump(lua_State* L); static int l_stackdump(lua_State* L);
/**
* Adds an inotify watch
*
* @param dir (Lua stack) path to directory
* @return (Lua stack) numeric watch descriptor
*/
static int
l_inotifyadd(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
lua_Integer wd = inotify_add_watch(inotify_fd, path, standard_event_mask);
lua_pushinteger(L, wd);
return 1;
}
/**
* Removes an inotify watch
*
* @param dir (Lua stack) numeric watch descriptor
* @return nil
*/
static int
l_inotifyrm(lua_State *L)
{
lua_Integer wd = luaL_checkinteger(L, 1);
inotify_rm_watch(inotify_fd, wd);
return 0;
}
/** /**
* Logs a message. * Logs a message.
* *
@ -764,17 +695,13 @@ l_exec(lua_State *L)
close(pipefd[1]); close(pipefd[1]);
logstring("Exec", "one-sweeped pipe"); logstring("Exec", "one-sweeped pipe");
} else { } else {
int p = pipes_len; struct pipemsg *pm;
logstring("Exec", "adding delayed pipe"); logstring("Exec", "adding pipe observer");
pipes_len++; pm = s_calloc(1, sizeof(struct pipemsg));
if (pipes_len > pipes_size) { pm->text = s_strdup(pipe_text);
pipes_size = pipes_len; pm->tlen = tlen;
pipes = s_realloc(pipes, pipes_size*sizeof(struct pipemsg)); pm->pos = len;
} observe_fd(pipefd[1], NULL, pipe_writey, pm);
pipes[p].fd = pipefd[1];
pipes[p].tlen = tlen;
pipes[p].pos = len;
pipes[p].text = s_strdup(pipe_text);
} }
close(pipefd[0]); close(pipefd[0]);
} }
@ -783,7 +710,6 @@ l_exec(lua_State *L)
return 1; return 1;
} }
/** /**
* Converts a relative directory path to an absolute. * Converts a relative directory path to an absolute.
* *
@ -996,8 +922,6 @@ static const luaL_reg lsyncdlib[] = {
{"configure", l_configure }, {"configure", l_configure },
{"earlier", l_earlier }, {"earlier", l_earlier },
{"exec", l_exec }, {"exec", l_exec },
{"inotifyadd", l_inotifyadd },
{"inotifyrm", l_inotifyrm },
{"log", l_log }, {"log", l_log },
{"now", l_now }, {"now", l_now },
{"readdir", l_readdir }, {"readdir", l_readdir },
@ -1027,7 +951,7 @@ static int callError;
* Pushes a function from the runner on the stack. * Pushes a function from the runner on the stack.
* Prior it pushed the callError handler. * Prior it pushed the callError handler.
*/ */
static void extern void
load_runner_func(lua_State *L, load_runner_func(lua_State *L,
const char *name) const char *name)
{ {
@ -1045,149 +969,138 @@ load_runner_func(lua_State *L,
lua_remove(L, -2); lua_remove(L, -2);
} }
/**
* Buffer for MOVE_FROM events.
* Lsyncd buffers MOVE_FROM events to check if
*/
struct inotify_event * move_event_buf = NULL;
/** /**
* Memory allocated for move_event_buf * An observer to be called when a file descritor becomes
* read-ready or write-ready.
*/ */
size_t move_event_buf_size = 0; 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;
};
/** /**
* true if the buffer is used. * List of file descriptor watches.
*/ */
bool move_event = false; static struct observer * observers = NULL;
static int observers_len = 0;
static int observers_size = 0;
/** /**
* Handles an inotify event. * List of file descriptors to unobserve.
* While working for the oberver lists, it may
* not be altered, thus unobserve stores here the
* actions that will be delayed.
*/ */
static void static int *unobservers = NULL;
handle_event(lua_State *L, static int unobservers_len = 0;
struct inotify_event *event) static int unobservers_size = 0;
/**
* true while the observers list is being handled.
*/
static bool observer_action = false;
/**
* Core watches a filedescriptor to become ready,
* one of read_ready or write_ready may be zero
*/
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)
{ {
int event_type; int pos;
if (observer_action) {
/* used to execute two events in case of unmatched MOVE_FROM buffer */ // TODO
struct inotify_event *after_buf = NULL; logstring("Error",
if (hup || term) { "Adding observers in ready/writey handlers not yet supported");
return;
}
if (event && (IN_Q_OVERFLOW & event->mask)) {
/* and overflow happened, tells the runner */
load_runner_func(L, "overflow");
if (lua_pcall(L, 0, 0, -2)) {
exit(-1); // ERRNO
}
lua_pop(L, 1);
hup = 1;
return;
}
/* cancel on ignored or resetting */
if (event && (IN_IGNORED & event->mask)) {
return;
}
if (event && event->len == 0) {
/* sometimes inotify sends such strange events,
* (e.g. when touching a dir */
return;
}
if (event == NULL) {
/* a buffered MOVE_FROM is not followed by anything,
thus it is unary */
event = move_event_buf;
event_type = DELETE;
move_event = false;
} else if (move_event &&
( !(IN_MOVED_TO & event->mask) ||
event->cookie != move_event_buf->cookie) ) {
/* there is a MOVE_FROM event in the buffer and this is not the match
* continue in this function iteration to handler the buffer instead */
after_buf = event;
event = move_event_buf;
event_type = DELETE;
move_event = false;
} else if ( move_event &&
(IN_MOVED_TO & event->mask) &&
event->cookie == move_event_buf->cookie ) {
/* this is indeed a matched move */
event_type = MOVE;
move_event = false;
} else if (IN_MOVED_FROM & event->mask) {
/* just the MOVE_FROM, buffers this event, and wait if next event is
* a matching MOVED_TO of this was an unary move out of the watched
* tree. */
size_t el = sizeof(struct inotify_event) + event->len;
if (move_event_buf_size < el) {
move_event_buf_size = el;
move_event_buf = s_realloc(move_event_buf, el);
}
memcpy(move_event_buf, event, el);
move_event = true;
return;
} else if (IN_MOVED_TO & event->mask) {
/* must be an unary move-to */
event_type = CREATE;
} else if (IN_MOVED_FROM & event->mask) {
/* must be an unary move-from */
event_type = DELETE;
} else if (IN_ATTRIB & event->mask) {
/* just attrib change */
event_type = ATTRIB;
} else if (IN_CLOSE_WRITE & event->mask) {
/* closed after written something */
event_type = MODIFY;
} else if (IN_CREATE & event->mask) {
/* a new file */
event_type = CREATE;
} else if (IN_DELETE & event->mask) {
/* rm'ed */
event_type = DELETE;
} else {
logstring("Inotify", "skipped some inotify event.");
return;
}
/* and hands over to runner */
load_runner_func(L, "inotifyEvent");
switch(event_type) {
case ATTRIB : lua_pushstring(L, "Attrib"); break;
case MODIFY : lua_pushstring(L, "Modify"); break;
case CREATE : lua_pushstring(L, "Create"); break;
case DELETE : lua_pushstring(L, "Delete"); break;
case MOVE : lua_pushstring(L, "Move"); break;
default :
logstring("Error", "Internal: unknown event in handle_event()");
exit(-1); // ERRNO
}
if (event_type != MOVE) {
lua_pushnumber(L, event->wd);
} else {
lua_pushnumber(L, move_event_buf->wd);
}
lua_pushboolean(L, (event->mask & IN_ISDIR) != 0);
lua_pushinteger(L, times(NULL));
if (event_type == MOVE) {
lua_pushstring(L, move_event_buf->name);
lua_pushnumber(L, event->wd);
lua_pushstring(L, event->name);
} else {
lua_pushstring(L, event->name);
lua_pushnil(L);
lua_pushnil(L);
}
if (lua_pcall(L, 7, 0, -9)) {
exit(-1); // ERRNO exit(-1); // ERRNO
} }
lua_pop(L, 1);
/* if there is a buffered event executes it */ if (observers_len + 1 > observers_size) {
if (after_buf) { observers_size = observers_len + 1;
logstring("Inotify", "handling buffered event."); observers = s_realloc(observers,
handle_event(L, after_buf); observers_size * sizeof(struct observer));
} }
for(pos = 0; pos < observers_len; pos++) {
if (observers[pos].fd <= fd) {
break;
}
}
if (observers[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)));
observers_len++;
observers[pos].fd = fd;
observers[pos].ready = ready;
observers[pos].writey = writey;
observers[pos].extra = extra;
}
/**
* Makes core no longer watch fd.
*/
extern void
unobserve_fd(int fd)
{
int pos;
if (observer_action) {
/* this function is called through a ready/writey handler
* while the core works through the observer 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));
}
unobservers[unobservers_len - 1] = fd;
return;
}
/* looks for the fd */
for(pos = 0; pos < observers_len; pos++) {
if (observers[pos].fd == fd) {
break;
}
}
if (pos >= observers_len) {
logstring("Error",
"internal fail, not observer file descriptor in unobserve");
exit(-1); //ERRNO
}
/* and moves the list down */
memmove(observers + pos, observers + pos + 1,
(observers_len - pos) * (sizeof(struct observer)));
observers_len--;
} }
/** /**
@ -1196,14 +1109,10 @@ handle_event(lua_State *L,
static void static void
masterloop(lua_State *L) masterloop(lua_State *L)
{ {
size_t readbuf_size = 2048;
char *readbuf = s_malloc(readbuf_size);
while(true) { while(true) {
bool have_alarm; bool have_alarm;
clock_t now = times(NULL); clock_t now = times(NULL);
clock_t alarm_time; clock_t alarm_time;
bool do_read = false;
ssize_t len;
/* queries runner about soonest alarm */ /* queries runner about soonest alarm */
load_runner_func(L, "getAlarm"); load_runner_func(L, "getAlarm");
@ -1239,113 +1148,69 @@ masterloop(lua_State *L)
} else { } else {
logstring("Masterloop", "going into select (no timeout)."); logstring("Masterloop", "going into select (no timeout).");
} }
/* if select returns a positive number there is data on inotify /* time for Lsyncd to try to put itself to rest into a select(),
* on zero the timemout occured. */ * configures timeouts, filedescriptors and signals
* that will wake it */
{ {
fd_set rfds; fd_set rfds;
fd_set wfds; fd_set wfds;
sigset_t sigset; sigset_t sigset;
sigemptyset(&sigset); int pi, pr;
int nfds = inotify_fd;
int pi;
sigemptyset(&sigset);
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_ZERO(&wfds); FD_ZERO(&wfds);
FD_SET(inotify_fd, &rfds);
for(pi = 0; pi < pipes_len; pi++) { for(pi = 0; pi < observers_len; pi++) {
int pfd = pipes[pi].fd; int fd = observers[pi].fd;
nfds = pfd > nfds ? pfd : nfds; if (observers[pi].ready) {
FD_SET(pfd, &wfds); FD_SET(fd, &rfds);
}
if (observers[pi].writey) {
FD_SET(fd, &wfds);
}
} }
/* reuse pi for result */ /* the great select */
pi = pselect(nfds + 1, &rfds, &wfds, NULL, pr = pselect(
observers[observers_len - 1].fd + 1,
&rfds, &wfds, NULL,
have_alarm ? &tv : NULL, &sigset); have_alarm ? &tv : NULL, &sigset);
if (pi >= 0) {
do_read = FD_ISSET(inotify_fd, &rfds); if (pr >= 0) {
} /* walks through the observers calling ready/writey fds */
if (do_read) { observer_action = true;
logstring("Masterloop", do_read > 0 ? for(pi = 0; pi < observers_len; pi++) {
"theres data on inotify." : int fd = observers[pi].fd;
"core: select() timeout or signal."); void *extra = observers[pi].extra;
if (hup || term) {
break;
}
if (observers[pi].ready && FD_ISSET(fd, &rfds)) {
observers[pi].ready(L, fd, extra);
}
if (hup || term) {
break;
}
if (unobservers_len > 0 &&
unobservers[unobservers_len - 1] == fd) {
/* ready() unobserved itself */
continue;
}
if (observers[pi].writey && FD_ISSET(fd, &wfds)) {
observers[pi].writey(L, fd, extra);
}
}
observer_action = false;
/* work through delayed unobserve_fd() calls */
for (pi = 0; pi < unobservers_len; pi++) {
unobserve_fd(unobservers[pi]);
}
unobservers_len = 0;
} }
} }
} }
/* reads possible events from inotify stream */
while(do_read) {
int i = 0;
do {
len = read (inotify_fd, readbuf, readbuf_size);
if (len < 0 && errno == EINVAL) {
/* kernel > 2.6.21 indicates that way that way that
* the buffer was too small to fit a filename.
* double its size and try again. When using a lower
* kernel and a filename > 2KB appears lsyncd
* will fail. (but does a 2KB filename really happen?)
*/
readbuf_size *= 2;
readbuf = s_realloc(readbuf, readbuf_size);
continue;
}
} while(0);
if (len == 0) {
/* nothing more inotify */
break;
}
if (len < 0) {
if (errno == EAGAIN) {
/* nothing more inotify */
break;
} else {
printlogf(L, "Error", "Read fail on inotify");
exit(-1); // ERRNO
}
}
while (i < len && !hup && !term) {
struct inotify_event *event =
(struct inotify_event *) &readbuf[i];
handle_event(L, event);
i += sizeof(struct inotify_event) + event->len;
}
if (!move_event) {
/* give it a pause if not endangering splitting a move */
break;
}
}
/* checks if there is an unary MOVE_FROM left in the buffer */
if (move_event) {
logstring("Inotify", "handling unary move from.");
handle_event(L, NULL);
}
{
/* writes into pipes if any */
int pi;
for(pi = 0; pi < pipes_len; pi++) {
struct pipemsg *pm = pipes + pi;
int len = write(pm->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;
} else if (pm->pos >= pm->tlen) {
logstring("Debug", "finished pipe.");
do_close = true;
}
if (do_close) {
close(pm->fd);
free(pm->text);
pipes_len--;
memmove(pipes + pi, pipes + pi + 1,
(pipes_len - pi) * sizeof(struct pipemsg));
pi--;
continue;
}
}
}
/* collects zombified child processes */ /* collects zombified child processes */
while(1) { while(1) {
int status; int status;
@ -1362,6 +1227,7 @@ masterloop(lua_State *L)
lua_pop(L, 1); lua_pop(L, 1);
} }
/* reacts on signals */
if (hup) { if (hup) {
load_runner_func(L, "hup"); load_runner_func(L, "hup");
if (lua_pcall(L, 0, 0, -2)) { if (lua_pcall(L, 0, 0, -2)) {
@ -1371,6 +1237,7 @@ masterloop(lua_State *L)
hup = 0; hup = 0;
} }
/* reacts on signals */
if (term == 1) { if (term == 1) {
load_runner_func(L, "term"); load_runner_func(L, "term");
if (lua_pcall(L, 0, 0, -2)) { if (lua_pcall(L, 0, 0, -2)) {
@ -1389,7 +1256,6 @@ masterloop(lua_State *L)
} }
if (!lua_toboolean(L, -1)) { if (!lua_toboolean(L, -1)) {
/* cycle told core to break mainloop */ /* cycle told core to break mainloop */
free(readbuf);
lua_pop(L, 2); lua_pop(L, 2);
return; return;
} }
@ -1455,6 +1321,12 @@ main1(int argc, char *argv[])
/* registers lsycnd core */ /* registers lsycnd core */
luaL_register(L, "lsyncd", lsyncdlib); luaL_register(L, "lsyncd", lsyncdlib);
lua_setglobal(L, "lysncd"); lua_setglobal(L, "lysncd");
lua_getglobal(L, "lysncd");
register_inotify(L);
lua_settable(L, -3);
lua_pop(L, 1);
l_stackdump(L);
if (check_logcat("Debug") >= settings.log_level) { if (check_logcat("Debug") >= settings.log_level) {
/* printlogf doesnt support %ld :-( */ /* printlogf doesnt support %ld :-( */
@ -1601,7 +1473,7 @@ main1(int argc, char *argv[])
} }
if (lsyncd_config_file) { if (lsyncd_config_file) {
/* checks for the configuration and existence of the config file */ /* checks existence of the config file */
struct stat st; struct stat st;
if (stat(lsyncd_config_file, &st)) { if (stat(lsyncd_config_file, &st)) {
printlogf(L, "Error", printlogf(L, "Error",
@ -1625,16 +1497,8 @@ main1(int argc, char *argv[])
} }
} }
/* opens inotify */ open_inotify(L);
inotify_fd = inotify_init(); l_stackdump(L);
if (inotify_fd == -1) {
printlogf(L, "Error",
"Cannot create inotify instance! (%d:%s)",
errno, strerror(errno));
exit(-1); // ERRNO
}
close_exec_fd(inotify_fd);
non_block_fd(inotify_fd);
{ {
/* adds signal handlers * /* adds signal handlers *
@ -1691,8 +1555,7 @@ main1(int argc, char *argv[])
settings.log_level = 0, settings.log_level = 0,
settings.nodaemon = false, settings.nodaemon = false,
/* closes inotify */ close_inotify();
close(inotify_fd);
lua_close(L); lua_close(L);
return 0; return 0;
} }

View File

@ -1493,7 +1493,7 @@ local Inotifies = (function()
local wd = pathwds[path] local wd = pathwds[path]
if not wd then if not wd then
-- lets the core registers watch with the kernel -- lets the core registers watch with the kernel
local wd = lsyncd.inotifyadd(path); local wd = lsyncd.inotify.addwatch(path);
if wd < 0 then if wd < 0 then
log("Error","Failure adding watch ",path," -> ignored ") log("Error","Failure adding watch ",path," -> ignored ")
return return
@ -1540,7 +1540,7 @@ local Inotifies = (function()
if not wd then if not wd then
return return
end end
lsyncd.inotifyrm(wd) lsyncd.inotify.rmwatch(wd)
wdpaths[wd] = nil wdpaths[wd] = nil
pathwds[path] = nil pathwds[path] = nil
end end