diff --git a/CMakeLists.txt b/CMakeLists.txt index c85092f..151887a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ set( LSYNCD_SRC core/log.c core/observe.c core/pipe.c + core/mci.c core/mem.c core/signal.c core/time.c diff --git a/core/core.c b/core/core.c index b0dcee5..ea68513 100644 --- a/core/core.c +++ b/core/core.c @@ -1,8 +1,6 @@ /* | core.c from Lsyncd -- the Live (Mirror) Syncing Demon | -| -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ @@ -35,6 +33,7 @@ #include #include "log.h" +#include "mci.h" #include "mem.h" #include "util.h" #include "pipe.h" @@ -47,17 +46,6 @@ #include "inotify.h" #endif -/* -| The Lua part of Lsyncd -*/ -extern const char mantle_out[]; -extern size_t mantle_size; - -/* -| The Lua coded default sync implementations -*/ -extern const char default_out[]; -extern size_t default_size; /* | Makes sure there is one file system monitor. @@ -69,7 +57,7 @@ extern size_t default_size; /* | All monitors supported by this Lsyncd. */ -static char *monitors[] = { +char *monitors[] = { #ifdef WITH_INOTIFY "inotify", @@ -113,667 +101,13 @@ char * lsyncd_config_file = NULL; bool first_time = true; -/*:::::::::::::::::::. -:: Helper Routines -'::::::::::::::::::::*/ - - -/* -| Variable which address is used as -| the cores index in the lua registry to -| index the mantle-core-interface -| -| Its value is used to determined if the -| mantle has registered itself already. -*/ -static int mci = 0; - - -/* -| Dummy variable which address is used as -| the cores index n the lua registry to -| the lua runners error handler. -*/ -int callError; - - -/*:::::::::::::::::::::::::::::::. -:: Library calls for the mantle -'::::::::::::::::::::::::::::::::*/ - - -int l_stackdump( lua_State* L ); - - - -/* -| Executes a subprocess. Does not wait for it to return. -| -| Params on Lua stack: -| -| 1: Path to binary to call -| 2: List of string as arguments -| or "<" in which case the next argument is a string -| that will be piped on stdin. -| The arguments will follow that one. -| -| Returns (Lua stack) the pid on success, 0 on failure. -*/ -static int -l_exec( lua_State *L ) -{ - // the binary to call - const char *binary = luaL_checkstring(L, 1); - - // number of arguments - int argc = lua_gettop( L ) - 1; - - // the pid spawned - pid_t pid; - - // the arguments position in the lua arguments - int li = 1; - - // the pipe to text - char const * pipe_text = NULL; - - // the pipes length - size_t pipe_len = 0; - - // the arguments - char const ** argv; - - // pipe file descriptors - int pipefd[ 2 ]; - - int i; - - // expands tables - // and removes nils - for( i = 1; i <= lua_gettop( L ); i++ ) - { - if( lua_isnil( L, i ) ) - { - lua_remove( L, i ); - i--; - argc--; - continue; - } - - if( lua_istable( L, i ) ) - { - int tlen; - int it; - lua_checkstack( L, lua_gettop( L ) + lua_objlen( L, i ) + 1 ); - - // moves table to top of stack - lua_pushvalue( L, i ); - lua_remove( L, i ); - argc--; - tlen = lua_objlen( L, -1 ); - - for( it = 1; it <= tlen; it++ ) - { - lua_pushinteger( L, it ); - lua_gettable( L, -2 ); - lua_insert( L, i ); - i++; - argc++; - } - i--; - lua_pop( L, 1 ); - } - } - - // writes a log message (if needed). - if( check_logcat( "Exec" ) <= settings.log_level ) - { - lua_checkstack( L, lua_gettop( L ) + argc * 3 + 2 ); - lua_pushvalue( L, 1 ); - - for( i = 1; i <= argc; i++ ) - { - lua_pushstring( L, " [" ); - lua_pushvalue( L, i + 1 ); - lua_pushstring( L, "]" ); - } - - lua_concat( L, 3 * argc + 1 ); - - // replaces midfile 0 chars by linefeed - size_t len = 0; - const char * cs = lua_tolstring( L, -1, &len ); - char * s = s_calloc( len + 1, sizeof( char ) ); - - for( i = 0; i < len; i++ ) - { - s[ i ] = cs[ i ] ? cs[ i ] : '\n'; - } - - logstring0( LOG_DEBUG, "Exec", s ); - - free( s ); - - lua_pop( L, 1 ); - } - - if( argc >= 2 && !strcmp( luaL_checkstring( L, 2 ), "<" ) ) - { - // pipes something into stdin - if( !lua_isstring( L, 3 ) ) - { - logstring( "Error", "in spawn(), expected a string after pipe '<'" ); - - exit( -1 ); - } - - pipe_text = lua_tolstring( L, 3, &pipe_len ); - - if( strlen( pipe_text ) > 0 ) - { - pipe_create( pipefd ); - } - else - { - pipe_text = NULL; - } - - argc -= 2; - li += 2; - } - - // prepares the arguments - argv = s_calloc( argc + 2, sizeof( char * ) ); - - argv[ 0 ] = binary; - - for( i = 1; i <= argc; i++ ) - { - argv[i] = luaL_checkstring( L, i + li ); - } - - argv[ i ] = NULL; - - // the fork! - pid = fork( ); - - if( pid == 0 ) - { - // replaces stdin for pipes - if( pipe_text ) dup2( pipefd[ 0 ], STDIN_FILENO ); - - // if lsyncd runs as a daemon and has a logfile it will redirect - // stdout/stderr of child processes to the logfile. - if( settings.log_file ) - { - if( !freopen( settings.log_file, "a", stdout ) ) - { - printlogf( L, "Error", "cannot redirect stdout to '%s'.", settings.log_file ); - } - - if( !freopen( settings.log_file, "a", stderr ) ) - { - printlogf( L, "Error", "cannot redirect stderr to '%s'.", settings.log_file ); - } - } - - execv( binary, ( char ** ) argv ); - - // in a sane world execv does not return! - printlogf( L, "Error", "Failed executing [ %s ]!", binary ); - - exit( -1 ); - } - - if( pipe_text ) - { - // closes read-end of pipe, this is for child process only - close( pipefd[ 0 ] ); - - pipe_write( pipefd, pipe_text, pipe_len ); - } - - free( argv ); - lua_pushnumber( L, pid ); - - return 1; -} - - -/* -| Registers the mantle core interface with the core. -| -| Params on Lua stack: -| 1: The luacode mantle. -| -| Returns on Lua stack: -| nothing -*/ -static int -l_mci( lua_State *L ) -{ - if( mci ) - { - logstring( "Error", "Luacode interface already registered!" ); - exit( -1 ); - } - - mci = 1; - - lua_pushlightuserdata( L, (void *) &mci ); - - // switches the passed mantle interface as parameter and the key &mci - lua_insert( L, 1 ); - - // saves the table of the mci in the lua registry - lua_settable( L, LUA_REGISTRYINDEX ); - - // saves the error function extras - - lua_pushlightuserdata( L, (void *) &callError ); - lua_pushlightuserdata( L, (void *) &mci ); - lua_gettable( L, LUA_REGISTRYINDEX ); - lua_pushstring( L, "callError" ); - lua_gettable( L, -2 ); - lua_remove( L, -2 ); - lua_settable( L, LUA_REGISTRYINDEX ); - - if( lua_gettop( L ) ) - { - logstring( "Error", "internal, stack is dirty." ); - l_stackdump( L ); - exit( -1 ); - } -} - - -/* -| Converts a relative directory path to an absolute. -| -| Params on Lua stack: -| 1: a relative path to directory -| -| Returns on Lua stack: -| The absolute path of directory -*/ -static int -l_realdir( lua_State *L ) -{ - luaL_Buffer b; - const char *rdir = luaL_checkstring(L, 1); - char *adir = get_realpath(rdir); - - if( !adir ) - { - printlogf( - L, "Error", - "failure getting absolute path of [%s]", - rdir - ); - - return 0; - } - - { - // makes sure its a directory - struct stat st; - if( stat( adir, &st ) ) - { - printlogf( - L, "Error", - "cannot get absolute path of dir '%s': %s", - rdir, - strerror( errno ) - ); - - free( adir ); - - return 0; - } - - if( !S_ISDIR( st.st_mode ) ) - { - printlogf( - L, "Error", - "cannot get absolute path of dir '%s': is not a directory", - rdir - ); - - free( adir ); - - return 0; - } - } - - // returns absolute path with a concated '/' - luaL_buffinit( L, &b ); - luaL_addstring( &b, adir ); - luaL_addchar( &b, '/' ); - luaL_pushresult( &b ); - - free( adir ); - - return 1; -} - - -/* -| Dumps the Lua stack. -| For debugging purposes. -*/ -int -l_stackdump( lua_State * L ) -{ - int i; - int top = lua_gettop( L ); - - printlogf( L, "Debug", "total on stack %d", top ); - - for( i = 1; i <= top; i++ ) - { - int t = lua_type( L, i ); - - switch( t ) - { - case LUA_TSTRING: - - printlogf( - L, "Debug", - "%d string: '%s'", i, lua_tostring( L, i ) - ); - - break; - - case LUA_TBOOLEAN: - - printlogf( L, "Debug", - "%d boolean %s", i, lua_toboolean( L, i ) ? "true" : "false" - ); - - break; - - case LUA_TNUMBER: - - printlogf( L, "Debug", "%d number: %g", i, lua_tonumber( L, i ) ); - - break; - - default: - - printlogf( L, "Debug", "%d %s", i, lua_typename( L, t ) ); - - break; - } - } - - return 0; -} - -/* -| Reads the directories entries. -| -| Params on Lua stack: -| 1: absolute path to directory -| -| Returns on Lua stack: -| a table of directory names. -| names are keys -| values are boolean true on dirs. -*/ -static int -l_readdir( lua_State *L ) -{ - const char * dirname = luaL_checkstring( L, 1 ); - - DIR *d; - - d = opendir( dirname ); - - if( d == NULL ) - { - printlogf( L, "Error", "cannot open dir [%s].", dirname ); - - return 0; - } - - lua_newtable( L ); - - while( !hup && !term ) - { - struct dirent *de = readdir( d ); - bool isdir; - - // finished? - if( de == NULL ) break; - - // ignores . and .. - if( !strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." ) ) continue; - - if( de->d_type == DT_UNKNOWN ) - { - // must call stat on some systems :-/ - // ( e.g. ReiserFS ) - char *entry = s_malloc( strlen( dirname ) + strlen( de->d_name ) + 2 ); - - struct stat st; - - strcpy( entry, dirname ); - strcat( entry, "/" ); - strcat( entry, de->d_name ); - - lstat( entry, &st ); - - isdir = S_ISDIR( st.st_mode ); - - free( entry ); - } - else - { - // otherwise readdir can be trusted - isdir = de->d_type == DT_DIR; - } - - // adds this entry to the Lua table - lua_pushstring( L, de->d_name ); - lua_pushboolean( L, isdir ); - lua_settable( L, -3 ); - } - - closedir( d ); - - return 1; -} - - -/* -| Immediately terminates Lsyncd. -| -| Params on Lua stack: -| 1: exitcode of Lsyncd. -| -| Does not return. -| -*/ -int -l_terminate( lua_State *L ) -{ - int exitcode = luaL_checkinteger( L, 1 ); - - exit( exitcode ); - - return 0; -} - - -/* -| Configures core parameters. -| -| Params on Lua stack: -| 1: a string, configure option -| 2: depends on Param 1 -*/ -static int -l_configure( lua_State *L ) -{ - const char * command = luaL_checkstring( L, 1 ); - - if( !strcmp( command, "running" ) ) - { - // set by mantle after first initialize - // from this on log to configurated log end instead of - // stdout/stderr - first_time = false; - - if( !settings.log_file ) - { - settings.log_syslog = true; - - const char * log_ident = settings.log_ident ? settings.log_ident : "lsyncd"; - - openlog( log_ident, 0, settings.log_facility ); - } - - logstring( "Normal", "--- Startup ---" ); - - } - else if( !strcmp( command, "logfile" ) ) - { - const char * file = luaL_checkstring( L, 2 ); - - if( settings.log_file ) - { - free( settings.log_file ); - } - - settings.log_file = - s_strdup( file ); - } - else if( !strcmp( command, "logfacility" ) ) - { - if( lua_isstring( L, 2 ) ) - { - const char * fname = luaL_checkstring( L, 2 ); - - settings.log_facility = log_getFacility( L, fname ); - } - else if (lua_isnumber(L, 2)) - { - settings.log_facility = luaL_checknumber( L, 2 ); - } - else - { - printlogf( L, "Error", "Logging facility must be a number or string" ); - - exit( -1 ); - } - } - else if( !strcmp( command, "logident" ) ) - { - const char * ident = luaL_checkstring( L, 2 ); - - if( settings.log_ident ) free( settings.log_ident ); - - settings.log_ident = s_strdup( ident ); - } - else - { - printlogf( - L, "Error", - "Internal error, unknown parameter in l_configure( %s )", - command - ); - - exit( -1 ); - } - - return 0; -} - - -/* -| The Lsnycd's core library. -*/ -static const luaL_Reg corelib[] = -{ - { "configure", l_configure }, - { "exec", l_exec }, - { "log", l_log }, - { "mci", l_mci }, - { "now", l_now }, - { "nonobserve_fd", l_nonobserve_fd }, - { "observe_fd", l_observe_fd }, - { "readdir", l_readdir }, - { "realdir", l_realdir }, - { "stackdump", l_stackdump }, - { "terminate", l_terminate }, - { NULL, NULL } -}; - - -/* -| Registers the Lsyncd's core library. -*/ -void -register_core( lua_State *L ) -{ - lua_newtable( L ); - luaL_setfuncs( L, corelib, 0 ); - lua_setglobal( L, LSYNCD_CORE_LIBNAME ); - - register_jiffies( L ); - -#ifdef WITH_INOTIFY - - lua_getglobal( L, LSYNCD_CORE_LIBNAME ); - register_inotify( L ); - lua_setfield( L, -2, LSYNCD_INOTIFY_LIBNAME ); - lua_pop( L, 1 ); - -#endif - - if( lua_gettop( L ) ) - { - logstring( "Error", "internal, stack not empty in lsyncd_register( )" ); - exit( -1 ); - } -} - - -/*:::::::::::::::. -:: Lsyncd Core -'::::::::::::::::*/ - - -/* -| Pushes a function from the mantle on the stack. -| As well as the callError handler. -*/ -extern void -load_mci( - lua_State * L, - const char * name -) -{ - printlogf( L, "Call", "%s( )", name ); - - // pushes the error handler - lua_pushlightuserdata( L, (void *) &callError ); - lua_gettable( L, LUA_REGISTRYINDEX ); - - // pushes the function - lua_pushlightuserdata( L, (void *) &mci ); - lua_gettable( L, LUA_REGISTRYINDEX ); - lua_pushstring( L, name ); - lua_gettable( L, -2 ); - lua_remove( L, -2 ); -} - - /* | Normal operation happens in here. */ static void -masterloop(lua_State *L) +masterloop( + lua_State *L +) { while( true ) { @@ -1002,61 +336,8 @@ main1( int argc, char *argv[] ) printf( "kernels clocks_per_sec=%ld\n", clocks_per_sec ); } - // loads the lsyncd mantle - if( luaL_loadbuffer( L, mantle_out, mantle_size, "mantle" ) ) - { - printlogf( L, "Error", "loading mantle: %s", lua_tostring( L, -1 ) ); - exit( -1 ); - } - - // prepares the luacode executing the script - if( lua_pcall( L, 0, 0, 0 ) ) - { - printlogf( L, "Error", "preparing mantle: %s", lua_tostring( L, -1 ) ); - exit( -1 ); - } - - { - // asserts the Lsyncd's version matches - // double checks the if mantle version is the same as core version - const char *lversion; - - lua_getglobal( L, "lsyncd_version" ); - lversion = luaL_checkstring( L, -1 ); - - if( strcmp( lversion, PACKAGE_VERSION ) ) - { - printlogf( - L, "Error", - "Version mismatch luacode is '%s', but core is '%s'", - lversion, PACKAGE_VERSION - ); - exit( -1 ); - } - - lua_pop( L, 1 ); - } - - // loads the default sync implementations - if( luaL_loadbuffer( L, default_out, default_size, "default" ) ) - { - printlogf( L, "Error", - "loading default sync implementations: %s", lua_tostring( L, -1 ) ); - exit( -1 ); - } - - // loads the user enivornment - // the default sync implementations are actually not priviledged in any way - lua_getglobal( L, "userENV" ); - lua_setupvalue( L, -2, 1 ); - - // prepares the default sync implementations - if( lua_pcall( L, 0, 0, 0 ) ) - { - printlogf( L, "Error", - "preparing default sync implementations: %s", lua_tostring( L, -1 ) ); - exit( -1 ); - } + mci_load_mantle( L ); + mci_load_default( L ); // checks if there is a "-help" or "--help" { diff --git a/core/inotify.c b/core/inotify.c index f8694dd..9335c47 100644 --- a/core/inotify.c +++ b/core/inotify.c @@ -1,10 +1,8 @@ /* | inotify.c from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Event interface for Lsyncd to Linux´ inotify. | -| | License: GPLv2 (see COPYING) or any later version | | Authors: Axel Kittenberger diff --git a/core/inotify.h b/core/inotify.h index 9ea53d5..8c7bbb0 100644 --- a/core/inotify.h +++ b/core/inotify.h @@ -1,12 +1,11 @@ /* | inotify.h from Lsyncd -- the Live (Mirror) Syncing Demon | -| +| Event interface for Lsyncd to Linux´ inotify. | | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ - #ifndef LSYNCD_INOTIFY_H #define LSYNCD_INOTIFY_H diff --git a/core/log.c b/core/log.c index 04f4e4b..b412c2a 100644 --- a/core/log.c +++ b/core/log.c @@ -1,10 +1,8 @@ /* | log.c from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Logging. | -| | This code assumes you have a 100 character wide display to view it (when tabstop is 4) | | License: GPLv2 (see COPYING) or any later version diff --git a/core/log.h b/core/log.h index e909af2..af37afd 100644 --- a/core/log.h +++ b/core/log.h @@ -1,10 +1,8 @@ /* | log.h from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Logging. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/mci.c b/core/mci.c new file mode 100644 index 0000000..ef62671 --- /dev/null +++ b/core/mci.c @@ -0,0 +1,788 @@ +/* +| mci.c from Lsyncd -- the Live (Mirror) Syncing Demon +| +| The (generic) C part of the inteface between mantle and core. +| +| Note that some mci functions are provided directly +| in their respective core subsystems +| +| License: GPLv2 (see COPYING) or any later version +| Authors: Axel Kittenberger +*/ + +#include "lsyncd.h" + +#include +#include +#include +#include +#include // FIXME abstract this away +#include // FIXME abstract this away +#include +#include + +#define LUA_USE_APICHECK 1 +#include +#include +#include +#include + +#include "log.h" +#include "mci.h" +#include "mem.h" +#include "observe.h" +#include "pipe.h" +#include "signal.h" +#include "time.h" +#include "userobs.h" +#include "util.h" + +#ifdef WITH_INOTIFY +# include "inotify.h" +#endif + +/* +| The Lua part of Lsyncd +*/ +extern const char mantle_out[]; +extern size_t mantle_size; + +/* +| The Lua coded default sync implementations +*/ +extern const char default_out[]; +extern size_t default_size; + + +/* +| True only on first time. +| FIXME do away. +*/ +extern bool first_time; + +/* +| Makes sure there is one file system monitor. +*/ +#ifndef WITH_INOTIFY +# error "needing at least one notification system. please rerun cmake" +#endif + +/* +| All monitors supported by this Lsyncd. +*/ +extern char *monitors[]; + + +/* +| Variable which address is used as +| the cores index in the lua registry to +| index the mantle-core-interface +| +| Its value is used to determined if the +| mantle has registered itself already. +*/ +static int mci = 0; + + +/* +| Dummy variable which address is used as +| the cores index n the lua registry to +| the lua runners error handler. +*/ +int callError; + + +/* +| Executes a subprocess. Does not wait for it to return. +| +| Params on Lua stack: +| +| 1: Path to binary to call +| 2: List of string as arguments +| or "<" in which case the next argument is a string +| that will be piped on stdin. +| The arguments will follow that one. +| +| Returns (Lua stack) the pid on success, 0 on failure. +*/ +static int +l_exec( lua_State *L ) +{ + // the binary to call + const char *binary = luaL_checkstring(L, 1); + + // number of arguments + int argc = lua_gettop( L ) - 1; + + // the pid spawned + pid_t pid; + + // the arguments position in the lua arguments + int li = 1; + + // the pipe to text + char const * pipe_text = NULL; + + // the pipes length + size_t pipe_len = 0; + + // the arguments + char const ** argv; + + // pipe file descriptors + int pipefd[ 2 ]; + + int i; + + // expands tables + // and removes nils + for( i = 1; i <= lua_gettop( L ); i++ ) + { + if( lua_isnil( L, i ) ) + { + lua_remove( L, i ); + i--; + argc--; + continue; + } + + if( lua_istable( L, i ) ) + { + int tlen; + int it; + lua_checkstack( L, lua_gettop( L ) + lua_objlen( L, i ) + 1 ); + + // moves table to top of stack + lua_pushvalue( L, i ); + lua_remove( L, i ); + argc--; + tlen = lua_objlen( L, -1 ); + + for( it = 1; it <= tlen; it++ ) + { + lua_pushinteger( L, it ); + lua_gettable( L, -2 ); + lua_insert( L, i ); + i++; + argc++; + } + i--; + lua_pop( L, 1 ); + } + } + + // writes a log message (if needed). + if( check_logcat( "Exec" ) <= settings.log_level ) + { + lua_checkstack( L, lua_gettop( L ) + argc * 3 + 2 ); + lua_pushvalue( L, 1 ); + + for( i = 1; i <= argc; i++ ) + { + lua_pushstring( L, " [" ); + lua_pushvalue( L, i + 1 ); + lua_pushstring( L, "]" ); + } + + lua_concat( L, 3 * argc + 1 ); + + // replaces midfile 0 chars by linefeed + size_t len = 0; + const char * cs = lua_tolstring( L, -1, &len ); + char * s = s_calloc( len + 1, sizeof( char ) ); + + for( i = 0; i < len; i++ ) + { + s[ i ] = cs[ i ] ? cs[ i ] : '\n'; + } + + logstring0( LOG_DEBUG, "Exec", s ); + + free( s ); + + lua_pop( L, 1 ); + } + + if( argc >= 2 && !strcmp( luaL_checkstring( L, 2 ), "<" ) ) + { + // pipes something into stdin + if( !lua_isstring( L, 3 ) ) + { + logstring( "Error", "in spawn(), expected a string after pipe '<'" ); + + exit( -1 ); + } + + pipe_text = lua_tolstring( L, 3, &pipe_len ); + + if( strlen( pipe_text ) > 0 ) + { + pipe_create( pipefd ); + } + else + { + pipe_text = NULL; + } + + argc -= 2; + li += 2; + } + + // prepares the arguments + argv = s_calloc( argc + 2, sizeof( char * ) ); + + argv[ 0 ] = binary; + + for( i = 1; i <= argc; i++ ) + { + argv[i] = luaL_checkstring( L, i + li ); + } + + argv[ i ] = NULL; + + // the fork! + pid = fork( ); + + if( pid == 0 ) + { + // replaces stdin for pipes + if( pipe_text ) dup2( pipefd[ 0 ], STDIN_FILENO ); + + // if lsyncd runs as a daemon and has a logfile it will redirect + // stdout/stderr of child processes to the logfile. + if( settings.log_file ) + { + if( !freopen( settings.log_file, "a", stdout ) ) + { + printlogf( L, "Error", "cannot redirect stdout to '%s'.", settings.log_file ); + } + + if( !freopen( settings.log_file, "a", stderr ) ) + { + printlogf( L, "Error", "cannot redirect stderr to '%s'.", settings.log_file ); + } + } + + execv( binary, ( char ** ) argv ); + + // in a sane world execv does not return! + printlogf( L, "Error", "Failed executing [ %s ]!", binary ); + + exit( -1 ); + } + + if( pipe_text ) + { + // closes read-end of pipe, this is for child process only + close( pipefd[ 0 ] ); + + pipe_write( pipefd, pipe_text, pipe_len ); + } + + free( argv ); + lua_pushnumber( L, pid ); + + return 1; +} + + +/* +| Registers the mantle core interface with the core. +| +| Params on Lua stack: +| 1: The luacode mantle. +| +| Returns on Lua stack: +| nothing +*/ +static int +l_mci( lua_State *L ) +{ + if( mci ) + { + logstring( "Error", "Luacode interface already registered!" ); + exit( -1 ); + } + + mci = 1; + + lua_pushlightuserdata( L, (void *) &mci ); + + // switches the passed mantle interface as parameter and the key &mci + lua_insert( L, 1 ); + + // saves the table of the mci in the lua registry + lua_settable( L, LUA_REGISTRYINDEX ); + + // saves the error function extras + + lua_pushlightuserdata( L, (void *) &callError ); + lua_pushlightuserdata( L, (void *) &mci ); + lua_gettable( L, LUA_REGISTRYINDEX ); + lua_pushstring( L, "callError" ); + lua_gettable( L, -2 ); + lua_remove( L, -2 ); + lua_settable( L, LUA_REGISTRYINDEX ); + + if( lua_gettop( L ) ) + { + logstring( "Error", "internal, stack is dirty." ); + l_stackdump( L ); + exit( -1 ); + } +} + + +/* +| Converts a relative directory path to an absolute. +| +| Params on Lua stack: +| 1: a relative path to directory +| +| Returns on Lua stack: +| The absolute path of directory +*/ +static int +l_realdir( lua_State *L ) +{ + luaL_Buffer b; + const char *rdir = luaL_checkstring(L, 1); + char *adir = get_realpath(rdir); + + if( !adir ) + { + printlogf( + L, "Error", + "failure getting absolute path of [%s]", + rdir + ); + + return 0; + } + + { + // makes sure its a directory + struct stat st; + if( stat( adir, &st ) ) + { + printlogf( + L, "Error", + "cannot get absolute path of dir '%s': %s", + rdir, + strerror( errno ) + ); + + free( adir ); + + return 0; + } + + if( !S_ISDIR( st.st_mode ) ) + { + printlogf( + L, "Error", + "cannot get absolute path of dir '%s': is not a directory", + rdir + ); + + free( adir ); + + return 0; + } + } + + // returns absolute path with a concated '/' + luaL_buffinit( L, &b ); + luaL_addstring( &b, adir ); + luaL_addchar( &b, '/' ); + luaL_pushresult( &b ); + + free( adir ); + + return 1; +} + + +/* +| Dumps the Lua stack. +| For debugging purposes. +*/ +int +l_stackdump( lua_State * L ) +{ + int i; + int top = lua_gettop( L ); + + printlogf( L, "Debug", "total on stack %d", top ); + + for( i = 1; i <= top; i++ ) + { + int t = lua_type( L, i ); + + switch( t ) + { + case LUA_TSTRING: + + printlogf( + L, "Debug", + "%d string: '%s'", i, lua_tostring( L, i ) + ); + + break; + + case LUA_TBOOLEAN: + + printlogf( L, "Debug", + "%d boolean %s", i, lua_toboolean( L, i ) ? "true" : "false" + ); + + break; + + case LUA_TNUMBER: + + printlogf( L, "Debug", "%d number: %g", i, lua_tonumber( L, i ) ); + + break; + + default: + + printlogf( L, "Debug", "%d %s", i, lua_typename( L, t ) ); + + break; + } + } + + return 0; +} + +/* +| Reads the directories entries. +| +| Params on Lua stack: +| 1: absolute path to directory +| +| Returns on Lua stack: +| a table of directory names. +| names are keys +| values are boolean true on dirs. +*/ +static int +l_readdir( lua_State *L ) +{ + const char * dirname = luaL_checkstring( L, 1 ); + + DIR *d; + + d = opendir( dirname ); + + if( d == NULL ) + { + printlogf( L, "Error", "cannot open dir [%s].", dirname ); + + return 0; + } + + lua_newtable( L ); + + while( !hup && !term ) + { + struct dirent *de = readdir( d ); + bool isdir; + + // finished? + if( de == NULL ) break; + + // ignores . and .. + if( !strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." ) ) continue; + + if( de->d_type == DT_UNKNOWN ) + { + // must call stat on some systems :-/ + // ( e.g. ReiserFS ) + char *entry = s_malloc( strlen( dirname ) + strlen( de->d_name ) + 2 ); + + struct stat st; + + strcpy( entry, dirname ); + strcat( entry, "/" ); + strcat( entry, de->d_name ); + + lstat( entry, &st ); + + isdir = S_ISDIR( st.st_mode ); + + free( entry ); + } + else + { + // otherwise readdir can be trusted + isdir = de->d_type == DT_DIR; + } + + // adds this entry to the Lua table + lua_pushstring( L, de->d_name ); + lua_pushboolean( L, isdir ); + lua_settable( L, -3 ); + } + + closedir( d ); + + return 1; +} + + +/* +| Immediately terminates Lsyncd. +| +| Params on Lua stack: +| 1: exitcode of Lsyncd. +| +| Does not return. +| +*/ +int +l_terminate( lua_State *L ) +{ + int exitcode = luaL_checkinteger( L, 1 ); + + exit( exitcode ); + + return 0; +} + + +/* +| Configures core parameters. +| +| Params on Lua stack: +| 1: a string, configure option +| 2: depends on Param 1 +*/ +static int +l_configure( lua_State *L ) +{ + const char * command = luaL_checkstring( L, 1 ); + + if( !strcmp( command, "running" ) ) + { + // set by mantle after first initialize + // from this on log to configurated log end instead of + // stdout/stderr + first_time = false; + + if( !settings.log_file ) + { + settings.log_syslog = true; + + const char * log_ident = settings.log_ident ? settings.log_ident : "lsyncd"; + + openlog( log_ident, 0, settings.log_facility ); + } + + logstring( "Normal", "--- Startup ---" ); + + } + else if( !strcmp( command, "logfile" ) ) + { + const char * file = luaL_checkstring( L, 2 ); + + if( settings.log_file ) + { + free( settings.log_file ); + } + + settings.log_file = + s_strdup( file ); + } + else if( !strcmp( command, "logfacility" ) ) + { + if( lua_isstring( L, 2 ) ) + { + const char * fname = luaL_checkstring( L, 2 ); + + settings.log_facility = log_getFacility( L, fname ); + } + else if (lua_isnumber(L, 2)) + { + settings.log_facility = luaL_checknumber( L, 2 ); + } + else + { + printlogf( L, "Error", "Logging facility must be a number or string" ); + + exit( -1 ); + } + } + else if( !strcmp( command, "logident" ) ) + { + const char * ident = luaL_checkstring( L, 2 ); + + if( settings.log_ident ) free( settings.log_ident ); + + settings.log_ident = s_strdup( ident ); + } + else + { + printlogf( + L, "Error", + "Internal error, unknown parameter in l_configure( %s )", + command + ); + + exit( -1 ); + } + + return 0; +} + + +/* +| The Lsnycd's core library. +*/ +static const luaL_Reg corelib[] = +{ + { "configure", l_configure }, + { "exec", l_exec }, + { "log", l_log }, + { "mci", l_mci }, + { "now", l_now }, + { "nonobserve_fd", l_nonobserve_fd }, + { "observe_fd", l_observe_fd }, + { "readdir", l_readdir }, + { "realdir", l_realdir }, + { "stackdump", l_stackdump }, + { "terminate", l_terminate }, + { NULL, NULL } +}; + + +/* +| Registers the Lsyncd's core library. +*/ +void +register_core( lua_State *L ) +{ + lua_newtable( L ); + luaL_setfuncs( L, corelib, 0 ); + lua_setglobal( L, LSYNCD_CORE_LIBNAME ); + + register_jiffies( L ); + +#ifdef WITH_INOTIFY + + lua_getglobal( L, LSYNCD_CORE_LIBNAME ); + register_inotify( L ); + lua_setfield( L, -2, LSYNCD_INOTIFY_LIBNAME ); + lua_pop( L, 1 ); + +#endif + + if( lua_gettop( L ) ) + { + logstring( "Error", "internal, stack not empty in lsyncd_register( )" ); + exit( -1 ); + } +} + + +/* +| Pushes a function from the mantle on the stack. +| As well as the callError handler. +| FIXME rename +*/ +void +load_mci( + lua_State * L, + const char * name +) +{ + printlogf( L, "Call", "%s( )", name ); + + // pushes the error handler + lua_pushlightuserdata( L, (void *) &callError ); + lua_gettable( L, LUA_REGISTRYINDEX ); + + // pushes the function + lua_pushlightuserdata( L, (void *) &mci ); + lua_gettable( L, LUA_REGISTRYINDEX ); + lua_pushstring( L, name ); + lua_gettable( L, -2 ); + lua_remove( L, -2 ); +} + + +/* +| Loads the mantle. +*/ +void +mci_load_mantle( + lua_State * L +) +{ + // loads the lsyncd mantle + if( luaL_loadbuffer( L, mantle_out, mantle_size, "mantle" ) ) + { + printlogf( L, "Error", "loading mantle: %s", lua_tostring( L, -1 ) ); + exit( -1 ); + } + + // prepares the luacode executing the script + if( lua_pcall( L, 0, 0, 0 ) ) + { + printlogf( L, "Error", "preparing mantle: %s", lua_tostring( L, -1 ) ); + exit( -1 ); + } + + { + // asserts the Lsyncd's version matches + // double checks the if mantle version is the same as core version + const char *lversion; + + lua_getglobal( L, "lsyncd_version" ); + lversion = luaL_checkstring( L, -1 ); + + if( strcmp( lversion, PACKAGE_VERSION ) ) + { + printlogf( + L, "Error", + "Version mismatch luacode is '%s', but core is '%s'", + lversion, PACKAGE_VERSION + ); + exit( -1 ); + } + + lua_pop( L, 1 ); + } +} + + +/* +| Loads the default implementations. +*/ +void +mci_load_default( + lua_State * L +) +{ + // loads the default sync implementations + if( luaL_loadbuffer( L, default_out, default_size, "default" ) ) + { + printlogf( L, "Error", + "loading default sync implementations: %s", lua_tostring( L, -1 ) ); + exit( -1 ); + } + + // loads the user enivornment + // the default sync implementations are actually not priviledged in any way + lua_getglobal( L, "userENV" ); + lua_setupvalue( L, -2, 1 ); + + // prepares the default sync implementations + if( lua_pcall( L, 0, 0, 0 ) ) + { + printlogf( L, "Error", + "preparing default sync implementations: %s", lua_tostring( L, -1 ) ); + exit( -1 ); + } +} + diff --git a/core/mci.h b/core/mci.h new file mode 100644 index 0000000..7196fc8 --- /dev/null +++ b/core/mci.h @@ -0,0 +1,22 @@ +/* +| mci.h from Lsyncd -- the Live (Mirror) Syncing Demon +| +| The (generic) C part of the inteface between mantle and core. +| +| License: GPLv2 (see COPYING) or any later version +| Authors: Axel Kittenberger +*/ +#ifndef LSYNCD_MCI_H +#define LSYNCD_MCI_H + +// FIXME doc + +int l_stackdump( lua_State* L ); + +void register_core( lua_State *L ); + +void mci_load_mantle( lua_State *L ); + +void mci_load_default( lua_State *L ); + +#endif diff --git a/core/mem.c b/core/mem.c index f80615a..e43ac8a 100644 --- a/core/mem.c +++ b/core/mem.c @@ -1,7 +1,6 @@ /* | mem.c from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Simple "secured" memory management. | | In future it might be an idea to call the lua garbage collecter in case memory allocation @@ -9,7 +8,6 @@ | when requesting a way too large memory block the system can ever handle, if the kernel | runs out of memory it goes instead into oom-killer mode. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/mem.h b/core/mem.h index 6d50422..9fa66a6 100644 --- a/core/mem.h +++ b/core/mem.h @@ -1,10 +1,8 @@ /* | mem.h from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Simple "secured" memory management. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/observe.c b/core/observe.c index 102e379..b8c20e2 100644 --- a/core/observe.c +++ b/core/observe.c @@ -1,10 +1,8 @@ /* | observe.c from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Handles observing file descriptors and the big select. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/observe.h b/core/observe.h index 36538fa..8888c53 100644 --- a/core/observe.h +++ b/core/observe.h @@ -1,10 +1,8 @@ /* | observe.h from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Handles observing file descriptors and the big select. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/pipe.c b/core/pipe.c index d4e14f2..4f6fb24 100644 --- a/core/pipe.c +++ b/core/pipe.c @@ -1,10 +1,8 @@ /* | pipe.c from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Manages the pipes used to communicate with spawned subprocesses (usually rsync). | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/pipe.h b/core/pipe.h index 8b9fd49..d90d0a0 100644 --- a/core/pipe.h +++ b/core/pipe.h @@ -1,10 +1,8 @@ /* | pipe.h from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Manages the pipes used to communicate with spawned subprocesses (usually rsync). | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/signal.c b/core/signal.c index ac31ca0..c9fc52b 100644 --- a/core/signal.c +++ b/core/signal.c @@ -1,10 +1,8 @@ /* | singal.c from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Signal handling. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/signal.h b/core/signal.h index 0faa872..d9e00d0 100644 --- a/core/signal.h +++ b/core/signal.h @@ -1,10 +1,8 @@ /* | signal.h from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Logging. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/time.c b/core/time.c index b7db597..e976e4c 100644 --- a/core/time.c +++ b/core/time.c @@ -1,13 +1,11 @@ /* | time.c from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Keeps time for Lsyncd, | | Provides a "jiffies" userdata for Lua which can be used | to track time, based on kernel jiffies. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/time.h b/core/time.h index 17ff047..0eb16f6 100644 --- a/core/time.h +++ b/core/time.h @@ -1,10 +1,8 @@ /* | time.h from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Time keeping. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/userobs.c b/core/userobs.c index 4dac64e..7898064 100644 --- a/core/userobs.c +++ b/core/userobs.c @@ -1,13 +1,11 @@ /* | userobs.c from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Allows user Lua scripts to observe file descriptors. | | They have to be opened by some other utility tough, | for example lua-posix. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/userobs.h b/core/userobs.h index eba38d7..db64b6d 100644 --- a/core/userobs.h +++ b/core/userobs.h @@ -1,13 +1,11 @@ /* | userobs.h from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Allows user Lua scripts to observe file descriptors. | | They have to be opened by some other utility tough, | for example lua-posix. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/util.c b/core/util.c index cc09ba8..48070eb 100644 --- a/core/util.c +++ b/core/util.c @@ -1,10 +1,8 @@ /* | util.c from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Small commonly used utils by Lsyncd. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */ diff --git a/core/util.h b/core/util.h index 4597135..415f767 100644 --- a/core/util.h +++ b/core/util.h @@ -1,10 +1,8 @@ /* | util.h from Lsyncd -- the Live (Mirror) Syncing Demon | -| | Small commonly used utils by Lsyncd. | -| | License: GPLv2 (see COPYING) or any later version | Authors: Axel Kittenberger */