new inheritance mechanics, code beautifications

This commit is contained in:
Axel Kittenberger 2012-10-05 09:41:46 +02:00
parent 2e9c103f55
commit 1bf1d13eaa
6 changed files with 610 additions and 276 deletions

View File

@ -2,7 +2,7 @@
# 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.0.7, axkibe@gmail.com) AC_INIT(lsyncd, 2.1.0-beta, axkibe@gmail.com)
AM_INIT_AUTOMAKE([foreign]) AM_INIT_AUTOMAKE([foreign])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])

View File

@ -15,15 +15,19 @@
-- --
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if not default then if not default then
error('default not loaded') error( 'default not loaded' )
end end
if default.rsync then if default.rsync then
error('default-rsync already loaded') error( 'default-rsync already loaded' )
end end
default.rsync = { } default.rsync = { }
local rsync = default.rsync
-- --
-- Spawns rsync for a list of events -- Spawns rsync for a list of events
@ -31,7 +35,7 @@ default.rsync = { }
-- Exlcusions are already handled by not having -- Exlcusions are already handled by not having
-- events for them. -- events for them.
-- --
default.rsync.action = function( inlet ) rsync.action = function( inlet )
-- --
-- gets all events ready for syncing -- gets all events ready for syncing
@ -51,10 +55,10 @@ default.rsync.action = function( inlet )
end end
return p: return p:
gsub('%?', '\\?'): gsub( '%?', '\\?' ):
gsub('%*', '\\*'): gsub( '%*', '\\*' ):
gsub('%[', '\\['): gsub( '%[', '\\[' ):
gsub('%]', '\\]') gsub( '%]', '\\]' )
end end
-- --
@ -153,10 +157,11 @@ default.rsync.action = function( inlet )
end end
-- --
-- Spawns the recursive startup sync -- Spawns the recursive startup sync
-- --
init = function(event) rsync.init = function(event)
local config = event.config local config = event.config
local inlet = event.inlet local inlet = event.inlet
@ -216,10 +221,11 @@ init = function(event)
end end
end end
-- --
-- Prepares and checks a syncs configuration on startup. -- Prepares and checks a syncs configuration on startup.
-- --
default.rsync.prepare = function( config ) rsync.prepare = function( config )
if not config.target then if not config.target then
error( error(
@ -317,19 +323,22 @@ default.rsync.prepare = function( config )
end end
end end
-- --
-- rsync uses default collect -- rsync uses default collect
-- --
-- --
-- By default do deletes. -- By default do deletes.
-- --
default.rsync.delete = true rsync.delete = true
-- --
-- Calls rsync with this default options -- Calls rsync with this default options
-- --
default.rsync.rsync = { rsync.rsync = {
-- The rsync binary to be called. -- The rsync binary to be called.
binary = '/usr/bin/rsync', binary = '/usr/bin/rsync',
links = true, links = true,
@ -337,12 +346,13 @@ default.rsync.rsync = {
protectArgs = true protectArgs = true
} }
-- --
-- Exit codes for rsync. -- Exit codes for rsync.
-- --
default.rsync.exitcodes = default.rsyncExitCodes rsync.exitcodes = default.rsyncExitCodes
-- --
-- Default delay -- Default delay
-- --
default.rsync.delay = 15 rsync.delay = 15

View File

@ -38,8 +38,10 @@ default = {
-- Called when collecting a finished child process -- Called when collecting a finished child process
-- --
collect = function(agent, exitcode) collect = function(agent, exitcode)
local config = agent.config local config = agent.config
local rc local rc
if config.exitcodes then if config.exitcodes then
rc = config.exitcodes[exitcode] rc = config.exitcodes[exitcode]
elseif exitcode == 0 then elseif exitcode == 0 then
@ -71,7 +73,8 @@ default = {
agent.source, agent.source,
'". Terminating since "insist" is not set.' '". Terminating since "insist" is not set.'
) )
terminate(-1) -- ERRNO
terminate( -1 )
end end
elseif rc == 'die' then elseif rc == 'die' then
log( log(
@ -80,7 +83,8 @@ default = {
agent.source, agent.source,
'".' '".'
) )
terminate(-1) -- ERRNO
terminate( -1 )
else else
log( log(
'Error', 'Error',
@ -96,13 +100,29 @@ default = {
if agent.isList then if agent.isList then
if rc == 'ok' then if rc == 'ok' then
log('Normal', 'Finished a list = ',exitcode) log(
'Normal',
'Finished a list after exitcode: ',
exitcode
)
elseif rc == 'again' then elseif rc == 'again' then
log('Normal', 'Retrying a list on exitcode = ',exitcode) log(
'Normal',
'Retrying a list after exitcode = ',
exitcode
)
elseif rc == 'die' then elseif rc == 'die' then
log('Error', 'Failure with a list on exitcode = ',exitcode) log(
'Error',
'Failure with a list width exitcode = ',
exitcode
)
else else
log('Error', 'Unknown exitcode "',exitcode,'" with a list') log(
'Error',
'Unknown exitcode "',exitcode,'" with a list'
)
rc = 'die' rc = 'die'
end end
else else
@ -164,34 +184,58 @@ default = {
-- Exitcodes of rsync and what to do. -- Exitcodes of rsync and what to do.
-- --
rsyncExitCodes = { rsyncExitCodes = {
[ 0] = 'ok',
[ 1] = 'die', --
[ 2] = 'die', -- if another config provides the same table
[ 3] = 'again', -- this will not be inherited (merged) into that one
[ 4] = 'die', --
[ 5] = 'again', -- if it does not, integer keys are to be copied
[ 6] = 'again', -- verbatim
[ 10] = 'again', --
[ 11] = 'again', _merge = false,
[ 12] = 'again', _verbatim = true,
[ 14] = 'again',
[ 20] = 'again', [ 0 ] = 'ok',
[ 21] = 'again', [ 1 ] = 'die',
[ 22] = 'again', [ 2 ] = 'die',
[ 23] = 'ok', -- partial transfers are ok, since Lsyncd has registered the event that [ 3 ] = 'again',
[ 24] = 'ok', -- caused the transfer to be partial and will recall rsync. [ 4 ] = 'die',
[ 25] = 'die', [ 5 ] = 'again',
[ 30] = 'again', [ 6 ] = 'again',
[ 35] = 'again', [ 10 ] = 'again',
[255] = 'again', [ 11 ] = 'again',
[ 12 ] = 'again',
[ 14 ] = 'again',
[ 20 ] = 'again',
[ 21 ] = 'again',
[ 22 ] = 'again',
-- partial transfers are ok, since Lsyncd has registered the event that
-- caused the transfer to be partial and will recall rsync.
[ 23 ] = 'ok',
[ 24 ] = 'ok',
[ 25 ] = 'die',
[ 30 ] = 'again',
[ 35 ] = 'again',
[ 255 ] = 'again',
}, },
----- -----
-- Exitcodes of ssh and what to do. -- Exitcodes of ssh and what to do.
-- --
sshExitCodes = { sshExitCodes = {
[0] = 'ok',
[255] = 'again', --
-- if another config provides the same table
-- this will not be inherited (merged) into that one
--
-- if it does not, integer keys are to be copied
-- verbatim
--
_merge = false,
_verbatim = true,
[ 0 ] = 'ok',
[ 255 ] = 'again',
}, },
----- -----

565
inotify.c
View File

@ -1,14 +1,14 @@
/** /*
* inotify.c from Lsyncd - Live (Mirror) Syncing Demon | inotify.c from Lsyncd - Live (Mirror) Syncing Demon
* |
* License: GPLv2 (see COPYING) or any later version | License: GPLv2 (see COPYING) or any later version
* |
* Authors: Axel Kittenberger <axkibe@gmail.com> | Authors: Axel Kittenberger <axkibe@gmail.com>
* |
* ----------------------------------------------------------------------- | -----------------------------------------------------------------------
* |
* Event interface for Lsyncd to Linux´ inotify. | Event interface for Lsyncd to Linux´ inotify.
*/ */
#include "lsyncd.h" #include "lsyncd.h"
@ -39,83 +39,130 @@
#include <lualib.h> #include <lualib.h>
#include <lauxlib.h> #include <lauxlib.h>
/*-----------------------------------------------------------------------------
* Event types. /*
*/ | Event types.
*/
static const char * ATTRIB = "Attrib"; static const char * ATTRIB = "Attrib";
static const char * MODIFY = "Modify"; static const char * MODIFY = "Modify";
static const char * CREATE = "Create"; static const char * CREATE = "Create";
static const char * DELETE = "Delete"; static const char * DELETE = "Delete";
static const char * MOVE = "Move"; static const char * MOVE = "Move";
/**
/*
* The inotify file descriptor. * The inotify file descriptor.
*/ */
static int inotify_fd = -1; static int inotify_fd = -1;
/**
* Standard inotify events to listen to. /*
*/ | Standard inotify events to listen to.
*/
static const uint32_t standard_event_mask = static const uint32_t standard_event_mask =
IN_ATTRIB | IN_CLOSE_WRITE | IN_CREATE | IN_ATTRIB |
IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM | IN_CLOSE_WRITE |
IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR; IN_CREATE |
IN_DELETE |
IN_DELETE_SELF |
IN_MOVED_FROM |
IN_MOVED_TO |
IN_DONT_FOLLOW |
IN_ONLYDIR;
/** /*
* Adds an inotify watch | Adds an inotify watch
* |
* @param dir (Lua stack) path to directory | param dir (Lua stack) path to directory
* @param inotifyMode (Lua stack) path to directory | param inotifyMode (Lua stack) which inotify event to react upon
* @return (Lua stack) numeric watch descriptor | "CloseWrite", "CloseWrite or Modify"
*/ |
| returns (Lua stack) numeric watch descriptor
*/
static int static int
l_addwatch(lua_State *L) l_addwatch( lua_State *L )
{ {
const char *path = luaL_checkstring(L, 1); const char *path = luaL_checkstring( L, 1 );
const char *imode = luaL_checkstring(L, 2); const char *imode = luaL_checkstring( L, 2 );
uint32_t mask = standard_event_mask; uint32_t mask = standard_event_mask;
if (*imode) {
if (!strcmp(imode, "Modify")) { // checks the desired inotify reaction mode
// act on modify instead of closeWrite if (*imode)
mask |= IN_MODIFY; {
if ( !strcmp( imode, "Modify" ) )
{
// acts on modify instead of closeWrite
mask |= IN_MODIFY;
mask &= ~IN_CLOSE_WRITE; mask &= ~IN_CLOSE_WRITE;
} else if (!strcmp(imode, "CloseWrite")) { }
// default else if ( !strcmp( imode, "CloseWrite" ) )
} else if (!strcmp(imode, "CloseWrite or Modify")) { {
// thats default
}
else if ( !strcmp( imode, "CloseWrite or Modify" ) )
{
// acts on modify and closeWrite // acts on modify and closeWrite
mask |= IN_MODIFY; mask |= IN_MODIFY;
} else if (!strcmp(imode, "CloseWrite after Modify")) { }
else if ( ! strcmp( imode, "CloseWrite after Modify") )
{
// might be done in future // might be done in future
printlogf(L, "Error", "'CloseWrite after Modify' not implemented."); printlogf(
exit(-1); // ERRNO L, "Error",
} else { "'CloseWrite after Modify' not implemented."
printlogf(L, "Error", "'%s' not a valid inotfiyMode.", imode); );
exit(-1); // ERRNO exit(-1);
}
else
{
printlogf(
L, "Error",
"'%s' not a valid inotfiyMode.",
imode
);
exit(-1);
} }
} }
// kernel call to create the inotify watch
int wd = inotify_add_watch( inotify_fd, path, mask );
int wd = inotify_add_watch(inotify_fd, path, mask); if (wd < 0)
if (wd < 0) { {
if (errno == ENOSPC) { if (errno == ENOSPC)
printlogf(L, "Error", "Terminating since out of inotify watches."); {
printlogf(L, "Error", "Consider increasing /proc/sys/fs/inotify/max_user_watches"); printlogf(
L, "Error",
"%s\n%s",
"Terminating since out of inotify watches.",
"Consider increasing /proc/sys/fs/inotify/max_user_watches"
);
exit(-1); // ERRNO. exit(-1); // ERRNO.
} }
printlogf(L, "Inotify", "addwatch(%s)->%d; err=%d:%s", path, wd, errno, strerror(errno));
} else { printlogf(
printlogf(L, "Inotify", "addwatch(%s)->%d", path, wd); L, "Inotify",
"addwatch( %s )-> % d; err= %d : %s",
path, wd, errno, strerror( errno )
);
} }
lua_pushinteger(L, wd); else
{
printlogf(L, "Inotify", "addwatch( %s )-> %d ", path, wd );
}
lua_pushinteger( L, wd );
return 1; return 1;
} }
/**
* Removes an inotify watch /*
* Removes an inotify watch.
* *
* @param dir (Lua stack) numeric watch descriptor * param dir (Lua stack) numeric watch descriptor
* @return nil *
* return nil
*/ */
static int static int
l_rmwatch(lua_State *L) l_rmwatch(lua_State *L)
@ -126,147 +173,214 @@ l_rmwatch(lua_State *L)
return 0; return 0;
} }
/**
* Cores inotify functions. /*
*/ | Lsyncd's core's inotify functions.
*/
static const luaL_Reg linotfylib[] = { static const luaL_Reg linotfylib[] = {
{"addwatch", l_addwatch }, { "addwatch", l_addwatch },
{"rmwatch", l_rmwatch }, { "rmwatch", l_rmwatch },
{NULL, NULL} { NULL, NULL}
}; };
/**
* Buffer for MOVE_FROM events. /*
* Lsyncd buffers MOVE_FROM events to check if | Buffer for MOVE_FROM events.
* they are followed by MOVE_TO events with identical cookie | Lsyncd buffers MOVE_FROM events to check if
* then they are condensed into one move event to be sent to the | they are followed by MOVE_TO events with identical cookie
* runner | then they are condensed into one move event to be sent to the
*/ | runner
*/
static struct inotify_event * move_event_buf = NULL; static struct inotify_event * move_event_buf = NULL;
/**
* Memory allocated for move_event_buf /*
*/ | Memory allocated for move_event_buf
*/
static size_t move_event_buf_size = 0; static size_t move_event_buf_size = 0;
/**
* true if the buffer is used. /*
*/ | True if the buffer is used.
*/
static bool move_event = false; static bool move_event = false;
/**
* Handles an inotify event. /*
*/ | Handles an inotify event.
*/
static void static void
handle_event(lua_State *L, handle_event(
struct inotify_event *event) lua_State *L,
struct inotify_event *event
)
{ {
const char *event_type = NULL; const char *event_type = NULL;
// used to execute two events in case of unmatched MOVE_FROM buffer // used to execute two events in case of unmatched MOVE_FROM buffer
struct inotify_event *after_buf = NULL; struct inotify_event *after_buf = NULL;
if (event && (IN_Q_OVERFLOW & event->mask)) { if( event && ( IN_Q_OVERFLOW & event->mask ) )
/* and overflow happened, tells the runner */ {
load_runner_func(L, "overflow"); // and overflow happened, tells the runner
if (lua_pcall(L, 0, 0, -2)) { load_runner_func( L, "overflow" );
exit(-1); // ERRNO
if( lua_pcall( L, 0, 0, -2 ) )
{
exit( -1 );
} }
lua_pop(L, 1); lua_pop( L, 1 );
hup = 1; hup = 1;
return; return;
} }
// cancel on ignored or resetting // cancel on ignored or resetting
if (event && (IN_IGNORED & event->mask)) { if( event && ( IN_IGNORED & event->mask ) )
{
return; return;
} }
if (event && event->len == 0) {
if( event && event->len == 0 )
{
// sometimes inotify sends such strange events, // sometimes inotify sends such strange events,
// (e.g. when touching a dir // (e.g. when touching a dir
return; return;
} }
if (event == NULL) { if( event == NULL )
{
// a buffered MOVE_FROM is not followed by anything, // a buffered MOVE_FROM is not followed by anything,
// thus it is unary // thus it is unary
event = move_event_buf; event = move_event_buf;
event_type = "Delete"; event_type = "Delete";
move_event = false; move_event = false;
} else if (move_event && }
( !(IN_MOVED_TO & event->mask) || else if(
event->cookie != move_event_buf->cookie) ) { 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 // there is a MOVE_FROM event in the buffer and this is not the match
// continue in this function iteration to handle the buffer instead */ // continue in this function iteration to handle the buffer instead */
logstring("Inotify", "icore, changing unary MOVE_FROM into DELETE") logstring(
"Inotify",
"icore, changing unary MOVE_FROM into DELETE"
)
after_buf = event; after_buf = event;
event = move_event_buf; event = move_event_buf;
event_type = "Delete"; event_type = "Delete";
move_event = false; move_event = false;
} else if ( move_event && }
(IN_MOVED_TO & event->mask) && else if(
event->cookie == move_event_buf->cookie ) { move_event &&
(
IN_MOVED_TO & event->mask ) &&
event->cookie == move_event_buf->cookie
)
{
// this is indeed a matched move */ // this is indeed a matched move */
event_type = "Move"; event_type = "Move";
move_event = false; move_event = false;
} else if (IN_MOVED_FROM & event->mask) { }
else if( IN_MOVED_FROM & event->mask )
{
// just the MOVE_FROM, buffers this event, and wait if next event is // 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 // a matching MOVED_TO of this was an unary move out of the watched
// tree. // tree.
size_t el = sizeof(struct inotify_event) + event->len; size_t el = sizeof( struct inotify_event ) + event->len;
if (move_event_buf_size < el) {
if( move_event_buf_size < el )
{
move_event_buf_size = el; move_event_buf_size = el;
move_event_buf = s_realloc(move_event_buf, el); move_event_buf = s_realloc( move_event_buf, el );
} }
memcpy(move_event_buf, event, el); memcpy( move_event_buf, event, el );
move_event = true; move_event = true;
return; return;
} else if (IN_MOVED_TO & event->mask) {
}
else if( IN_MOVED_TO & event->mask )
{
// must be an unary move-to // must be an unary move-to
event_type = CREATE; event_type = CREATE;
} else if (IN_ATTRIB & event->mask) { }
else if( IN_ATTRIB & event->mask )
{
// just attrib change // just attrib change
event_type = ATTRIB; event_type = ATTRIB;
} else if ((IN_CLOSE_WRITE | IN_MODIFY) & event->mask) { }
else if( ( IN_CLOSE_WRITE | IN_MODIFY) & event->mask )
{
// modify, or closed after written something // modify, or closed after written something
// the event type received depends settings.inotifyMode // the event type received depends settings.inotifyMode
event_type = MODIFY; event_type = MODIFY;
} else if (IN_CREATE & event->mask) { }
else if( IN_CREATE & event->mask )
{
// a new file // a new file
event_type = CREATE; event_type = CREATE;
} else if (IN_DELETE & event->mask) { }
else if( IN_DELETE & event->mask )
{
// rm'ed // rm'ed
event_type = DELETE; event_type = DELETE;
} else { }
logstring("Inotify", "icore, skipped some inotify event."); else
{
logstring(
"Inotify",
"skipped some inotify event."
);
return; return;
} }
// and hands over to runner // hands the event over to the runner
load_runner_func(L, "inotifyEvent"); load_runner_func( L, "inotifyEvent" );
if (!event_type) {
logstring("Error", "Internal: unknown event in handle_event()"); if( !event_type )
exit(-1); // ERRNO {
logstring(
"Error",
"internal failure: unknown event in handle_event()"
);
exit( -1 );
} }
lua_pushstring(L, event_type);
if (event_type != MOVE) { lua_pushstring( L, event_type );
lua_pushnumber(L, event->wd); if( event_type != MOVE )
} else { {
lua_pushnumber(L, move_event_buf->wd); lua_pushnumber( L, event->wd );
} }
lua_pushboolean(L, (event->mask & IN_ISDIR) != 0); else
l_now(L); {
if (event_type == MOVE) { lua_pushnumber( L, move_event_buf->wd );
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)) { lua_pushboolean( L, ( event->mask & IN_ISDIR ) != 0 );
exit(-1); // ERRNO
l_now( L );
if( event_type == MOVE )
{
lua_pushstring( L, move_event_buf->name );
lua_pushnumber( L, event->wd );
lua_pushstring( L, event->name );
} }
lua_pop(L, 1); else
{
lua_pushstring( L, event->name );
lua_pushnil( L );
lua_pushnil( L );
}
if( lua_pcall( L, 7, 0, -9 ) )
{
exit( -1 );
}
lua_pop( L, 1 );
// if there is a buffered event, executes it // if there is a buffered event, executes it
if (after_buf) { if (after_buf) {
@ -275,31 +389,44 @@ handle_event(lua_State *L,
} }
} }
/**
* buffer to read inotify events into /*
*/ | buffer to read inotify events into
*/
static size_t readbuf_size = 2048; static size_t readbuf_size = 2048;
static char * readbuf = NULL; static char * readbuf = NULL;
/**
* Called by function pointer from when the inotify file descriptor /*
* became ready. Reads it contents and forward all received events | Called when the inotify file descriptor became ready.
* to the runner. | Reads it contents and forwards all received events
*/ | to the runner.
*/
static void static void
inotify_ready(lua_State *L, struct observance *obs) inotify_ready(
lua_State *L,
struct observance *obs
)
{ {
if (obs->fd != inotify_fd) { // sanity check
logstring("Error", "Internal, inotify_fd != ob->fd"); if( obs->fd != inotify_fd )
exit(-1); // ERRNO {
logstring(
"Error",
"internal failure, inotify_fd != ob->fd"
);
exit( -1 );
} }
while(true) {
while( true )
{
ptrdiff_t len; ptrdiff_t len;
int err; int err;
do { do {
len = read (inotify_fd, readbuf, readbuf_size); len = read( inotify_fd, readbuf, readbuf_size );
err = errno; err = errno;
if (len < 0 && err == EINVAL) { if( len < 0 && err == EINVAL )
{
// kernel > 2.6.21 indicates that way that way that // kernel > 2.6.21 indicates that way that way that
// the buffer was too small to fit a filename. // the buffer was too small to fit a filename.
// double its size and try again. When using a lower // double its size and try again. When using a lower
@ -309,90 +436,138 @@ inotify_ready(lua_State *L, struct observance *obs)
readbuf_size *= 2; readbuf_size *= 2;
readbuf = s_realloc(readbuf, readbuf_size); readbuf = s_realloc(readbuf, readbuf_size);
} }
} while(len < 0 && err == EINVAL); } while( len < 0 && err == EINVAL );
if (len == 0) {
// nothing more inotify if( len == 0 )
{
// no more inotify events
break; break;
} }
if (len < 0) {
if (len < 0)
{
if (err == EAGAIN) { if (err == EAGAIN) {
// nothing more inotify // nothing more inotify
break; break;
} else { }
printlogf(L, "Error", "Read fail on inotify"); else
exit(-1); // ERRNO {
printlogf(
L, "Error",
"Read fail on inotify"
);
exit( -1 );
} }
} }
{ {
int i = 0; int i = 0;
while (i < len && !hup && !term) { while( i < len && !hup && !term )
{
struct inotify_event *event = struct inotify_event *event =
(struct inotify_event *) &readbuf[i]; ( struct inotify_event * )
handle_event(L, event); (readbuf + i);
i += sizeof(struct inotify_event) + event->len;
handle_event( L, event );
i += sizeof( struct inotify_event ) + event->len;
} }
} }
if (!move_event) {
if( !move_event )
{
// give it a pause if not endangering splitting a move // give it a pause if not endangering splitting a move
break; break;
} }
} }
// checks if there is an unary MOVE_FROM left in the buffer // checks if there is an unary MOVE_FROM left in the buffer
if (move_event) { if( move_event )
logstring("Inotify", "icore, handling unary move from."); {
handle_event(L, NULL); logstring(
"Inotify",
"handling unary move from."
);
handle_event( L, NULL );
} }
} }
/**
* registers inotify functions. /*
*/ | Registers the inotify functions.
*/
extern void extern void
register_inotify(lua_State *L) register_inotify( lua_State *L )
{ {
luaL_register(L, LSYNCD_INOTIFYLIBNAME, linotfylib); luaL_register( L, LSYNCD_INOTIFYLIBNAME, linotfylib );
} }
/**
* closes inotify /*
*/ | Cleans up the inotify handling.
*/
static void static void
inotify_tidy(struct observance *obs) inotify_tidy( struct observance *obs )
{ {
if (obs->fd != inotify_fd) { if( obs->fd != inotify_fd )
logstring("Error", "Internal, inotify_fd != ob->fd"); {
exit(-1); // ERRNO logstring(
"Error",
"internal failure: inotify_fd != ob->fd"
);
exit( -1 );
} }
close(inotify_fd);
free(readbuf); close( inotify_fd );
free( readbuf );
readbuf = NULL; readbuf = NULL;
} }
/** /*
* opens and initalizes inotify. | Initalizes inotify handling
*/ */
extern void extern void
open_inotify(lua_State *L) open_inotify( lua_State *L )
{ {
if (readbuf) { if( readbuf )
logstring("Error", {
"internal fail, inotify readbuf!=NULL in open_inotify()") logstring(
exit(-1); // ERRNO "Error",
"internal failure, inotify readbuf != NULL in open_inotify()"
)
exit(-1);
} }
readbuf = s_malloc(readbuf_size);
inotify_fd = inotify_init(); readbuf = s_malloc( readbuf_size );
if (inotify_fd < 0) {
printlogf(L, "Error", inotify_fd = inotify_init( );
"Cannot access inotify monitor! (%d:%s)",
errno, strerror(errno)); if( inotify_fd < 0 )
exit(-1); // ERRNO {
printlogf(
L,
"Error",
"Cannot access inotify monitor! ( %d : %s )",
errno, strerror(errno)
);
exit( -1 );
} }
printlogf(L, "Inotify", "inotify fd = %d", inotify_fd);
close_exec_fd(inotify_fd); printlogf(
non_block_fd(inotify_fd); L, "Inotify",
observe_fd(inotify_fd, inotify_ready, NULL, inotify_tidy, NULL); "inotify fd = %d",
inotify_fd
);
close_exec_fd( inotify_fd );
non_block_fd( inotify_fd );
observe_fd(
inotify_fd,
inotify_ready,
NULL,
inotify_tidy,
NULL
);
} }

View File

@ -30,7 +30,7 @@ if lsyncd_version then
lsyncd.terminate( -1 ) lsyncd.terminate( -1 )
end end
lsyncd_version = '2.0.7' lsyncd_version = '2.1.0-beta'
-- --
-- Hides the core interface from user scripts. -- Hides the core interface from user scripts.
@ -1630,12 +1630,12 @@ local Sync = ( function( )
log( log(
'Function', 'Function',
'delay(', 'delay( ',
self.config.name, ', ', self.config.name, ', ',
etype, ', ', etype, ', ',
path, ', ', path, ', ',
path2, path2,
')' ' )'
) )
-- TODO -- TODO
@ -1777,14 +1777,24 @@ local Sync = ( function( )
) )
if nd.etype == 'Init' or nd.etype == 'Blanket' then if nd.etype == 'Init' or nd.etype == 'Blanket' then
-- always stack blanket events on the last event
log('Delay', 'Stacking ',nd.etype,' event.') -- always stack init or blanket events on the last event
log(
'Delay',
'Stacking ',
nd.etype,
' event.'
)
if self.delays.size > 0 then if self.delays.size > 0 then
stack( self.delays[ self.delays.last ], nd ) stack( self.delays[ self.delays.last ], nd )
end end
nd.dpos = Queue.push( self.delays, nd ) nd.dpos = Queue.push( self.delays, nd )
recurse( ) recurse( )
return return
end end
-- detects blocks and combos by working from back until -- detects blocks and combos by working from back until
@ -1896,11 +1906,10 @@ local Sync = ( function( )
log( log(
'Function', 'Function',
'invokeActions("', 'invokeActions( "',
self.config.name, self.config.name, '", ',
'",', timestamp,
timestamp, ' )'
')'
) )
if self.processes:size( ) >= self.config.maxProcesses then if self.processes:size( ) >= self.config.maxProcesses then
@ -1909,6 +1918,7 @@ local Sync = ( function( )
end end
for _, d in Queue.qpairs( self.delays ) do for _, d in Queue.qpairs( self.delays ) do
-- if reached the global limit return -- if reached the global limit return
if settings.maxProcesses and if settings.maxProcesses and
processCount >= settings.maxProcesses processCount >= settings.maxProcesses
@ -1927,12 +1937,14 @@ local Sync = ( function( )
end end
if d.status == 'wait' then if d.status == 'wait' then
-- found a waiting delay -- found a waiting delay
if d.etype ~= 'Init' then if d.etype ~= 'Init' then
self.config.action( self.inlet ) self.config.action( self.inlet )
else else
self.config.init( InletFactory.d2e( d ) ) self.config.init( InletFactory.d2e( d ) )
end end
if self.processes:size( ) >= self.config.maxProcesses then if self.processes:size( ) >= self.config.maxProcesses then
-- no further processes -- no further processes
return return
@ -1980,8 +1992,11 @@ local Sync = ( function( )
-- Used as startup marker to call init asap. -- Used as startup marker to call init asap.
-- --
local function addInitDelay( self ) local function addInitDelay( self )
local newd = Delay.new( 'Init', self, true, '' ) local newd = Delay.new( 'Init', self, true, '' )
newd.dpos = Queue.push( self.delays, newd ) newd.dpos = Queue.push( self.delays, newd )
return newd return newd
end end
@ -2113,7 +2128,7 @@ local Syncs = ( function( )
local round = 1 local round = 1
-- --
-- The cycle() sheduler goes into the next round of roundrobin. -- The cycle( ) sheduler goes into the next round of roundrobin.
-- --
local function nextRound( ) local function nextRound( )
@ -2141,31 +2156,85 @@ local Syncs = ( function( )
end end
-- --
-- Inheritly copies all non integer keys from -- Helper function for inherit
-- table copy source ( cs ) to -- defined below
-- table copy destination ( cd ).
-- --
-- All entries with integer keys are treated as new sources to copy local inheritKV
--
-- Recurvely inherits a source table to a destionation table
-- copying all keys from source.
--
-- table copy source ( cs )
-- table copy destination ( cd )
--
-- All entries with integer keys are inherited as additional
-- sources for non-verbatim tables
-- --
local function inherit( cd, cs ) local function inherit( cd, cs )
-- first copies from source all --
-- non-defined non-integer keyed values -- First copies all entries with non-integer keys
-- tables are merged, already present keys are not
-- overwritten
--
-- For verbatim tables integer keys are treated like
-- non integer keys
--
for k, v in pairs( cs ) do for k, v in pairs( cs ) do
if type( k ) ~= 'number' and cd[ k ] == nil then if type( k ) ~= 'number' or cs._verbatim == true then
cd[ k ] = v inheritKV( cd, k, v )
end end
end end
-- first recurses into all integer keyed tables --
for i, v in ipairs( cs ) do -- recursevely inherits all integer keyed tables
if type( v ) == 'table' then -- ( for non-verbatim tables )
inherit( cd, v ) --
if cs._verbatim ~= true then
local n = nil
for k, v in ipairs( cs ) do
n = k
if type( v ) == 'table' then
inherit( cd, v )
else
cd[ #cd + 1 ] = v
end
end end
end
end
--
-- Helper to inherit. Inherits one key.
--
inheritKV = function( cd, k, v )
local dtype = type( cd [ k ] )
if type( v ) == 'table' then
if dtype == 'nil' then
cd[ k ] = { }
inherit( cd[ k ], v )
elseif dtype == 'table' and v._merge ~= false then
inherit( cd[ k ], v )
end
elseif dtype == 'nil' then
cd[ k ] = v
end end
end end
-- --
-- Adds a new sync (directory-tree to observe). -- Adds a new sync (directory-tree to observe).
-- --
@ -2175,7 +2244,7 @@ local Syncs = ( function( )
-- from integer keyed tables -- from integer keyed tables
local uconfig = config local uconfig = config
config = { } config = { }
inherit( config, uconfig ) inherit( config, uconfig, false )
-- Lets settings or commandline override delay values. -- Lets settings or commandline override delay values.
if settings then if settings then
@ -2227,7 +2296,7 @@ local Syncs = ( function( )
'Error', 'Error',
info.short_src, ':', info.short_src, ':',
info.currentline, info.currentline,
': no actions specified, use e.g. "config = default.rsync".' ': no actions specified.'
) )
terminate( -1 ) terminate( -1 )
@ -2391,14 +2460,21 @@ local Inotify = ( function( )
pathwds[ path ] = nil pathwds[ path ] = nil
end end
-----
--
-- Adds watches for a directory (optionally) including all subdirectories. -- Adds watches for a directory (optionally) including all subdirectories.
-- --
-- @param path absolute path of directory to observe -- @param path absolute path of directory to observe
-- @param recurse true if recursing into subdirs -- @param recurse true if recursing into subdirs
-- --
local function addWatch(path) local function addWatch(path)
log('Function','Inotify.addWatch(',path,')')
log(
'Function',
'Inotify.addWatch( ',
path,
' )'
)
if not Syncs.concerns(path) then if not Syncs.concerns(path) then
log('Inotify', 'not concerning "',path,'"') log('Inotify', 'not concerning "',path,'"')
@ -3075,9 +3151,9 @@ local StatusFile = ( function( )
log( log(
'Function', 'Function',
'write(', 'write( ',
timestamp, timestamp,
')' ' )'
) )
-- takes care not write too often -- takes care not write too often
@ -3313,20 +3389,25 @@ function runner.cycle(
) )
if lsyncdStatus == 'fade' then if lsyncdStatus == 'fade' then
if processCount > 0 then if processCount > 0 then
log( log(
'Normal', 'Normal',
'waiting for ', 'waiting for ',
processCount, processCount,
' more child processes.' ' more child processes.'
) )
return true return true
else else
return false return false
end end
end end
if lsyncdStatus ~= 'run' then if lsyncdStatus ~= 'run' then
error( 'runner.cycle() called while not running!' ) error( 'runner.cycle() called while not running!' )
end end
@ -3340,17 +3421,19 @@ function runner.cycle(
processCount < settings.maxProcesses processCount < settings.maxProcesses
then then
local start = Syncs.getRound( ) local start = Syncs.getRound( )
local ir = start local ir = start
repeat repeat
local s = Syncs.get( ir ) local s = Syncs.get( ir )
s:invokeActions( timestamp ) s:invokeActions( timestamp )
ir = ir + 1 ir = ir + 1
if ir > Syncs.size( ) then if ir > Syncs.size( ) then
ir = 1 ir = 1
end end
until ir == start until ir == start
Syncs.nextRound( ) Syncs.nextRound( )
@ -3652,13 +3735,19 @@ end
-- --
function runner.initialize( firstTime ) function runner.initialize( firstTime )
--
-- creates settings if user didnt -- creates settings if user didnt
--
settings = settings or {} settings = settings or {}
--
-- From this point on, no globals may be created anymore -- From this point on, no globals may be created anymore
lockGlobals() --
lockGlobals( )
-- copies simple settings with numeric keys to 'key=true' settings. --
-- copies simple settings with numeric keys to 'key = true' settings.
--
for k, v in ipairs( settings ) do for k, v in ipairs( settings ) do
if settings[ v ] then if settings[ v ] then
@ -3714,23 +3803,23 @@ function runner.initialize( firstTime )
end end
if settings.nodaemon then if settings.nodaemon then
lsyncd.configure('nodaemon') lsyncd.configure( 'nodaemon' )
end end
if settings.logfile then if settings.logfile then
lsyncd.configure('logfile', settings.logfile) lsyncd.configure( 'logfile', settings.logfile )
end end
if settings.logident then if settings.logident then
lsyncd.configure('logident', settings.logident) lsyncd.configure( 'logident', settings.logident )
end end
if settings.logfacility then if settings.logfacility then
lsyncd.configure('logfacility', settings.logfacility) lsyncd.configure( 'logfacility', settings.logfacility )
end end
if settings.pidfile then if settings.pidfile then
lsyncd.configure('pidfile', settings.pidfile) lsyncd.configure( 'pidfile', settings.pidfile )
end end
-- --
@ -3753,6 +3842,7 @@ function runner.initialize( firstTime )
-- from now on use logging as configured instead of stdout/err. -- from now on use logging as configured instead of stdout/err.
lsyncdStatus = 'run'; lsyncdStatus = 'run';
lsyncd.configure( 'running' ); lsyncd.configure( 'running' );
local ufuncs = { local ufuncs = {
@ -3766,34 +3856,49 @@ function runner.initialize( firstTime )
-- translates layer 3 scripts -- translates layer 3 scripts
for _, s in Syncs.iwalk() do for _, s in Syncs.iwalk() do
-- checks if any user functions is a layer 3 string. -- checks if any user functions is a layer 3 string.
local config = s.config local config = s.config
for _, fn in ipairs(ufuncs) do for _, fn in ipairs(ufuncs) do
if type(config[fn]) == 'string' then if type(config[fn]) == 'string' then
local ft = functionWriter.translate(config[fn]) local ft = functionWriter.translate(config[fn])
config[fn] = assert(loadstring('return '..ft))() config[fn] = assert(loadstring('return '..ft))()
end end
end end
end end
-- runs through the Syncs created by users -- runs through the Syncs created by users
for _, s in Syncs.iwalk( ) do for _, s in Syncs.iwalk( ) do
if s.config.monitor == 'inotify' then if s.config.monitor == 'inotify' then
Inotify.addSync( s, s.source ) Inotify.addSync( s, s.source )
elseif s.config.monitor == 'fsevents' then elseif s.config.monitor == 'fsevents' then
Fsevents.addSync( s, s.source ) Fsevents.addSync( s, s.source )
else else
error( error(
'sync ' .. 'sync ' ..
s.config.name .. s.config.name ..
' has no known event monitor interface.' ' has no known event monitor interface.'
) )
end end
-- if the sync has an init function, the init delay -- if the sync has an init function, the init delay
-- is stacked which causes the init function to be called. -- is stacked which causes the init function to be called.
if s.config.init then if s.config.init then
s:addInitDelay( ) s:addInitDelay( )
end end
end end

View File

@ -73,7 +73,7 @@ end
cwriteln("testing startup excludes"); cwriteln("testing startup excludes");
writefiles(); writefiles();
cwriteln("starting Lsyncd"); cwriteln("starting Lsyncd");
local pid = spawn("./lsyncd", cfgfile); local pid = spawn("./lsyncd", cfgfile, '-log', 'all');
cwriteln("waiting for Lsyncd to start"); cwriteln("waiting for Lsyncd to start");
posix.sleep(3) posix.sleep(3)
cwriteln("testing excludes after startup"); cwriteln("testing excludes after startup");