From 1bf1d13eaac51962ae80272745c828aa8f2f734e Mon Sep 17 00:00:00 2001 From: Axel Kittenberger Date: Fri, 5 Oct 2012 09:41:46 +0200 Subject: [PATCH] new inheritance mechanics, code beautifications --- configure.ac | 2 +- default-rsync.lua | 36 ++- default.lua | 100 +++++-- inotify.c | 565 ++++++++++++++++++++++++++-------------- lsyncd.lua | 181 ++++++++++--- tests/exclude-rsync.lua | 2 +- 6 files changed, 610 insertions(+), 276 deletions(-) diff --git a/configure.ac b/configure.ac index c9c491d..e5ad276 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. #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]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/default-rsync.lua b/default-rsync.lua index 86731a7..73a3c4e 100644 --- a/default-rsync.lua +++ b/default-rsync.lua @@ -15,15 +15,19 @@ -- --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + if not default then - error('default not loaded') + error( 'default not loaded' ) end + if default.rsync then - error('default-rsync already loaded') + error( 'default-rsync already loaded' ) end + default.rsync = { } +local rsync = default.rsync -- -- Spawns rsync for a list of events @@ -31,7 +35,7 @@ default.rsync = { } -- Exlcusions are already handled by not having -- events for them. -- -default.rsync.action = function( inlet ) +rsync.action = function( inlet ) -- -- gets all events ready for syncing @@ -51,10 +55,10 @@ default.rsync.action = function( inlet ) end return p: - gsub('%?', '\\?'): - gsub('%*', '\\*'): - gsub('%[', '\\['): - gsub('%]', '\\]') + gsub( '%?', '\\?' ): + gsub( '%*', '\\*' ): + gsub( '%[', '\\[' ): + gsub( '%]', '\\]' ) end -- @@ -153,10 +157,11 @@ default.rsync.action = function( inlet ) end + -- -- Spawns the recursive startup sync -- -init = function(event) +rsync.init = function(event) local config = event.config local inlet = event.inlet @@ -216,10 +221,11 @@ init = function(event) end end + -- -- Prepares and checks a syncs configuration on startup. -- -default.rsync.prepare = function( config ) +rsync.prepare = function( config ) if not config.target then error( @@ -317,19 +323,22 @@ default.rsync.prepare = function( config ) end end + -- -- rsync uses default collect -- + -- -- By default do deletes. -- -default.rsync.delete = true +rsync.delete = true + -- -- Calls rsync with this default options -- -default.rsync.rsync = { +rsync.rsync = { -- The rsync binary to be called. binary = '/usr/bin/rsync', links = true, @@ -337,12 +346,13 @@ default.rsync.rsync = { protectArgs = true } + -- -- Exit codes for rsync. -- -default.rsync.exitcodes = default.rsyncExitCodes +rsync.exitcodes = default.rsyncExitCodes -- -- Default delay -- -default.rsync.delay = 15 +rsync.delay = 15 diff --git a/default.lua b/default.lua index 7fde188..7ec7e05 100644 --- a/default.lua +++ b/default.lua @@ -38,8 +38,10 @@ default = { -- Called when collecting a finished child process -- collect = function(agent, exitcode) + local config = agent.config local rc + if config.exitcodes then rc = config.exitcodes[exitcode] elseif exitcode == 0 then @@ -71,7 +73,8 @@ default = { agent.source, '". Terminating since "insist" is not set.' ) - terminate(-1) -- ERRNO + + terminate( -1 ) end elseif rc == 'die' then log( @@ -80,7 +83,8 @@ default = { agent.source, '".' ) - terminate(-1) -- ERRNO + + terminate( -1 ) else log( 'Error', @@ -96,13 +100,29 @@ default = { if agent.isList then if rc == 'ok' then - log('Normal', 'Finished a list = ',exitcode) + log( + 'Normal', + 'Finished a list after exitcode: ', + exitcode + ) elseif rc == 'again' then - log('Normal', 'Retrying a list on exitcode = ',exitcode) + log( + 'Normal', + 'Retrying a list after exitcode = ', + exitcode + ) elseif rc == 'die' then - log('Error', 'Failure with a list on exitcode = ',exitcode) + log( + 'Error', + 'Failure with a list width exitcode = ', + exitcode + ) else - log('Error', 'Unknown exitcode "',exitcode,'" with a list') + log( + 'Error', + 'Unknown exitcode "',exitcode,'" with a list' + ) + rc = 'die' end else @@ -164,34 +184,58 @@ default = { -- Exitcodes of rsync and what to do. -- rsyncExitCodes = { - [ 0] = 'ok', - [ 1] = 'die', - [ 2] = 'die', - [ 3] = 'again', - [ 4] = 'die', - [ 5] = 'again', - [ 6] = 'again', - [ 10] = 'again', - [ 11] = 'again', - [ 12] = 'again', - [ 14] = 'again', - [ 20] = 'again', - [ 21] = 'again', - [ 22] = 'again', - [ 23] = 'ok', -- partial transfers are ok, since Lsyncd has registered the event that - [ 24] = 'ok', -- caused the transfer to be partial and will recall rsync. - [ 25] = 'die', - [ 30] = 'again', - [ 35] = 'again', - [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', + [ 1 ] = 'die', + [ 2 ] = 'die', + [ 3 ] = 'again', + [ 4 ] = 'die', + [ 5 ] = 'again', + [ 6 ] = 'again', + [ 10 ] = '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. -- 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', }, ----- diff --git a/inotify.c b/inotify.c index fcbcef0..335225a 100644 --- a/inotify.c +++ b/inotify.c @@ -1,14 +1,14 @@ -/** - * inotify.c from Lsyncd - Live (Mirror) Syncing Demon - * - * License: GPLv2 (see COPYING) or any later version - * - * Authors: Axel Kittenberger - * - * ----------------------------------------------------------------------- - * - * Event interface for Lsyncd to Linux´ inotify. - */ +/* +| inotify.c from Lsyncd - Live (Mirror) Syncing Demon +| +| License: GPLv2 (see COPYING) or any later version +| +| Authors: Axel Kittenberger +| +| ----------------------------------------------------------------------- +| +| Event interface for Lsyncd to Linux´ inotify. +*/ #include "lsyncd.h" @@ -39,83 +39,130 @@ #include #include -/*----------------------------------------------------------------------------- - * Event types. - */ + +/* +| Event types. +*/ static const char * ATTRIB = "Attrib"; static const char * MODIFY = "Modify"; static const char * CREATE = "Create"; static const char * DELETE = "Delete"; static const char * MOVE = "Move"; -/** + +/* * The inotify file descriptor. */ static int inotify_fd = -1; -/** - * Standard inotify events to listen to. - */ + +/* +| Standard inotify events to listen to. +*/ 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; + 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 - * @param inotifyMode (Lua stack) path to directory - * @return (Lua stack) numeric watch descriptor - */ +/* +| Adds an inotify watch +| +| param dir (Lua stack) path to directory +| param inotifyMode (Lua stack) which inotify event to react upon +| "CloseWrite", "CloseWrite or Modify" +| +| returns (Lua stack) numeric watch descriptor +*/ static int -l_addwatch(lua_State *L) +l_addwatch( lua_State *L ) { - const char *path = luaL_checkstring(L, 1); - const char *imode = luaL_checkstring(L, 2); + const char *path = luaL_checkstring( L, 1 ); + const char *imode = luaL_checkstring( L, 2 ); uint32_t mask = standard_event_mask; - if (*imode) { - if (!strcmp(imode, "Modify")) { - // act on modify instead of closeWrite - mask |= IN_MODIFY; + + // checks the desired inotify reaction mode + if (*imode) + { + if ( !strcmp( imode, "Modify" ) ) + { + // acts on modify instead of closeWrite + mask |= IN_MODIFY; mask &= ~IN_CLOSE_WRITE; - } else if (!strcmp(imode, "CloseWrite")) { - // default - } else if (!strcmp(imode, "CloseWrite or Modify")) { + } + else if ( !strcmp( imode, "CloseWrite" ) ) + { + // thats default + } + else if ( !strcmp( imode, "CloseWrite or Modify" ) ) + { // acts on modify and closeWrite mask |= IN_MODIFY; - } else if (!strcmp(imode, "CloseWrite after Modify")) { + } + else if ( ! strcmp( imode, "CloseWrite after Modify") ) + { // might be done in future - printlogf(L, "Error", "'CloseWrite after Modify' not implemented."); - exit(-1); // ERRNO - } else { - printlogf(L, "Error", "'%s' not a valid inotfiyMode.", imode); - exit(-1); // ERRNO + printlogf( + L, "Error", + "'CloseWrite after Modify' not implemented." + ); + 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 (errno == ENOSPC) { - printlogf(L, "Error", "Terminating since out of inotify watches."); - printlogf(L, "Error", "Consider increasing /proc/sys/fs/inotify/max_user_watches"); + if (wd < 0) + { + if (errno == ENOSPC) + { + printlogf( + L, "Error", + "%s\n%s", + "Terminating since out of inotify watches.", + "Consider increasing /proc/sys/fs/inotify/max_user_watches" + ); exit(-1); // ERRNO. } - printlogf(L, "Inotify", "addwatch(%s)->%d; err=%d:%s", path, wd, errno, strerror(errno)); - } else { - printlogf(L, "Inotify", "addwatch(%s)->%d", path, wd); + + printlogf( + 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; } -/** - * Removes an inotify watch + +/* + * Removes an inotify watch. * - * @param dir (Lua stack) numeric watch descriptor - * @return nil + * param dir (Lua stack) numeric watch descriptor + * + * return nil */ static int l_rmwatch(lua_State *L) @@ -126,147 +173,214 @@ l_rmwatch(lua_State *L) return 0; } -/** - * Cores inotify functions. - */ + +/* +| Lsyncd's core's inotify functions. +*/ static const luaL_Reg linotfylib[] = { - {"addwatch", l_addwatch }, - {"rmwatch", l_rmwatch }, - {NULL, NULL} + { "addwatch", l_addwatch }, + { "rmwatch", l_rmwatch }, + { NULL, NULL} }; -/** - * Buffer for MOVE_FROM events. - * Lsyncd buffers MOVE_FROM events to check if - * they are followed by MOVE_TO events with identical cookie - * then they are condensed into one move event to be sent to the - * runner - */ + +/* +| Buffer for MOVE_FROM events. +| Lsyncd buffers MOVE_FROM events to check if +| they are followed by MOVE_TO events with identical cookie +| then they are condensed into one move event to be sent to the +| runner +*/ 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; -/** - * true if the buffer is used. - */ + +/* +| True if the buffer is used. +*/ static bool move_event = false; -/** - * Handles an inotify event. - */ + +/* +| Handles an inotify event. +*/ static void -handle_event(lua_State *L, - struct inotify_event *event) +handle_event( + lua_State *L, + struct inotify_event *event +) { const char *event_type = NULL; // 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 + 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 ); } - lua_pop(L, 1); + lua_pop( L, 1 ); hup = 1; return; } + // cancel on ignored or resetting - if (event && (IN_IGNORED & event->mask)) { + if( event && ( IN_IGNORED & event->mask ) ) + { return; } - if (event && event->len == 0) { + + if( event && event->len == 0 ) + { // sometimes inotify sends such strange events, // (e.g. when touching a dir return; } - if (event == NULL) { + 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) ) { + } + 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 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; 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 ) { + } + 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) { + } + 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) { + 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); + move_event_buf = s_realloc( move_event_buf, el ); } - memcpy(move_event_buf, event, el); + memcpy( move_event_buf, event, el ); move_event = true; return; - } else if (IN_MOVED_TO & event->mask) { + + } + else if( IN_MOVED_TO & event->mask ) + { // must be an unary move-to event_type = CREATE; - } else if (IN_ATTRIB & event->mask) { + } + else if( IN_ATTRIB & event->mask ) + { // just attrib change 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 // the event type received depends settings.inotifyMode event_type = MODIFY; - } else if (IN_CREATE & event->mask) { + } + else if( IN_CREATE & event->mask ) + { // a new file event_type = CREATE; - } else if (IN_DELETE & event->mask) { + } + else if( IN_DELETE & event->mask ) + { // rm'ed event_type = DELETE; - } else { - logstring("Inotify", "icore, skipped some inotify event."); + } + else + { + logstring( + "Inotify", + "skipped some inotify event." + ); return; } - // and hands over to runner - load_runner_func(L, "inotifyEvent"); - if (!event_type) { - logstring("Error", "Internal: unknown event in handle_event()"); - exit(-1); // ERRNO + // hands the event over to the runner + load_runner_func( L, "inotifyEvent" ); + + if( !event_type ) + { + logstring( + "Error", + "internal failure: unknown event in handle_event()" + ); + + exit( -1 ); } - lua_pushstring(L, event_type); - if (event_type != MOVE) { - lua_pushnumber(L, event->wd); - } else { - lua_pushnumber(L, move_event_buf->wd); + + lua_pushstring( L, event_type ); + if( event_type != MOVE ) + { + lua_pushnumber( L, event->wd ); } - lua_pushboolean(L, (event->mask & IN_ISDIR) != 0); - l_now(L); - 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); + else + { + lua_pushnumber( L, move_event_buf->wd ); } - if (lua_pcall(L, 7, 0, -9)) { - exit(-1); // ERRNO + lua_pushboolean( L, ( event->mask & IN_ISDIR ) != 0 ); + + 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 (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 char * readbuf = NULL; -/** - * Called by function pointer from when the inotify file descriptor - * became ready. Reads it contents and forward all received events - * to the runner. - */ + +/* +| Called when the inotify file descriptor became ready. +| Reads it contents and forwards all received events +| to the runner. +*/ static void -inotify_ready(lua_State *L, struct observance *obs) +inotify_ready( + lua_State *L, + struct observance *obs +) { - if (obs->fd != inotify_fd) { - logstring("Error", "Internal, inotify_fd != ob->fd"); - exit(-1); // ERRNO + // sanity check + if( obs->fd != inotify_fd ) + { + logstring( + "Error", + "internal failure, inotify_fd != ob->fd" + ); + exit( -1 ); } - while(true) { + + while( true ) + { ptrdiff_t len; int err; do { - len = read (inotify_fd, readbuf, readbuf_size); + len = read( inotify_fd, readbuf, readbuf_size ); err = errno; - if (len < 0 && err == EINVAL) { + if( len < 0 && err == 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 @@ -309,90 +436,138 @@ inotify_ready(lua_State *L, struct observance *obs) readbuf_size *= 2; readbuf = s_realloc(readbuf, readbuf_size); } - } while(len < 0 && err == EINVAL); - if (len == 0) { - // nothing more inotify + } while( len < 0 && err == EINVAL ); + + if( len == 0 ) + { + // no more inotify events break; } - if (len < 0) { + + if (len < 0) + { if (err == EAGAIN) { // nothing more inotify break; - } else { - printlogf(L, "Error", "Read fail on inotify"); - exit(-1); // ERRNO + } + else + { + printlogf( + L, "Error", + "Read fail on inotify" + ); + exit( -1 ); } } + { int i = 0; - while (i < len && !hup && !term) { + 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; + ( struct inotify_event * ) + (readbuf + i); + + 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 break; } } // checks if there is an unary MOVE_FROM left in the buffer - if (move_event) { - logstring("Inotify", "icore, handling unary move from."); - handle_event(L, NULL); + if( move_event ) + { + logstring( + "Inotify", + "handling unary move from." + ); + handle_event( L, NULL ); } } -/** - * registers inotify functions. - */ + +/* +| Registers the inotify functions. +*/ 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 -inotify_tidy(struct observance *obs) +inotify_tidy( struct observance *obs ) { - if (obs->fd != inotify_fd) { - logstring("Error", "Internal, inotify_fd != ob->fd"); - exit(-1); // ERRNO + if( obs->fd != inotify_fd ) + { + logstring( + "Error", + "internal failure: inotify_fd != ob->fd" + ); + exit( -1 ); } - close(inotify_fd); - free(readbuf); + + close( inotify_fd ); + free( readbuf ); readbuf = NULL; } -/** - * opens and initalizes inotify. - */ +/* +| Initalizes inotify handling +*/ extern void -open_inotify(lua_State *L) +open_inotify( lua_State *L ) { - if (readbuf) { - logstring("Error", - "internal fail, inotify readbuf!=NULL in open_inotify()") - exit(-1); // ERRNO + if( readbuf ) + { + logstring( + "Error", + "internal failure, inotify readbuf != NULL in open_inotify()" + ) + exit(-1); } - readbuf = s_malloc(readbuf_size); - inotify_fd = inotify_init(); - if (inotify_fd < 0) { - printlogf(L, "Error", - "Cannot access inotify monitor! (%d:%s)", - errno, strerror(errno)); - exit(-1); // ERRNO + readbuf = s_malloc( readbuf_size ); + + inotify_fd = inotify_init( ); + + if( inotify_fd < 0 ) + { + 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); - non_block_fd(inotify_fd); - observe_fd(inotify_fd, inotify_ready, NULL, inotify_tidy, NULL); + printlogf( + L, "Inotify", + "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 + ); } diff --git a/lsyncd.lua b/lsyncd.lua index 1f566a2..aa6e803 100644 --- a/lsyncd.lua +++ b/lsyncd.lua @@ -30,7 +30,7 @@ if lsyncd_version then lsyncd.terminate( -1 ) end -lsyncd_version = '2.0.7' +lsyncd_version = '2.1.0-beta' -- -- Hides the core interface from user scripts. @@ -1630,12 +1630,12 @@ local Sync = ( function( ) log( 'Function', - 'delay(', + 'delay( ', self.config.name, ', ', etype, ', ', path, ', ', path2, - ')' + ' )' ) -- TODO @@ -1777,14 +1777,24 @@ local Sync = ( function( ) ) 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 stack( self.delays[ self.delays.last ], nd ) end + nd.dpos = Queue.push( self.delays, nd ) recurse( ) + return + end -- detects blocks and combos by working from back until @@ -1896,11 +1906,10 @@ local Sync = ( function( ) log( 'Function', - 'invokeActions("', - self.config.name, - '",', - timestamp, - ')' + 'invokeActions( "', + self.config.name, '", ', + timestamp, + ' )' ) if self.processes:size( ) >= self.config.maxProcesses then @@ -1909,6 +1918,7 @@ local Sync = ( function( ) end for _, d in Queue.qpairs( self.delays ) do + -- if reached the global limit return if settings.maxProcesses and processCount >= settings.maxProcesses @@ -1927,12 +1937,14 @@ local Sync = ( function( ) end if d.status == 'wait' then + -- found a waiting delay if d.etype ~= 'Init' then self.config.action( self.inlet ) else self.config.init( InletFactory.d2e( d ) ) end + if self.processes:size( ) >= self.config.maxProcesses then -- no further processes return @@ -1980,8 +1992,11 @@ local Sync = ( function( ) -- Used as startup marker to call init asap. -- local function addInitDelay( self ) + local newd = Delay.new( 'Init', self, true, '' ) + newd.dpos = Queue.push( self.delays, newd ) + return newd end @@ -2113,7 +2128,7 @@ local Syncs = ( function( ) 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( ) @@ -2141,31 +2156,85 @@ local Syncs = ( function( ) end -- - -- Inheritly copies all non integer keys from - -- table copy source ( cs ) to - -- table copy destination ( cd ). + -- Helper function for inherit + -- defined below -- - -- 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 ) - -- 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 - if type( k ) ~= 'number' and cd[ k ] == nil then - cd[ k ] = v + if type( k ) ~= 'number' or cs._verbatim == true then + inheritKV( cd, k, v ) end end - -- first recurses into all integer keyed tables - for i, v in ipairs( cs ) do - if type( v ) == 'table' then - inherit( cd, v ) + -- + -- recursevely inherits all integer keyed tables + -- ( for non-verbatim tables ) + -- + 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 + + -- + -- 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 + -- -- Adds a new sync (directory-tree to observe). -- @@ -2175,7 +2244,7 @@ local Syncs = ( function( ) -- from integer keyed tables local uconfig = config config = { } - inherit( config, uconfig ) + inherit( config, uconfig, false ) -- Lets settings or commandline override delay values. if settings then @@ -2227,7 +2296,7 @@ local Syncs = ( function( ) 'Error', info.short_src, ':', info.currentline, - ': no actions specified, use e.g. "config = default.rsync".' + ': no actions specified.' ) terminate( -1 ) @@ -2391,14 +2460,21 @@ local Inotify = ( function( ) pathwds[ path ] = nil end - ----- + + -- -- Adds watches for a directory (optionally) including all subdirectories. -- -- @param path absolute path of directory to observe -- @param recurse true if recursing into subdirs -- local function addWatch(path) - log('Function','Inotify.addWatch(',path,')') + + log( + 'Function', + 'Inotify.addWatch( ', + path, + ' )' + ) if not Syncs.concerns(path) then log('Inotify', 'not concerning "',path,'"') @@ -3075,9 +3151,9 @@ local StatusFile = ( function( ) log( 'Function', - 'write(', - timestamp, - ')' + 'write( ', + timestamp, + ' )' ) -- takes care not write too often @@ -3313,20 +3389,25 @@ function runner.cycle( ) if lsyncdStatus == 'fade' then + if processCount > 0 then + log( 'Normal', 'waiting for ', processCount, ' more child processes.' ) + return true else + return false end end if lsyncdStatus ~= 'run' then + error( 'runner.cycle() called while not running!' ) end @@ -3340,17 +3421,19 @@ function runner.cycle( processCount < settings.maxProcesses then local start = Syncs.getRound( ) + local ir = start repeat + local s = Syncs.get( ir ) s:invokeActions( timestamp ) ir = ir + 1 if ir > Syncs.size( ) then + ir = 1 end - until ir == start Syncs.nextRound( ) @@ -3652,13 +3735,19 @@ end -- function runner.initialize( firstTime ) + -- -- creates settings if user didnt + -- settings = settings or {} + -- -- 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 if settings[ v ] then @@ -3714,23 +3803,23 @@ function runner.initialize( firstTime ) end if settings.nodaemon then - lsyncd.configure('nodaemon') + lsyncd.configure( 'nodaemon' ) end if settings.logfile then - lsyncd.configure('logfile', settings.logfile) + lsyncd.configure( 'logfile', settings.logfile ) end if settings.logident then - lsyncd.configure('logident', settings.logident) + lsyncd.configure( 'logident', settings.logident ) end if settings.logfacility then - lsyncd.configure('logfacility', settings.logfacility) + lsyncd.configure( 'logfacility', settings.logfacility ) end if settings.pidfile then - lsyncd.configure('pidfile', settings.pidfile) + lsyncd.configure( 'pidfile', settings.pidfile ) end -- @@ -3753,6 +3842,7 @@ function runner.initialize( firstTime ) -- from now on use logging as configured instead of stdout/err. lsyncdStatus = 'run'; + lsyncd.configure( 'running' ); local ufuncs = { @@ -3766,34 +3856,49 @@ function runner.initialize( firstTime ) -- translates layer 3 scripts for _, s in Syncs.iwalk() do + -- checks if any user functions is a layer 3 string. local config = s.config + for _, fn in ipairs(ufuncs) do + if type(config[fn]) == 'string' then + local ft = functionWriter.translate(config[fn]) config[fn] = assert(loadstring('return '..ft))() + end + end end -- runs through the Syncs created by users for _, s in Syncs.iwalk( ) do + if s.config.monitor == 'inotify' then + Inotify.addSync( s, s.source ) + elseif s.config.monitor == 'fsevents' then + Fsevents.addSync( s, s.source ) + else + error( 'sync ' .. s.config.name .. ' has no known event monitor interface.' ) + end -- if the sync has an init function, the init delay -- is stacked which causes the init function to be called. if s.config.init then + s:addInitDelay( ) + end end diff --git a/tests/exclude-rsync.lua b/tests/exclude-rsync.lua index 6fcdd27..4bf6bb2 100755 --- a/tests/exclude-rsync.lua +++ b/tests/exclude-rsync.lua @@ -73,7 +73,7 @@ end cwriteln("testing startup excludes"); writefiles(); cwriteln("starting Lsyncd"); -local pid = spawn("./lsyncd", cfgfile); +local pid = spawn("./lsyncd", cfgfile, '-log', 'all'); cwriteln("waiting for Lsyncd to start"); posix.sleep(3) cwriteln("testing excludes after startup");