allowing multiple config files, allowing stdin as config, allowing commandline commands as configs

This commit is contained in:
Axel Kittenberger 2018-06-20 08:39:16 +02:00
parent 4d9f3d9f7e
commit d0c6770b7c
9 changed files with 226 additions and 164 deletions

View File

@ -24,6 +24,7 @@ set( LSYNCD_SRC
core/mci.c
core/mem.c
core/signal.c
core/stdin.c
core/time.c
core/userobs.c
core/util.c

View File

@ -1,13 +1,21 @@
????-??-??: 3.0.0
change: switched to systemd-style daemon (that is Lsyncd will no longer fork itself)
change: dropping /dev/fsevents hack (OSX support)
change: dropping exclude and excludeFrom (replaced by filter and filterFrom)
change: "insist" by default
change: removed _extra (if someone is hacky enough to really need it,
they can hack Lsyncd itself)
change: user scripts run in their own global lua environment
change: removed _merge
change: moved the default layer 1 functions to default.proto
* switching to systemd-style daemon
this means Lsyncd will no longer fork itself
* heavily modularized source code
* dropping /dev/fsevents hack
this means, no more OSX support, sorry
* "insist" by default and no longer an option
* remove the command line configs -rsync -rsyncssh and -direct
* allowing multiple config files in the command line
* allowing "-" to read config from stdin
* added "-c" for command line lua configs
* removed _extra
if someone is hacky enough to really need it, they can hack Lsyncd source themself
* added uses overloadable signal handling
* signal TERM is forwarded to (rsync) subprocesses
* user scripts run in their own lua environment
* removed _merge inheritance template
* moved the default layer 1 functions to default.proto
2018-03-09: 2.2.3
enhaencement: supporting includes with new filter and filterFrom options

View File

@ -8,27 +8,13 @@
*/
#include "feature.h"
// FIXME remove unneeded headers
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <syslog.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
#define LUA_USE_APICHECK 1
#include <lua.h>
@ -46,7 +32,7 @@
#include "userobs.h"
#ifdef WITH_INOTIFY
#include "inotify.h"
# include "inotify.h"
#endif
@ -95,12 +81,6 @@ struct settings settings = {
bool no_output = false;
/*
| The config file loaded by Lsyncd.
*/
char * lsyncd_config_file = NULL;
/*
| False after first time Lsyncd started up.
|
@ -376,69 +356,9 @@ main1( int argc, char *argv[] )
if( lua_pcall( L, 2, 1, -4 ) ) exit( -1 );
if( first_time )
{
// If not first time, simply retains the config file given
s = lua_tostring( L, -1 );
if( s ) lsyncd_config_file = s_strdup( s );
}
lua_pop( L, 2 );
}
// checks existence of the config file
if( lsyncd_config_file )
{
struct stat st;
// gets the absolute path to the config file
// so in case of HUPing the daemon, it finds it again
char * apath = get_realpath( lsyncd_config_file );
if( !apath )
{
printlogf( L, "Error", "Cannot find config file at '%s'.", lsyncd_config_file );
exit( -1 );
}
free( lsyncd_config_file );
lsyncd_config_file = apath;
if( stat( lsyncd_config_file, &st ) )
{
printlogf( L, "Error", "Cannot find config file at '%s'.", lsyncd_config_file );
exit( -1 );
}
// loads and executes the config file
if( luaL_loadfile( L, lsyncd_config_file ) )
{
printlogf(
L, "Error",
"error loading %s: %s", lsyncd_config_file, lua_tostring( L, -1 )
);
exit( -1 );
}
// loads the user enivornment
lua_getglobal( L, "userenv" );
lua_setupvalue( L, -2, 1 );
if( lua_pcall( L, 0, LUA_MULTRET, 0) )
{
printlogf(
L, "Error",
"error preparing %s: %s", lsyncd_config_file, lua_tostring( L, -1 )
);
exit( -1 );
}
}
// runs initializations from mantle
// it will set the configuration and add watches
{

View File

@ -33,6 +33,7 @@
#include "observe.h"
#include "pipe.h"
#include "signal.h"
#include "stdin.h"
#include "time.h"
#include "userobs.h"
#include "util.h"
@ -673,6 +674,7 @@ static const luaL_Reg corelib[ ] =
{ "realdir", l_realdir },
{ "softreset", l_softreset },
{ "stackdump", l_stackdump },
{ "stdin", l_stdin },
{ "terminate", l_terminate },
{ NULL, NULL }
};

102
core/stdin.c Normal file
View File

@ -0,0 +1,102 @@
/*
| stdin.c from Lsyncd -- the Live (Mirror) Syncing Demon
|
| Reads a config file from stdin and buffers it.
|
| On every run of Lsyncd a config file from stdin is
| read only once, in case of a HUP soft reset the buffered
| version is used.
|
| License: GPLv2 (see COPYING) or any later version
| Authors: Axel Kittenberger <axkibe@gmail.com>
*/
#include "feature.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#define LUA_USE_APICHECK 1
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "log.h"
#include "mem.h"
/*
| Stdin read buffer.
*/
static char * buf = NULL;
/*
| Size of stdin buffer.
*/
static size_t bsize = 0;
/*
| Bytes read from stdin
*/
static size_t bread = 0;
/*
| Reads a config file from stdin.
| Or returns an already read file.
*/
char const *
read_stdin(
lua_State *L
)
{
if( buf ) return buf;
bsize = 1024;
buf = s_malloc( bsize );
while( true )
{
bread += fread( buf + bread, 1, bsize - bread - 1, stdin );
if( ferror( stdin ) )
{
printlogf( L, "Error", "Failure reading stdin" );
exit( -1 );
}
if( feof( stdin ) ) break;
if( bsize - bread < 1024 ) buf = s_realloc( buf, bsize *= 2 );
}
buf[ bread ] = 0;
return buf;
}
/*
| Lua wrapper to read_stdin( ).
|
| Params on Lua stack:
| none
|
| Returns on Lua stack:
| the config file
*/
int
l_stdin(
lua_State *L
)
{
char const * b = read_stdin( L );
lua_pushstring( L, b );
return 1;
}

30
core/stdin.h Normal file
View File

@ -0,0 +1,30 @@
/*
| stdinh from Lsyncd -- the Live (Mirror) Syncing Demon
|
| Reads a config file from stdin and buffers it.
|
| On every run of Lsyncd a config file from stdin is
| read only once, in case of a HUP soft reset the buffered
| version is used.
|
| License: GPLv2 (see COPYING) or any later version
| Authors: Axel Kittenberger <axkibe@gmail.com>
*/
#ifndef LSYNCD_STDIN_H
#define LSYNCD_STDIN_H
/*
| Reads a config file from stdin.
| Or returns an already read file.
*/
extern char const * read_stdin( lua_State *L );
/*
| Lua wrapper to read_stdin( ).
*/
extern int l_stdin( lua_State *L );
#endif

View File

@ -115,17 +115,14 @@ proto.collect = function
return 'ok'
elseif rc == 'again'
then
if settings( 'insist' )
then
log(
'Normal',
'Retrying startup of ',
agent.source, ' -> ', agent.target,
': ', exitcode
)
log(
'Normal',
'Retrying startup of ',
agent.source, ' -> ', agent.target,
': ', exitcode
)
return 'again'
end
return 'again'
elseif rc == 'die'
then
log(

View File

@ -94,7 +94,6 @@ init =
local hup = getsignal( 'HUP' )
local int = getsignal( 'INT' )
local term = getsignal( 'TERM' )
local usr1 = getsignal( 'USR1' )
if hup ~= false
then
@ -103,7 +102,7 @@ init =
if int ~= false
then
int = makeSignalHandler( 'INT', 'INT', 'terminating', finishInt )
int = makeSignalHandler( 'INT', nil, 'terminating', finishInt )
end
if term ~= false
@ -111,11 +110,6 @@ init =
term = makeSignalHandler( 'TERM', 'TERM', 'terminating', finishTerm )
end
if usr1 ~= false
then
usr1 = makeSignalHandler( 'USR1', nil, 'terminating', finishTerm )
end
onsignal( 'HUP', hup, 'INT', int, 'TERM', term, 'USR1', usr1 )
onsignal( 'HUP', hup, 'INT', int, 'TERM', term )
end

View File

@ -222,14 +222,15 @@ function mci.help( )
[[
USAGE:
lsyncd [OPTIONS] [CONFIG-FILE]
lsyncd [OPTIONS] [CONFIG-FILE(S)]
OPTIONS:
-delay SECS Overrides default delay times
-c STRING Executes STRING as Lua config
-delay SECS Overrides default delay times
-help Shows this
-log all Logs everything (debug)
-log scarce Logs errors only
-log [Category] Turns on logging for a debug category
-log all Logs everything (debug)
-log scarce Logs errors only
-log CATEGORY Turns on logging for a debug category
-logfile FILE Writes log to FILE (DEFAULT: uses syslog)
-version Prints versions and exits
@ -253,11 +254,19 @@ end
-- terminates on invalid arguments.
--
function mci.configure(
args, -- arguments given by user
args, -- command line arguments
monitors -- list of monitors the core can do
)
Monitor.initialize( monitors )
-- confs is filled with
-- all config file
-- stdin read requests
-- inline configs
local confs = { }
local i = 1
--
-- a list of all valid options
--
@ -269,62 +278,41 @@ function mci.configure(
--
local options =
{
-- log is handled by core already.
c =
{ 1, function( string ) table.insert( confs, { command = string, n = i } ) end },
delay =
{
1,
function( secs )
clSettings.delay = secs + 0
end
},
{ 1, function( secs ) clSettings.delay = secs + 0 end },
log = { 1, nil },
-- log is handled by core already.
log =
{ 1, nil },
logfile =
{
1,
function( file )
clSettings.logfile = file
end
},
{ 1, function( file ) clSettings.logfile = file end },
version =
{
0,
function( )
io.stdout:write( 'Version: ', lsyncd_version, '\n' )
os.exit( 0 )
end
}
{ 0, function( ) io.stdout:write( 'Version: ', lsyncd_version, '\n' ) os.exit( 0 ) end }
}
-- non-opts is filled with all args that were no part dash options
local nonopts = { }
local i = 1
while i <= #args
do
local a = args[ i ]
if a:sub( 1, 1 ) ~= '-'
then
table.insert( nonopts, args[ i ] )
table.insert( confs, { file = args[ i ] } )
elseif a == '-'
then
table.insert( confs, { stdin = true } )
else
if a:sub( 1, 2 ) == '--'
then
a = a:sub( 3 )
else
a = a:sub( 2 )
end
if a:sub( 1, 2 ) == '--' then a = a:sub( 3 ) else a = a:sub( 2 ) end
local o = options[ a ]
if not o
then
log( 'Error', 'unknown option command line option ', args[ i ] )
log( 'Error', 'unknown command line option ', args[ i ] )
os.exit( -1 )
end
@ -346,33 +334,53 @@ function mci.configure(
o[ 2 ]( )
elseif o[ 1 ] == 1
then
o[ 2 ]( args[ i + 1] )
o[ 2 ]( args[ i + 1 ] )
elseif o[ 1 ] == 2
then
o[ 2 ]( args[ i + 1], args[ i + 2] )
o[ 2 ]( args[ i + 1 ], args[ i + 2 ] )
elseif o[ 1 ] == 3
then
o[ 2 ]( args[ i + 1], args[ i + 2], args[ i + 3] )
then
o[ 2 ]( args[ i + 1 ], args[ i + 2 ], args[ i + 3 ] )
end
end
i = i + o[1]
i = i + o[ 1 ]
end
i = i + 1
end
if #nonopts == 0
then
mci.help( args[ 0 ] )
elseif #nonopts == 1
then
return nonopts[ 1 ]
else
-- TODO make this possible
log( 'Error', 'There can only be one config file in the command line.' )
if #confs == 0 then mci.help( args[ 0 ] ) end
os.exit( -1 )
for _, conf in ipairs( confs )
do
local f, err, status
if conf.stdin
then
f, err = load( core.stdin( ), 'stdin', 't', userenv )
elseif conf.command
then
f, err = load( conf.command, 'arg: '..conf.n, 't', userenv )
else
f, err = loadfile( conf.file, 't', userenv )
end
if not f
then
log( 'Error', err )
os.exit( -1 )
end
status, err = pcall( f )
if not status
then
log( 'Error', err )
os.exit( -1 )
end
end
end