2012-02-15 19:10:50 +00:00
|
|
|
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2010-10-19 10:20:27 +00:00
|
|
|
-- lsyncd.lua Live (Mirror) Syncing Demon
|
|
|
|
--
|
2010-11-17 11:14:36 +00:00
|
|
|
-- This is the "runner" part of Lsyncd. It containts all its high-level logic.
|
|
|
|
-- It works closely together with the Lsyncd core in lsyncd.c. This means it
|
2010-10-19 10:20:27 +00:00
|
|
|
-- cannot be runned directly from the standard lua interpreter.
|
2012-02-15 19:10:50 +00:00
|
|
|
--
|
2012-10-03 15:37:49 +00:00
|
|
|
-- This code assumes your editor is at least 100 chars wide.
|
|
|
|
--
|
2012-02-15 19:10:50 +00:00
|
|
|
-- License: GPLv2 (see COPYING) or any later version
|
|
|
|
-- Authors: Axel Kittenberger <axkibe@gmail.com>
|
|
|
|
--
|
|
|
|
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2010-10-19 10:20:27 +00:00
|
|
|
-- A security measurement.
|
2012-10-02 05:53:13 +00:00
|
|
|
-- The core will exit if version ids mismatch.
|
2010-10-25 14:55:40 +00:00
|
|
|
--
|
2016-12-01 12:25:49 +00:00
|
|
|
if lsyncd_version
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
-- ensures the runner is not being loaded twice
|
2018-03-01 14:08:26 +00:00
|
|
|
lsyncd.log( 'Error', 'You cannot use the lsyncd runner as configuration file!' )
|
2012-10-03 15:37:49 +00:00
|
|
|
|
|
|
|
lsyncd.terminate( -1 )
|
2010-10-19 21:56:00 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2022-11-10 03:20:54 +00:00
|
|
|
---@diagnostic disable-next-line: lowercase-global
|
2022-10-28 13:12:41 +00:00
|
|
|
lsyncd_version = '2.3.1'
|
2010-10-18 17:09:59 +00:00
|
|
|
|
2022-06-07 19:28:18 +00:00
|
|
|
-- compatibility with 5.1
|
|
|
|
if table.unpack == nil then
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line deprecated
|
2022-06-07 19:28:18 +00:00
|
|
|
table.unpack = unpack
|
|
|
|
end
|
|
|
|
|
2022-11-10 03:20:54 +00:00
|
|
|
local _LUA_VERSION_MAJOR, _LUA_VERSION_MINOR = string.gmatch(
|
|
|
|
_VERSION, "%w (%d).(%d)")()
|
|
|
|
---@type any
|
2022-06-07 19:28:18 +00:00
|
|
|
_LUA_VERSION_MAJOR = tonumber(_LUA_VERSION_MAJOR)
|
|
|
|
_LUA_VERSION_MINOR = tonumber(_LUA_VERSION_MINOR)
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2010-10-21 12:37:27 +00:00
|
|
|
-- Shortcuts (which user is supposed to be able to use them as well)
|
2010-10-22 12:58:57 +00:00
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
---@diagnostic disable: lowercase-global
|
2010-11-29 20:32:54 +00:00
|
|
|
log = lsyncd.log
|
2010-10-27 19:34:56 +00:00
|
|
|
terminate = lsyncd.terminate
|
2010-11-29 20:32:54 +00:00
|
|
|
now = lsyncd.now
|
2011-07-19 13:29:19 +00:00
|
|
|
readdir = lsyncd.readdir
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2022-11-10 03:20:54 +00:00
|
|
|
---@diagnostic enable: lowercase-global
|
2022-06-01 19:27:33 +00:00
|
|
|
--
|
|
|
|
-- Debug helper. Prints contents of `tbl`, with indentation.
|
|
|
|
-- `indent` sets the initial level of indentation.
|
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
---@diagnostic disable-next-line: lowercase-global
|
2022-06-01 19:27:33 +00:00
|
|
|
function dump(tbl, indent)
|
|
|
|
if not indent then indent = 0 end
|
|
|
|
for k, v in pairs(tbl) do
|
2022-11-09 21:41:04 +00:00
|
|
|
if type(k) ~= "string" then
|
|
|
|
k = tostring(k)
|
|
|
|
end
|
|
|
|
local formatting = string.rep(" ", indent) .. k .. ": "
|
2022-06-01 19:27:33 +00:00
|
|
|
if type(v) == "table" then
|
|
|
|
print(formatting)
|
2022-11-09 21:41:04 +00:00
|
|
|
if indent > 3 then
|
|
|
|
print("dump: Already 3 deep, skip")
|
|
|
|
else
|
|
|
|
dump(v, indent+1)
|
|
|
|
end
|
|
|
|
elseif type(v) ~= 'string' then
|
2022-06-01 19:27:33 +00:00
|
|
|
print(formatting .. tostring(v))
|
|
|
|
else
|
|
|
|
print(formatting .. v)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
lsyncd.dump = dump
|
|
|
|
|
2022-04-19 10:41:06 +00:00
|
|
|
local inherit = nil
|
|
|
|
local inheritKV = nil
|
|
|
|
local CountArray = nil
|
2022-06-03 00:45:53 +00:00
|
|
|
local functionWriter = nil
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-04-19 10:41:06 +00:00
|
|
|
--
|
2022-03-11 06:11:39 +00:00
|
|
|
--
|
|
|
|
-- Recurvely inherits a source table to a destionation table
|
|
|
|
-- copying all keys from source.
|
|
|
|
--
|
|
|
|
-- All entries with integer keys are inherited as additional
|
|
|
|
-- sources for non-verbatim tables
|
|
|
|
--
|
|
|
|
inherit = function
|
|
|
|
(
|
|
|
|
cd, -- table copy destination
|
|
|
|
cs, -- table copy source
|
|
|
|
verbatim, -- forced verbatim ( for e.g. 'exitcodes' )
|
|
|
|
ignored -- table of keys not to copy
|
|
|
|
)
|
|
|
|
-- 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(ignored) == 'table' and table.contains(ignored, k)
|
|
|
|
then
|
|
|
|
-- do nothing
|
|
|
|
-- print("ignore x", k)
|
|
|
|
elseif
|
|
|
|
(
|
|
|
|
type( k ) ~= 'number'
|
|
|
|
or verbatim
|
|
|
|
or cs._verbatim == true
|
|
|
|
)
|
|
|
|
and
|
|
|
|
(
|
|
|
|
type( cs ) ~= CountArray
|
|
|
|
and type( cs._merge ) ~= 'table'
|
|
|
|
or cs._merge[ k ] == true
|
|
|
|
)
|
|
|
|
then
|
|
|
|
inheritKV( cd, k, v )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- recursevely inherits all integer keyed tables
|
|
|
|
-- ( for non-verbatim tables )
|
|
|
|
if cs._verbatim ~= true
|
|
|
|
then
|
|
|
|
for k, v in ipairs( cs )
|
|
|
|
do
|
|
|
|
if type( v ) == 'table'
|
|
|
|
then
|
|
|
|
inherit( cd, v )
|
|
|
|
else
|
|
|
|
cd[ #cd + 1 ] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
table.contains = function
|
|
|
|
(
|
|
|
|
t, -- array to search in. Only the numeric values are tested
|
|
|
|
needle -- value to search for
|
|
|
|
)
|
|
|
|
for _, v in ipairs(t) do
|
|
|
|
if needle == v then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
-- lsyncd.inherit = inherit
|
|
|
|
-- print("inherit ")
|
|
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Helper to inherit. Inherits one key.
|
|
|
|
--
|
|
|
|
inheritKV =
|
|
|
|
function(
|
|
|
|
cd, -- table copy destination
|
|
|
|
k, -- key
|
|
|
|
v -- value
|
|
|
|
)
|
|
|
|
|
|
|
|
-- don't merge inheritance controls
|
|
|
|
if k == '_merge' or k == '_verbatim' then return end
|
|
|
|
|
|
|
|
local dtype = type( cd [ k ] )
|
|
|
|
|
|
|
|
if type( v ) == 'table'
|
|
|
|
then
|
|
|
|
if dtype == 'nil'
|
|
|
|
then
|
|
|
|
cd[ k ] = { }
|
|
|
|
inherit( cd[ k ], v, k == 'exitcodes' )
|
|
|
|
elseif
|
|
|
|
dtype == 'table' and
|
|
|
|
v._merge ~= false
|
|
|
|
then
|
|
|
|
inherit( cd[ k ], v, k == 'exitcodes' )
|
|
|
|
end
|
|
|
|
elseif dtype == 'nil'
|
|
|
|
then
|
|
|
|
cd[ k ] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-11-10 03:20:54 +00:00
|
|
|
local function alarm2string(a)
|
2022-03-30 21:02:03 +00:00
|
|
|
if type(a) == 'userdata' then
|
|
|
|
return a.string
|
|
|
|
end
|
|
|
|
return tostring( a )
|
|
|
|
end
|
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- Coping globals to ensure userscripts cannot change this.
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2010-11-29 20:32:54 +00:00
|
|
|
local log = log
|
|
|
|
local terminate = terminate
|
|
|
|
local now = now
|
2018-03-01 10:26:12 +00:00
|
|
|
local readdir = readdir
|
2022-03-11 06:11:39 +00:00
|
|
|
local inherit = inherit
|
|
|
|
local inheritKV = inheritKV
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- Predeclarations.
|
2010-11-28 10:47:57 +00:00
|
|
|
--
|
|
|
|
local Monitors
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- Global: total number of processess running.
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
local processCount = 0
|
|
|
|
|
2022-03-25 18:01:19 +00:00
|
|
|
local crontab = nil
|
|
|
|
|
|
|
|
local function loadCrontab()
|
2022-10-28 12:08:00 +00:00
|
|
|
local names = {"crontab.crontab", "crontab", "lua-crontab"}
|
|
|
|
for _,lname in ipairs(names) do
|
|
|
|
local ok, mod = pcall(require, lname)
|
|
|
|
if ok then
|
|
|
|
-- print update crontab
|
|
|
|
log('Debug', "Using crontab: "..lname)
|
|
|
|
crontab = mod
|
|
|
|
return true
|
|
|
|
end
|
2022-03-25 18:01:19 +00:00
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2016-12-01 12:25:49 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- All valid entries in a settings{} call.
|
2016-12-01 12:25:49 +00:00
|
|
|
--
|
|
|
|
local settingsCheckgauge =
|
|
|
|
{
|
|
|
|
logfile = true,
|
|
|
|
pidfile = true,
|
|
|
|
nodaemon = true,
|
2018-12-05 06:05:18 +00:00
|
|
|
onepass = true,
|
2016-12-01 12:25:49 +00:00
|
|
|
statusFile = true,
|
|
|
|
statusInterval = true,
|
|
|
|
logfacility = true,
|
|
|
|
logident = true,
|
2017-01-09 10:14:23 +00:00
|
|
|
insist = true,
|
2016-12-01 12:25:49 +00:00
|
|
|
inotifyMode = true,
|
|
|
|
maxProcesses = true,
|
|
|
|
maxDelays = true,
|
|
|
|
}
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-07 19:40:05 +00:00
|
|
|
--
|
|
|
|
-- Settings specified by command line.
|
|
|
|
--
|
|
|
|
local clSettings = { }
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-08 07:10:03 +00:00
|
|
|
--
|
|
|
|
-- Settings specified by config scripts.
|
|
|
|
--
|
|
|
|
local uSettings = { }
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-08 07:10:03 +00:00
|
|
|
--
|
|
|
|
-- A copy of the settings function to see if the
|
|
|
|
-- user script replaced the settings() by a table
|
|
|
|
-- ( pre Lsyncd 2.1 style )
|
|
|
|
--
|
|
|
|
local settingsSafe
|
2012-10-07 19:40:05 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
Implement batchSizeLimit for rsync based transfers
If the batchSizeLimit is set, only files lower then this limit will
be grouped in one rsync transfer.
Each file larger then this limit will spawn their own transfer process.
This will cause large files to no longer block small file transfers under the
circumstance the maxProcess limit on the sync is larger then 1
A very optimized, very secure transfer configuration based on a
pool of ssh connection looks like this:
```
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@targetmachine"},
mode = "pool",
parallel = 2,
},
source = "/tmp/src",
target = "rsync://localhost:${localport}/test",
delay = 5,
batchSizeLimit = 1024 * 1024 * 30,
maxProcesses = 4,
rsync = {
verbose = true,
inplace = true,
}
}
```
If you configure remote ssh configuration only allows portforwarding and your rsync daemon
is configured correctly, you can very securely transfer data without giving shell access.
2022-04-14 12:05:49 +00:00
|
|
|
-- Access to process counter
|
|
|
|
lsyncd.get_process_info = function()
|
|
|
|
return processCount, uSettings.maxProcesses
|
|
|
|
end
|
|
|
|
|
2010-10-25 17:38:57 +00:00
|
|
|
--============================================================================
|
2011-11-23 10:05:42 +00:00
|
|
|
-- Lsyncd Prototypes
|
2010-10-25 17:38:57 +00:00
|
|
|
--============================================================================
|
2010-10-25 14:55:40 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2010-10-25 14:55:40 +00:00
|
|
|
--
|
2012-10-02 05:53:13 +00:00
|
|
|
-- Array tables error if accessed with a non-number.
|
|
|
|
--
|
2018-03-01 10:26:12 +00:00
|
|
|
local Array = ( function
|
|
|
|
( )
|
2016-12-12 18:53:44 +00:00
|
|
|
--
|
|
|
|
-- Metatable.
|
|
|
|
--
|
2012-10-02 05:53:13 +00:00
|
|
|
local mt = { }
|
2010-11-02 13:18:34 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
--
|
|
|
|
-- On accessing a nil index.
|
|
|
|
--
|
|
|
|
mt.__index = function
|
|
|
|
(
|
|
|
|
t, -- table accessed
|
|
|
|
k -- key value accessed
|
|
|
|
)
|
2016-12-01 12:25:49 +00:00
|
|
|
if type(k) ~= 'number'
|
|
|
|
then
|
2012-10-02 05:53:13 +00:00
|
|
|
error( 'Key "'..k..'" invalid for Array', 2 )
|
2010-10-25 14:55:40 +00:00
|
|
|
end
|
2016-12-01 12:25:49 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
return rawget( t, k )
|
2010-11-02 13:18:34 +00:00
|
|
|
end
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
--
|
|
|
|
-- On assigning a new index.
|
|
|
|
--
|
|
|
|
mt.__newindex = function
|
|
|
|
(
|
|
|
|
t, -- table getting a new index assigned
|
|
|
|
k, -- key value to assign to
|
|
|
|
v -- value to assign
|
|
|
|
)
|
2016-12-01 12:25:49 +00:00
|
|
|
if type( k ) ~= 'number'
|
|
|
|
then
|
2012-10-02 05:53:13 +00:00
|
|
|
error( 'Key "'..k..'" invalid for Array', 2 )
|
2010-10-25 17:38:57 +00:00
|
|
|
end
|
2016-12-01 12:25:49 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
rawset( t, k, v )
|
2010-10-25 14:55:40 +00:00
|
|
|
end
|
2010-11-02 13:18:34 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
--
|
|
|
|
-- Creates a new object
|
|
|
|
--
|
|
|
|
local function new
|
|
|
|
( )
|
2012-10-02 05:53:13 +00:00
|
|
|
local o = { }
|
2016-12-01 12:25:49 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
setmetatable( o, mt )
|
2016-12-01 12:25:49 +00:00
|
|
|
|
2010-11-02 13:18:34 +00:00
|
|
|
return o
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
|
|
|
-- Public interface
|
|
|
|
--
|
2012-10-02 05:53:13 +00:00
|
|
|
return { new = new }
|
|
|
|
end )( )
|
2010-10-25 14:55:40 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Count array tables error if accessed with a non-number.
|
|
|
|
--
|
|
|
|
-- Additionally they maintain their length as 'size' attribute,
|
|
|
|
-- since Lua's # operator does not work on tables whose key values are not
|
2010-10-25 17:38:57 +00:00
|
|
|
-- strictly linear.
|
|
|
|
--
|
2022-04-19 10:41:06 +00:00
|
|
|
CountArray = ( function
|
2016-12-14 08:02:51 +00:00
|
|
|
( )
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2010-11-02 13:18:34 +00:00
|
|
|
-- Metatable
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
|
|
|
local mt = { }
|
2010-11-02 13:18:34 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
|
|
|
-- Key to native table
|
|
|
|
--
|
|
|
|
local k_nt = { }
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
|
|
|
-- On accessing a nil index.
|
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
mt.__index = function
|
|
|
|
(
|
|
|
|
t, -- table being accessed
|
|
|
|
k -- key used to access
|
|
|
|
)
|
2022-03-11 06:11:39 +00:00
|
|
|
if k == '_merge' or k == '_verbatim'
|
|
|
|
then
|
|
|
|
return nil
|
|
|
|
end
|
2016-12-01 12:25:49 +00:00
|
|
|
if type( k ) ~= 'number'
|
|
|
|
then
|
2016-12-12 18:53:44 +00:00
|
|
|
error( 'Key "' .. k .. '" invalid for CountArray', 2 )
|
2010-10-25 17:38:57 +00:00
|
|
|
end
|
2016-12-01 12:25:49 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
return t[ k_nt ][ k ]
|
2010-11-02 13:18:34 +00:00
|
|
|
end
|
2010-10-25 17:38:57 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
|
|
|
-- On assigning a new index.
|
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
mt.__newindex = function
|
|
|
|
(
|
|
|
|
t, -- table getting a new index assigned
|
|
|
|
k, -- key value to assign to
|
|
|
|
v -- value to assign
|
|
|
|
)
|
|
|
|
if type( k ) ~= 'number'
|
2016-12-01 12:25:49 +00:00
|
|
|
then
|
2012-10-02 05:53:13 +00:00
|
|
|
error( 'Key "'..k..'" invalid for CountArray', 2 )
|
2010-10-25 17:38:57 +00:00
|
|
|
end
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2010-11-02 13:18:34 +00:00
|
|
|
-- value before
|
2012-10-02 05:53:13 +00:00
|
|
|
local vb = t[ k_nt ][ k ]
|
2016-12-12 18:53:44 +00:00
|
|
|
|
|
|
|
if v and not vb
|
|
|
|
then
|
2010-11-03 11:37:25 +00:00
|
|
|
t._size = t._size + 1
|
2016-12-12 18:53:44 +00:00
|
|
|
elseif not v and vb
|
|
|
|
then
|
2010-11-03 11:37:25 +00:00
|
|
|
t._size = t._size - 1
|
2010-10-25 17:38:57 +00:00
|
|
|
end
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
t[ k_nt ][ k ] = v
|
2010-11-02 13:18:34 +00:00
|
|
|
end
|
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2010-11-09 19:15:41 +00:00
|
|
|
-- Walks through all entries in any order.
|
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
local function walk
|
|
|
|
(
|
|
|
|
self -- the count array
|
|
|
|
)
|
2012-10-02 05:53:13 +00:00
|
|
|
return pairs( self[ k_nt ] )
|
2010-11-02 13:18:34 +00:00
|
|
|
end
|
2010-11-03 11:37:25 +00:00
|
|
|
|
2010-11-09 19:15:41 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- Returns the count.
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
local function size
|
|
|
|
(
|
|
|
|
self -- the count array
|
|
|
|
)
|
2010-11-03 11:37:25 +00:00
|
|
|
return self._size
|
|
|
|
end
|
|
|
|
|
2010-11-09 19:15:41 +00:00
|
|
|
--
|
2012-10-02 05:53:13 +00:00
|
|
|
-- Creates a new count array
|
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
local function new
|
|
|
|
( )
|
|
|
|
-- k_nt is a native table, private to this object.
|
|
|
|
local o =
|
|
|
|
{
|
2012-10-02 05:53:13 +00:00
|
|
|
_size = 0,
|
|
|
|
walk = walk,
|
|
|
|
size = size,
|
2016-12-12 18:53:44 +00:00
|
|
|
[ k_nt ] = { }
|
2012-10-02 05:53:13 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 08:02:51 +00:00
|
|
|
setmetatable( o, mt )
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2010-11-02 13:18:34 +00:00
|
|
|
return o
|
2010-10-25 14:55:40 +00:00
|
|
|
end
|
2010-11-02 13:18:34 +00:00
|
|
|
|
2010-11-09 19:15:41 +00:00
|
|
|
--
|
2012-10-02 05:53:13 +00:00
|
|
|
-- Public interface
|
|
|
|
--
|
|
|
|
return { new = new }
|
|
|
|
end )( )
|
2010-10-25 14:55:40 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2011-11-23 10:05:42 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- A queue is optimized for pushing and poping.
|
|
|
|
-- TODO: make this an object
|
2010-12-11 19:31:26 +00:00
|
|
|
--
|
2016-12-14 15:29:33 +00:00
|
|
|
Queue = ( function
|
|
|
|
( )
|
|
|
|
--
|
|
|
|
-- Metatable
|
|
|
|
--
|
|
|
|
local mt = { }
|
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
|
|
|
|
--
|
2016-12-14 15:29:33 +00:00
|
|
|
-- Key to native table
|
2011-08-18 13:29:18 +00:00
|
|
|
--
|
2016-12-14 15:29:33 +00:00
|
|
|
local k_nt = { }
|
|
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
-- On accessing a nil index.
|
|
|
|
--
|
|
|
|
mt.__index = function
|
|
|
|
(
|
|
|
|
t, -- table being accessed
|
|
|
|
k -- key used to access
|
|
|
|
)
|
|
|
|
if type( k ) ~= 'number'
|
|
|
|
then
|
|
|
|
error( 'Key "' .. k .. '" invalid for Queue', 2 )
|
|
|
|
end
|
|
|
|
|
|
|
|
return t[ k_nt ][ k ]
|
2010-12-11 19:31:26 +00:00
|
|
|
end
|
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- On assigning a new index.
|
|
|
|
--
|
|
|
|
mt.__newindex = function
|
|
|
|
(
|
|
|
|
t, -- table getting a new index assigned
|
|
|
|
k, -- key value to assign to
|
|
|
|
v -- value to assign
|
|
|
|
)
|
|
|
|
error( 'Queues are not directly assignable.', 2 )
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Returns the first item of the Queue.
|
|
|
|
--
|
|
|
|
local function first
|
|
|
|
(
|
|
|
|
self
|
|
|
|
)
|
|
|
|
local nt = self[ k_nt ]
|
|
|
|
|
|
|
|
return nt[ nt.first ]
|
|
|
|
end
|
2018-02-27 09:09:28 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
--
|
|
|
|
-- Returns the last item of the Queue.
|
|
|
|
--
|
|
|
|
local function last
|
|
|
|
(
|
|
|
|
self
|
|
|
|
)
|
|
|
|
local nt = self[ k_nt ]
|
|
|
|
|
|
|
|
return nt[ nt.last ]
|
|
|
|
end
|
2018-02-27 09:09:28 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
--
|
|
|
|
-- Returns the size of the queue.
|
|
|
|
--
|
|
|
|
local function size
|
|
|
|
(
|
|
|
|
self
|
|
|
|
)
|
|
|
|
return self[ k_nt ].size
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2010-12-11 19:31:26 +00:00
|
|
|
-- Pushes a value on the queue.
|
|
|
|
-- Returns the last value
|
2011-08-18 13:29:18 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
local function push
|
|
|
|
(
|
2016-12-14 15:29:33 +00:00
|
|
|
self, -- queue to push to
|
2016-12-12 18:53:44 +00:00
|
|
|
value -- value to push
|
|
|
|
)
|
2016-12-01 12:25:49 +00:00
|
|
|
if not value
|
|
|
|
then
|
2016-12-14 15:29:33 +00:00
|
|
|
error( 'Queue pushing nil value', 2 )
|
2010-12-11 19:31:26 +00:00
|
|
|
end
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
local nt = self[ k_nt ]
|
|
|
|
|
|
|
|
local last = nt.last + 1
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
nt.last = last
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
nt[ last ] = value
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
nt.size = nt.size + 1
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2010-12-11 19:31:26 +00:00
|
|
|
return last
|
|
|
|
end
|
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
|
2010-12-11 19:31:26 +00:00
|
|
|
--
|
2012-10-02 05:53:13 +00:00
|
|
|
-- Removes an item at pos from the Queue.
|
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
local function remove
|
|
|
|
(
|
2016-12-14 15:29:33 +00:00
|
|
|
self, -- the queue
|
|
|
|
pos -- position to remove
|
2016-12-12 18:53:44 +00:00
|
|
|
)
|
2016-12-14 15:29:33 +00:00
|
|
|
local nt = self[ k_nt ]
|
|
|
|
|
|
|
|
if nt[ pos ] == nil
|
2016-12-12 18:53:44 +00:00
|
|
|
then
|
|
|
|
error( 'Removing nonexisting item in Queue', 2 )
|
2010-12-11 19:31:26 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
-- if removing first or last element,
|
|
|
|
-- the queue limits are adjusted.
|
2016-12-14 15:29:33 +00:00
|
|
|
if pos == nt.first
|
2016-12-12 18:53:44 +00:00
|
|
|
then
|
2022-11-09 14:22:58 +00:00
|
|
|
nt[ pos ] = nil
|
|
|
|
nt.first = pos + 1
|
2016-12-14 15:29:33 +00:00
|
|
|
elseif pos == nt.last
|
2016-12-12 18:53:44 +00:00
|
|
|
then
|
2022-11-09 14:22:58 +00:00
|
|
|
nt[ pos ] = nil
|
|
|
|
nt.last = nt.last - 1
|
|
|
|
else
|
2016-12-21 12:11:55 +00:00
|
|
|
local first = nt.first
|
2022-11-09 14:22:58 +00:00
|
|
|
local last = nt.first
|
2016-12-14 15:29:33 +00:00
|
|
|
|
2022-11-09 14:22:58 +00:00
|
|
|
local i = pos
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2022-11-09 14:22:58 +00:00
|
|
|
while i < last do
|
|
|
|
if i == pos then
|
|
|
|
nt[ i ] = nt[ i + 1 ]
|
|
|
|
i = i + 1
|
|
|
|
end
|
|
|
|
i = i + 1
|
|
|
|
end
|
|
|
|
nt.last = last - 1
|
2010-12-11 19:31:26 +00:00
|
|
|
end
|
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
-- reset the indizies if the queue is empty
|
2016-12-14 15:29:33 +00:00
|
|
|
if nt.last < nt.first
|
2016-12-12 18:53:44 +00:00
|
|
|
then
|
2016-12-14 15:29:33 +00:00
|
|
|
nt.first = 1
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
nt.last = 0
|
2010-12-11 19:31:26 +00:00
|
|
|
end
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
nt.size = nt.size - 1
|
2010-12-11 19:31:26 +00:00
|
|
|
end
|
|
|
|
|
2022-11-09 14:22:58 +00:00
|
|
|
--
|
|
|
|
-- Injects a value in front of the Queue.
|
|
|
|
--
|
|
|
|
local function inject
|
|
|
|
(
|
|
|
|
self, -- the queue
|
|
|
|
value -- position to remove
|
|
|
|
)
|
|
|
|
local nt = self[ k_nt ]
|
|
|
|
|
|
|
|
local pos = nt.last
|
|
|
|
while pos >= nt.first
|
|
|
|
do
|
|
|
|
nt[pos + 1] = nt[pos]
|
|
|
|
pos = pos - 1
|
|
|
|
end
|
|
|
|
|
|
|
|
nt[nt.first] = value
|
|
|
|
nt.size = nt.size + 1
|
|
|
|
nt.last = nt.last + 1
|
|
|
|
end
|
|
|
|
|
2016-12-21 12:11:55 +00:00
|
|
|
--
|
|
|
|
-- Replaces a value.
|
|
|
|
--
|
|
|
|
local function replace
|
|
|
|
(
|
|
|
|
self, -- the queue
|
|
|
|
pos, -- position to replace
|
|
|
|
value -- the new entry
|
|
|
|
)
|
|
|
|
local nt = self[ k_nt ]
|
|
|
|
|
|
|
|
if nt[ pos ] == nil
|
|
|
|
then
|
|
|
|
error( 'Trying to replace an unset Queue entry.' )
|
|
|
|
end
|
|
|
|
|
|
|
|
nt[ pos ] = value
|
|
|
|
end
|
2016-12-14 15:29:33 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- Queue iterator ( stateless )
|
2016-12-14 15:29:33 +00:00
|
|
|
-- TODO rename next
|
2011-08-18 13:29:18 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
local function iter
|
|
|
|
(
|
2016-12-14 15:29:33 +00:00
|
|
|
self, -- queue to iterate
|
|
|
|
pos -- current position
|
2016-12-12 18:53:44 +00:00
|
|
|
)
|
2016-12-14 15:29:33 +00:00
|
|
|
local nt = self[ k_nt ]
|
|
|
|
|
2010-12-11 19:31:26 +00:00
|
|
|
pos = pos + 1
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
while nt[ pos ] == nil and pos <= nt.last
|
2016-12-12 18:53:44 +00:00
|
|
|
do
|
2010-12-11 19:31:26 +00:00
|
|
|
pos = pos + 1
|
|
|
|
end
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
if pos > nt.last
|
2016-12-12 18:53:44 +00:00
|
|
|
then
|
2010-12-11 19:31:26 +00:00
|
|
|
return nil
|
|
|
|
end
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
return pos, nt[ pos ]
|
2010-12-11 19:31:26 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
|
2012-03-16 15:05:16 +00:00
|
|
|
--
|
2012-10-02 05:53:13 +00:00
|
|
|
-- Reverse queue iterator (stateless)
|
2016-12-14 15:29:33 +00:00
|
|
|
-- TODO rename prev
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
local function iterReverse
|
|
|
|
(
|
2016-12-14 15:29:33 +00:00
|
|
|
self, -- queue to iterate
|
|
|
|
pos -- current position
|
2016-12-12 18:53:44 +00:00
|
|
|
)
|
2016-12-14 15:29:33 +00:00
|
|
|
local nt = self[ k_nt ]
|
|
|
|
|
2010-12-11 20:00:48 +00:00
|
|
|
pos = pos - 1
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
while nt[ pos ] == nil and pos >= nt.first
|
2016-12-12 18:53:44 +00:00
|
|
|
do
|
2010-12-11 20:00:48 +00:00
|
|
|
pos = pos - 1
|
|
|
|
end
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
if pos < nt.first
|
2016-12-12 18:53:44 +00:00
|
|
|
then
|
2010-12-11 20:00:48 +00:00
|
|
|
return nil
|
|
|
|
end
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
return pos, nt[ pos ]
|
2010-12-11 20:00:48 +00:00
|
|
|
end
|
2010-12-11 19:31:26 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2010-12-11 19:31:26 +00:00
|
|
|
-- Iteraters through the queue
|
2012-10-02 05:53:13 +00:00
|
|
|
-- returning all non-nil pos-value entries.
|
2011-08-18 13:29:18 +00:00
|
|
|
--
|
2016-12-14 15:29:33 +00:00
|
|
|
local function qpairs
|
|
|
|
(
|
|
|
|
self
|
|
|
|
)
|
|
|
|
return iter, self, self[ k_nt ].first - 1
|
2010-12-11 19:31:26 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2010-12-11 20:00:48 +00:00
|
|
|
-- Iteraters backwards through the queue
|
2012-10-02 05:53:13 +00:00
|
|
|
-- returning all non-nil pos-value entries.
|
2011-08-18 13:29:18 +00:00
|
|
|
--
|
2016-12-14 15:29:33 +00:00
|
|
|
local function qpairsReverse
|
|
|
|
(
|
|
|
|
self
|
|
|
|
)
|
|
|
|
return iterReverse, self, self[ k_nt ].last + 1
|
2010-12-11 20:00:48 +00:00
|
|
|
end
|
2010-12-11 19:31:26 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
--
|
|
|
|
-- Creates a new queue.
|
|
|
|
--
|
|
|
|
local function new
|
|
|
|
( )
|
|
|
|
local q = {
|
|
|
|
first = first,
|
|
|
|
last = last,
|
|
|
|
push = push,
|
2022-11-09 14:22:58 +00:00
|
|
|
inject = inject,
|
2016-12-14 15:29:33 +00:00
|
|
|
qpairs = qpairs,
|
|
|
|
qpairsReverse = qpairsReverse,
|
|
|
|
remove = remove,
|
2016-12-21 12:11:55 +00:00
|
|
|
replace = replace,
|
2016-12-14 15:29:33 +00:00
|
|
|
size = size,
|
|
|
|
|
|
|
|
[ k_nt ] =
|
|
|
|
{
|
|
|
|
first = 1,
|
|
|
|
last = 0,
|
|
|
|
size = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setmetatable( q, mt )
|
|
|
|
|
|
|
|
return q
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Public interface
|
|
|
|
--
|
|
|
|
return { new = new }
|
2012-10-02 05:53:13 +00:00
|
|
|
end )( )
|
2010-12-11 19:31:26 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- Locks globals.
|
2010-11-01 16:38:39 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- No more globals can be created after this!
|
|
|
|
--
|
|
|
|
local function lockGlobals
|
|
|
|
( )
|
2010-11-01 16:38:39 +00:00
|
|
|
local t = _G
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
local mt = getmetatable( t ) or { }
|
|
|
|
|
|
|
|
-- TODO try to remove the underscore exceptions
|
2016-12-12 18:53:44 +00:00
|
|
|
mt.__index = function
|
|
|
|
(
|
|
|
|
t, -- table being accessed
|
|
|
|
k -- key used to access
|
|
|
|
)
|
|
|
|
if k ~= '_' and string.sub( k, 1, 2 ) ~= '__'
|
|
|
|
then
|
|
|
|
error( 'Access of non-existing global "' .. k ..'"', 2 )
|
2010-11-01 19:57:53 +00:00
|
|
|
else
|
2012-10-02 05:53:13 +00:00
|
|
|
rawget( t, k )
|
2010-11-01 19:57:53 +00:00
|
|
|
end
|
|
|
|
end
|
2012-10-02 05:53:13 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
mt.__newindex = function
|
|
|
|
(
|
|
|
|
t, -- table getting a new index assigned
|
|
|
|
k, -- key value to assign to
|
|
|
|
v -- value to assign
|
|
|
|
)
|
|
|
|
if k ~= '_' and string.sub( k, 1, 2 ) ~= '__'
|
|
|
|
then
|
|
|
|
error(
|
|
|
|
'Lsyncd does not allow GLOBALS to be created on the fly. '
|
|
|
|
.. 'Declare "' .. k.. '" local or declare global on load.',
|
|
|
|
2
|
|
|
|
)
|
2010-11-01 16:38:39 +00:00
|
|
|
else
|
2012-10-02 05:53:13 +00:00
|
|
|
rawset( t, k, v )
|
2010-11-01 16:38:39 +00:00
|
|
|
end
|
|
|
|
end
|
2012-10-02 05:53:13 +00:00
|
|
|
|
|
|
|
setmetatable( t, mt )
|
2010-10-31 22:25:34 +00:00
|
|
|
end
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2010-11-04 13:43:57 +00:00
|
|
|
--
|
2012-10-02 05:53:13 +00:00
|
|
|
-- Holds the information about a delayed event for one Sync.
|
|
|
|
--
|
2016-12-14 08:02:51 +00:00
|
|
|
-- Valid stati of an delay are:
|
|
|
|
-- 'wait' ... the event is ready to be handled.
|
|
|
|
-- 'active' ... there is process running catering for this event.
|
|
|
|
-- 'blocked' ... this event waits for another to be handled first.
|
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
local Delay = ( function
|
|
|
|
( )
|
2016-12-14 08:02:51 +00:00
|
|
|
--
|
|
|
|
-- Metatable.
|
|
|
|
--
|
|
|
|
local mt = { }
|
|
|
|
|
|
|
|
--
|
2016-12-14 13:25:20 +00:00
|
|
|
-- Secret key to native table
|
2016-12-14 08:02:51 +00:00
|
|
|
--
|
|
|
|
local k_nt = { }
|
|
|
|
|
2016-12-14 13:25:20 +00:00
|
|
|
local assignAble =
|
|
|
|
{
|
|
|
|
dpos = true,
|
|
|
|
etype = true,
|
|
|
|
path = true,
|
|
|
|
path2 = true,
|
|
|
|
status = true,
|
|
|
|
}
|
|
|
|
|
2016-12-14 08:02:51 +00:00
|
|
|
--
|
|
|
|
-- On accessing a nil index.
|
|
|
|
--
|
|
|
|
mt.__index = function
|
|
|
|
(
|
|
|
|
t, -- table accessed
|
|
|
|
k -- key value accessed
|
|
|
|
)
|
|
|
|
return t[ k_nt ][ k ]
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- On assigning a new index.
|
|
|
|
--
|
|
|
|
mt.__newindex = function
|
|
|
|
(
|
|
|
|
t, -- table getting a new index assigned
|
|
|
|
k, -- key value to assign to
|
|
|
|
v -- value to assign
|
|
|
|
)
|
2016-12-14 13:25:20 +00:00
|
|
|
if not assignAble[ k ]
|
2016-12-14 08:02:51 +00:00
|
|
|
then
|
2016-12-14 13:25:20 +00:00
|
|
|
error( 'Cannot assign new key "' .. k .. '" to Delay' )
|
2016-12-14 08:02:51 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
t[ k_nt ][ k ] = v
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- This delay is being blocked by another delay
|
|
|
|
--
|
|
|
|
local function blockedBy
|
|
|
|
(
|
|
|
|
self, -- this delay
|
|
|
|
delay -- the blocking delay
|
|
|
|
)
|
|
|
|
self[ k_nt ].status = 'block'
|
|
|
|
|
2016-12-21 12:11:55 +00:00
|
|
|
local blocks = delay[ k_nt ].blocks
|
2016-12-14 13:25:20 +00:00
|
|
|
|
2016-12-21 12:11:55 +00:00
|
|
|
if not blocks
|
2016-12-14 08:02:51 +00:00
|
|
|
then
|
|
|
|
blocks = { }
|
|
|
|
|
2016-12-21 12:11:55 +00:00
|
|
|
delay[ k_nt ].blocks = blocks
|
2016-12-14 08:02:51 +00:00
|
|
|
end
|
|
|
|
|
2016-12-21 12:11:55 +00:00
|
|
|
table.insert( blocks, self )
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Sets the delay status to 'active'.
|
|
|
|
--
|
|
|
|
local function setActive
|
|
|
|
(
|
|
|
|
self
|
|
|
|
)
|
|
|
|
self[ k_nt ].status = 'active'
|
2016-12-14 08:02:51 +00:00
|
|
|
end
|
|
|
|
|
2017-02-06 16:00:39 +00:00
|
|
|
--
|
|
|
|
-- Sets the delay status to 'wait'
|
|
|
|
--
|
|
|
|
local function wait
|
|
|
|
(
|
|
|
|
self, -- this delay
|
|
|
|
alarm -- alarm for the delay
|
|
|
|
)
|
|
|
|
self[ k_nt ].status = 'wait'
|
|
|
|
|
|
|
|
self[ k_nt ].alarm = alarm
|
|
|
|
end
|
|
|
|
|
2022-03-30 21:02:03 +00:00
|
|
|
--
|
|
|
|
-- Returns a debug string of the delay
|
|
|
|
--
|
|
|
|
local function debug(self, deep)
|
|
|
|
local rv = "<Delay "..self.status.." dpos:"..self.dpos.." type:"..self.etype.." alarm:"..alarm2string(self.alarm).." blocked:"..(self.blocks and #self.blocks or 0).." path:"..self.path
|
|
|
|
if deep and self.blocks then
|
|
|
|
for k,v in ipairs(self.blocks) do
|
|
|
|
rv = rv.."\n blocked: "..v:debug(false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
rv = rv..">"
|
|
|
|
return rv
|
|
|
|
end
|
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2010-11-02 14:11:26 +00:00
|
|
|
-- Creates a new delay.
|
2011-11-23 10:05:42 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function new
|
|
|
|
(
|
|
|
|
etype, -- type of event.
|
|
|
|
-- 'Create', 'Modify', 'Attrib', 'Delete' or 'Move'
|
|
|
|
sync, -- the Sync this delay belongs to
|
|
|
|
alarm, -- latest point in time this should be catered for
|
|
|
|
path, -- path and file-/dirname of the delay relative
|
|
|
|
-- -- to the syncs root.
|
|
|
|
path2 -- used only in moves, path and file-/dirname of
|
|
|
|
-- move destination
|
|
|
|
)
|
2016-12-14 08:02:51 +00:00
|
|
|
local delay =
|
|
|
|
{
|
|
|
|
blockedBy = blockedBy,
|
2016-12-21 12:11:55 +00:00
|
|
|
setActive = setActive,
|
2017-02-06 16:00:39 +00:00
|
|
|
wait = wait,
|
2022-03-30 21:02:03 +00:00
|
|
|
debug = debug,
|
2016-12-14 08:02:51 +00:00
|
|
|
[ k_nt ] =
|
|
|
|
{
|
|
|
|
etype = etype,
|
|
|
|
sync = sync,
|
|
|
|
alarm = alarm,
|
|
|
|
path = path,
|
|
|
|
path2 = path2,
|
2016-12-14 13:25:20 +00:00
|
|
|
status = 'wait'
|
2016-12-14 08:02:51 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
setmetatable( delay, mt )
|
|
|
|
|
|
|
|
return delay
|
2010-11-02 14:11:26 +00:00
|
|
|
end
|
2010-10-31 22:25:34 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
|
|
|
-- Public interface
|
|
|
|
--
|
|
|
|
return { new = new }
|
|
|
|
end )( )
|
2010-11-02 14:11:26 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2010-11-28 23:39:18 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- Combines delays.
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local Combiner = ( function
|
|
|
|
( )
|
2010-11-29 00:12:55 +00:00
|
|
|
--
|
2012-10-02 05:53:13 +00:00
|
|
|
-- The new delay replaces the old one if it's a file
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function refi
|
|
|
|
(
|
|
|
|
d1, -- old delay
|
|
|
|
d2 -- new delay
|
|
|
|
)
|
2012-10-02 05:53:13 +00:00
|
|
|
-- but a directory blocks
|
2016-12-06 12:19:35 +00:00
|
|
|
if d2.path:byte( -1 ) == 47
|
|
|
|
then
|
2012-10-02 05:53:13 +00:00
|
|
|
log(
|
|
|
|
'Delay',
|
2016-12-06 12:19:35 +00:00
|
|
|
d2.etype,': ',d2.path,
|
2012-10-02 05:53:13 +00:00
|
|
|
' blocked by ',
|
2016-12-06 12:19:35 +00:00
|
|
|
d1.etype,': ',d1.path
|
2012-10-02 05:53:13 +00:00
|
|
|
)
|
|
|
|
|
2012-01-27 13:01:00 +00:00
|
|
|
return 'stack'
|
2010-11-29 00:12:55 +00:00
|
|
|
end
|
2012-10-02 05:53:13 +00:00
|
|
|
|
|
|
|
log(
|
|
|
|
'Delay',
|
2016-12-06 12:19:35 +00:00
|
|
|
d2.etype, ': ', d2.path,
|
2012-10-02 05:53:13 +00:00
|
|
|
' replaces ',
|
2016-12-06 12:19:35 +00:00
|
|
|
d1.etype, ': ', d1.path
|
2012-10-02 05:53:13 +00:00
|
|
|
)
|
|
|
|
|
2012-01-27 13:01:00 +00:00
|
|
|
return 'replace'
|
2010-11-29 00:12:55 +00:00
|
|
|
end
|
|
|
|
|
2012-10-02 06:35:31 +00:00
|
|
|
--
|
|
|
|
-- Table on how to combine events that dont involve a move.
|
2010-11-28 23:39:18 +00:00
|
|
|
--
|
|
|
|
local combineNoMove = {
|
2012-10-02 06:35:31 +00:00
|
|
|
|
|
|
|
Attrib = {
|
2016-12-21 15:29:29 +00:00
|
|
|
Attrib = 'absorb',
|
|
|
|
Modify = 'replace',
|
|
|
|
Create = 'replace',
|
|
|
|
Delete = 'replace'
|
2012-10-02 06:35:31 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
Modify = {
|
2016-12-21 15:29:29 +00:00
|
|
|
Attrib = 'absorb',
|
|
|
|
Modify = 'absorb',
|
|
|
|
Create = 'replace',
|
|
|
|
Delete = 'replace'
|
2012-10-02 06:35:31 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
Create = {
|
2016-12-21 15:29:29 +00:00
|
|
|
Attrib = 'absorb',
|
|
|
|
Modify = 'absorb',
|
|
|
|
Create = 'absorb',
|
|
|
|
Delete = 'replace'
|
2012-10-02 06:35:31 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
Delete = {
|
2016-12-21 15:29:29 +00:00
|
|
|
Attrib = 'absorb',
|
|
|
|
Modify = 'absorb',
|
|
|
|
Create = 'replace file,block dir',
|
|
|
|
Delete = 'absorb'
|
2012-10-02 06:35:31 +00:00
|
|
|
},
|
2010-11-28 23:39:18 +00:00
|
|
|
}
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 05:53:13 +00:00
|
|
|
--
|
2016-12-21 15:29:29 +00:00
|
|
|
-- Returns the way two Delay should be combined.
|
|
|
|
--
|
|
|
|
-- Result:
|
|
|
|
-- nil -- They don't affect each other.
|
|
|
|
-- 'stack' -- Old Delay blocks new Delay.
|
|
|
|
-- 'replace' -- Old Delay is replaced by new Delay.
|
|
|
|
-- 'absorb' -- Old Delay absorbs new Delay.
|
|
|
|
-- 'toDelete,stack' -- Old Delay is turned into a Delete
|
|
|
|
-- and blocks the new Delay.
|
|
|
|
-- 'split' -- New Delay a Move is to be split
|
|
|
|
-- into a Create and Delete.
|
2010-11-28 23:39:18 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function combine
|
|
|
|
(
|
|
|
|
d1, -- old delay
|
|
|
|
d2 -- new delay
|
|
|
|
)
|
2016-12-06 11:57:32 +00:00
|
|
|
if d1.etype == 'Init' or d1.etype == 'Blanket'
|
|
|
|
then
|
2012-01-27 13:01:00 +00:00
|
|
|
return 'stack'
|
2010-11-28 23:39:18 +00:00
|
|
|
end
|
|
|
|
|
2022-03-31 01:54:21 +00:00
|
|
|
-- A full sync does not affect us
|
|
|
|
if d1.etype == 'Full' or d2.etype == 'Full' then
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
2012-10-02 06:35:31 +00:00
|
|
|
-- two normal events
|
2016-12-06 11:57:32 +00:00
|
|
|
if d1.etype ~= 'Move' and d2.etype ~= 'Move'
|
|
|
|
then
|
|
|
|
if d1.path == d2.path
|
|
|
|
then
|
2016-12-12 18:53:44 +00:00
|
|
|
-- lookups up the function in the combination matrix
|
|
|
|
-- and calls it
|
2016-12-21 15:29:29 +00:00
|
|
|
local result = combineNoMove[ d1.etype ][ d2.etype ]
|
|
|
|
|
|
|
|
if result == 'replace file,block dir'
|
|
|
|
then
|
|
|
|
if d2.path:byte( -1 ) == 47
|
|
|
|
then
|
|
|
|
return 'stack'
|
|
|
|
else
|
|
|
|
return 'replace'
|
|
|
|
end
|
|
|
|
end
|
2010-11-28 23:39:18 +00:00
|
|
|
end
|
|
|
|
|
2012-10-02 06:35:31 +00:00
|
|
|
-- if one is a parent directory of another, events are blocking
|
2016-12-12 18:53:44 +00:00
|
|
|
if d1.path:byte( -1 ) == 47 and string.starts( d2.path, d1.path )
|
|
|
|
or d2.path:byte( -1 ) == 47 and string.starts( d1.path, d2.path )
|
2010-11-28 23:39:18 +00:00
|
|
|
then
|
2012-01-27 13:01:00 +00:00
|
|
|
return 'stack'
|
2010-11-28 23:39:18 +00:00
|
|
|
end
|
2012-10-02 06:35:31 +00:00
|
|
|
|
2010-11-28 23:39:18 +00:00
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
2012-10-02 06:35:31 +00:00
|
|
|
-- non-move event on a move.
|
2016-12-12 18:53:44 +00:00
|
|
|
if d1.etype == 'Move' and d2.etype ~= 'Move'
|
|
|
|
then
|
|
|
|
-- if the move source could be damaged the events are stacked
|
2016-12-06 11:57:32 +00:00
|
|
|
if d1.path == d2.path
|
2016-12-12 18:53:44 +00:00
|
|
|
or d2.path:byte( -1 ) == 47 and string.starts( d1.path, d2.path )
|
|
|
|
or d1.path:byte( -1 ) == 47 and string.starts( d2.path, d1.path )
|
2010-11-28 23:39:18 +00:00
|
|
|
then
|
2012-01-27 13:01:00 +00:00
|
|
|
return 'stack'
|
2010-11-28 23:39:18 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 06:35:31 +00:00
|
|
|
-- the event does something with the move destination
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
if d1.path2 == d2.path
|
|
|
|
then
|
|
|
|
if d2.etype == 'Delete'
|
|
|
|
or d2.etype == 'Create'
|
2016-12-06 11:57:32 +00:00
|
|
|
then
|
2016-12-21 12:11:55 +00:00
|
|
|
return 'toDelete,stack'
|
2010-11-28 23:39:18 +00:00
|
|
|
end
|
2012-10-02 06:35:31 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
-- on 'Attrib' or 'Modify' simply stack on moves
|
2012-01-27 13:01:00 +00:00
|
|
|
return 'stack'
|
2010-11-28 23:39:18 +00:00
|
|
|
end
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
if d2.path:byte( -1 ) == 47 and string.starts( d1.path2, d2.path )
|
|
|
|
or d1.path2:byte( -1 ) == 47 and string.starts( d2.path, d1.path2 )
|
2010-11-28 23:39:18 +00:00
|
|
|
then
|
2012-01-27 14:19:17 +00:00
|
|
|
return 'stack'
|
2010-11-28 23:39:18 +00:00
|
|
|
end
|
2012-10-02 06:35:31 +00:00
|
|
|
|
2010-11-28 23:39:18 +00:00
|
|
|
return nil
|
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 06:35:31 +00:00
|
|
|
-- a move upon a non-move event
|
2016-12-12 18:53:44 +00:00
|
|
|
if d1.etype ~= 'Move' and d2.etype == 'Move'
|
|
|
|
then
|
|
|
|
if d1.path == d2.path
|
|
|
|
or d1.path == d2.path2
|
|
|
|
or d1.path:byte( -1 ) == 47 and string.starts( d2.path, d1.path )
|
|
|
|
or d1.path:byte( -1 ) == 47 and string.starts( d2.path2, d1.path )
|
|
|
|
or d2.path:byte( -1 ) == 47 and string.starts( d1.path, d2.path )
|
|
|
|
or d2.path2:byte( -1 ) == 47 and string.starts( d1.path, d2.path2 )
|
2010-11-28 23:39:18 +00:00
|
|
|
then
|
2012-01-27 13:01:00 +00:00
|
|
|
return 'split'
|
2010-11-28 23:39:18 +00:00
|
|
|
end
|
2012-10-02 06:35:31 +00:00
|
|
|
|
2010-11-28 23:39:18 +00:00
|
|
|
return nil
|
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2012-10-02 06:35:31 +00:00
|
|
|
-- a move event upon a move event
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
if d1.etype == 'Move' and d2.etype == 'Move'
|
|
|
|
then
|
2010-11-28 23:39:18 +00:00
|
|
|
-- TODO combine moves,
|
2016-12-12 18:53:44 +00:00
|
|
|
if d1.path == d2.path
|
|
|
|
or d1.path == d2.path2
|
|
|
|
or d1.path2 == d2.path
|
|
|
|
or d2.path2 == d2.path
|
|
|
|
or d1.path:byte( -1 ) == 47 and string.starts( d2.path, d1.path )
|
|
|
|
or d1.path:byte( -1 ) == 47 and string.starts( d2.path2, d1.path )
|
|
|
|
or d1.path2:byte( -1 ) == 47 and string.starts( d2.path, d1.path2 )
|
|
|
|
or d1.path2:byte( -1 ) == 47 and string.starts( d2.path2, d1.path2 )
|
|
|
|
or d2.path:byte( -1 ) == 47 and string.starts( d1.path, d2.path )
|
|
|
|
or d2.path:byte( -1 ) == 47 and string.starts( d1.path2, d2.path )
|
|
|
|
or d2.path2:byte( -1 ) == 47 and string.starts( d1.path, d2.path2 )
|
|
|
|
or d2.path2:byte( -1 ) == 47 and string.starts( d1.path2, d2.path2 )
|
2010-11-28 23:39:18 +00:00
|
|
|
then
|
2012-01-27 14:19:17 +00:00
|
|
|
return 'split'
|
2010-11-28 23:39:18 +00:00
|
|
|
end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2010-11-28 23:39:18 +00:00
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
2012-10-02 06:35:31 +00:00
|
|
|
error( 'reached impossible state' )
|
2010-11-28 23:39:18 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-21 15:29:29 +00:00
|
|
|
--
|
|
|
|
-- The new delay is absorbed by an older one.
|
|
|
|
--
|
|
|
|
local function logAbsorb
|
|
|
|
(
|
|
|
|
d1, -- old delay
|
|
|
|
d2 -- new delay
|
|
|
|
)
|
|
|
|
log(
|
|
|
|
'Delay',
|
|
|
|
d2.etype, ': ',d2.path,
|
|
|
|
' absorbed by ',
|
|
|
|
d1.etype,': ',d1.path
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- The new delay replaces the old one if it's a file.
|
|
|
|
--
|
|
|
|
local function logReplace
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2016-12-21 15:29:29 +00:00
|
|
|
(
|
|
|
|
d1, -- old delay
|
|
|
|
d2 -- new delay
|
|
|
|
)
|
|
|
|
log(
|
|
|
|
'Delay',
|
|
|
|
d2.etype, ': ', d2.path,
|
|
|
|
' replaces ',
|
|
|
|
d1.etype, ': ', d1.path
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2017-02-16 11:17:37 +00:00
|
|
|
|
2016-12-21 15:29:29 +00:00
|
|
|
--
|
|
|
|
-- The new delay splits on the old one.
|
|
|
|
--
|
|
|
|
local function logSplit
|
|
|
|
(
|
|
|
|
d1, -- old delay
|
|
|
|
d2 -- new delay
|
|
|
|
)
|
|
|
|
log(
|
|
|
|
'Delay',
|
|
|
|
d2.etype, ': ',
|
2016-12-21 15:38:04 +00:00
|
|
|
d2.path, ' -> ', d2.path2,
|
2016-12-21 15:29:29 +00:00
|
|
|
' splits on ',
|
|
|
|
d1.etype, ': ', d1.path
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- The new delay is blocked by the old delay.
|
|
|
|
--
|
|
|
|
local function logStack
|
|
|
|
(
|
|
|
|
d1, -- old delay
|
|
|
|
d2 -- new delay
|
|
|
|
)
|
|
|
|
local active = ''
|
|
|
|
|
|
|
|
if d1.active
|
|
|
|
then
|
|
|
|
active = 'active '
|
|
|
|
end
|
|
|
|
|
|
|
|
if d2.path2
|
|
|
|
then
|
|
|
|
log(
|
|
|
|
'Delay',
|
|
|
|
d2.etype, ': ',
|
|
|
|
d2.path, '->', d2.path2,
|
|
|
|
' blocked by ',
|
|
|
|
active,
|
|
|
|
d1.etype, ': ', d1.path
|
|
|
|
)
|
|
|
|
else
|
|
|
|
log(
|
|
|
|
'Delay',
|
|
|
|
d2.etype, ': ', d2.path,
|
|
|
|
' blocked by ',
|
|
|
|
active,
|
|
|
|
d1.etype, ': ', d1.path
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
2017-02-16 11:17:37 +00:00
|
|
|
|
|
|
|
|
2016-12-21 15:29:29 +00:00
|
|
|
--
|
|
|
|
-- The new delay turns the old one (a move) into a delete and is blocked.
|
|
|
|
--
|
|
|
|
local function logToDeleteStack
|
|
|
|
(
|
|
|
|
d1, -- old delay
|
|
|
|
d2 -- new delay
|
|
|
|
)
|
|
|
|
if d1.path2
|
|
|
|
then
|
|
|
|
log(
|
|
|
|
'Delay',
|
|
|
|
d2.etype, ': ', d2.path,
|
|
|
|
' turns ',
|
|
|
|
d1.etype, ': ', d1.path, ' -> ', d1.path2,
|
|
|
|
' into Delete: ', d1.path
|
|
|
|
)
|
|
|
|
else
|
|
|
|
log(
|
|
|
|
'Delay',
|
|
|
|
d2.etype, ': ', d2.path,
|
|
|
|
' turns ',
|
|
|
|
d1.etype, ': ', d1.path,
|
|
|
|
' into Delete: ', d1.path
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local logFuncs =
|
|
|
|
{
|
|
|
|
absorb = logAbsorb,
|
|
|
|
replace = logReplace,
|
|
|
|
split = logSplit,
|
|
|
|
stack = logStack,
|
|
|
|
[ 'toDelete,stack' ] = logToDeleteStack
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Prints the log message for a combination result
|
|
|
|
--
|
|
|
|
local function log
|
|
|
|
(
|
|
|
|
result, -- the combination result
|
|
|
|
d1, -- old delay
|
|
|
|
d2 -- new delay
|
|
|
|
)
|
|
|
|
local lf = logFuncs[ result ]
|
|
|
|
|
|
|
|
if not lf
|
|
|
|
then
|
|
|
|
error( 'unknown combination result: ' .. result )
|
|
|
|
end
|
|
|
|
|
|
|
|
lf( d1, d2 )
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
|
|
|
-- Public interface
|
|
|
|
--
|
2016-12-21 15:29:29 +00:00
|
|
|
return
|
|
|
|
{
|
|
|
|
combine = combine,
|
|
|
|
log = log
|
|
|
|
}
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2012-10-02 06:35:31 +00:00
|
|
|
end )( )
|
2010-11-28 23:39:18 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2011-01-07 17:11:17 +00:00
|
|
|
-- Creates inlets for syncs: the user interface for events.
|
2010-11-08 12:14:10 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local InletFactory = ( function
|
|
|
|
( )
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Table to receive the delay of an event
|
2012-03-22 08:39:15 +00:00
|
|
|
-- or the delay list of an event list.
|
|
|
|
--
|
|
|
|
-- Keys are events and values are delays.
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
local e2d = { }
|
2012-03-22 08:39:15 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Table to ensure the uniqueness of every event
|
2012-03-22 08:39:15 +00:00
|
|
|
-- related to a delay.
|
|
|
|
--
|
|
|
|
-- Keys are delay and values are events.
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
local e2d2 = { }
|
2012-03-22 08:39:15 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Allows the garbage collector to remove not refrenced
|
2012-03-22 08:39:15 +00:00
|
|
|
-- events.
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
setmetatable( e2d, { __mode = 'k' } )
|
|
|
|
setmetatable( e2d2, { __mode = 'v' } )
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Removes the trailing slash from a path.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function cutSlash
|
|
|
|
(
|
|
|
|
path -- path to cut
|
|
|
|
)
|
|
|
|
if string.byte( path, -1 ) == 47
|
2016-12-05 14:11:00 +00:00
|
|
|
then
|
2016-12-13 13:41:35 +00:00
|
|
|
return string.sub( path, 1, -2 )
|
2010-11-08 12:14:10 +00:00
|
|
|
else
|
|
|
|
return path
|
|
|
|
end
|
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Gets the path of an event.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function getPath
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2016-12-05 14:11:00 +00:00
|
|
|
if event.move ~= 'To'
|
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].path
|
2010-11-10 11:23:26 +00:00
|
|
|
else
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].path2
|
2010-11-10 11:23:26 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-12 18:52:43 +00:00
|
|
|
-- Interface for user scripts to get event fields.
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2010-11-08 12:14:10 +00:00
|
|
|
local eventFields = {
|
2012-10-02 20:02:09 +00:00
|
|
|
|
|
|
|
--
|
2010-11-10 22:03:02 +00:00
|
|
|
-- Returns a copy of the configuration as called by sync.
|
|
|
|
-- But including all inherited data and default values.
|
|
|
|
--
|
|
|
|
-- TODO give user a readonly version.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
config = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].sync.config
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
|
|
|
|
2016-12-02 15:24:07 +00:00
|
|
|
--
|
2011-02-25 14:16:22 +00:00
|
|
|
-- Returns the inlet belonging to an event.
|
2011-11-23 10:05:42 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
inlet = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].sync.inlet
|
2010-11-13 19:22:05 +00:00
|
|
|
end,
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-08 12:14:10 +00:00
|
|
|
-- Returns the type of the event.
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2012-01-27 14:19:17 +00:00
|
|
|
-- Can be: 'Attrib', 'Create', 'Delete', 'Modify' or 'Move',
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2016-12-14 08:02:51 +00:00
|
|
|
etype = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].etype
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
2010-11-12 09:45:22 +00:00
|
|
|
|
2010-11-12 18:52:43 +00:00
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Events are not lists.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
isList = function
|
|
|
|
( )
|
2010-11-12 18:52:43 +00:00
|
|
|
return false
|
|
|
|
end,
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Returns the status of the event.
|
|
|
|
--
|
2011-02-25 14:16:22 +00:00
|
|
|
-- Can be:
|
|
|
|
-- 'wait', 'active', 'block'.
|
2011-11-23 10:05:42 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
status = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].status
|
2010-11-11 15:17:22 +00:00
|
|
|
end,
|
|
|
|
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Returns true if event relates to a directory
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
isdir = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return string.byte( getPath( event ), -1 ) == 47
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-08 12:14:10 +00:00
|
|
|
-- Returns the name of the file/dir.
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-08 12:14:10 +00:00
|
|
|
-- Includes a trailing slash for dirs.
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
name = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return string.match( getPath( event ), '[^/]+/?$' )
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Returns the name of the file/dir
|
|
|
|
-- excluding a trailing slash for dirs.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
basename = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return string.match( getPath( event ), '([^/]+)/?$')
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
|
|
|
|
2016-12-02 15:24:07 +00:00
|
|
|
--
|
2010-11-08 12:14:10 +00:00
|
|
|
-- Returns the file/dir relative to watch root
|
2012-10-02 20:02:09 +00:00
|
|
|
-- including a trailing slash for dirs.
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
path = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2017-01-04 10:24:55 +00:00
|
|
|
local p = getPath( event )
|
|
|
|
|
2017-01-05 09:29:38 +00:00
|
|
|
if string.byte( p, 1 ) == 47
|
2017-01-04 10:24:55 +00:00
|
|
|
then
|
|
|
|
p = string.sub( p, 2, -1 )
|
|
|
|
end
|
|
|
|
|
|
|
|
return p
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-17 18:52:55 +00:00
|
|
|
-- Returns the directory of the file/dir relative to watch root
|
|
|
|
-- Always includes a trailing slash.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
pathdir = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2017-01-04 10:24:55 +00:00
|
|
|
local p = getPath( event )
|
|
|
|
|
2017-01-05 09:29:38 +00:00
|
|
|
if string.byte( p, 1 ) == 47
|
2017-01-04 10:24:55 +00:00
|
|
|
then
|
|
|
|
p = string.sub( p, 2, -1 )
|
|
|
|
end
|
|
|
|
|
|
|
|
return string.match( p, '^(.*/)[^/]+/?' ) or ''
|
2010-11-17 18:52:55 +00:00
|
|
|
end,
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-08 12:14:10 +00:00
|
|
|
-- Returns the file/dir relativ to watch root
|
2012-10-02 20:02:09 +00:00
|
|
|
-- excluding a trailing slash for dirs.
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
pathname = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2017-01-04 10:24:55 +00:00
|
|
|
local p = getPath( event )
|
|
|
|
|
2017-01-05 09:29:38 +00:00
|
|
|
if string.byte( p, 1 ) == 47
|
2017-01-04 10:24:55 +00:00
|
|
|
then
|
|
|
|
p = string.sub( p, 2, -1 )
|
|
|
|
end
|
|
|
|
|
|
|
|
return cutSlash( p )
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2016-12-02 15:24:07 +00:00
|
|
|
--
|
2010-11-08 12:14:10 +00:00
|
|
|
-- Returns the absolute path of the watch root.
|
2012-10-02 20:02:09 +00:00
|
|
|
-- All symlinks are resolved.
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
source = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].sync.source
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
|
|
|
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Returns the absolute path of the file/dir
|
|
|
|
-- including a trailing slash for dirs.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
sourcePath = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].sync.source .. getPath( event )
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
2012-01-27 11:08:10 +00:00
|
|
|
|
2010-11-29 16:37:46 +00:00
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Returns the absolute dir of the file/dir
|
|
|
|
-- including a trailing slash.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
sourcePathdir = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
|
|
|
return(
|
|
|
|
e2d[event].sync.source
|
|
|
|
.. (
|
|
|
|
string.match( getPath( event ), '^(.*/)[^/]+/?' )
|
|
|
|
or ''
|
|
|
|
)
|
|
|
|
)
|
2010-11-29 16:37:46 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2016-12-02 15:24:07 +00:00
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Returns the absolute path of the file/dir
|
|
|
|
-- excluding a trailing slash for dirs.
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
sourcePathname = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].sync.source .. cutSlash( getPath( event ) )
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-01-27 11:08:10 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- Returns the configured target.
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
target = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].sync.config.target
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
|
|
|
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
Implement batchSizeLimit for rsync based transfers
If the batchSizeLimit is set, only files lower then this limit will
be grouped in one rsync transfer.
Each file larger then this limit will spawn their own transfer process.
This will cause large files to no longer block small file transfers under the
circumstance the maxProcess limit on the sync is larger then 1
A very optimized, very secure transfer configuration based on a
pool of ssh connection looks like this:
```
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@targetmachine"},
mode = "pool",
parallel = 2,
},
source = "/tmp/src",
target = "rsync://localhost:${localport}/test",
delay = 5,
batchSizeLimit = 1024 * 1024 * 30,
maxProcesses = 4,
rsync = {
verbose = true,
inplace = true,
}
}
```
If you configure remote ssh configuration only allows portforwarding and your rsync daemon
is configured correctly, you can very securely transfer data without giving shell access.
2022-04-14 12:05:49 +00:00
|
|
|
-- Returns the absolute dir/file appended to the target
|
2012-10-02 20:02:09 +00:00
|
|
|
-- including a trailing slash for dirs.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
targetPath = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].sync.config.target .. getPath( event )
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2010-11-29 16:37:46 +00:00
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Returns the dir of the dir/file appended to the target
|
|
|
|
-- including a trailing slash.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
targetPathdir = function
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
|
|
|
return(
|
|
|
|
e2d[ event ].sync.config.target
|
|
|
|
.. (
|
|
|
|
string.match( getPath( event ), '^(.*/)[^/]+/?' )
|
|
|
|
or ''
|
|
|
|
)
|
|
|
|
)
|
2010-11-29 16:37:46 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Returns the relative dir/file appended to the target
|
|
|
|
-- excluding a trailing slash for dirs.
|
|
|
|
--
|
|
|
|
targetPathname = function( event )
|
2016-12-13 13:41:35 +00:00
|
|
|
return(
|
|
|
|
e2d[ event ].sync.config.target
|
|
|
|
.. cutSlash( getPath( event ) )
|
|
|
|
)
|
2010-11-08 12:14:10 +00:00
|
|
|
end,
|
|
|
|
}
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-12 18:52:43 +00:00
|
|
|
-- Retrievs event fields for the user script.
|
2010-11-10 22:03:02 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
local eventMeta =
|
|
|
|
{
|
2016-12-13 13:41:35 +00:00
|
|
|
__index = function
|
|
|
|
(
|
|
|
|
event,
|
|
|
|
field
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
local f = eventFields[ field ]
|
2016-12-12 18:53:44 +00:00
|
|
|
|
|
|
|
if not f
|
|
|
|
then
|
|
|
|
if field == 'move'
|
|
|
|
then
|
2010-11-10 11:23:26 +00:00
|
|
|
-- possibly undefined
|
|
|
|
return nil
|
|
|
|
end
|
2016-12-12 18:53:44 +00:00
|
|
|
|
|
|
|
error( 'event does not have field "' .. field .. '"', 2 )
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
return f( event )
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
|
|
|
}
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Interface for user scripts to get list fields.
|
2010-11-12 18:52:43 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local eventListFuncs =
|
|
|
|
{
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-20 22:32:25 +00:00
|
|
|
-- Returns a list of paths of all events in list.
|
2012-03-21 10:39:52 +00:00
|
|
|
--
|
2010-11-20 22:32:25 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
getPaths = function
|
|
|
|
(
|
|
|
|
elist, -- handle returned by getevents( )
|
|
|
|
mutator -- if not nil called with ( etype, path, path2 )
|
|
|
|
-- returns one or two strings to add.
|
|
|
|
)
|
2016-12-05 14:11:00 +00:00
|
|
|
local dlist = e2d[ elist ]
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-05 14:11:00 +00:00
|
|
|
if not dlist
|
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
error( 'cannot find delay list from event list.' )
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
|
|
|
local result = { }
|
2010-12-11 23:00:33 +00:00
|
|
|
local resultn = 1
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
for k, d in ipairs( dlist )
|
|
|
|
do
|
2010-12-11 23:00:33 +00:00
|
|
|
local s1, s2
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
if mutator
|
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
s1, s2 = mutator( d.etype, d.path, d.path2 )
|
2010-12-11 23:00:33 +00:00
|
|
|
else
|
|
|
|
s1, s2 = d.path, d.path2
|
|
|
|
end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
|
|
|
result[ resultn ] = s1
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2010-12-11 23:00:33 +00:00
|
|
|
resultn = resultn + 1
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
if s2
|
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
result[ resultn ] = s2
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2010-12-11 23:00:33 +00:00
|
|
|
resultn = resultn + 1
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
|
|
|
end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2010-11-24 16:18:48 +00:00
|
|
|
return result
|
2012-10-02 20:02:09 +00:00
|
|
|
|
Implement batchSizeLimit for rsync based transfers
If the batchSizeLimit is set, only files lower then this limit will
be grouped in one rsync transfer.
Each file larger then this limit will spawn their own transfer process.
This will cause large files to no longer block small file transfers under the
circumstance the maxProcess limit on the sync is larger then 1
A very optimized, very secure transfer configuration based on a
pool of ssh connection looks like this:
```
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@targetmachine"},
mode = "pool",
parallel = 2,
},
source = "/tmp/src",
target = "rsync://localhost:${localport}/test",
delay = 5,
batchSizeLimit = 1024 * 1024 * 30,
maxProcesses = 4,
rsync = {
verbose = true,
inplace = true,
}
}
```
If you configure remote ssh configuration only allows portforwarding and your rsync daemon
is configured correctly, you can very securely transfer data without giving shell access.
2022-04-14 12:05:49 +00:00
|
|
|
end,
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Returns the size of the eventlist
|
|
|
|
--
|
|
|
|
size = function( elist )
|
|
|
|
local dlist = e2d[ elist ]
|
|
|
|
|
|
|
|
if not dlist then
|
|
|
|
return 0
|
|
|
|
else
|
|
|
|
return #dlist
|
|
|
|
end
|
|
|
|
end,
|
2022-11-11 14:11:09 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Returns the list of events
|
|
|
|
--
|
|
|
|
getList = function( elist )
|
|
|
|
local dlist = e2d[ elist ]
|
|
|
|
|
|
|
|
if not dlist then
|
|
|
|
return {}
|
|
|
|
else
|
|
|
|
return dlist
|
|
|
|
end
|
|
|
|
end,
|
2010-11-12 18:52:43 +00:00
|
|
|
}
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Retrievs event list fields for the user script
|
2010-11-12 18:52:43 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
local eventListMeta =
|
|
|
|
{
|
2016-12-13 13:41:35 +00:00
|
|
|
__index = function
|
|
|
|
(
|
|
|
|
elist,
|
|
|
|
func
|
|
|
|
)
|
2016-12-05 14:11:00 +00:00
|
|
|
if func == 'isList'
|
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2016-12-05 14:11:00 +00:00
|
|
|
if func == 'config'
|
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ elist ].sync.config
|
|
|
|
end
|
|
|
|
|
|
|
|
local f = eventListFuncs[ func ]
|
2010-11-12 18:52:43 +00:00
|
|
|
|
2016-12-05 14:11:00 +00:00
|
|
|
if not f
|
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
error(
|
|
|
|
'event list does not have function "' .. func .. '"',
|
|
|
|
2
|
|
|
|
)
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2016-12-13 13:41:35 +00:00
|
|
|
return function
|
|
|
|
( ... )
|
2012-10-02 20:02:09 +00:00
|
|
|
return f( elist, ... )
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
2010-11-30 22:56:34 +00:00
|
|
|
|
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Table of all inlets with their syncs.
|
|
|
|
--
|
|
|
|
local inlets = { }
|
2010-11-30 22:56:34 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Allows the garbage collector to remove entries.
|
|
|
|
--
|
|
|
|
setmetatable( inlets, { __mode = 'v' } )
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-12 18:52:43 +00:00
|
|
|
-- Encapsulates a delay into an event for the user script.
|
2010-11-08 12:14:10 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function d2e
|
|
|
|
(
|
|
|
|
delay -- delay to encapsulate
|
|
|
|
)
|
2012-03-22 08:39:15 +00:00
|
|
|
-- already created?
|
2016-12-13 13:41:35 +00:00
|
|
|
local eu = e2d2[ delay ]
|
2012-03-22 08:39:15 +00:00
|
|
|
|
2016-12-05 14:11:00 +00:00
|
|
|
if delay.etype ~= 'Move'
|
|
|
|
then
|
2018-02-27 09:09:28 +00:00
|
|
|
if eu then return eu end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
|
|
|
local event = { }
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
setmetatable( event, eventMeta )
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
e2d[ event ] = delay
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
e2d2[ delay ] = event
|
|
|
|
|
2012-03-22 08:39:15 +00:00
|
|
|
return event
|
2010-11-10 12:59:51 +00:00
|
|
|
else
|
|
|
|
-- moves have 2 events - origin and destination
|
2018-02-27 09:09:28 +00:00
|
|
|
if eu then return eu[1], eu[2] end
|
2012-03-22 08:39:15 +00:00
|
|
|
|
|
|
|
local event = { move = 'Fr' }
|
|
|
|
local event2 = { move = 'To' }
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
setmetatable( event, eventMeta )
|
2012-10-02 20:02:09 +00:00
|
|
|
setmetatable( event2, eventMeta )
|
|
|
|
|
|
|
|
e2d[ event ] = delay
|
|
|
|
e2d[ event2 ] = delay
|
|
|
|
|
|
|
|
e2d2[ delay ] = { event, event2 }
|
|
|
|
|
2012-03-22 08:39:15 +00:00
|
|
|
-- move events have a field 'move'
|
|
|
|
return event, event2
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-12 18:52:43 +00:00
|
|
|
-- Encapsulates a delay list into an event list for the user script.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function dl2el
|
|
|
|
(
|
|
|
|
dlist
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
local eu = e2d2[ dlist ]
|
|
|
|
|
2018-02-27 09:09:28 +00:00
|
|
|
if eu then return eu end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
|
|
|
local elist = { }
|
|
|
|
|
|
|
|
setmetatable( elist, eventListMeta )
|
|
|
|
|
|
|
|
e2d [ elist ] = dlist
|
2016-12-05 14:11:00 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
e2d2[ dlist ] = elist
|
2012-03-22 08:39:15 +00:00
|
|
|
|
|
|
|
return elist
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
2010-11-08 12:14:10 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-12-02 11:57:04 +00:00
|
|
|
-- The functions the inlet provides.
|
2010-11-11 15:17:22 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local inletFuncs =
|
|
|
|
{
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Adds an exclude.
|
2010-11-30 22:56:34 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
addExclude = function
|
|
|
|
(
|
|
|
|
sync, -- the sync of the inlet
|
|
|
|
pattern -- exlusion pattern to add
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
sync:addExclude( pattern )
|
2010-11-30 22:56:34 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2018-02-27 16:14:36 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Appens a filter.
|
|
|
|
--
|
|
|
|
appendFilter = function
|
|
|
|
(
|
|
|
|
sync, -- the sync of the inlet
|
|
|
|
rule, -- '+' or '-'
|
|
|
|
pattern -- exlusion pattern to add
|
|
|
|
)
|
|
|
|
sync:appendFilter( rule, pattern )
|
|
|
|
end,
|
|
|
|
|
2010-11-30 22:56:34 +00:00
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Removes an exclude.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
rmExclude = function
|
|
|
|
(
|
|
|
|
sync, -- the sync of the inlet
|
|
|
|
pattern -- exlusion pattern to remove
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
sync:rmExclude( pattern )
|
2010-11-30 22:56:34 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2011-01-19 15:17:11 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- Gets the list of excludes in their
|
2018-02-27 16:14:36 +00:00
|
|
|
-- rsync-like patterns form.
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
getExcludes = function
|
|
|
|
(
|
|
|
|
sync -- the sync of the inlet
|
|
|
|
)
|
2011-01-19 15:17:11 +00:00
|
|
|
-- creates a copy
|
2012-10-02 20:02:09 +00:00
|
|
|
local e = { }
|
2011-01-19 15:17:11 +00:00
|
|
|
local en = 1;
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-05 14:11:00 +00:00
|
|
|
for k, _ in pairs( sync.excludes.list )
|
|
|
|
do
|
2012-10-02 20:02:09 +00:00
|
|
|
e[ en ] = k;
|
2011-01-19 15:17:11 +00:00
|
|
|
en = en + 1;
|
|
|
|
end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2011-01-19 15:17:11 +00:00
|
|
|
return e;
|
|
|
|
end,
|
|
|
|
|
2018-02-27 16:14:36 +00:00
|
|
|
--
|
|
|
|
-- Gets the list of filters and excldues
|
|
|
|
-- as rsync-like filter/patterns form.
|
|
|
|
--
|
|
|
|
getFilters = function
|
|
|
|
(
|
|
|
|
sync -- the sync of the inlet
|
|
|
|
)
|
|
|
|
-- creates a copy
|
|
|
|
local e = { }
|
|
|
|
local en = 1;
|
|
|
|
|
|
|
|
-- first takes the filters
|
|
|
|
if sync.filters
|
|
|
|
then
|
|
|
|
for _, entry in ipairs( sync.filters.list )
|
|
|
|
do
|
|
|
|
e[ en ] = entry.rule .. ' ' .. entry.pattern;
|
|
|
|
en = en + 1;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- then the excludes
|
|
|
|
for k, _ in pairs( sync.excludes.list )
|
|
|
|
do
|
|
|
|
e[ en ] = '- ' .. k;
|
|
|
|
en = en + 1;
|
|
|
|
end
|
|
|
|
|
|
|
|
return e;
|
|
|
|
end,
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Returns true if the sync has filters
|
|
|
|
--
|
|
|
|
hasFilters = function
|
|
|
|
(
|
|
|
|
sync -- the sync of the inlet
|
|
|
|
)
|
|
|
|
return not not sync.filters
|
|
|
|
end,
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-30 22:56:34 +00:00
|
|
|
-- Creates a blanketEvent that blocks everything
|
|
|
|
-- and is blocked by everything.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
createBlanketEvent = function
|
|
|
|
(
|
|
|
|
sync -- the sync of the inlet
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return d2e( sync:addBlanketDelay( ) )
|
2010-11-30 22:56:34 +00:00
|
|
|
end,
|
2010-11-11 15:17:22 +00:00
|
|
|
|
2022-11-11 14:11:09 +00:00
|
|
|
--
|
|
|
|
-- Creates a blanketEvent that blocks everything
|
|
|
|
-- and is blocked by everything.
|
|
|
|
--
|
|
|
|
createFullEvent = function
|
|
|
|
(
|
|
|
|
sync, -- the sync of the inlet
|
|
|
|
path -- path for the full event
|
|
|
|
)
|
|
|
|
-- return d2e( sync:delay("Full", timestamp, path, nil) )
|
|
|
|
return d2e( sync:addFullDelay(path) )
|
|
|
|
end,
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-30 22:56:34 +00:00
|
|
|
-- Discards a waiting event.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
discardEvent = function
|
|
|
|
(
|
|
|
|
sync,
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
local delay = e2d[ event ]
|
2016-12-05 14:11:00 +00:00
|
|
|
|
|
|
|
if delay.status ~= 'wait'
|
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
log(
|
|
|
|
'Error',
|
2012-01-27 13:01:00 +00:00
|
|
|
'Ignored cancel of a non-waiting event of type ',
|
2012-10-02 20:02:09 +00:00
|
|
|
event.etype
|
|
|
|
)
|
2016-12-05 14:11:00 +00:00
|
|
|
|
2010-11-30 22:56:34 +00:00
|
|
|
return
|
|
|
|
end
|
2016-12-05 14:11:00 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
sync:removeDelay( delay )
|
2010-11-30 22:56:34 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-30 22:56:34 +00:00
|
|
|
-- Gets the next not blocked event from queue.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
getEvent = function
|
|
|
|
(
|
|
|
|
sync
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return d2e( sync:getNextDelay( now( ) ) )
|
2010-11-30 22:56:34 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-30 22:56:34 +00:00
|
|
|
-- Gets all events that are not blocked by active events.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
getEvents = function
|
|
|
|
(
|
2017-01-03 14:30:13 +00:00
|
|
|
sync, -- the sync of the inlet
|
|
|
|
test -- if not nil use this function to test if to include an event
|
2016-12-13 13:41:35 +00:00
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
local dlist = sync:getDelays( test )
|
2016-12-05 14:11:00 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
return dl2el( dlist )
|
2010-11-30 22:56:34 +00:00
|
|
|
end,
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- Returns the configuration table specified by sync{ }
|
2010-11-30 22:56:34 +00:00
|
|
|
--
|
2012-10-02 20:02:09 +00:00
|
|
|
getConfig = function( sync )
|
2016-12-12 18:53:44 +00:00
|
|
|
-- TODO give a readonly handler only.
|
2010-11-30 22:56:34 +00:00
|
|
|
return sync.config
|
|
|
|
end,
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Returns the sync for this Inlet
|
|
|
|
--
|
|
|
|
getSync = function( sync )
|
|
|
|
return sync
|
|
|
|
end,
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Substitutes parameters in arguments
|
|
|
|
--
|
|
|
|
getSubstitutionData = function( sync, event, data)
|
|
|
|
return sync.getSubstitutionData(sync, event, data)
|
|
|
|
end,
|
2010-11-30 22:56:34 +00:00
|
|
|
}
|
2010-11-08 12:14:10 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-30 22:56:34 +00:00
|
|
|
-- Forwards access to inlet functions.
|
2010-11-08 12:14:10 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local inletMeta =
|
|
|
|
{
|
|
|
|
__index = function
|
|
|
|
(
|
|
|
|
inlet,
|
|
|
|
func
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
local f = inletFuncs[ func ]
|
2016-12-12 18:53:44 +00:00
|
|
|
|
|
|
|
if not f
|
|
|
|
then
|
2018-02-27 09:09:28 +00:00
|
|
|
error( 'inlet does not have function "'..func..'"', 2 )
|
2012-10-02 20:02:09 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
return function( ... )
|
|
|
|
return f( inlets[ inlet ], ... )
|
|
|
|
end
|
2010-11-30 22:56:34 +00:00
|
|
|
end,
|
|
|
|
}
|
2010-11-08 12:14:10 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- Creates a new inlet for a sync.
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function newInlet
|
|
|
|
(
|
|
|
|
sync -- the sync to create the inlet for
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
-- Lsyncd runner controlled variables
|
|
|
|
local inlet = { }
|
2010-11-30 22:56:34 +00:00
|
|
|
|
|
|
|
-- sets use access methods
|
2012-10-02 20:02:09 +00:00
|
|
|
setmetatable( inlet, inletMeta )
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
inlets[ inlet ] = sync
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2011-11-23 10:05:42 +00:00
|
|
|
return inlet
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-12 18:52:43 +00:00
|
|
|
-- Returns the delay from a event.
|
2010-11-30 22:56:34 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function getDelayOrList
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ]
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-30 22:56:34 +00:00
|
|
|
-- Returns the sync from an event or list
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function getSync
|
|
|
|
(
|
|
|
|
event
|
|
|
|
)
|
2012-10-02 20:02:09 +00:00
|
|
|
return e2d[ event ].sync
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
|
|
|
-- Public interface.
|
|
|
|
--
|
2010-11-08 12:14:10 +00:00
|
|
|
return {
|
2010-11-30 22:56:34 +00:00
|
|
|
getDelayOrList = getDelayOrList,
|
|
|
|
d2e = d2e,
|
|
|
|
dl2el = dl2el,
|
|
|
|
getSync = getSync,
|
|
|
|
newInlet = newInlet,
|
|
|
|
}
|
2012-10-02 20:02:09 +00:00
|
|
|
end )( )
|
2010-11-13 16:59:46 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
|
|
|
|
--
|
2018-02-27 09:09:28 +00:00
|
|
|
-- A set of exclude patterns.
|
2010-11-13 16:59:46 +00:00
|
|
|
--
|
2018-03-01 10:26:12 +00:00
|
|
|
local Excludes = ( function
|
|
|
|
( )
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-13 16:59:46 +00:00
|
|
|
-- Turns a rsync like file pattern to a lua pattern.
|
2012-10-02 20:02:09 +00:00
|
|
|
-- ( at best it can )
|
2011-11-23 10:05:42 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function toLuaPattern
|
|
|
|
(
|
|
|
|
p -- the rsync like pattern
|
|
|
|
)
|
2010-11-13 16:59:46 +00:00
|
|
|
local o = p
|
2018-02-27 09:09:28 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
p = string.gsub( p, '%%', '%%%%' )
|
|
|
|
p = string.gsub( p, '%^', '%%^' )
|
|
|
|
p = string.gsub( p, '%$', '%%$' )
|
|
|
|
p = string.gsub( p, '%(', '%%(' )
|
|
|
|
p = string.gsub( p, '%)', '%%)' )
|
|
|
|
p = string.gsub( p, '%.', '%%.' )
|
|
|
|
p = string.gsub( p, '%[', '%%[' )
|
|
|
|
p = string.gsub( p, '%]', '%%]' )
|
|
|
|
p = string.gsub( p, '%+', '%%+' )
|
|
|
|
p = string.gsub( p, '%-', '%%-' )
|
|
|
|
p = string.gsub( p, '%?', '[^/]' )
|
|
|
|
p = string.gsub( p, '%*', '[^/]*' )
|
2011-11-23 10:05:42 +00:00
|
|
|
-- this was a ** before
|
2012-10-02 20:02:09 +00:00
|
|
|
p = string.gsub( p, '%[%^/%]%*%[%^/%]%*', '.*' )
|
|
|
|
p = string.gsub( p, '^/', '^/' )
|
|
|
|
|
2017-01-09 10:43:23 +00:00
|
|
|
if p:sub( 1, 2 ) ~= '^/'
|
|
|
|
then
|
|
|
|
-- if does not begin with '^/'
|
|
|
|
-- then all matches should begin with '/'.
|
|
|
|
p = '/' .. p;
|
|
|
|
end
|
|
|
|
|
2018-02-27 09:09:28 +00:00
|
|
|
log( 'Exclude', 'toLuaPattern "', o, '" = "', p, '"' )
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2010-11-13 16:59:46 +00:00
|
|
|
return p
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- Adds a pattern to exclude.
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function add
|
|
|
|
(
|
|
|
|
self,
|
|
|
|
pattern -- the pattern to exclude
|
|
|
|
)
|
2016-12-12 18:53:44 +00:00
|
|
|
if self.list[ pattern ]
|
2016-12-13 13:41:35 +00:00
|
|
|
then -- already in the list
|
2010-11-13 16:59:46 +00:00
|
|
|
return
|
|
|
|
end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
|
|
|
local lp = toLuaPattern( pattern )
|
|
|
|
|
2016-12-13 13:41:35 +00:00
|
|
|
self.list[ pattern ] = lp
|
2010-11-13 16:59:46 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-13 19:22:05 +00:00
|
|
|
-- Removes a pattern to exclude.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function remove
|
|
|
|
(
|
|
|
|
self, -- self
|
|
|
|
pattern -- the pattern to remove
|
|
|
|
)
|
2018-02-27 16:14:36 +00:00
|
|
|
-- already in the list?
|
2016-12-12 18:53:44 +00:00
|
|
|
if not self.list[ pattern ]
|
2018-02-27 16:14:36 +00:00
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
log(
|
|
|
|
'Normal',
|
|
|
|
'Removing not excluded exclude "' .. pattern .. '"'
|
|
|
|
)
|
|
|
|
|
2010-11-13 19:22:05 +00:00
|
|
|
return
|
|
|
|
end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-13 13:41:35 +00:00
|
|
|
self.list[ pattern ] = nil
|
2010-11-13 19:22:05 +00:00
|
|
|
end
|
|
|
|
|
2016-12-02 15:24:07 +00:00
|
|
|
--
|
2010-11-13 16:59:46 +00:00
|
|
|
-- Adds a list of patterns to exclude.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function addList
|
|
|
|
(
|
|
|
|
self,
|
|
|
|
plist
|
|
|
|
)
|
2018-02-27 09:09:28 +00:00
|
|
|
for _, v in ipairs( plist )
|
2016-12-12 18:53:44 +00:00
|
|
|
do
|
2018-02-27 09:09:28 +00:00
|
|
|
add( self, v )
|
2010-11-13 16:59:46 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- Loads the excludes from a file.
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function loadFile
|
|
|
|
(
|
|
|
|
self, -- self
|
|
|
|
file -- filename to load from
|
|
|
|
)
|
2022-11-10 03:20:54 +00:00
|
|
|
local f, err = io.open( file )
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
if not f
|
|
|
|
then
|
2018-02-27 09:09:28 +00:00
|
|
|
log( 'Error', 'Cannot open exclude file "', file,'": ', err )
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2022-11-10 03:20:54 +00:00
|
|
|
return terminate( -1 )
|
2010-11-13 16:59:46 +00:00
|
|
|
end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
for line in f:lines()
|
|
|
|
do
|
2010-11-13 16:59:46 +00:00
|
|
|
-- lsyncd 2.0 does not support includes
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
if not string.match( line, '^%s*%+' )
|
|
|
|
and not string.match( line, '^%s*#' )
|
|
|
|
and not string.match( line, '^%s*$' )
|
|
|
|
then
|
|
|
|
local p = string.match( line, '%s*-?%s*(.*)' )
|
|
|
|
|
|
|
|
if p
|
|
|
|
then
|
|
|
|
add( self, p )
|
2012-10-02 20:02:09 +00:00
|
|
|
end
|
2010-11-13 16:59:46 +00:00
|
|
|
end
|
|
|
|
end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
|
|
|
f:close( )
|
2010-11-13 16:59:46 +00:00
|
|
|
end
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-12-04 12:17:07 +00:00
|
|
|
-- Tests if 'path' is excluded.
|
2010-11-13 16:59:46 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function test
|
|
|
|
(
|
|
|
|
self, -- self
|
|
|
|
path -- the path to test
|
|
|
|
)
|
2017-01-09 10:43:23 +00:00
|
|
|
if path:byte( 1 ) ~= 47
|
|
|
|
then
|
|
|
|
error( 'Paths for exlusion tests must start with \'/\'' )
|
|
|
|
end
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
for _, p in pairs( self.list )
|
|
|
|
do
|
|
|
|
if p:byte( -1 ) == 36
|
|
|
|
then
|
2011-01-19 13:28:44 +00:00
|
|
|
-- ends with $
|
2016-12-12 18:53:44 +00:00
|
|
|
if path:match( p )
|
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
return true
|
|
|
|
end
|
2011-01-19 13:28:44 +00:00
|
|
|
else
|
2012-01-27 14:19:17 +00:00
|
|
|
-- ends either end with / or $
|
2016-12-12 18:53:44 +00:00
|
|
|
if path:match( p .. '/' )
|
|
|
|
or path:match( p .. '$' )
|
|
|
|
then
|
2012-10-02 20:02:09 +00:00
|
|
|
return true
|
|
|
|
end
|
2010-11-13 16:59:46 +00:00
|
|
|
end
|
|
|
|
end
|
2012-10-02 20:02:09 +00:00
|
|
|
|
2010-11-13 16:59:46 +00:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- Cretes a new exclude set.
|
2010-11-13 16:59:46 +00:00
|
|
|
--
|
2016-12-14 08:02:51 +00:00
|
|
|
local function new
|
|
|
|
( )
|
2011-11-23 10:05:42 +00:00
|
|
|
return {
|
2012-10-02 20:02:09 +00:00
|
|
|
list = { },
|
2010-11-13 16:59:46 +00:00
|
|
|
|
|
|
|
-- functions
|
2010-11-13 19:22:05 +00:00
|
|
|
add = add,
|
2010-12-03 21:16:39 +00:00
|
|
|
addList = addList,
|
2010-11-13 16:59:46 +00:00
|
|
|
loadFile = loadFile,
|
2010-11-13 19:22:05 +00:00
|
|
|
remove = remove,
|
|
|
|
test = test,
|
2010-11-13 16:59:46 +00:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
-- Public interface.
|
2012-10-02 20:02:09 +00:00
|
|
|
--
|
2010-11-13 16:59:46 +00:00
|
|
|
return { new = new }
|
2012-10-02 20:02:09 +00:00
|
|
|
end )( )
|
2010-11-13 16:59:46 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2018-02-27 16:14:36 +00:00
|
|
|
--
|
|
|
|
-- A set of filter patterns.
|
|
|
|
--
|
|
|
|
-- Filters allow excludes and includes
|
|
|
|
--
|
2018-03-01 10:26:12 +00:00
|
|
|
local Filters = ( function
|
|
|
|
( )
|
2018-02-27 16:14:36 +00:00
|
|
|
--
|
|
|
|
-- Turns a rsync like file pattern to a lua pattern.
|
|
|
|
-- ( at best it can )
|
|
|
|
--
|
|
|
|
local function toLuaPattern
|
|
|
|
(
|
|
|
|
p -- the rsync like pattern
|
|
|
|
)
|
|
|
|
local o = p
|
|
|
|
|
|
|
|
p = string.gsub( p, '%%', '%%%%' )
|
|
|
|
p = string.gsub( p, '%^', '%%^' )
|
|
|
|
p = string.gsub( p, '%$', '%%$' )
|
|
|
|
p = string.gsub( p, '%(', '%%(' )
|
|
|
|
p = string.gsub( p, '%)', '%%)' )
|
|
|
|
p = string.gsub( p, '%.', '%%.' )
|
|
|
|
p = string.gsub( p, '%[', '%%[' )
|
|
|
|
p = string.gsub( p, '%]', '%%]' )
|
|
|
|
p = string.gsub( p, '%+', '%%+' )
|
|
|
|
p = string.gsub( p, '%-', '%%-' )
|
|
|
|
p = string.gsub( p, '%?', '[^/]' )
|
|
|
|
p = string.gsub( p, '%*', '[^/]*' )
|
|
|
|
-- this was a ** before
|
|
|
|
p = string.gsub( p, '%[%^/%]%*%[%^/%]%*', '.*' )
|
|
|
|
p = string.gsub( p, '^/', '^/' )
|
|
|
|
|
|
|
|
if p:sub( 1, 2 ) ~= '^/'
|
|
|
|
then
|
|
|
|
-- if does not begin with '^/'
|
|
|
|
-- then all matches should begin with '/'.
|
|
|
|
p = '/' .. p;
|
|
|
|
end
|
|
|
|
|
|
|
|
log( 'Filter', 'toLuaPattern "', o, '" = "', p, '"' )
|
|
|
|
|
|
|
|
return p
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Appends a filter pattern
|
|
|
|
--
|
|
|
|
local function append
|
|
|
|
(
|
|
|
|
self, -- the filters object
|
|
|
|
line -- filter line
|
|
|
|
)
|
|
|
|
local rule, pattern = string.match( line, '%s*([+|-])%s*(.*)' )
|
|
|
|
|
|
|
|
if not rule or not pattern
|
|
|
|
then
|
|
|
|
log( 'Error', 'Unknown filter rule: "', line, '"' )
|
|
|
|
terminate( -1 )
|
|
|
|
end
|
|
|
|
|
|
|
|
local lp = toLuaPattern( pattern )
|
|
|
|
|
|
|
|
table.insert( self. list, { rule = rule, pattern = pattern, lp = lp } )
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Adds a list of patterns to exclude.
|
|
|
|
--
|
|
|
|
local function appendList
|
|
|
|
(
|
|
|
|
self,
|
|
|
|
plist
|
|
|
|
)
|
|
|
|
for _, v in ipairs( plist )
|
|
|
|
do
|
|
|
|
append( self, v )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Loads the filters from a file.
|
|
|
|
--
|
|
|
|
local function loadFile
|
|
|
|
(
|
|
|
|
self, -- self
|
|
|
|
file -- filename to load from
|
|
|
|
)
|
2022-11-10 03:20:54 +00:00
|
|
|
local f, err = io.open( file )
|
2018-02-27 16:14:36 +00:00
|
|
|
|
|
|
|
if not f
|
|
|
|
then
|
|
|
|
log( 'Error', 'Cannot open filter file "', file, '": ', err )
|
|
|
|
|
2022-11-10 03:20:54 +00:00
|
|
|
return terminate( -1 )
|
2018-02-27 16:14:36 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
for line in f:lines( )
|
|
|
|
do
|
|
|
|
if string.match( line, '^%s*#' )
|
|
|
|
or string.match( line, '^%s*$' )
|
|
|
|
then
|
|
|
|
-- a comment or empty line: ignore
|
|
|
|
else
|
|
|
|
append( self, line )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
f:close( )
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
2018-03-01 13:14:28 +00:00
|
|
|
-- Tests if 'path' is filtered.
|
2018-02-27 16:14:36 +00:00
|
|
|
--
|
|
|
|
local function test
|
|
|
|
(
|
|
|
|
self, -- self
|
|
|
|
path -- the path to test
|
|
|
|
)
|
|
|
|
if path:byte( 1 ) ~= 47
|
|
|
|
then
|
2018-03-01 13:14:28 +00:00
|
|
|
error( 'Paths for filter tests must start with \'/\'' )
|
2018-02-27 16:14:36 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
for _, entry in ipairs( self.list )
|
|
|
|
do
|
|
|
|
local rule = entry.rule
|
|
|
|
local lp = entry.lp -- lua pattern
|
|
|
|
|
|
|
|
if lp:byte( -1 ) == 36
|
|
|
|
then
|
|
|
|
-- ends with $
|
|
|
|
if path:match( lp )
|
|
|
|
then
|
|
|
|
return rule == '-'
|
|
|
|
end
|
|
|
|
else
|
|
|
|
-- ends either end with / or $
|
|
|
|
if path:match( lp .. '/' )
|
|
|
|
or path:match( lp .. '$' )
|
|
|
|
then
|
|
|
|
return rule == '-'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-03-01 13:14:28 +00:00
|
|
|
-- nil means neither a positivie
|
|
|
|
-- or negative hit, thus excludes have to
|
|
|
|
-- be queried
|
|
|
|
return nil
|
2018-02-27 16:14:36 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Cretes a new filter set.
|
|
|
|
--
|
|
|
|
local function new
|
|
|
|
( )
|
|
|
|
return {
|
|
|
|
list = { },
|
|
|
|
-- functions
|
|
|
|
append = append,
|
|
|
|
appendList = appendList,
|
|
|
|
loadFile = loadFile,
|
|
|
|
test = test,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Public interface.
|
|
|
|
--
|
|
|
|
return { new = new }
|
|
|
|
|
|
|
|
end )( )
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2014-02-28 09:15:48 +00:00
|
|
|
-- Holds information about one observed directory including subdirs.
|
2010-11-02 14:11:26 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local Sync = ( function
|
|
|
|
( )
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2011-11-23 10:05:42 +00:00
|
|
|
-- Syncs that have no name specified by the user script
|
2010-11-10 22:03:02 +00:00
|
|
|
-- get an incremental default name 'Sync[X]'
|
2010-11-06 18:26:59 +00:00
|
|
|
--
|
|
|
|
local nextDefaultName = 1
|
2010-11-12 20:43:27 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-13 19:22:05 +00:00
|
|
|
-- Adds an exclude.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function addExclude
|
|
|
|
(
|
|
|
|
self,
|
|
|
|
pattern
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
return self.excludes:add( pattern )
|
2010-11-13 19:22:05 +00:00
|
|
|
end
|
|
|
|
|
2022-11-09 21:41:46 +00:00
|
|
|
--
|
|
|
|
-- Appends a filter line to the Sync
|
|
|
|
--
|
2018-02-27 16:14:36 +00:00
|
|
|
local function appendFilter
|
|
|
|
(
|
|
|
|
self,
|
2022-11-09 21:41:46 +00:00
|
|
|
line
|
2018-02-27 16:14:36 +00:00
|
|
|
)
|
|
|
|
if not self.filters then self.filters = Filters.new( ) end
|
|
|
|
|
2022-11-09 21:41:46 +00:00
|
|
|
return self.filters:append( line )
|
2018-02-27 16:14:36 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-13 19:22:05 +00:00
|
|
|
-- Removes an exclude.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function rmExclude
|
|
|
|
(
|
|
|
|
self,
|
|
|
|
pattern
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
return self.excludes:remove( pattern )
|
2010-11-13 19:22:05 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-11 15:17:22 +00:00
|
|
|
-- Removes a delay.
|
2010-11-12 20:43:27 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function removeDelay
|
|
|
|
(
|
|
|
|
self,
|
|
|
|
delay
|
|
|
|
)
|
2016-12-12 18:53:44 +00:00
|
|
|
if self.delays[ delay.dpos ] ~= delay
|
|
|
|
then
|
2016-12-14 15:29:33 +00:00
|
|
|
error( 'Queue is broken, delay not at dpos' )
|
2010-11-11 15:17:22 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
self.delays:remove( delay.dpos )
|
2010-11-12 11:04:45 +00:00
|
|
|
|
2016-12-14 08:02:51 +00:00
|
|
|
-- frees all delays blocked by this one.
|
2016-12-06 10:11:48 +00:00
|
|
|
if delay.blocks
|
|
|
|
then
|
2016-12-12 18:53:44 +00:00
|
|
|
for _, vd in pairs( delay.blocks )
|
2016-12-06 10:11:48 +00:00
|
|
|
do
|
2012-01-27 13:01:00 +00:00
|
|
|
vd.status = 'wait'
|
2010-11-12 11:04:45 +00:00
|
|
|
end
|
|
|
|
end
|
2010-11-11 15:17:22 +00:00
|
|
|
end
|
2022-03-16 00:12:42 +00:00
|
|
|
|
|
|
|
|
2018-03-01 13:14:28 +00:00
|
|
|
--
|
|
|
|
-- Returns true if the relative path is excluded or filtered
|
2022-03-16 00:12:42 +00:00
|
|
|
--
|
2018-03-01 13:14:28 +00:00
|
|
|
local function testFilter
|
|
|
|
(
|
|
|
|
self, -- the Sync
|
|
|
|
path -- the relative path
|
|
|
|
)
|
|
|
|
-- never filter the relative root itself
|
|
|
|
-- ( that would make zero sense )
|
|
|
|
if path == '/' then return false end
|
|
|
|
|
|
|
|
local filter = self.filters and self.filters:test( path )
|
|
|
|
|
|
|
|
if filter ~= nil then return filter end
|
|
|
|
|
|
|
|
-- otherwise check excludes if concerned
|
|
|
|
return self.excludes:test( path )
|
|
|
|
end
|
2010-11-11 15:17:22 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- Returns true if this Sync concerns about 'path'.
|
2010-12-04 12:17:07 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function concerns
|
|
|
|
(
|
2018-03-01 13:14:28 +00:00
|
|
|
self, -- the Sync
|
|
|
|
path -- the absolute path
|
2016-12-13 13:41:35 +00:00
|
|
|
)
|
|
|
|
-- not concerned if watch rootdir doesn't match
|
2016-12-06 10:11:48 +00:00
|
|
|
if not path:starts( self.source )
|
|
|
|
then
|
2010-12-04 12:17:07 +00:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
-- a sub dir and not concerned about subdirs
|
2017-01-09 10:14:23 +00:00
|
|
|
if self.config.subdirs == false
|
|
|
|
and path:sub( #self.source, -1 ):match( '[^/]+/?' )
|
2010-12-04 12:17:07 +00:00
|
|
|
then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2018-03-01 13:14:28 +00:00
|
|
|
return not testFilter( self, path:sub( #self.source ) )
|
2010-12-04 12:17:07 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- Collects a child process.
|
2010-11-08 12:14:10 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function collect
|
|
|
|
(
|
|
|
|
self, -- the sync
|
|
|
|
pid, -- process id of collected child process
|
|
|
|
exitcode -- exitcode of child process
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
local delay = self.processes[ pid ]
|
|
|
|
|
2018-03-01 13:14:28 +00:00
|
|
|
-- not a child of this sync?
|
2022-03-16 00:12:42 +00:00
|
|
|
if not delay then
|
|
|
|
return false
|
|
|
|
end
|
2010-11-10 22:03:02 +00:00
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if delay.status
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
log( 'Delay', 'collected an event' )
|
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if delay.status ~= 'active'
|
|
|
|
then
|
2017-02-06 16:00:39 +00:00
|
|
|
error( 'collecting a non-active process' )
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-30 22:56:34 +00:00
|
|
|
local rc = self.config.collect(
|
2012-10-03 07:23:18 +00:00
|
|
|
InletFactory.d2e( delay ),
|
|
|
|
exitcode
|
|
|
|
)
|
|
|
|
|
2016-08-29 11:15:29 +00:00
|
|
|
if rc == 'die'
|
|
|
|
then
|
|
|
|
log( 'Error', 'Critical exitcode.' )
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
terminate( -1 )
|
2017-02-06 16:00:39 +00:00
|
|
|
elseif rc ~= 'again'
|
2016-08-29 11:15:29 +00:00
|
|
|
then
|
2010-11-13 20:21:12 +00:00
|
|
|
-- if its active again the collecter restarted the event
|
2012-10-03 07:23:18 +00:00
|
|
|
removeDelay( self, delay )
|
2017-02-06 16:00:39 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
|
|
|
'Delay',
|
|
|
|
'Finish of ',
|
|
|
|
delay.etype,
|
|
|
|
' on ',
|
|
|
|
self.source,delay.path,
|
|
|
|
' = ',
|
|
|
|
exitcode
|
|
|
|
)
|
2021-12-10 14:05:30 +00:00
|
|
|
-- sets the initDone after the first success
|
|
|
|
self.initDone = true
|
|
|
|
|
2011-11-23 10:05:42 +00:00
|
|
|
else
|
2010-11-13 20:21:12 +00:00
|
|
|
-- sets the delay on wait again
|
2011-11-23 10:05:42 +00:00
|
|
|
local alarm = self.config.delay
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-13 20:31:24 +00:00
|
|
|
-- delays at least 1 second
|
2018-03-01 10:26:12 +00:00
|
|
|
if alarm < 1 then alarm = 1 end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2017-02-06 16:00:39 +00:00
|
|
|
delay:wait( now( ) + alarm )
|
2010-11-13 20:21:12 +00:00
|
|
|
end
|
2010-11-12 18:52:43 +00:00
|
|
|
else
|
2018-03-01 10:26:12 +00:00
|
|
|
log( 'Delay', 'collected a list' )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-30 22:56:34 +00:00
|
|
|
local rc = self.config.collect(
|
2012-10-03 07:23:18 +00:00
|
|
|
InletFactory.dl2el( delay ),
|
|
|
|
exitcode
|
|
|
|
)
|
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if rc == 'die'
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
log( 'Error', 'Critical exitcode.' );
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
terminate( -1 )
|
2017-02-06 16:00:39 +00:00
|
|
|
elseif rc == 'again'
|
2016-12-06 10:11:48 +00:00
|
|
|
then
|
2010-11-13 20:31:24 +00:00
|
|
|
-- sets the delay on wait again
|
2011-11-23 10:05:42 +00:00
|
|
|
local alarm = self.config.delay
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2018-03-01 13:14:28 +00:00
|
|
|
-- delays are at least 1 second
|
|
|
|
if alarm < 1 then alarm = 1 end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-29 20:32:54 +00:00
|
|
|
alarm = now() + alarm
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
for _, d in ipairs( delay )
|
|
|
|
do
|
2017-02-06 16:00:39 +00:00
|
|
|
d:wait( alarm )
|
2010-11-13 20:31:24 +00:00
|
|
|
end
|
2017-02-06 16:00:39 +00:00
|
|
|
else
|
|
|
|
for _, d in ipairs( delay )
|
|
|
|
do
|
2012-10-03 07:23:18 +00:00
|
|
|
removeDelay( self, d )
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
log( 'Delay','Finished list = ',exitcode )
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
self.processes[ pid ] = nil
|
2022-03-16 00:12:42 +00:00
|
|
|
-- we handled this process
|
|
|
|
return true
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
2010-11-06 18:26:59 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2011-11-23 10:05:42 +00:00
|
|
|
-- Stacks a newDelay on the oldDelay,
|
2010-11-12 09:45:22 +00:00
|
|
|
-- the oldDelay blocks the new Delay.
|
|
|
|
--
|
2011-11-23 10:05:42 +00:00
|
|
|
-- A delay can block 'n' other delays,
|
2010-11-12 09:45:22 +00:00
|
|
|
-- but is blocked at most by one, the latest delay.
|
2011-11-23 10:05:42 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function stack
|
|
|
|
(
|
|
|
|
oldDelay,
|
|
|
|
newDelay
|
|
|
|
)
|
2016-12-14 08:02:51 +00:00
|
|
|
newDelay:blockedBy( oldDelay )
|
2010-11-12 09:45:22 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-06 18:26:59 +00:00
|
|
|
-- Puts an action on the delay stack.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function delay
|
|
|
|
(
|
|
|
|
self, -- the sync
|
|
|
|
etype, -- the event type
|
|
|
|
time, -- time of the event
|
|
|
|
path, -- path of the event
|
|
|
|
path2 -- desitination path of move events
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
|
|
|
'Function',
|
2012-10-05 07:41:46 +00:00
|
|
|
'delay( ',
|
2012-10-03 07:23:18 +00:00
|
|
|
self.config.name, ', ',
|
|
|
|
etype, ', ',
|
|
|
|
path, ', ',
|
|
|
|
path2,
|
2012-10-05 07:41:46 +00:00
|
|
|
' )'
|
2012-10-03 07:23:18 +00:00
|
|
|
)
|
2012-02-16 15:49:34 +00:00
|
|
|
|
2016-12-21 12:11:55 +00:00
|
|
|
--
|
|
|
|
-- In case new directories were created
|
|
|
|
-- looks through this directories and makes create events for
|
|
|
|
-- new stuff found in there.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function recurse
|
|
|
|
( )
|
2016-12-06 10:11:48 +00:00
|
|
|
if etype == 'Create' and path:byte( -1 ) == 47
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
local entries = lsyncd.readdir( self.source .. path )
|
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if entries
|
|
|
|
then
|
|
|
|
for dirname, isdir in pairs( entries )
|
|
|
|
do
|
2012-02-16 15:05:33 +00:00
|
|
|
local pd = path .. dirname
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-02-27 09:09:28 +00:00
|
|
|
if isdir then pd = pd..'/' end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-03-01 10:26:12 +00:00
|
|
|
log( 'Delay', 'Create creates Create on ', pd )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
delay( self, 'Create', time, pd, nil )
|
2012-02-16 15:05:33 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2010-11-20 22:32:25 +00:00
|
|
|
|
|
|
|
-- exclusion tests
|
2016-12-06 10:11:48 +00:00
|
|
|
if not path2
|
|
|
|
then
|
2011-01-19 15:17:11 +00:00
|
|
|
-- simple test for single path events
|
2018-03-01 13:14:28 +00:00
|
|
|
if testFilter( self, path )
|
2016-12-06 10:11:48 +00:00
|
|
|
then
|
2018-03-01 13:14:28 +00:00
|
|
|
log( 'Filter', 'filtered ', etype, ' on "', path, '"' )
|
2018-02-27 16:14:36 +00:00
|
|
|
|
2010-11-13 16:59:46 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
else
|
2016-12-06 10:11:48 +00:00
|
|
|
-- for double paths ( move ) it might result into a split
|
2018-03-01 13:14:28 +00:00
|
|
|
local ex1 = testFilter( self, path )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-03-01 13:14:28 +00:00
|
|
|
local ex2 = testFilter( self, path2 )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if ex1 and ex2
|
|
|
|
then
|
2018-03-01 13:14:28 +00:00
|
|
|
log(
|
|
|
|
'Filter',
|
|
|
|
'filtered "', etype, ' on "', path,
|
|
|
|
'" -> "', path2, '"'
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-13 16:59:46 +00:00
|
|
|
return
|
2016-12-06 10:11:48 +00:00
|
|
|
elseif not ex1 and ex2
|
|
|
|
then
|
2010-11-13 16:59:46 +00:00
|
|
|
-- splits the move if only partly excluded
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
2018-03-01 13:14:28 +00:00
|
|
|
'Filter',
|
|
|
|
'filtered destination transformed ',
|
2012-10-03 07:23:18 +00:00
|
|
|
etype,
|
|
|
|
' to Delete ',
|
|
|
|
path
|
|
|
|
)
|
|
|
|
|
2018-02-27 16:14:36 +00:00
|
|
|
delay( self, 'Delete', time, path, nil )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-13 16:59:46 +00:00
|
|
|
return
|
2016-12-06 10:11:48 +00:00
|
|
|
elseif ex1 and not ex2
|
|
|
|
then
|
2010-11-13 16:59:46 +00:00
|
|
|
-- splits the move if only partly excluded
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
2018-03-01 13:14:28 +00:00
|
|
|
'Filter',
|
|
|
|
'filtered origin transformed ',
|
2012-10-03 07:23:18 +00:00
|
|
|
etype,
|
|
|
|
' to Create.',
|
|
|
|
path2
|
|
|
|
)
|
|
|
|
|
2018-02-27 16:14:36 +00:00
|
|
|
delay( self, 'Create', time, path2, nil )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-13 16:59:46 +00:00
|
|
|
return
|
|
|
|
end
|
2010-11-10 09:49:44 +00:00
|
|
|
end
|
2010-11-06 18:26:59 +00:00
|
|
|
|
2018-03-01 13:14:28 +00:00
|
|
|
if etype == 'Move'
|
|
|
|
and not self.config.onMove
|
2016-12-06 10:11:48 +00:00
|
|
|
then
|
2011-11-23 10:05:42 +00:00
|
|
|
-- if there is no move action defined,
|
2010-11-12 09:45:22 +00:00
|
|
|
-- split a move as delete/create
|
2010-11-20 22:32:25 +00:00
|
|
|
-- layer 1 scripts which want moves events have to
|
2012-01-27 13:01:00 +00:00
|
|
|
-- set onMove simply to 'true'
|
2012-10-03 07:23:18 +00:00
|
|
|
log( 'Delay', 'splitting Move into Delete & Create' )
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
delay( self, 'Delete', time, path, nil )
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
delay( self, 'Create', time, path2, nil )
|
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
return
|
2010-11-06 18:26:59 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- creates the new action
|
2011-11-23 10:05:42 +00:00
|
|
|
local alarm
|
2016-12-06 10:11:48 +00:00
|
|
|
|
|
|
|
if time and self.config.delay
|
|
|
|
then
|
2010-11-29 10:56:39 +00:00
|
|
|
alarm = time + self.config.delay
|
2010-11-06 18:26:59 +00:00
|
|
|
else
|
2012-10-03 07:23:18 +00:00
|
|
|
alarm = now( )
|
2010-11-06 18:26:59 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-10 09:49:44 +00:00
|
|
|
-- new delay
|
2018-02-27 16:14:36 +00:00
|
|
|
local nd = Delay.new( etype, self, alarm, path, path2 )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-11-11 14:11:09 +00:00
|
|
|
if nd.etype == 'Init' or nd.etype == 'Blanket' or nd.etype == 'Full'
|
2016-12-06 10:11:48 +00:00
|
|
|
then
|
2012-10-05 07:41:46 +00:00
|
|
|
-- always stack init or blanket events on the last event
|
|
|
|
log(
|
|
|
|
'Delay',
|
|
|
|
'Stacking ',
|
|
|
|
nd.etype,
|
|
|
|
' event.'
|
|
|
|
)
|
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
if self.delays:size( ) > 0
|
2016-12-06 10:11:48 +00:00
|
|
|
then
|
2016-12-14 15:29:33 +00:00
|
|
|
stack( self.delays:last( ), nd )
|
2010-11-12 09:45:22 +00:00
|
|
|
end
|
2012-10-05 07:41:46 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
nd.dpos = self.delays:push( nd )
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
recurse( )
|
2012-10-05 07:41:46 +00:00
|
|
|
|
2010-11-10 12:59:51 +00:00
|
|
|
return
|
2010-11-10 09:49:44 +00:00
|
|
|
end
|
|
|
|
|
2011-11-23 10:05:42 +00:00
|
|
|
-- detects blocks and combos by working from back until
|
2010-11-10 09:49:44 +00:00
|
|
|
-- front through the fifo
|
2016-12-14 15:29:33 +00:00
|
|
|
for il, od in self.delays:qpairsReverse( )
|
2016-12-06 10:11:48 +00:00
|
|
|
do
|
2010-12-11 20:00:48 +00:00
|
|
|
-- asks Combiner what to do
|
2012-10-03 07:23:18 +00:00
|
|
|
local ac = Combiner.combine( od, nd )
|
2010-11-10 11:23:26 +00:00
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if ac
|
|
|
|
then
|
2016-12-21 15:29:29 +00:00
|
|
|
Combiner.log( ac, od, nd )
|
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if ac == 'remove'
|
|
|
|
then
|
2016-12-14 15:29:33 +00:00
|
|
|
self.delays:remove( il )
|
2016-12-06 10:11:48 +00:00
|
|
|
elseif ac == 'stack'
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
stack( od, nd )
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
nd.dpos = self.delays:push( nd )
|
2016-12-21 12:11:55 +00:00
|
|
|
elseif ac == 'toDelete,stack'
|
|
|
|
then
|
2016-12-22 13:59:18 +00:00
|
|
|
if od.status ~= 'active'
|
|
|
|
then
|
|
|
|
-- turns olddelay into a delete
|
|
|
|
local rd = Delay.new( 'Delete', self, od.alarm, od.path )
|
2016-12-21 12:11:55 +00:00
|
|
|
|
2016-12-22 13:59:18 +00:00
|
|
|
self.delays:replace( il, rd )
|
2016-12-21 12:11:55 +00:00
|
|
|
|
2016-12-22 13:59:18 +00:00
|
|
|
rd.dpos = il
|
2016-12-22 12:55:59 +00:00
|
|
|
|
2016-12-22 14:15:17 +00:00
|
|
|
-- and stacks delay2
|
|
|
|
stack( rd, nd )
|
|
|
|
else
|
|
|
|
-- and stacks delay2
|
|
|
|
stack( od, nd )
|
|
|
|
end
|
2016-12-22 12:55:59 +00:00
|
|
|
|
|
|
|
nd.dpos = self.delays:push( nd )
|
2016-12-06 10:11:48 +00:00
|
|
|
elseif ac == 'absorb'
|
|
|
|
then
|
2012-02-16 15:05:33 +00:00
|
|
|
-- nada
|
2016-12-06 10:11:48 +00:00
|
|
|
elseif ac == 'replace'
|
|
|
|
then
|
2016-12-22 13:59:18 +00:00
|
|
|
if od.status ~= 'active'
|
|
|
|
then
|
|
|
|
self.delays:replace( il, nd )
|
2016-12-21 12:11:55 +00:00
|
|
|
|
2016-12-22 13:59:18 +00:00
|
|
|
nd.dpos = il
|
|
|
|
else
|
|
|
|
stack( od, nd )
|
|
|
|
|
|
|
|
nd.dpos = self.delays:push( nd )
|
|
|
|
end
|
2016-12-06 10:11:48 +00:00
|
|
|
elseif ac == 'split'
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
delay( self, 'Delete', time, path, nil )
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
delay( self, 'Create', time, path2, nil )
|
2011-11-23 10:05:42 +00:00
|
|
|
else
|
2012-10-03 07:23:18 +00:00
|
|
|
error( 'unknown result of combine()' )
|
2010-11-06 18:26:59 +00:00
|
|
|
end
|
2016-12-06 11:57:32 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
recurse( )
|
2016-12-06 11:57:32 +00:00
|
|
|
|
2012-02-16 15:05:33 +00:00
|
|
|
return
|
2010-11-06 18:26:59 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-10 09:49:44 +00:00
|
|
|
il = il - 1
|
2010-11-06 18:26:59 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if nd.path2
|
|
|
|
then
|
2016-12-21 12:11:55 +00:00
|
|
|
log( 'Delay', 'New ', nd.etype, ': ', nd.path, ' -> ', nd.path2 )
|
2010-11-29 00:21:17 +00:00
|
|
|
else
|
2016-12-21 12:11:55 +00:00
|
|
|
log( 'Delay', 'New ', nd.etype, ': ', nd.path )
|
2010-11-29 00:21:17 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-28 23:39:18 +00:00
|
|
|
-- no block or combo
|
2016-12-14 15:29:33 +00:00
|
|
|
nd.dpos = self.delays:push( nd )
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
recurse( )
|
2010-11-06 18:26:59 +00:00
|
|
|
end
|
2010-11-20 22:32:25 +00:00
|
|
|
|
2022-03-25 18:01:19 +00:00
|
|
|
local function updateNextCronAlarm(self, timestamp)
|
|
|
|
if timestamp == nil then
|
|
|
|
timestamp = now()
|
|
|
|
end
|
|
|
|
|
2022-03-31 01:54:59 +00:00
|
|
|
local nalarm = nil
|
2022-03-25 18:01:19 +00:00
|
|
|
for i, c in ipairs(self.cron) do
|
|
|
|
local na = c:get_next_occurrence(timestamp.seconds)
|
|
|
|
if nalarm == nil or nalarm > na then
|
|
|
|
nalarm = na
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if nalarm ~= nil then
|
|
|
|
self.nextCronAlarm = lsyncd.jiffies_from_seconds(nalarm)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-11-06 21:29:22 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- Returns the soonest alarm for this Sync.
|
|
|
|
--
|
2016-12-14 13:25:20 +00:00
|
|
|
local function getAlarm
|
|
|
|
(
|
|
|
|
self
|
|
|
|
)
|
2016-12-06 10:11:48 +00:00
|
|
|
if self.processes:size( ) >= self.config.maxProcesses
|
|
|
|
then
|
2010-12-01 13:25:05 +00:00
|
|
|
return false
|
2010-11-30 23:14:17 +00:00
|
|
|
end
|
2010-11-06 21:29:22 +00:00
|
|
|
|
2022-03-25 18:01:19 +00:00
|
|
|
local rv = false
|
|
|
|
|
|
|
|
if self.cron ~= nil and self.nextCronAlarm == false then
|
|
|
|
updateNextCronAlarm(self)
|
|
|
|
end
|
|
|
|
|
2012-02-15 13:45:46 +00:00
|
|
|
-- first checks if more processes could be spawned
|
2022-04-19 18:32:33 +00:00
|
|
|
if self.processes:size( ) > self.config.maxProcesses
|
2016-12-06 10:11:48 +00:00
|
|
|
then
|
2022-04-19 18:32:33 +00:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
-- finds the nearest delay waiting to be spawned
|
|
|
|
for _, d in self.delays:qpairs( )
|
|
|
|
do
|
|
|
|
if d.status == 'wait'
|
|
|
|
then
|
|
|
|
if type(d.alarm) == "boolean" and d.alarm == true then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
if type(d.alarm) == "userdata" then
|
|
|
|
if rv == false or
|
|
|
|
d.alarm < rv then
|
2022-03-25 18:01:19 +00:00
|
|
|
rv = d.alarm
|
|
|
|
end
|
2016-12-06 10:11:48 +00:00
|
|
|
end
|
2010-11-11 19:52:20 +00:00
|
|
|
end
|
2010-11-06 21:29:22 +00:00
|
|
|
end
|
2022-04-19 18:32:33 +00:00
|
|
|
|
2022-03-25 18:01:19 +00:00
|
|
|
if rv == false and self.nextCronAlarm ~= false then
|
|
|
|
rv = self.nextCronAlarm
|
|
|
|
elseif self.nextCronAlarm ~= false and self.nextCronAlarm < rv then
|
|
|
|
rv = self.nextCronAlarm
|
|
|
|
end
|
2010-11-30 23:14:17 +00:00
|
|
|
-- nothing to spawn
|
2022-03-25 18:01:19 +00:00
|
|
|
return rv
|
2010-11-06 21:29:22 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-12 18:52:43 +00:00
|
|
|
-- Gets all delays that are not blocked by active delays.
|
2010-11-08 12:14:10 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function getDelays
|
|
|
|
(
|
|
|
|
self, -- the sync
|
|
|
|
test -- function to test each delay
|
|
|
|
)
|
2016-12-06 10:11:48 +00:00
|
|
|
local dlist = { sync = self }
|
|
|
|
|
2010-12-11 23:00:33 +00:00
|
|
|
local dlistn = 1
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
local blocks = { }
|
2010-11-12 18:52:43 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-12 18:52:43 +00:00
|
|
|
-- inheritly transfers all blocks from delay
|
|
|
|
--
|
2016-12-13 15:37:57 +00:00
|
|
|
local function getBlocks
|
|
|
|
(
|
|
|
|
delay
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
blocks[ delay ] = true
|
2016-12-06 10:11:48 +00:00
|
|
|
|
|
|
|
if delay.blocks
|
|
|
|
then
|
2016-12-12 18:53:44 +00:00
|
|
|
for _, d in ipairs( delay.blocks )
|
2016-12-06 10:11:48 +00:00
|
|
|
do
|
2012-10-03 07:23:18 +00:00
|
|
|
getBlocks( d )
|
2010-11-13 18:04:37 +00:00
|
|
|
end
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
for _, d in self.delays:qpairs( )
|
2016-12-06 10:11:48 +00:00
|
|
|
do
|
2017-01-03 14:30:13 +00:00
|
|
|
local tr = true
|
|
|
|
|
|
|
|
if test
|
|
|
|
then
|
|
|
|
tr = test( InletFactory.d2e( d ) )
|
|
|
|
end
|
|
|
|
|
2018-02-27 16:14:36 +00:00
|
|
|
if tr == 'break' then break end
|
2017-01-03 14:30:13 +00:00
|
|
|
|
|
|
|
if d.status == 'active' or not tr
|
2010-11-13 18:04:37 +00:00
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
getBlocks( d )
|
2016-12-06 10:11:48 +00:00
|
|
|
elseif not blocks[ d ]
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
dlist[ dlistn ] = d
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2010-12-11 23:00:33 +00:00
|
|
|
dlistn = dlistn + 1
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2010-11-12 18:52:43 +00:00
|
|
|
return dlist
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-07 01:06:08 +00:00
|
|
|
-- Creates new actions
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function invokeActions
|
|
|
|
(
|
|
|
|
self,
|
|
|
|
timestamp
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
|
|
|
'Function',
|
2012-10-05 07:41:46 +00:00
|
|
|
'invokeActions( "',
|
|
|
|
self.config.name, '", ',
|
|
|
|
timestamp,
|
|
|
|
' )'
|
2012-10-03 07:23:18 +00:00
|
|
|
)
|
2021-12-10 14:05:30 +00:00
|
|
|
if self.disabled
|
|
|
|
then
|
|
|
|
return
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
-- tunnel configured but not up
|
|
|
|
if self.config.tunnel and
|
|
|
|
self.config.tunnel:isReady() == false then
|
|
|
|
log('Tunnel', 'Tunnel for Sync ', self.config.name, ' not ready. Blocking events')
|
|
|
|
self.config.tunnel:blockSync(self)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2016-12-01 12:25:49 +00:00
|
|
|
if self.processes:size( ) >= self.config.maxProcesses
|
|
|
|
then
|
2010-11-08 12:14:10 +00:00
|
|
|
-- no new processes
|
2010-11-07 01:06:08 +00:00
|
|
|
return
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-03-25 18:01:19 +00:00
|
|
|
if self.nextCronAlarm ~= false and self.nextCronAlarm < timestamp then
|
|
|
|
-- time fo a full sync
|
|
|
|
log('Info', 'Crontab triggered full sync')
|
2022-11-11 14:11:09 +00:00
|
|
|
self.inlet.createFullEvent("/")
|
2022-03-25 18:01:19 +00:00
|
|
|
updateNextCronAlarm(self, timestamp)
|
|
|
|
end
|
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
for _, d in self.delays:qpairs( )
|
2016-12-01 12:25:49 +00:00
|
|
|
do
|
2011-08-18 13:29:18 +00:00
|
|
|
-- if reached the global limit return
|
2016-12-13 13:41:35 +00:00
|
|
|
if uSettings.maxProcesses
|
|
|
|
and processCount >= uSettings.maxProcesses
|
2012-10-03 07:23:18 +00:00
|
|
|
then
|
2012-01-27 13:01:00 +00:00
|
|
|
log('Alarm', 'at global process limit.')
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2011-08-18 13:29:18 +00:00
|
|
|
return
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
if self.delays:size( ) < self.config.maxDelays
|
2016-12-06 10:11:48 +00:00
|
|
|
then
|
2011-11-23 10:05:42 +00:00
|
|
|
-- time constrains are only concerned if not maxed
|
2010-11-12 20:55:22 +00:00
|
|
|
-- the delay FIFO already.
|
2016-12-06 10:11:48 +00:00
|
|
|
if d.alarm ~= true and timestamp < d.alarm
|
|
|
|
then
|
2010-11-12 20:55:22 +00:00
|
|
|
-- reached point in stack where delays are in future
|
|
|
|
return
|
|
|
|
end
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if d.status == 'wait'
|
|
|
|
then
|
2010-11-08 12:14:10 +00:00
|
|
|
-- found a waiting delay
|
2022-11-11 14:11:09 +00:00
|
|
|
if d.etype == 'Init' then
|
2012-10-03 07:23:18 +00:00
|
|
|
self.config.init( InletFactory.d2e( d ) )
|
2022-11-11 14:11:09 +00:00
|
|
|
elseif d.etype == 'Full' and self.config.full then
|
|
|
|
self.config.full( InletFactory.d2e( d ) )
|
|
|
|
else
|
|
|
|
self.config.action( self.inlet )
|
2011-08-18 13:29:18 +00:00
|
|
|
end
|
2012-10-05 07:41:46 +00:00
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if self.processes:size( ) >= self.config.maxProcesses
|
|
|
|
then
|
2010-11-08 12:14:10 +00:00
|
|
|
-- no further processes
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
2010-11-07 01:06:08 +00:00
|
|
|
end
|
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-12 18:52:43 +00:00
|
|
|
-- Gets the next event to be processed.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function getNextDelay
|
|
|
|
(
|
|
|
|
self,
|
|
|
|
timestamp
|
|
|
|
)
|
2016-12-14 15:29:33 +00:00
|
|
|
for i, d in self.delays:qpairs( )
|
2016-12-06 10:11:48 +00:00
|
|
|
do
|
2016-12-14 15:29:33 +00:00
|
|
|
if self.delays:size( ) < self.config.maxDelays
|
2016-12-06 10:11:48 +00:00
|
|
|
then
|
2011-11-23 10:05:42 +00:00
|
|
|
-- time constrains are only concerned if not maxed
|
2010-11-12 20:55:22 +00:00
|
|
|
-- the delay FIFO already.
|
2016-12-06 10:11:48 +00:00
|
|
|
if d.alarm ~= true and timestamp < d.alarm
|
|
|
|
then
|
2010-11-12 20:55:22 +00:00
|
|
|
-- reached point in stack where delays are in future
|
|
|
|
return nil
|
|
|
|
end
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if d.status == 'wait'
|
|
|
|
then
|
2010-11-12 18:52:43 +00:00
|
|
|
-- found a waiting delay
|
|
|
|
return d
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2010-11-07 01:06:08 +00:00
|
|
|
|
2016-12-02 15:24:07 +00:00
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
-- Adds and returns a blanket delay thats blocks all.
|
|
|
|
-- Used as custom marker.
|
2010-11-07 09:53:39 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function addBlanketDelay
|
|
|
|
(
|
|
|
|
self
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
local newd = Delay.new( 'Blanket', self, true, '' )
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
newd.dpos = self.delays:push( newd )
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2011-11-23 10:05:42 +00:00
|
|
|
return newd
|
2010-11-07 09:53:39 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2022-11-11 14:11:09 +00:00
|
|
|
--
|
|
|
|
-- Adds an full delay that will initiate a full transfer.
|
|
|
|
--
|
|
|
|
local function addFullDelay
|
|
|
|
(
|
|
|
|
self,
|
|
|
|
path
|
|
|
|
)
|
|
|
|
local newd = Delay.new( 'Full', self, true, path )
|
|
|
|
|
|
|
|
newd.dpos = self.delays:push( newd )
|
|
|
|
|
|
|
|
return newd
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
-- Adds and returns a blanket delay thats blocks all.
|
|
|
|
-- Used as startup marker to call init asap.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function addInitDelay
|
|
|
|
(
|
|
|
|
self
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
local newd = Delay.new( 'Init', self, true, '' )
|
2012-10-05 07:41:46 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
newd.dpos = self.delays:push( newd )
|
2012-10-05 07:41:46 +00:00
|
|
|
|
2011-11-23 10:05:42 +00:00
|
|
|
return newd
|
2011-08-18 13:29:18 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-12 10:07:58 +00:00
|
|
|
-- Writes a status report about delays in this sync.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function statusReport
|
|
|
|
(
|
|
|
|
self,
|
|
|
|
f
|
|
|
|
)
|
2012-01-27 13:01:00 +00:00
|
|
|
local spaces = ' '
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
f:write( self.config.name, ' source=', self.source, '\n' )
|
2016-12-06 10:11:48 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
f:write( 'There are ', self.delays:size( ), ' delays\n')
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-14 15:29:33 +00:00
|
|
|
for i, vd in self.delays:qpairs( )
|
2016-12-06 10:11:48 +00:00
|
|
|
do
|
2010-11-12 11:04:45 +00:00
|
|
|
local st = vd.status
|
2016-12-14 15:29:33 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
f:write( st, string.sub( spaces, 1, 7 - #st ) )
|
|
|
|
f:write( vd.etype, ' ' )
|
|
|
|
f:write( vd.path )
|
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if vd.path2
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
f:write( ' -> ',vd.path2 )
|
2010-11-12 10:07:58 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2012-01-27 13:01:00 +00:00
|
|
|
f:write('\n')
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-12 10:07:58 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-03-01 13:14:28 +00:00
|
|
|
f:write( 'Filtering:\n' )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-13 16:59:46 +00:00
|
|
|
local nothing = true
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-03-01 13:14:28 +00:00
|
|
|
if self.filters
|
|
|
|
then
|
|
|
|
for _, e in pairs( self.filters.list )
|
|
|
|
do
|
|
|
|
nothing = false
|
|
|
|
|
|
|
|
f:write( e.rule, ' ', e.pattern,'\n' )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if #self.excludes.list > 0
|
|
|
|
then
|
|
|
|
f:write( 'From excludes:\n' )
|
|
|
|
|
|
|
|
for t, p in pairs( self.excludes.list )
|
|
|
|
do
|
|
|
|
nothing = false
|
|
|
|
|
|
|
|
f:write( '- ', t,'\n' )
|
|
|
|
end
|
2010-11-13 16:59:46 +00:00
|
|
|
end
|
2016-12-06 10:11:48 +00:00
|
|
|
|
|
|
|
if nothing
|
|
|
|
then
|
2012-01-27 13:01:00 +00:00
|
|
|
f:write(' nothing.\n')
|
2010-11-13 16:59:46 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
f:write( '\n' )
|
2010-11-20 22:32:25 +00:00
|
|
|
end
|
2010-11-13 16:59:46 +00:00
|
|
|
|
2022-03-30 21:02:03 +00:00
|
|
|
--
|
|
|
|
-- Returns a debug string describing the Sync
|
|
|
|
--
|
|
|
|
local function debug
|
|
|
|
(
|
|
|
|
self
|
|
|
|
)
|
|
|
|
local rv = "<Sync "..self.config.name.." delays:"..self.delays:size( ).."> "
|
|
|
|
return rv
|
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
--
|
|
|
|
-- Returns substitude data for event
|
|
|
|
--
|
|
|
|
local function getSubstitutionData(self, event, data)
|
|
|
|
if self.config.tunnel then
|
|
|
|
data = self.config.tunnel:getSubstitutionData(event, data)
|
|
|
|
end
|
|
|
|
return data
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- Creates a new Sync.
|
2010-11-02 14:11:26 +00:00
|
|
|
--
|
2018-03-01 13:14:28 +00:00
|
|
|
local function new
|
|
|
|
(
|
|
|
|
config
|
|
|
|
)
|
2016-12-06 10:11:48 +00:00
|
|
|
local s =
|
|
|
|
{
|
2010-11-10 09:49:44 +00:00
|
|
|
-- fields
|
2010-11-02 14:11:26 +00:00
|
|
|
config = config,
|
2012-10-03 07:23:18 +00:00
|
|
|
delays = Queue.new( ),
|
2010-11-05 15:18:01 +00:00
|
|
|
source = config.source,
|
2012-10-03 07:23:18 +00:00
|
|
|
processes = CountArray.new( ),
|
|
|
|
excludes = Excludes.new( ),
|
2018-02-27 16:14:36 +00:00
|
|
|
filters = nil,
|
2021-12-10 14:05:30 +00:00
|
|
|
initDone = false,
|
|
|
|
disabled = false,
|
2022-03-11 06:11:39 +00:00
|
|
|
tunnelBlock = nil,
|
2022-03-25 18:01:19 +00:00
|
|
|
cron = nil,
|
|
|
|
nextCronAlarm = false,
|
2010-11-06 21:29:22 +00:00
|
|
|
|
|
|
|
-- functions
|
2010-11-13 19:22:05 +00:00
|
|
|
addBlanketDelay = addBlanketDelay,
|
2022-11-11 14:11:09 +00:00
|
|
|
addFullDelay = addFullDelay,
|
2010-11-13 19:22:05 +00:00
|
|
|
addExclude = addExclude,
|
2011-08-18 13:29:18 +00:00
|
|
|
addInitDelay = addInitDelay,
|
2018-02-27 16:14:36 +00:00
|
|
|
appendFilter = appendFilter,
|
2010-11-08 12:14:10 +00:00
|
|
|
collect = collect,
|
2010-12-04 12:17:07 +00:00
|
|
|
concerns = concerns,
|
2010-11-08 12:14:10 +00:00
|
|
|
delay = delay,
|
2022-03-30 21:02:03 +00:00
|
|
|
debug = debug,
|
2010-11-08 12:14:10 +00:00
|
|
|
getAlarm = getAlarm,
|
2010-11-12 18:52:43 +00:00
|
|
|
getDelays = getDelays,
|
2010-11-08 12:14:10 +00:00
|
|
|
getNextDelay = getNextDelay,
|
|
|
|
invokeActions = invokeActions,
|
2010-11-11 15:17:22 +00:00
|
|
|
removeDelay = removeDelay,
|
2010-11-13 19:22:05 +00:00
|
|
|
rmExclude = rmExclude,
|
2010-11-12 10:07:58 +00:00
|
|
|
statusReport = statusReport,
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
getSubstitutionData = getSubstitutionData,
|
2010-11-02 14:11:26 +00:00
|
|
|
}
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
s.inlet = InletFactory.newInlet( s )
|
2010-11-30 22:56:34 +00:00
|
|
|
|
2010-11-06 18:26:59 +00:00
|
|
|
-- provides a default name if needed
|
2016-12-06 10:11:48 +00:00
|
|
|
if not config.name
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
config.name = 'Sync' .. nextDefaultName
|
2010-11-06 18:26:59 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
-- increments defaults if a config name was given or not
|
|
|
|
-- so Sync{n} will be the n-th call to sync{}
|
2010-11-06 18:26:59 +00:00
|
|
|
nextDefaultName = nextDefaultName + 1
|
2010-11-13 16:59:46 +00:00
|
|
|
|
2018-02-27 16:14:36 +00:00
|
|
|
-- loads filters
|
|
|
|
if config.filter
|
|
|
|
then
|
|
|
|
local te = type( config.filter )
|
|
|
|
|
|
|
|
s.filters = Filters.new( )
|
|
|
|
|
|
|
|
if te == 'table'
|
|
|
|
then
|
|
|
|
s.filters:appendList( config.filter )
|
|
|
|
elseif te == 'string'
|
|
|
|
then
|
|
|
|
s.filters:append( config.filter )
|
|
|
|
else
|
|
|
|
error( 'type for filter must be table or string', 2 )
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2010-11-13 16:59:46 +00:00
|
|
|
-- loads exclusions
|
2016-12-06 10:11:48 +00:00
|
|
|
if config.exclude
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
local te = type( config.exclude )
|
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if te == 'table'
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
s.excludes:addList( config.exclude )
|
2016-12-06 10:11:48 +00:00
|
|
|
elseif te == 'string'
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
s.excludes:add( config.exclude )
|
2010-12-03 21:16:39 +00:00
|
|
|
else
|
2012-10-03 07:23:18 +00:00
|
|
|
error( 'type for exclude must be table or string', 2 )
|
2010-12-03 21:16:39 +00:00
|
|
|
end
|
2014-02-28 09:15:48 +00:00
|
|
|
|
2010-11-13 16:59:46 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-02-27 16:14:36 +00:00
|
|
|
if config.delay ~= nil
|
|
|
|
and ( type( config.delay ) ~= 'number' or config.delay < 0 )
|
2013-06-07 12:09:57 +00:00
|
|
|
then
|
|
|
|
error( 'delay must be a number and >= 0', 2 )
|
|
|
|
end
|
|
|
|
|
2018-02-27 16:14:36 +00:00
|
|
|
if config.filterFrom
|
|
|
|
then
|
|
|
|
if not s.filters then s.filters = Filters.new( ) end
|
|
|
|
|
|
|
|
s.filters:loadFile( config.filterFrom )
|
|
|
|
end
|
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if config.excludeFrom
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
s.excludes:loadFile( config.excludeFrom )
|
2010-11-13 16:59:46 +00:00
|
|
|
end
|
|
|
|
|
2022-03-25 18:01:19 +00:00
|
|
|
if config.crontab and loadCrontab() == false then
|
2022-06-03 03:06:50 +00:00
|
|
|
error("Sync ".. config.name.." uses a crontab, but lua-crontab dependency is not available", 0)
|
2022-03-25 18:01:19 +00:00
|
|
|
elseif config.crontab then
|
|
|
|
local cdata = {}
|
|
|
|
for i, v in ipairs( config.crontab ) do
|
|
|
|
local ok, cd = pcall(crontab.make_raw_cron_data_from_string, v)
|
|
|
|
if ok then
|
|
|
|
local props = crontab.make_cron_properties(cd)
|
|
|
|
local getter = crontab.make_next_occurrence_getter(props)
|
2022-06-03 03:06:50 +00:00
|
|
|
|
2022-03-25 18:01:19 +00:00
|
|
|
table.insert( cdata, getter )
|
|
|
|
else
|
2022-06-03 03:06:50 +00:00
|
|
|
error("Sync: "..config.name.." - crontab rule ".. i .." is not valid: ".. cd.. " . Rule: ".. v, 0)
|
2022-03-25 18:01:19 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
-- local ok, cron = pcall(crontab.make_crontab, cdata)
|
|
|
|
if #cdata then
|
|
|
|
s.cron = cdata
|
|
|
|
else
|
2022-11-10 03:20:54 +00:00
|
|
|
error("Can't parse crontab data: "..cdata, 0)
|
2022-03-25 18:01:19 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-11-06 18:26:59 +00:00
|
|
|
return s
|
2010-11-02 14:11:26 +00:00
|
|
|
end
|
|
|
|
|
2010-11-08 12:14:10 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- Public interface
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
return { new = new }
|
2012-10-03 07:23:18 +00:00
|
|
|
end )( )
|
2010-11-02 14:11:26 +00:00
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
--
|
2022-06-03 00:45:53 +00:00
|
|
|
-- Writes functions for the user for layer 3 configurations.
|
2022-03-11 06:11:39 +00:00
|
|
|
--
|
2022-06-03 00:45:53 +00:00
|
|
|
local functionWriter = ( function( )
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
--
|
|
|
|
-- All variables known to layer 3 configs.
|
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
local transVars = {
|
2022-06-03 00:45:53 +00:00
|
|
|
{ '%^pathname', 'event.pathname', 1 },
|
|
|
|
{ '%^pathdir', 'event.pathdir', 1 },
|
|
|
|
{ '%^path', 'event.path', 1 },
|
|
|
|
{ '%^sourcePathname', 'event.sourcePathname', 1 },
|
|
|
|
{ '%^sourcePathdir', 'event.sourcePathdir', 1 },
|
|
|
|
{ '%^sourcePath', 'event.sourcePath', 1 },
|
|
|
|
{ '%^source', 'event.source', 1 },
|
|
|
|
{ '%^targetPathname', 'event.targetPathname', 1 },
|
|
|
|
{ '%^targetPathdir', 'event.targetPathdir', 1 },
|
|
|
|
{ '%^targetPath', 'event.targetPath', 1 },
|
|
|
|
{ '%^target', 'event.target', 1 },
|
|
|
|
{ '%^o%.pathname', 'event.pathname', 1 },
|
|
|
|
{ '%^o%.path', 'event.path', 1 },
|
|
|
|
{ '%^o%.sourcePathname', 'event.sourcePathname', 1 },
|
|
|
|
{ '%^o%.sourcePathdir', 'event.sourcePathdir', 1 },
|
|
|
|
{ '%^o%.sourcePath', 'event.sourcePath', 1 },
|
|
|
|
{ '%^o%.targetPathname', 'event.targetPathname', 1 },
|
|
|
|
{ '%^o%.targetPathdir', 'event.targetPathdir', 1 },
|
|
|
|
{ '%^o%.targetPath', 'event.targetPath', 1 },
|
|
|
|
{ '%^d%.pathname', 'event2.pathname', 2 },
|
|
|
|
{ '%^d%.path', 'event2.path', 2 },
|
|
|
|
{ '%^d%.sourcePathname', 'event2.sourcePathname', 2 },
|
|
|
|
{ '%^d%.sourcePathdir', 'event2.sourcePathdir', 2 },
|
|
|
|
{ '%^d%.sourcePath', 'event2.sourcePath', 2 },
|
|
|
|
{ '%^d%.targetPathname', 'event2.targetPathname', 2 },
|
|
|
|
{ '%^d%.targetPathdir', 'event2.targetPathdir', 2 },
|
|
|
|
{ '%^d%.targetPath', 'event2.targetPath', 2 },
|
2022-03-11 06:11:39 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
--
|
|
|
|
-- Splits a user string into its arguments.
|
|
|
|
-- Returns a table of arguments
|
|
|
|
--
|
|
|
|
local function splitStr(
|
|
|
|
str -- a string where parameters are seperated by spaces.
|
|
|
|
)
|
|
|
|
local args = { }
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
while str ~= ''
|
|
|
|
do
|
|
|
|
-- break where argument stops
|
|
|
|
local bp = #str
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
-- in a quote
|
|
|
|
local inQuote = false
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
-- tests characters to be space and not within quotes
|
|
|
|
for i = 1, #str
|
|
|
|
do
|
|
|
|
local c = string.sub( str, i, i )
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if c == '"'
|
|
|
|
then
|
|
|
|
inQuote = not inQuote
|
|
|
|
elseif c == ' ' and not inQuote
|
|
|
|
then
|
|
|
|
bp = i - 1
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
local arg = string.sub( str, 1, bp )
|
|
|
|
arg = string.gsub( arg, '"', '\\"' )
|
|
|
|
table.insert( args, arg )
|
|
|
|
str = string.sub( str, bp + 1, -1 )
|
|
|
|
str = string.match( str, '^%s*(.-)%s*$' )
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
end
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
return args
|
|
|
|
end
|
2022-03-11 06:11:39 +00:00
|
|
|
|
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
--
|
|
|
|
-- Translates a call to a binary to a lua function.
|
|
|
|
-- TODO this has a little too blocking.
|
|
|
|
--
|
|
|
|
local function translateBinary
|
|
|
|
(
|
|
|
|
str
|
|
|
|
)
|
|
|
|
-- splits the string
|
|
|
|
local args = splitStr( str )
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
-- true if there is a second event
|
|
|
|
local haveEvent2 = false
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
for ia, iv in ipairs( args )
|
|
|
|
do
|
|
|
|
-- a list of arguments this arg is being split into
|
|
|
|
local a = { { true, iv } }
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
-- goes through all translates
|
|
|
|
for _, v in ipairs( transVars )
|
|
|
|
do
|
|
|
|
local ai = 1
|
|
|
|
while ai <= #a
|
|
|
|
do
|
|
|
|
if a[ ai ][ 1 ]
|
|
|
|
then
|
|
|
|
local pre, post =
|
|
|
|
string.match( a[ ai ][ 2 ], '(.*)'..v[1]..'(.*)' )
|
2022-03-17 01:25:27 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if pre
|
|
|
|
then
|
|
|
|
if v[3] > 1
|
|
|
|
then
|
|
|
|
haveEvent2 = true
|
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if pre ~= ''
|
|
|
|
then
|
|
|
|
table.insert( a, ai, { true, pre } )
|
|
|
|
ai = ai + 1
|
|
|
|
end
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
a[ ai ] = { false, v[ 2 ] }
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if post ~= ''
|
|
|
|
then
|
|
|
|
table.insert( a, ai + 1, { true, post } )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
ai = ai + 1
|
|
|
|
end
|
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
-- concats the argument pieces into a string.
|
|
|
|
local as = ''
|
|
|
|
local first = true
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
for _, v in ipairs( a )
|
|
|
|
do
|
|
|
|
if not first then as = as..' .. ' end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if v[ 1 ]
|
|
|
|
then
|
|
|
|
as = as .. '"' .. v[ 2 ] .. '"'
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
else
|
2022-06-03 00:45:53 +00:00
|
|
|
as = as .. v[ 2 ]
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
end
|
2022-06-03 00:45:53 +00:00
|
|
|
|
|
|
|
first = false
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
end
|
2022-06-03 00:45:53 +00:00
|
|
|
|
|
|
|
args[ ia ] = as
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
end
|
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
local ft
|
|
|
|
|
|
|
|
if not haveEvent2
|
|
|
|
then
|
|
|
|
ft = 'function( event )\n'
|
|
|
|
else
|
|
|
|
ft = 'function( event, event2 )\n'
|
|
|
|
end
|
|
|
|
|
|
|
|
ft = ft ..
|
|
|
|
" log('Normal', 'Event ', event.etype, \n" ..
|
|
|
|
" ' spawns action \"".. str.."\"')\n" ..
|
|
|
|
" spawn( event"
|
|
|
|
|
|
|
|
for _, v in ipairs( args )
|
|
|
|
do
|
|
|
|
ft = ft .. ',\n ' .. v
|
|
|
|
end
|
|
|
|
|
|
|
|
ft = ft .. ')\nend'
|
|
|
|
return ft
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Translates a call using a shell to a lua function
|
|
|
|
--
|
|
|
|
local function translateShell
|
|
|
|
(
|
|
|
|
str
|
|
|
|
)
|
|
|
|
local argn = 1
|
|
|
|
|
|
|
|
local args = { }
|
|
|
|
|
|
|
|
local cmd = str
|
|
|
|
|
|
|
|
local lc = str
|
|
|
|
|
|
|
|
-- true if there is a second event
|
|
|
|
local haveEvent2 = false
|
|
|
|
|
|
|
|
for _, v in ipairs( transVars )
|
|
|
|
do
|
|
|
|
local occur = false
|
|
|
|
|
|
|
|
cmd = string.gsub(
|
|
|
|
cmd,
|
|
|
|
v[ 1 ],
|
|
|
|
function
|
|
|
|
( )
|
|
|
|
occur = true
|
|
|
|
return '"$' .. argn .. '"'
|
|
|
|
end
|
|
|
|
)
|
|
|
|
|
|
|
|
lc = string.gsub( lc, v[1], ']]..' .. v[2] .. '..[[' )
|
|
|
|
|
|
|
|
if occur
|
|
|
|
then
|
|
|
|
argn = argn + 1
|
|
|
|
|
|
|
|
table.insert( args, v[ 2 ] )
|
|
|
|
|
|
|
|
if v[ 3 ] > 1
|
|
|
|
then
|
|
|
|
haveEvent2 = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
local ft
|
|
|
|
|
|
|
|
if not haveEvent2
|
|
|
|
then
|
|
|
|
ft = 'function( event )\n'
|
|
|
|
else
|
|
|
|
ft = 'function( event, event2 )\n'
|
|
|
|
end
|
|
|
|
|
|
|
|
-- TODO do array joining instead
|
|
|
|
ft = ft..
|
|
|
|
" log('Normal', 'Event ',event.etype,\n"..
|
|
|
|
" [[ spawns shell \""..lc.."\"]])\n"..
|
|
|
|
" spawnShell(event, [["..cmd.."]]"
|
|
|
|
|
|
|
|
for _, v in ipairs( args )
|
|
|
|
do
|
|
|
|
ft = ft..',\n '..v
|
|
|
|
end
|
|
|
|
|
|
|
|
ft = ft .. ')\nend'
|
|
|
|
|
|
|
|
return ft
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Writes a lua function for a layer 3 user script.
|
|
|
|
--
|
|
|
|
local function translate
|
|
|
|
(
|
|
|
|
str
|
|
|
|
)
|
|
|
|
-- trims spaces
|
|
|
|
str = string.match( str, '^%s*(.-)%s*$' )
|
|
|
|
|
|
|
|
local ft
|
|
|
|
|
|
|
|
if string.byte( str, 1, 1 ) == 47
|
|
|
|
then
|
|
|
|
-- starts with /
|
|
|
|
ft = translateBinary( str )
|
|
|
|
elseif string.byte( str, 1, 1 ) == 94
|
|
|
|
then
|
|
|
|
-- starts with ^
|
|
|
|
ft = translateShell( str:sub( 2, -1 ) )
|
|
|
|
else
|
|
|
|
ft = translateShell( str )
|
|
|
|
end
|
|
|
|
|
|
|
|
log( 'FWrite', 'translated "', str, '" to \n', ft )
|
|
|
|
|
|
|
|
return ft
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Public interface.
|
|
|
|
--
|
|
|
|
return {
|
|
|
|
translate = translate,
|
|
|
|
splitStr = splitStr
|
|
|
|
}
|
|
|
|
|
|
|
|
end )( )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Basic Tunnel provider.
|
|
|
|
--
|
|
|
|
Tunnel = (function()
|
|
|
|
|
|
|
|
Tunnel = {}
|
|
|
|
|
|
|
|
local TUNNEL_CMD_TYPES = {
|
|
|
|
CMD = 1,
|
|
|
|
CHK = 2
|
|
|
|
}
|
|
|
|
|
|
|
|
local TUNNEL_STATUS = {
|
|
|
|
UNKNOWN = 0,
|
|
|
|
DOWN = 1,
|
|
|
|
DISABLED = 2,
|
|
|
|
CONNECTING = 3,
|
|
|
|
UP = 4,
|
|
|
|
RETRY_TIMEOUT = 5,
|
|
|
|
UP_RETRY_TIMEOUT = 6,
|
|
|
|
}
|
|
|
|
|
|
|
|
local TUNNEL_MODES = {
|
|
|
|
COMMAND = "command",
|
|
|
|
POOL = "pool",
|
|
|
|
}
|
|
|
|
|
|
|
|
local TUNNEL_DISTRIBUTION = {
|
|
|
|
ROUNDROBIN = "rr",
|
|
|
|
}
|
|
|
|
|
|
|
|
local TUNNEL_SUBSTITIONS = {
|
|
|
|
"localhost",
|
|
|
|
"localport"
|
|
|
|
}
|
|
|
|
|
|
|
|
local nextTunnelName = 1
|
|
|
|
|
|
|
|
Tunnel.defaults = {
|
|
|
|
mode = TUNNEL_MODES.COMMAND,
|
|
|
|
parallel = 1,
|
|
|
|
distribution = TUNNEL_DISTRIBUTION.ROUNDROBIN,
|
|
|
|
command = nil,
|
|
|
|
checkCommand = nil,
|
|
|
|
checkExitCodes = {0},
|
|
|
|
checkMaxFailed = 5,
|
|
|
|
retryDelay = 10,
|
|
|
|
readyDelay = 5,
|
|
|
|
localhost = 'localhost',
|
|
|
|
}
|
|
|
|
-- export constants
|
|
|
|
Tunnel.TUNNEL_CMD_TYPES = TUNNEL_CMD_TYPES
|
|
|
|
Tunnel.TUNNEL_STATUS = TUNNEL_STATUS
|
|
|
|
Tunnel.TUNNEL_MODES = TUNNEL_MODES
|
|
|
|
Tunnel.TUNNEL_DISTRIBUTION = TUNNEL_DISTRIBUTION
|
|
|
|
Tunnel.TUNNEL_SUBSTITIONS = TUNNEL_SUBSTITIONS
|
|
|
|
|
|
|
|
function Tunnel.new(
|
|
|
|
options
|
|
|
|
)
|
|
|
|
local rv = {
|
|
|
|
processes = CountArray.new( ),
|
|
|
|
blocks = {},
|
|
|
|
ready = false,
|
|
|
|
retryCount = 0,
|
|
|
|
status = TUNNEL_STATUS.DOWN,
|
|
|
|
alarm = true,
|
|
|
|
rrCounter = 0,
|
|
|
|
}
|
|
|
|
-- provides a default name if needed
|
|
|
|
if options.name == nil
|
|
|
|
then
|
|
|
|
options.name = 'Tunnel' .. nextTunnelName
|
|
|
|
end
|
|
|
|
|
|
|
|
nextTunnelName = nextTunnelName + 1
|
|
|
|
|
|
|
|
inherit(options, Tunnel.defaults)
|
|
|
|
|
|
|
|
rv.options = options
|
|
|
|
|
|
|
|
inherit(rv, Tunnel)
|
|
|
|
|
|
|
|
--setmetatable(rv, Tunnel)
|
|
|
|
-- self.__index = self
|
|
|
|
|
|
|
|
return rv
|
|
|
|
end
|
|
|
|
|
|
|
|
function Tunnel.statusToText(status)
|
|
|
|
for n, i in pairs(TUNNEL_STATUS) do
|
|
|
|
if status == i then
|
|
|
|
return n
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return TUNNEL_STATUS.UNKNOWN
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Returns the status of tunnel as text
|
|
|
|
function Tunnel:statusText()
|
|
|
|
return Tunnel.statusToText(self.status)
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Returns next alarm
|
|
|
|
--
|
|
|
|
function Tunnel:getAlarm()
|
|
|
|
return self.alarm
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- User supplied function to check if tunnel is up
|
|
|
|
function Tunnel:check()
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
function Tunnel:isReady()
|
|
|
|
return self.status == TUNNEL_STATUS.UP or
|
|
|
|
self.status == TUNNEL_STATUS.UP_RETRY_TIMEOUT
|
|
|
|
end
|
|
|
|
|
|
|
|
function Tunnel:setStatus(status)
|
|
|
|
log('Tunnel',self.options.name,': status change: ',
|
|
|
|
self:statusText(), " -> ", Tunnel.statusToText(status))
|
|
|
|
self.status = status
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Returns the number of processes currently running
|
|
|
|
--
|
|
|
|
function Tunnel:countProcs(timestamp)
|
|
|
|
local run = 0
|
|
|
|
local starting = 0
|
|
|
|
local dead = 0
|
|
|
|
if timestamp == nil then
|
|
|
|
timestamp = now()
|
|
|
|
end
|
|
|
|
|
|
|
|
for pid, pd in self.processes:walk() do
|
|
|
|
if pd.type == TUNNEL_CMD_TYPES.CMD then
|
|
|
|
-- process needs to run for at least some time
|
|
|
|
if lsyncd.kill(pid, 0) ~= 0 then
|
|
|
|
dead = dead + 1
|
|
|
|
elseif (pd.started + self.options.readyDelay) > timestamp then
|
|
|
|
starting = starting + 1
|
|
|
|
else
|
|
|
|
pd.ready = true
|
|
|
|
run = run + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return run, starting, dead
|
|
|
|
end
|
2022-03-11 06:11:39 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Check if the tunnel is up
|
|
|
|
function Tunnel:invoke(timestamp)
|
|
|
|
-- lsyncd.kill()
|
2022-03-17 01:27:02 +00:00
|
|
|
if self:check() == false then
|
|
|
|
-- check failed, consider tunnel broken
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self:setStatus(TUNNEL_STATUS.DOWN)
|
2022-03-17 01:27:02 +00:00
|
|
|
end
|
|
|
|
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
if self.status == TUNNEL_STATUS.RETRY_TIMEOUT then
|
|
|
|
if self.alarm <= timestamp then
|
2022-03-11 06:11:39 +00:00
|
|
|
log(
|
|
|
|
'Tunnel',
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
'Retry setup ', self.options.name
|
2022-03-11 06:11:39 +00:00
|
|
|
)
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self:start()
|
|
|
|
return
|
2022-03-11 06:11:39 +00:00
|
|
|
else
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
-- timeout not yet reached
|
2022-03-11 06:11:39 +00:00
|
|
|
self.alarm = now() + 1
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
return
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
elseif self.status == TUNNEL_STATUS.DOWN then
|
|
|
|
self:start()
|
|
|
|
return
|
|
|
|
elseif self.status == TUNNEL_STATUS.DISABLED then
|
|
|
|
self.alarm = false
|
|
|
|
return
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
|
|
|
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
local parallel = self.options.parallel
|
|
|
|
local run, starting, dead = self:countProcs(timestamp)
|
|
|
|
|
|
|
|
-- check if enough child processes are running
|
|
|
|
if self.status == TUNNEL_STATUS.CONNECTING then
|
|
|
|
if run > 0 then
|
2022-03-16 00:12:42 +00:00
|
|
|
log(
|
|
|
|
'Tunnel',
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
'Setup of tunnel ', self.options.name, ' sucessfull'
|
2022-03-16 00:12:42 +00:00
|
|
|
)
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self:setStatus(TUNNEL_STATUS.UP)
|
|
|
|
self:unblockSyncs()
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
elseif self.status == TUNNEL_STATUS.UP and run == 0 then
|
|
|
|
-- no good process running, degrade
|
|
|
|
log(
|
|
|
|
'Tunnel',
|
|
|
|
'Tunnel ', self.options.name, ' changed to CONNECTING'
|
|
|
|
)
|
|
|
|
self:setStatus(TUNNEL_STATUS.CONNECTING)
|
|
|
|
end
|
|
|
|
|
|
|
|
local spawned = 0
|
|
|
|
-- start more processes if necesarry
|
|
|
|
while run + starting + spawned < self.options.parallel do
|
|
|
|
self:spawn()
|
|
|
|
spawned = spawned + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
-- trigger next delay
|
|
|
|
if starting + spawned == 0 then
|
2022-03-16 00:12:42 +00:00
|
|
|
self.alarm = false
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
else
|
|
|
|
self.alarm = now() + 1
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Check if Sync is already blocked by Tunnel
|
|
|
|
function Tunnel:getBlockerForSync(
|
|
|
|
sync
|
|
|
|
)
|
|
|
|
for _, eblock in ipairs(self.blocks) do
|
|
|
|
if eblock.sync == sync then
|
|
|
|
return eblock
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Create a block on the sync until the tunnel reaches ready state
|
|
|
|
function Tunnel:blockSync(
|
|
|
|
sync
|
|
|
|
)
|
|
|
|
local block = self:getBlockerForSync(sync)
|
|
|
|
|
|
|
|
if block then
|
|
|
|
-- delay the block by another second
|
|
|
|
block:wait( now( ) + 1 )
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local block = sync:addBlanketDelay()
|
|
|
|
sync.tunnelBlock = block
|
|
|
|
|
|
|
|
table.insert (self.blocks, block)
|
|
|
|
-- set the new delay to be a block for existing delays
|
|
|
|
for _, eblock in sync.delays:qpairs() do
|
|
|
|
if eblock ~= block then
|
|
|
|
eblock:blockedBy(block)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
-- delay tunnel check by 1 second
|
2022-03-16 00:12:42 +00:00
|
|
|
block:wait( now( ) + 1 )
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Create a block on the sync until the tunnel reaches ready state
|
|
|
|
function Tunnel:unblockSyncs()
|
|
|
|
for i,blk in ipairs(self.blocks) do
|
|
|
|
blk.sync:removeDelay(blk)
|
|
|
|
blk.sync.tunnelBlock = nil
|
|
|
|
end
|
|
|
|
self.blocks = {}
|
|
|
|
end
|
|
|
|
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
--
|
|
|
|
-- Spawn a single tunnel program
|
|
|
|
--
|
|
|
|
function Tunnel:spawn()
|
|
|
|
local opts = {
|
|
|
|
type = TUNNEL_CMD_TYPES.CMD,
|
|
|
|
started = now(),
|
|
|
|
localhost = self.options.localhost,
|
|
|
|
ready = false,
|
|
|
|
}
|
|
|
|
local cmd = self.options.command
|
|
|
|
|
|
|
|
if self.options.mode == TUNNEL_MODES.POOL then
|
|
|
|
opts.localport = lsyncd.get_free_port()
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
2022-06-03 00:45:53 +00:00
|
|
|
if type(cmd) == "string" then
|
|
|
|
cmd = functionWriter.splitStr(cmd)
|
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
cmd = substitudeCommands(cmd, opts)
|
2022-03-16 00:12:42 +00:00
|
|
|
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
if #cmd < 1 then
|
|
|
|
log('Error',
|
|
|
|
'',
|
|
|
|
self.options
|
2022-03-11 06:11:39 +00:00
|
|
|
)
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
error( 'start tunnel of mode command with empty command', 2 )
|
|
|
|
-- FIXME: add line which tunnel was called
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
local bin = cmd[1]
|
|
|
|
-- for _,v in ipairs(cmd) do
|
|
|
|
-- if type( v ) ~= 'string' then
|
|
|
|
-- error( 'tunnel command must be a list of strings', 2 )
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
log(
|
|
|
|
'Info',
|
|
|
|
'Start tunnel command ',
|
|
|
|
cmd
|
|
|
|
)
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line: param-type-mismatch
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
local pid = lsyncd.exec(bin, table.unpack(cmd, 2))
|
|
|
|
--local pid = spawn(bin, table.unpack(self.options.command, 2))
|
|
|
|
if pid and pid > 0 then
|
|
|
|
self.processes[pid] = opts
|
|
|
|
self.retryCount = 0
|
|
|
|
self.alarm = now() + 1
|
|
|
|
else
|
|
|
|
self.alarm = now() + self.options.retryDelay
|
|
|
|
if self.status == TUNNEL_STATUS.UP then
|
|
|
|
self:setStatus(TUNNEL_STATUS.UP_RETRY_TIMEOUT)
|
2022-03-11 06:11:39 +00:00
|
|
|
else
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self:setStatus(TUNNEL_STATUS.RETRY_TIMEOUT)
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function Tunnel:start()
|
|
|
|
if self.status == TUNNEL_STATUS.UP or
|
|
|
|
self.status == TUNNEL_STATUS.CONNECTING then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if self.options.mode == TUNNEL_MODES.COMMAND or
|
|
|
|
self.options.mode == TUNNEL_MODES.POOL then
|
2022-03-11 06:11:39 +00:00
|
|
|
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self:setStatus(TUNNEL_STATUS.CONNECTING)
|
|
|
|
self:invoke(now())
|
2022-03-11 06:11:39 +00:00
|
|
|
else
|
|
|
|
error('unknown tunnel mode:' .. self.options.mode)
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self:setStatus(TUNNEL_STATUS.DISABLED)
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- collect pids of exited child processes. Restart the tunnel if necessary
|
|
|
|
---
|
|
|
|
function Tunnel:collect (
|
|
|
|
pid,
|
|
|
|
exitcode
|
|
|
|
)
|
2022-03-16 00:12:42 +00:00
|
|
|
local proc = self.processes[pid]
|
|
|
|
|
|
|
|
if proc == nil then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
log('Debug',
|
|
|
|
"collect tunnel event. pid: ", pid," exitcode: ", exitcode)
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
local run, starting, dead = self:countProcs()
|
2022-03-11 06:11:39 +00:00
|
|
|
-- cases in which the tunnel command is handled
|
2022-03-16 00:12:42 +00:00
|
|
|
if proc.type == TUNNEL_CMD_TYPES.CMD then
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
if self.status == TUNNEL_STATUS.CONNECTING then
|
2022-03-11 06:11:39 +00:00
|
|
|
log(
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
'Warning',
|
|
|
|
'Starting tunnel failed.',
|
|
|
|
self.options.name
|
2022-03-11 06:11:39 +00:00
|
|
|
)
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self:setStatus(TUNNEL_STATUS.RETRY_TIMEOUT)
|
|
|
|
self.alarm = now() + self.options.retryDelay
|
2022-03-11 06:11:39 +00:00
|
|
|
else
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
log(
|
|
|
|
'Info',
|
|
|
|
'Tunnel died. Will Restarting',
|
2022-03-11 06:11:39 +00:00
|
|
|
self.options.name
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
)
|
2022-03-16 00:12:42 +00:00
|
|
|
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
if run == 0 then
|
|
|
|
self:setStatus(TUNNEL_STATUS.DOWN)
|
2022-03-16 00:12:42 +00:00
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self.alarm = true
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
|
|
|
-- cases in which the check function has executed a program
|
2022-03-16 00:12:42 +00:00
|
|
|
elseif proc.type == TUNNEL_CMD_TYPES.CHK then
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
local good = false
|
2022-03-11 06:11:39 +00:00
|
|
|
if type(self.options.checkExitCodes) == 'table' then
|
|
|
|
|
2022-11-10 03:20:54 +00:00
|
|
|
for _,i in ipairs(self.options.checkExitCodes) do
|
2022-03-11 06:11:39 +00:00
|
|
|
if exitcode == i then
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
good = true
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if self.options.checkExitCodes == exitcode then
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
good = true
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
if good then
|
2022-11-10 03:20:54 +00:00
|
|
|
if self:isReady() == false then
|
2022-03-11 06:11:39 +00:00
|
|
|
log(
|
|
|
|
'Info',
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self.options.name,
|
|
|
|
' Tunnel setup complete '
|
2022-03-11 06:11:39 +00:00
|
|
|
)
|
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self:setStatus(TUNNEL_STATUS.UP)
|
|
|
|
self.checksFailed = 0
|
2022-03-11 06:11:39 +00:00
|
|
|
else
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
if self.ready then
|
2022-03-11 06:11:39 +00:00
|
|
|
log(
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
'Tunnel',
|
2022-03-11 06:11:39 +00:00
|
|
|
self.options.name
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
' Check failed.'
|
2022-03-11 06:11:39 +00:00
|
|
|
)
|
|
|
|
self.checksFailed = self.checksFailed + 1
|
|
|
|
if self.checksFailed > self.options.checkMaxFailed then
|
|
|
|
self:kill()
|
|
|
|
end
|
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self:setStatus(TUNNEL_STATUS.DOWN)
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
self.processes[pid] = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Stops all tunnel processes
|
|
|
|
--
|
|
|
|
function Tunnel:kill ()
|
2022-03-16 00:12:42 +00:00
|
|
|
log('Tunnel', 'Shutdown tunnel ', self.options.name)
|
|
|
|
for pid, pr in self.processes:walk() do
|
|
|
|
if pr.type == TUNNEL_CMD_TYPES.CMD then
|
|
|
|
log('Tunnel','Kill process ', pid)
|
2022-03-11 06:11:39 +00:00
|
|
|
lsyncd.kill(pid, 9)
|
|
|
|
end
|
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
self:setStatus(TUNNEL_STATUS.DISABLED)
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function Tunnel:isReady ()
|
|
|
|
return self.status == TUNNEL_STATUS.UP
|
|
|
|
end
|
|
|
|
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
--
|
|
|
|
-- Fills/changes the opts table with additional values
|
|
|
|
-- for the transfer to be started
|
|
|
|
--
|
|
|
|
function Tunnel:getSubstitutionData(event, opts)
|
|
|
|
local useProc, useProcLast = nil, nil
|
|
|
|
if self.options.mode == TUNNEL_MODES.POOL then
|
|
|
|
if self.options.distribution == TUNNEL_DISTRIBUTION.ROUNDROBIN then
|
|
|
|
local i = 0
|
|
|
|
for pid, proc in self.processes:walk() do
|
|
|
|
if proc.ready == true then
|
|
|
|
useProcLast = proc
|
|
|
|
if (i % self.processes:size()) == self.rrCounter then
|
|
|
|
useProc = proc
|
|
|
|
self.rrCounter = self.rrCounter + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if useProc == nil then
|
|
|
|
self.rrCounter = 0
|
|
|
|
useProc = useProcLast
|
|
|
|
end
|
|
|
|
else
|
|
|
|
log('Tunnel', 'Unknown distribution mode: ', self.options.distribution)
|
|
|
|
os.exit(1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if useProc then
|
|
|
|
for k,v in pairs(self.TUNNEL_SUBSTITIONS) do
|
|
|
|
if useProc[v] ~= nil then
|
|
|
|
opts[v] = useProc[v]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return opts
|
|
|
|
end
|
|
|
|
|
2022-03-17 01:25:27 +00:00
|
|
|
--
|
|
|
|
-- Writes a status report about this tunnel
|
|
|
|
--
|
|
|
|
function Tunnel:statusReport(f)
|
|
|
|
f:write( 'Tunnel: name=', self.options.name, ' status=', self:statusText(), '\n' )
|
|
|
|
|
|
|
|
f:write( 'Running processes: ', self.processes:size( ), '\n')
|
|
|
|
|
|
|
|
for pid, prc in self.processes:walk( )
|
|
|
|
do
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
f:write(" pid=", pid, " type=", prc.type, " started="..prc.started, '\n')
|
2022-03-17 01:25:27 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
f:write( '\n' )
|
|
|
|
end
|
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
return Tunnel
|
2022-03-17 01:25:27 +00:00
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
end)() -- Tunnel scope
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Tunnels - a singleton
|
|
|
|
--
|
|
|
|
-- Tunnels maintains all configured tunnels.
|
|
|
|
--
|
|
|
|
local Tunnels = ( function
|
|
|
|
( )
|
|
|
|
--
|
|
|
|
-- the list of all tunnels
|
|
|
|
--
|
|
|
|
local tunnelList = Array.new( )
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Returns sync at listpos i
|
|
|
|
--
|
|
|
|
local function get
|
|
|
|
( i )
|
|
|
|
return tunnelList[ i ];
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Adds a new tunnel.
|
|
|
|
--
|
|
|
|
local function add
|
|
|
|
(
|
|
|
|
tunnel
|
|
|
|
)
|
|
|
|
table.insert( tunnelList, tunnel )
|
2022-03-16 00:12:42 +00:00
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
return tunnel
|
|
|
|
end
|
2022-03-16 00:12:42 +00:00
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
--
|
|
|
|
-- Allows a for-loop to walk through all syncs.
|
|
|
|
--
|
|
|
|
local function iwalk
|
|
|
|
( )
|
|
|
|
return ipairs( tunnelList )
|
|
|
|
end
|
2022-03-16 00:12:42 +00:00
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
--
|
|
|
|
-- Returns the number of syncs.
|
|
|
|
--
|
|
|
|
local size = function
|
|
|
|
( )
|
|
|
|
return #tunnelList
|
|
|
|
end
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @type any
|
2022-03-30 21:07:45 +00:00
|
|
|
local nextCycle = true
|
2022-03-11 06:11:39 +00:00
|
|
|
--
|
|
|
|
-- Cycle through all tunnels and call their invoke function
|
|
|
|
--
|
|
|
|
local function invoke(timestamp)
|
|
|
|
for _,tunnel in ipairs( tunnelList )
|
|
|
|
do
|
|
|
|
tunnel:invoke(timestamp)
|
|
|
|
end
|
2022-03-30 21:07:45 +00:00
|
|
|
if size() > 0 then
|
|
|
|
nextCycle = now() + 5
|
|
|
|
else
|
|
|
|
nextCycle = false
|
|
|
|
end
|
2022-03-11 06:11:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- returns the next alarm
|
|
|
|
--
|
|
|
|
local function getAlarm()
|
|
|
|
local rv = nextCycle
|
|
|
|
for _, tunnel in ipairs( tunnelList ) do
|
|
|
|
local ta = tunnel:getAlarm()
|
2022-04-01 00:09:08 +00:00
|
|
|
if ta == true or (type(ta) == "userdata"
|
|
|
|
and ta < rv) then
|
2022-03-11 06:11:39 +00:00
|
|
|
rv = ta
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return rv
|
|
|
|
end
|
2022-03-16 00:12:42 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- closes all tunnels
|
|
|
|
--
|
|
|
|
local function killAll()
|
|
|
|
local rv = true
|
|
|
|
for _, tunnel in ipairs( tunnelList ) do
|
|
|
|
local ta = tunnel:kill()
|
|
|
|
if ta ~= true then
|
|
|
|
rv = false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return rv
|
|
|
|
end
|
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
--
|
|
|
|
-- Public interface
|
|
|
|
--
|
|
|
|
return {
|
|
|
|
add = add,
|
|
|
|
get = get,
|
|
|
|
iwalk = iwalk,
|
|
|
|
size = size,
|
|
|
|
invoke = invoke,
|
2022-03-16 00:12:42 +00:00
|
|
|
getAlarm = getAlarm,
|
2022-11-10 03:20:54 +00:00
|
|
|
killAll = killAll
|
2022-03-11 06:11:39 +00:00
|
|
|
}
|
|
|
|
end )( )
|
|
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
-- create a new tunnel from the passed options and registers the tunnel
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line: lowercase-global
|
2022-03-11 06:11:39 +00:00
|
|
|
tunnel = function (options)
|
|
|
|
log(
|
|
|
|
'Debug',
|
|
|
|
'create tunnel:', options
|
|
|
|
)
|
|
|
|
local rv = Tunnel.new(options)
|
|
|
|
Tunnels.add(rv)
|
2022-03-16 00:12:42 +00:00
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
return rv
|
|
|
|
|
|
|
|
end
|
2022-03-16 00:12:42 +00:00
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-06 10:10:00 +00:00
|
|
|
-- Syncs - a singleton
|
2011-11-23 10:05:42 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- Syncs maintains all configured syncs.
|
2010-11-02 14:11:26 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local Syncs = ( function
|
|
|
|
( )
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-06 10:33:26 +00:00
|
|
|
-- the list of all syncs
|
2010-11-06 18:26:59 +00:00
|
|
|
--
|
2012-10-06 11:43:55 +00:00
|
|
|
local syncsList = Array.new( )
|
2011-08-18 13:29:18 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2011-11-23 10:05:42 +00:00
|
|
|
-- The round robin pointer. In case of global limited maxProcesses
|
2011-08-18 13:29:18 +00:00
|
|
|
-- gives every sync equal chances to spawn the next process.
|
|
|
|
--
|
|
|
|
local round = 1
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2012-10-05 07:41:46 +00:00
|
|
|
-- The cycle( ) sheduler goes into the next round of roundrobin.
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function nextRound
|
|
|
|
( )
|
2011-08-18 13:29:18 +00:00
|
|
|
round = round + 1;
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-06 10:11:48 +00:00
|
|
|
if round > #syncsList
|
|
|
|
then
|
2011-08-18 13:29:18 +00:00
|
|
|
round = 1
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2011-08-18 13:29:18 +00:00
|
|
|
return round
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
-- Returns the round
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function getRound
|
|
|
|
( )
|
2011-08-18 13:29:18 +00:00
|
|
|
return round
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
-- Returns sync at listpos i
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function get
|
|
|
|
( i )
|
2012-10-06 11:43:55 +00:00
|
|
|
return syncsList[ i ];
|
2011-08-18 13:29:18 +00:00
|
|
|
end
|
|
|
|
|
2012-10-05 07:41:46 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- Adds a new sync.
|
2010-11-03 11:37:25 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function add
|
|
|
|
(
|
|
|
|
config
|
|
|
|
)
|
2016-12-01 11:52:09 +00:00
|
|
|
-- Checks if user overwrote the settings function.
|
|
|
|
-- ( was Lsyncd <2.1 style )
|
2016-08-29 11:15:29 +00:00
|
|
|
if settings ~= settingsSafe
|
|
|
|
then
|
2012-10-09 16:06:46 +00:00
|
|
|
log(
|
2016-12-01 11:52:09 +00:00
|
|
|
'Error',
|
|
|
|
'Do not use settings = { ... }\n'..
|
2012-10-09 16:06:46 +00:00
|
|
|
' please use settings{ ... } (without the equal sign)'
|
|
|
|
)
|
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
os.exit( -1 )
|
2012-10-09 16:06:46 +00:00
|
|
|
end
|
|
|
|
|
2012-10-06 11:43:55 +00:00
|
|
|
-- Creates a new config table which inherits all keys/values
|
2010-11-06 10:10:00 +00:00
|
|
|
-- from integer keyed tables
|
2010-11-03 15:53:20 +00:00
|
|
|
local uconfig = config
|
2012-10-06 11:43:55 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
config = { }
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
-- inherit the config but do not deep copy the tunnel object
|
|
|
|
-- the tunnel object is a reference to a object that might be shared
|
|
|
|
inherit( config, uconfig, nil, {"tunnel"} )
|
2012-10-06 11:43:55 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- last and least defaults are inherited
|
|
|
|
--
|
|
|
|
inherit( config, default )
|
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
-- copy references
|
|
|
|
config.tunnel = uconfig.tunnel
|
|
|
|
|
2012-10-06 11:43:55 +00:00
|
|
|
local inheritSettings = {
|
|
|
|
'delay',
|
|
|
|
'maxDelays',
|
|
|
|
'maxProcesses'
|
|
|
|
}
|
2012-10-07 19:40:05 +00:00
|
|
|
|
|
|
|
-- Lets settings override these values.
|
2016-08-29 11:15:29 +00:00
|
|
|
for _, v in ipairs( inheritSettings )
|
|
|
|
do
|
|
|
|
if uSettings[ v ]
|
|
|
|
then
|
2012-10-08 07:10:03 +00:00
|
|
|
config[ v ] = uSettings[ v ]
|
2012-10-06 11:43:55 +00:00
|
|
|
end
|
2010-11-28 20:16:56 +00:00
|
|
|
end
|
|
|
|
|
2012-10-07 19:40:05 +00:00
|
|
|
-- Lets commandline override these values.
|
2016-08-29 11:15:29 +00:00
|
|
|
for _, v in ipairs( inheritSettings )
|
|
|
|
do
|
|
|
|
if clSettings[ v ]
|
|
|
|
then
|
2012-10-08 07:10:03 +00:00
|
|
|
config[ v ] = clSettings[ v ]
|
2012-10-07 19:40:05 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-10-06 11:43:55 +00:00
|
|
|
--
|
|
|
|
-- lets the userscript 'prepare' function
|
|
|
|
-- check and complete the config
|
|
|
|
--
|
2016-08-29 11:15:29 +00:00
|
|
|
if type( config.prepare ) == 'function'
|
|
|
|
then
|
2012-10-06 11:43:55 +00:00
|
|
|
-- prepare is given a writeable copy of config
|
2012-10-06 12:22:08 +00:00
|
|
|
config.prepare( config, 4 )
|
2012-01-27 11:08:10 +00:00
|
|
|
end
|
2010-11-11 15:17:22 +00:00
|
|
|
|
2018-02-27 09:09:28 +00:00
|
|
|
if not config[ 'source' ]
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
local info = debug.getinfo( 3, 'Sl' )
|
2018-02-27 09:09:28 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
|
|
|
'Error',
|
|
|
|
info.short_src,':',
|
|
|
|
info.currentline,': source missing from sync.'
|
|
|
|
)
|
2018-02-27 09:09:28 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
terminate( -1 )
|
2010-11-02 20:18:05 +00:00
|
|
|
end
|
2011-11-23 10:05:42 +00:00
|
|
|
|
2012-10-06 11:43:55 +00:00
|
|
|
--
|
2010-11-02 14:11:26 +00:00
|
|
|
-- absolute path of source
|
2012-10-06 11:43:55 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
local realsrc = lsyncd.realdir( config.source )
|
|
|
|
|
2016-08-29 11:15:29 +00:00
|
|
|
if not realsrc
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
|
|
|
'Error',
|
|
|
|
'Cannot access source directory: ',
|
|
|
|
config.source
|
|
|
|
)
|
2018-02-27 09:09:28 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
terminate( -1 )
|
2010-11-02 14:11:26 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-06 10:10:00 +00:00
|
|
|
config._source = config.source
|
2010-11-10 22:03:02 +00:00
|
|
|
config.source = realsrc
|
2010-11-02 20:18:05 +00:00
|
|
|
|
2016-12-13 13:41:35 +00:00
|
|
|
if not config.action
|
|
|
|
and not config.onAttrib
|
|
|
|
and not config.onCreate
|
|
|
|
and not config.onModify
|
|
|
|
and not config.onDelete
|
|
|
|
and not config.onMove
|
2022-03-31 01:54:21 +00:00
|
|
|
and not config.onFull
|
2010-11-02 20:18:05 +00:00
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
local info = debug.getinfo( 3, 'Sl' )
|
2018-02-27 09:09:28 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
|
|
|
'Error',
|
|
|
|
info.short_src, ':',
|
|
|
|
info.currentline,
|
2012-10-05 07:41:46 +00:00
|
|
|
': no actions specified.'
|
2012-10-03 07:23:18 +00:00
|
|
|
)
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
terminate( -1 )
|
2010-11-02 20:18:05 +00:00
|
|
|
end
|
|
|
|
|
2010-11-28 10:47:57 +00:00
|
|
|
-- the monitor to use
|
2012-01-27 11:08:10 +00:00
|
|
|
config.monitor =
|
2012-10-08 07:10:03 +00:00
|
|
|
uSettings.monitor or
|
2012-10-03 07:23:18 +00:00
|
|
|
config.monitor or
|
|
|
|
Monitors.default( )
|
|
|
|
|
2016-12-13 13:41:35 +00:00
|
|
|
if config.monitor ~= 'inotify'
|
|
|
|
and config.monitor ~= 'fsevents'
|
2012-10-03 07:23:18 +00:00
|
|
|
then
|
|
|
|
local info = debug.getinfo( 3, 'Sl' )
|
|
|
|
|
|
|
|
log(
|
|
|
|
'Error',
|
|
|
|
info.short_src, ':',
|
|
|
|
info.currentline,
|
|
|
|
': event monitor "',
|
|
|
|
config.monitor,
|
|
|
|
'" unknown.'
|
|
|
|
)
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
terminate( -1 )
|
2010-11-28 10:47:57 +00:00
|
|
|
end
|
|
|
|
|
2016-12-02 15:24:07 +00:00
|
|
|
-- creates the new sync
|
2012-10-03 07:23:18 +00:00
|
|
|
local s = Sync.new( config )
|
2012-10-06 11:43:55 +00:00
|
|
|
|
|
|
|
table.insert( syncsList, s )
|
|
|
|
|
2010-11-30 22:56:34 +00:00
|
|
|
return s
|
2010-11-02 14:11:26 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
-- Allows a for-loop to walk through all syncs.
|
2010-11-06 18:26:59 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function iwalk
|
|
|
|
( )
|
2012-10-06 11:43:55 +00:00
|
|
|
return ipairs( syncsList )
|
2010-11-02 14:11:26 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
-- Returns the number of syncs.
|
2010-11-06 18:26:59 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local size = function
|
|
|
|
( )
|
2012-10-06 11:43:55 +00:00
|
|
|
return #syncsList
|
2010-11-02 14:11:26 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
-- Tests if any sync is interested in a path.
|
2010-12-04 12:17:07 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function concerns
|
2017-01-09 10:14:23 +00:00
|
|
|
(
|
|
|
|
path
|
|
|
|
)
|
2016-12-13 13:41:35 +00:00
|
|
|
for _, s in ipairs( syncsList )
|
|
|
|
do
|
|
|
|
if s:concerns( path )
|
|
|
|
then
|
2010-12-04 12:17:07 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-12-04 12:17:07 +00:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
|
|
|
-- Public interface
|
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
return {
|
|
|
|
add = add,
|
|
|
|
get = get,
|
|
|
|
getRound = getRound,
|
|
|
|
concerns = concerns,
|
2012-01-27 11:08:10 +00:00
|
|
|
iwalk = iwalk,
|
2011-08-18 13:29:18 +00:00
|
|
|
nextRound = nextRound,
|
|
|
|
size = size
|
|
|
|
}
|
2012-10-03 07:23:18 +00:00
|
|
|
end )( )
|
2010-10-25 17:38:57 +00:00
|
|
|
|
2010-11-11 18:34:44 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
|
|
|
-- Utility function,
|
|
|
|
-- Returns the relative part of absolute path if it
|
2010-11-20 13:10:52 +00:00
|
|
|
-- begins with root
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function splitPath
|
|
|
|
(
|
|
|
|
path,
|
|
|
|
root
|
|
|
|
)
|
2012-01-27 11:08:10 +00:00
|
|
|
local rlen = #root
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
local sp = string.sub( path, 1, rlen )
|
2010-11-20 13:10:52 +00:00
|
|
|
|
2016-12-13 13:41:35 +00:00
|
|
|
if sp == root
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
return string.sub( path, rlen, -1 )
|
2010-11-20 13:10:52 +00:00
|
|
|
else
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-06-03 00:47:23 +00:00
|
|
|
local function splitQuotedString
|
2021-12-08 17:21:16 +00:00
|
|
|
(
|
|
|
|
text
|
|
|
|
)
|
2022-11-10 03:20:54 +00:00
|
|
|
local spat, epat, buf, quoted = [=[^(['"])]=], [=[(['"])$]=], nil, nil
|
2021-12-08 17:21:16 +00:00
|
|
|
local rv = {}
|
|
|
|
for str in text:gmatch("%S+") do
|
|
|
|
local squoted = str:match(spat)
|
|
|
|
local equoted = str:match(epat)
|
|
|
|
local escaped = str:match([=[(\*)['"]$]=])
|
|
|
|
if squoted and not quoted and not equoted then
|
|
|
|
buf, quoted = str, squoted
|
|
|
|
elseif buf and equoted == quoted and #escaped % 2 == 0 then
|
|
|
|
str, buf, quoted = buf .. ' ' .. str, nil, nil
|
|
|
|
elseif buf then
|
|
|
|
buf = buf .. ' ' .. str
|
|
|
|
end
|
|
|
|
if not buf
|
|
|
|
then
|
|
|
|
table.insert(rv, (str:gsub(spat,""):gsub(epat,"")))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if buf
|
|
|
|
then
|
|
|
|
print("Missing matching quote for "..buf)
|
|
|
|
end
|
|
|
|
return rv
|
|
|
|
end
|
|
|
|
|
2022-06-03 00:47:23 +00:00
|
|
|
lsyncd.splitQuotedString = splitQuotedString
|
|
|
|
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line: lowercase-global
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
function substitudeCommands(cmd, data)
|
2022-03-16 16:38:03 +00:00
|
|
|
assert(type(data) == "table")
|
2022-06-03 00:47:36 +00:00
|
|
|
|
2022-03-16 16:38:03 +00:00
|
|
|
if type(cmd) == "string" then
|
2022-06-03 00:47:36 +00:00
|
|
|
local rv = cmd
|
|
|
|
for key,value in pairs(data) do
|
|
|
|
local getData = function()
|
|
|
|
return tostring(value)
|
|
|
|
end
|
|
|
|
rv = string.gsub(rv, "%^("..key..")", getData)
|
|
|
|
end
|
|
|
|
return rv
|
2022-03-16 16:38:03 +00:00
|
|
|
elseif type(cmd) == "table" then
|
|
|
|
local rv = {}
|
|
|
|
for i, v in ipairs(cmd) do
|
2022-06-03 00:47:36 +00:00
|
|
|
rv[i] = v
|
|
|
|
for key, value in pairs(data) do
|
|
|
|
local getData = function()
|
|
|
|
return tostring(value)
|
|
|
|
end
|
|
|
|
rv[i] = string.gsub(rv[i], "%^("..key..")", getData)
|
|
|
|
end
|
2022-03-16 16:38:03 +00:00
|
|
|
end
|
|
|
|
return rv
|
|
|
|
else
|
2022-06-03 00:47:36 +00:00
|
|
|
log("Error", "Unsupported type in substitudeCommands")
|
2022-03-16 16:38:03 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-10-28 17:56:33 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- Interface to inotify.
|
2010-10-21 12:37:27 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- watches recursively subdirs and sends events.
|
|
|
|
--
|
|
|
|
-- All inotify specific implementation is enclosed here.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local Inotify = ( function
|
|
|
|
( )
|
2010-11-20 13:10:52 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- A list indexed by inotify watch descriptors yielding
|
|
|
|
-- the directories absolute paths.
|
|
|
|
--
|
|
|
|
local wdpaths = CountArray.new( )
|
2010-11-09 19:15:41 +00:00
|
|
|
|
2010-11-03 11:37:25 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- The same vice versa,
|
|
|
|
-- all watch descriptors by their absolute paths.
|
|
|
|
--
|
|
|
|
local pathwds = { }
|
2010-11-17 18:52:55 +00:00
|
|
|
|
2010-11-20 13:10:52 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- A list indexed by syncs containing yielding
|
|
|
|
-- the root paths the syncs are interested in.
|
|
|
|
--
|
|
|
|
local syncRoots = { }
|
2012-01-27 11:08:10 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-24 19:21:43 +00:00
|
|
|
-- Stops watching a directory
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function removeWatch
|
|
|
|
(
|
|
|
|
path, -- absolute path to unwatch
|
|
|
|
core -- if false not actually send the unwatch to the kernel
|
|
|
|
-- ( used in moves which reuse the watch )
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
local wd = pathwds[ path ]
|
|
|
|
|
2016-12-13 13:41:35 +00:00
|
|
|
if not wd
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2016-12-13 13:41:35 +00:00
|
|
|
if core
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
lsyncd.inotify.rmwatch( wd )
|
|
|
|
end
|
|
|
|
|
|
|
|
wdpaths[ wd ] = nil
|
|
|
|
pathwds[ path ] = nil
|
2010-11-24 19:21:43 +00:00
|
|
|
end
|
2010-10-22 08:34:41 +00:00
|
|
|
|
2012-10-05 07:41:46 +00:00
|
|
|
|
|
|
|
--
|
2010-11-20 13:10:52 +00:00
|
|
|
-- Adds watches for a directory (optionally) including all subdirectories.
|
|
|
|
--
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function addWatch
|
|
|
|
(
|
|
|
|
path -- absolute path of directory to observe
|
|
|
|
)
|
2016-12-14 13:25:20 +00:00
|
|
|
log( 'Function', 'Inotify.addWatch( ', path, ' )' )
|
2010-11-17 18:52:55 +00:00
|
|
|
|
2017-01-09 10:14:23 +00:00
|
|
|
if not Syncs.concerns( path )
|
2016-12-05 14:11:00 +00:00
|
|
|
then
|
2017-01-09 10:14:23 +00:00
|
|
|
log('Inotify', 'not concerning "', path, '"')
|
2016-12-05 14:11:00 +00:00
|
|
|
|
2010-12-04 12:17:07 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2012-02-17 08:12:01 +00:00
|
|
|
-- registers the watch
|
2012-10-08 07:10:03 +00:00
|
|
|
local inotifyMode = ( uSettings and uSettings.inotifyMode ) or '';
|
|
|
|
|
2017-01-09 10:14:23 +00:00
|
|
|
local wd = lsyncd.inotify.addwatch( path, inotifyMode ) ;
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-05 14:11:00 +00:00
|
|
|
if wd < 0
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
log( 'Inotify','Unable to add watch "', path, '"' )
|
2017-01-09 10:14:23 +00:00
|
|
|
|
2010-11-24 19:21:43 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
do
|
2012-02-17 08:12:01 +00:00
|
|
|
-- If this watch descriptor is registered already
|
2016-12-13 13:41:35 +00:00
|
|
|
-- the kernel reuses it since the old dir is gone.
|
2012-10-03 07:23:18 +00:00
|
|
|
local op = wdpaths[ wd ]
|
2016-12-05 14:11:00 +00:00
|
|
|
|
|
|
|
if op and op ~= path
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
pathwds[ op ] = nil
|
2010-11-20 13:10:52 +00:00
|
|
|
end
|
2010-11-09 19:15:41 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
pathwds[ path ] = wd
|
2016-12-05 14:11:00 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
wdpaths[ wd ] = path
|
2010-11-03 11:37:25 +00:00
|
|
|
|
2012-01-27 11:08:10 +00:00
|
|
|
-- registers and adds watches for all subdirectories
|
2012-10-03 07:23:18 +00:00
|
|
|
local entries = lsyncd.readdir( path )
|
|
|
|
|
2016-12-05 14:11:00 +00:00
|
|
|
if not entries
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2016-12-05 14:11:00 +00:00
|
|
|
for dirname, isdir in pairs( entries )
|
|
|
|
do
|
|
|
|
if isdir
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
addWatch( path .. dirname .. '/' )
|
|
|
|
end
|
2010-11-03 11:37:25 +00:00
|
|
|
end
|
|
|
|
end
|
2010-10-25 14:55:40 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2012-01-31 14:01:11 +00:00
|
|
|
-- Adds a Sync to receive events.
|
2010-11-20 13:10:52 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function addSync
|
|
|
|
(
|
|
|
|
sync, -- object to receive events.
|
|
|
|
rootdir -- root dir to watch
|
|
|
|
)
|
|
|
|
if syncRoots[ sync ]
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
error( 'duplicate sync in Inotify.addSync()' )
|
|
|
|
end
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
syncRoots[ sync ] = rootdir
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
addWatch( rootdir )
|
2010-11-09 19:15:41 +00:00
|
|
|
end
|
|
|
|
|
2010-11-03 11:37:25 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- Called when an event has occured.
|
2010-11-03 11:37:25 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function event
|
|
|
|
(
|
2012-10-03 07:23:18 +00:00
|
|
|
etype, -- 'Attrib', 'Modify', 'Create', 'Delete', 'Move'
|
|
|
|
wd, -- watch descriptor, matches lsyncd.inotifyadd()
|
|
|
|
isdir, -- true if filename is a directory
|
|
|
|
time, -- time of event
|
|
|
|
filename, -- string filename without path
|
|
|
|
wd2, -- watch descriptor for target if it's a Move
|
|
|
|
filename2 -- string filename without path of Move target
|
|
|
|
)
|
2016-12-01 11:30:58 +00:00
|
|
|
if isdir
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
filename = filename .. '/'
|
|
|
|
|
2016-12-01 11:30:58 +00:00
|
|
|
if filename2
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
filename2 = filename2 .. '/'
|
|
|
|
end
|
|
|
|
end
|
2010-11-20 13:10:52 +00:00
|
|
|
|
2016-12-01 11:30:58 +00:00
|
|
|
if filename2
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
|
|
|
'Inotify',
|
|
|
|
'got event ',
|
|
|
|
etype,
|
|
|
|
' ',
|
|
|
|
filename,
|
|
|
|
'(', wd, ') to ',
|
|
|
|
filename2,
|
|
|
|
'(', wd2 ,')'
|
|
|
|
)
|
2012-01-27 11:08:10 +00:00
|
|
|
else
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
|
|
|
'Inotify',
|
|
|
|
'got event ',
|
|
|
|
etype,
|
|
|
|
' ',
|
|
|
|
filename,
|
|
|
|
'(', wd, ')'
|
|
|
|
)
|
2010-11-03 11:37:25 +00:00
|
|
|
end
|
2010-10-22 08:34:41 +00:00
|
|
|
|
2010-11-03 11:37:25 +00:00
|
|
|
-- looks up the watch descriptor id
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @type any
|
2012-10-03 07:23:18 +00:00
|
|
|
local path = wdpaths[ wd ]
|
2016-12-01 11:30:58 +00:00
|
|
|
|
|
|
|
if path
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
path = path..filename
|
|
|
|
end
|
2012-01-27 11:08:10 +00:00
|
|
|
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @type any
|
2012-10-03 07:23:18 +00:00
|
|
|
local path2 = wd2 and wdpaths[ wd2 ]
|
|
|
|
|
2016-12-01 11:30:58 +00:00
|
|
|
if path2 and filename2
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
path2 = path2..filename2
|
|
|
|
end
|
2012-01-27 11:08:10 +00:00
|
|
|
|
2016-12-01 11:30:58 +00:00
|
|
|
if not path and path2 and etype == 'Move'
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
|
|
|
'Inotify',
|
|
|
|
'Move from deleted directory ',
|
|
|
|
path2,
|
|
|
|
' becomes Create.'
|
|
|
|
)
|
2016-12-01 11:30:58 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
path = path2
|
2016-12-01 11:30:58 +00:00
|
|
|
|
2010-11-22 10:04:04 +00:00
|
|
|
path2 = nil
|
2016-12-01 11:30:58 +00:00
|
|
|
|
2012-01-31 14:01:11 +00:00
|
|
|
etype = 'Create'
|
2010-11-22 10:04:04 +00:00
|
|
|
end
|
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if not path
|
2016-12-01 11:30:58 +00:00
|
|
|
then
|
2022-06-03 00:45:53 +00:00
|
|
|
-- this is normal in case of deleted subdirs
|
|
|
|
log(
|
|
|
|
'Inotify',
|
|
|
|
'event belongs to unknown watch descriptor.'
|
|
|
|
)
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
return
|
2010-12-10 16:12:15 +00:00
|
|
|
end
|
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
for sync, root in pairs( syncRoots )
|
2016-12-01 11:30:58 +00:00
|
|
|
do repeat
|
2022-06-03 00:45:53 +00:00
|
|
|
local relative = splitPath( path, root )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
local relative2 = nil
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if path2
|
2016-12-01 11:30:58 +00:00
|
|
|
then
|
2022-06-03 00:45:53 +00:00
|
|
|
relative2 = splitPath( path2, root )
|
2010-12-10 15:30:45 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if not relative and not relative2
|
2016-12-01 11:30:58 +00:00
|
|
|
then
|
2022-06-03 00:45:53 +00:00
|
|
|
-- sync is not interested in this dir
|
|
|
|
break -- continue
|
2010-12-10 15:30:45 +00:00
|
|
|
end
|
2012-01-27 11:08:10 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
-- makes a copy of etype to possibly change it
|
2012-01-27 11:08:10 +00:00
|
|
|
local etyped = etype
|
2016-12-01 11:30:58 +00:00
|
|
|
|
|
|
|
if etyped == 'Move'
|
|
|
|
then
|
|
|
|
if not relative2
|
|
|
|
then
|
2022-06-03 00:45:53 +00:00
|
|
|
log(
|
|
|
|
'Normal',
|
|
|
|
'Transformed Move to Delete for ',
|
|
|
|
sync.config.name
|
|
|
|
)
|
2016-12-01 11:30:58 +00:00
|
|
|
|
2012-02-15 23:28:03 +00:00
|
|
|
etyped = 'Delete'
|
2016-12-01 11:30:58 +00:00
|
|
|
elseif not relative
|
|
|
|
then
|
2010-12-10 15:30:45 +00:00
|
|
|
relative = relative2
|
2016-12-01 11:30:58 +00:00
|
|
|
|
2010-12-10 15:30:45 +00:00
|
|
|
relative2 = nil
|
2016-12-01 11:30:58 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
log(
|
|
|
|
'Normal',
|
|
|
|
'Transformed Move to Create for ',
|
|
|
|
sync.config.name
|
|
|
|
)
|
2016-12-01 11:30:58 +00:00
|
|
|
|
2012-02-15 23:28:03 +00:00
|
|
|
etyped = 'Create'
|
2010-12-10 15:30:45 +00:00
|
|
|
end
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if isdir
|
|
|
|
then
|
|
|
|
if etyped == 'Create'
|
|
|
|
then
|
|
|
|
addWatch( path )
|
|
|
|
elseif etyped == 'Delete'
|
|
|
|
then
|
|
|
|
removeWatch( path, true )
|
|
|
|
elseif etyped == 'Move'
|
|
|
|
then
|
|
|
|
removeWatch( path, false )
|
|
|
|
addWatch( path2 )
|
2010-11-13 13:13:51 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
sync:delay( etyped, time, relative, relative2 )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
until true end
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
--
|
|
|
|
-- Writes a status report about inotify to a file descriptor
|
|
|
|
--
|
|
|
|
local function statusReport( f )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
f:write( 'Inotify watching ', wdpaths:size(), ' directories\n' )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
for wd, path in wdpaths:walk( )
|
|
|
|
do
|
|
|
|
f:write( ' ', wd, ': ', path, '\n' )
|
2010-11-13 13:13:51 +00:00
|
|
|
end
|
2022-06-03 00:45:53 +00:00
|
|
|
end
|
2010-11-13 13:13:51 +00:00
|
|
|
|
2018-02-27 16:14:36 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
--
|
|
|
|
-- Public interface.
|
|
|
|
--
|
|
|
|
return {
|
|
|
|
addSync = addSync,
|
|
|
|
event = event,
|
|
|
|
statusReport = statusReport,
|
|
|
|
}
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
end)( )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Interface to OSX /dev/fsevents
|
|
|
|
--
|
|
|
|
-- This watches all the filesystems at once,
|
|
|
|
-- but needs root access.
|
|
|
|
--
|
|
|
|
-- All fsevents specific implementation are enclosed here.
|
|
|
|
--
|
|
|
|
local Fsevents = ( function
|
|
|
|
( )
|
|
|
|
--
|
|
|
|
-- A list indexed by syncs yielding
|
|
|
|
-- the root path the sync is interested in.
|
|
|
|
--
|
|
|
|
local syncRoots = { }
|
|
|
|
|
|
|
|
--
|
|
|
|
-- Adds a Sync to receive events.
|
|
|
|
--
|
|
|
|
local function addSync
|
|
|
|
(
|
|
|
|
sync, -- object to receive events
|
|
|
|
dir -- dir to watch
|
|
|
|
)
|
|
|
|
if syncRoots[ sync ]
|
|
|
|
then
|
|
|
|
error( 'duplicate sync in Fanotify.addSync()' )
|
2010-11-13 13:13:51 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
syncRoots[ sync ] = dir
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-13 13:13:51 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2022-06-03 00:45:53 +00:00
|
|
|
-- Called when an event has occured.
|
2010-11-13 13:13:51 +00:00
|
|
|
--
|
2022-06-03 00:45:53 +00:00
|
|
|
local function event
|
2016-12-13 13:41:35 +00:00
|
|
|
(
|
2022-06-03 00:45:53 +00:00
|
|
|
etype, -- 'Attrib', 'Modify', 'Create', 'Delete', 'Move'
|
|
|
|
isdir, -- true if filename is a directory
|
|
|
|
time, -- time of event
|
|
|
|
path, -- path of file
|
|
|
|
path2 -- path of target in case of 'Move'
|
2016-12-13 13:41:35 +00:00
|
|
|
)
|
2022-06-03 00:45:53 +00:00
|
|
|
if isdir
|
|
|
|
then
|
|
|
|
path = path .. '/'
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if path2 then path2 = path2 .. '/' end
|
|
|
|
end
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
log( 'Fsevents', etype, ',', isdir, ',', time, ',', path, ',', path2 )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
for _, sync in Syncs.iwalk()
|
|
|
|
do repeat
|
2010-11-13 13:13:51 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
local root = sync.source
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
-- TODO combine ifs
|
|
|
|
if not path:starts( root )
|
|
|
|
then
|
|
|
|
if not path2 or not path2:starts( root )
|
|
|
|
then
|
|
|
|
break -- continue
|
2012-10-03 07:23:18 +00:00
|
|
|
end
|
2022-06-03 00:45:53 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
local relative = splitPath( path, root )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
local relative2
|
|
|
|
|
|
|
|
if path2
|
2016-12-13 13:41:35 +00:00
|
|
|
then
|
2022-06-03 00:45:53 +00:00
|
|
|
relative2 = splitPath( path2, root )
|
|
|
|
end
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
-- possibly change etype for this iteration only
|
|
|
|
local etyped = etype
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
if etyped == 'Move'
|
|
|
|
then
|
|
|
|
if not relative2
|
2016-12-13 13:41:35 +00:00
|
|
|
then
|
2022-06-03 00:45:53 +00:00
|
|
|
log( 'Normal', 'Transformed Move to Delete for ', sync.config.name )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
etyped = 'Delete'
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
elseif not relative
|
|
|
|
then
|
|
|
|
relative = relative2
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
relative2 = nil
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
log( 'Normal', 'Transformed Move to Create for ', sync.config.name )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
etyped = 'Create'
|
|
|
|
end
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
sync:delay( etyped, time, relative, relative2 )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
until true end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-13 13:13:51 +00:00
|
|
|
end
|
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2022-06-03 00:45:53 +00:00
|
|
|
-- Writes a status report about fsevents to a filedescriptor.
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2022-06-03 00:45:53 +00:00
|
|
|
local function statusReport
|
2016-12-13 13:41:35 +00:00
|
|
|
(
|
2022-06-03 00:45:53 +00:00
|
|
|
f
|
2016-12-13 13:41:35 +00:00
|
|
|
)
|
2022-06-03 00:45:53 +00:00
|
|
|
-- TODO
|
|
|
|
end
|
2010-11-13 13:13:51 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
--
|
|
|
|
-- Public interface
|
|
|
|
--
|
|
|
|
return {
|
|
|
|
addSync = addSync,
|
|
|
|
event = event,
|
|
|
|
statusReport = statusReport
|
|
|
|
}
|
|
|
|
end )( )
|
2018-03-01 14:08:26 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
--
|
|
|
|
-- Holds information about the event monitor capabilities
|
|
|
|
-- of the core.
|
|
|
|
--
|
|
|
|
Monitors = ( function
|
|
|
|
( )
|
|
|
|
--
|
|
|
|
-- The cores monitor list
|
|
|
|
--
|
|
|
|
local list = { }
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- The default event monitor.
|
|
|
|
--
|
|
|
|
local function default
|
|
|
|
( )
|
|
|
|
return list[ 1 ]
|
2010-11-13 13:13:51 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-13 13:13:51 +00:00
|
|
|
--
|
2022-06-03 00:45:53 +00:00
|
|
|
-- Initializes with info received from core
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2022-06-03 00:45:53 +00:00
|
|
|
local function initialize( clist )
|
|
|
|
for k, v in ipairs( clist )
|
|
|
|
do
|
|
|
|
list[ k ] = v
|
|
|
|
end
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
|
2022-06-03 00:45:53 +00:00
|
|
|
--
|
|
|
|
-- Public interface
|
|
|
|
--
|
|
|
|
return {
|
|
|
|
default = default,
|
|
|
|
list = list,
|
|
|
|
initialize = initialize
|
|
|
|
}
|
|
|
|
|
|
|
|
end)( )
|
2010-11-13 13:13:51 +00:00
|
|
|
|
|
|
|
|
2010-10-28 17:56:33 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- Writes a status report file at most every 'statusintervall' seconds.
|
2010-11-06 10:10:57 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local StatusFile = ( function
|
|
|
|
( )
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-06 10:10:57 +00:00
|
|
|
-- Timestamp when the status file has been written.
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-06 10:10:57 +00:00
|
|
|
local lastWritten = false
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Timestamp when a status file should be written.
|
|
|
|
--
|
2010-11-06 10:10:57 +00:00
|
|
|
local alarm = false
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Returns the alarm when the status file should be written-
|
2010-11-06 10:10:57 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function getAlarm
|
|
|
|
( )
|
2010-11-06 10:10:57 +00:00
|
|
|
return alarm
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
--
|
2010-11-06 10:10:57 +00:00
|
|
|
-- Called to check if to write a status file.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function write
|
|
|
|
(
|
|
|
|
timestamp
|
|
|
|
)
|
2016-12-14 13:25:20 +00:00
|
|
|
log( 'Function', 'write( ', timestamp, ' )' )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2012-10-08 07:10:03 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- takes care not write too often
|
2012-10-08 07:10:03 +00:00
|
|
|
--
|
2016-12-01 12:25:49 +00:00
|
|
|
if uSettings.statusInterval > 0
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
-- already waiting?
|
2016-12-01 12:25:49 +00:00
|
|
|
if alarm and timestamp < alarm
|
|
|
|
then
|
2018-03-01 14:08:26 +00:00
|
|
|
log( 'Statusfile', 'waiting(', timestamp, ' < ', alarm, ')' )
|
2016-12-01 12:25:49 +00:00
|
|
|
|
2010-11-06 10:10:57 +00:00
|
|
|
return
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-06 10:33:26 +00:00
|
|
|
-- determines when a next write will be possible
|
2016-12-01 12:25:49 +00:00
|
|
|
if not alarm
|
|
|
|
then
|
2018-03-01 14:08:26 +00:00
|
|
|
local nextWrite = lastWritten and timestamp + uSettings.statusInterval
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-01 12:25:49 +00:00
|
|
|
if nextWrite and timestamp < nextWrite
|
|
|
|
then
|
2018-03-01 14:08:26 +00:00
|
|
|
log( 'Statusfile', 'setting alarm: ', nextWrite )
|
2010-11-06 10:10:57 +00:00
|
|
|
alarm = nextWrite
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-06 10:10:57 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-29 20:32:54 +00:00
|
|
|
lastWritten = timestamp
|
2010-11-06 10:10:57 +00:00
|
|
|
alarm = false
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
log( 'Statusfile', 'writing now' )
|
|
|
|
|
2012-10-08 07:10:03 +00:00
|
|
|
local f, err = io.open( uSettings.statusFile, 'w' )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-13 13:41:35 +00:00
|
|
|
if not f
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
log(
|
|
|
|
'Error',
|
|
|
|
'Cannot open status file "' ..
|
2012-10-08 07:10:03 +00:00
|
|
|
uSettings.statusFile ..
|
2012-10-03 07:23:18 +00:00
|
|
|
'" :' ..
|
|
|
|
err
|
|
|
|
)
|
2010-11-06 10:10:57 +00:00
|
|
|
return
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
f:write( 'Lsyncd status report at ', os.date( ), '\n\n' )
|
|
|
|
|
2016-12-13 13:41:35 +00:00
|
|
|
for i, s in Syncs.iwalk( )
|
|
|
|
do
|
2012-10-03 07:23:18 +00:00
|
|
|
s:statusReport( f )
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
f:write( '\n' )
|
2010-11-12 10:07:58 +00:00
|
|
|
end
|
2012-01-27 11:08:10 +00:00
|
|
|
|
2022-03-17 01:25:27 +00:00
|
|
|
for i, t in Tunnels.iwalk( )
|
|
|
|
do
|
|
|
|
t:statusReport( f )
|
|
|
|
|
|
|
|
f:write( '\n' )
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
Inotify.statusReport( f )
|
2016-12-13 13:41:35 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
f:close( )
|
2010-11-05 18:04:29 +00:00
|
|
|
end
|
2010-11-06 10:10:57 +00:00
|
|
|
|
2010-10-28 17:56:33 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
|
|
|
-- Public interface
|
|
|
|
--
|
|
|
|
return {
|
|
|
|
write = write,
|
|
|
|
getAlarm = getAlarm
|
|
|
|
}
|
|
|
|
|
|
|
|
end )( )
|
|
|
|
|
|
|
|
|
2010-11-30 23:14:17 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- Lets userscripts make their own alarms.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local UserAlarms = ( function
|
|
|
|
( )
|
2012-10-03 07:23:18 +00:00
|
|
|
local alarms = { }
|
|
|
|
|
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
-- Calls the user function at timestamp.
|
2010-11-30 23:14:17 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function alarm
|
|
|
|
(
|
|
|
|
timestamp,
|
|
|
|
func,
|
|
|
|
extra
|
|
|
|
)
|
2012-01-27 11:08:10 +00:00
|
|
|
local idx
|
2016-11-25 13:55:59 +00:00
|
|
|
|
|
|
|
for k, v in ipairs( alarms )
|
|
|
|
do
|
|
|
|
if timestamp < v.timestamp
|
|
|
|
then
|
2010-11-30 23:14:17 +00:00
|
|
|
idx = k
|
2016-11-25 13:55:59 +00:00
|
|
|
|
2010-11-30 23:14:17 +00:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
local a =
|
|
|
|
{
|
2012-10-03 07:23:18 +00:00
|
|
|
timestamp = timestamp,
|
|
|
|
func = func,
|
|
|
|
extra = extra
|
|
|
|
}
|
|
|
|
|
2016-11-25 13:55:59 +00:00
|
|
|
if idx
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
table.insert( alarms, idx, a )
|
2010-11-30 23:14:17 +00:00
|
|
|
else
|
2012-10-03 07:23:18 +00:00
|
|
|
table.insert( alarms, a )
|
2010-11-30 23:14:17 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-30 23:14:17 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- Retrieves the soonest alarm.
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
local function getAlarm
|
|
|
|
( )
|
2016-11-25 13:55:59 +00:00
|
|
|
if #alarms == 0
|
|
|
|
then
|
2012-01-27 11:08:10 +00:00
|
|
|
return false
|
2010-11-30 23:14:17 +00:00
|
|
|
else
|
|
|
|
return alarms[1].timestamp
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
--
|
2011-08-18 13:29:18 +00:00
|
|
|
-- Calls user alarms.
|
2010-11-30 23:14:17 +00:00
|
|
|
--
|
2018-03-01 14:08:26 +00:00
|
|
|
local function invoke
|
|
|
|
(
|
|
|
|
timestamp
|
|
|
|
)
|
|
|
|
while #alarms > 0
|
|
|
|
and alarms[ 1 ].timestamp <= timestamp
|
2012-10-03 07:23:18 +00:00
|
|
|
do
|
|
|
|
alarms[ 1 ].func( alarms[ 1 ].timestamp, alarms[ 1 ].extra )
|
|
|
|
table.remove( alarms, 1 )
|
2010-11-30 23:14:17 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Public interface
|
|
|
|
--
|
|
|
|
return {
|
|
|
|
alarm = alarm,
|
|
|
|
getAlarm = getAlarm,
|
|
|
|
invoke = invoke
|
|
|
|
}
|
|
|
|
|
|
|
|
end )( )
|
2010-11-30 23:14:17 +00:00
|
|
|
|
2010-11-10 15:57:37 +00:00
|
|
|
--============================================================================
|
2012-10-03 07:23:18 +00:00
|
|
|
-- Lsyncd runner's plugs. These functions are called from core.
|
2010-11-10 15:57:37 +00:00
|
|
|
--============================================================================
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
|
|
|
-- Current status of Lsyncd.
|
2010-11-10 15:57:37 +00:00
|
|
|
--
|
2012-01-30 14:01:18 +00:00
|
|
|
-- 'init' ... on (re)init
|
|
|
|
-- 'run' ... normal operation
|
|
|
|
-- 'fade' ... waits for remaining processes
|
2010-11-11 19:52:20 +00:00
|
|
|
--
|
2012-01-30 14:01:18 +00:00
|
|
|
local lsyncdStatus = 'init'
|
2010-11-10 15:57:37 +00:00
|
|
|
|
2010-11-29 20:32:54 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- The cores interface to the runner.
|
|
|
|
--
|
|
|
|
local runner = { }
|
2010-11-10 15:57:37 +00:00
|
|
|
|
2012-10-23 12:31:54 +00:00
|
|
|
--
|
|
|
|
-- Last time said to be waiting for more child processes
|
|
|
|
--
|
|
|
|
local lastReportedWaiting = false
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
|
|
|
-- Called from core whenever Lua code failed.
|
|
|
|
--
|
2010-11-10 15:57:37 +00:00
|
|
|
-- Logs a backtrace
|
|
|
|
--
|
2016-12-14 13:25:20 +00:00
|
|
|
function runner.callError
|
|
|
|
(
|
|
|
|
message
|
|
|
|
)
|
2018-03-01 14:08:26 +00:00
|
|
|
log( 'Error', 'in Lua: ', message )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2010-11-10 15:57:37 +00:00
|
|
|
-- prints backtrace
|
|
|
|
local level = 2
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-11-25 13:55:59 +00:00
|
|
|
while true
|
|
|
|
do
|
2012-10-03 07:23:18 +00:00
|
|
|
local info = debug.getinfo( level, 'Sl' )
|
|
|
|
|
2016-11-25 13:55:59 +00:00
|
|
|
if not info
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
terminate( -1 )
|
2010-11-10 15:57:37 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
log(
|
|
|
|
'Error',
|
|
|
|
'Backtrace ',
|
|
|
|
level - 1, ' :',
|
|
|
|
info.short_src, ':',
|
|
|
|
info.currentline
|
|
|
|
)
|
|
|
|
|
2010-11-10 15:57:37 +00:00
|
|
|
level = level + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Called from core whenever a child process has finished and
|
|
|
|
-- the zombie process was collected by core.
|
2010-11-10 15:57:37 +00:00
|
|
|
--
|
2018-03-01 14:08:26 +00:00
|
|
|
function runner.collectProcess
|
|
|
|
(
|
|
|
|
pid, -- process id
|
|
|
|
exitcode -- exitcode
|
|
|
|
)
|
2022-03-11 06:11:39 +00:00
|
|
|
for _, s in Syncs.iwalk( )
|
|
|
|
do
|
|
|
|
if s:collect( pid, exitcode ) then
|
|
|
|
processCount = processCount - 1
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, s in Tunnels.iwalk( )
|
|
|
|
do
|
|
|
|
if s:collect( pid, exitcode ) then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
if processCount < 0
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
error( 'negative number of processes!' )
|
|
|
|
end
|
2011-08-18 13:29:18 +00:00
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
|
2010-11-10 15:57:37 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-05 18:04:29 +00:00
|
|
|
-- Called from core everytime a masterloop cycle runs through.
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2012-01-27 11:08:10 +00:00
|
|
|
-- This happens in case of
|
2010-11-05 18:04:29 +00:00
|
|
|
-- * an expired alarm.
|
|
|
|
-- * a returned child process.
|
2011-08-18 13:29:18 +00:00
|
|
|
-- * received filesystem events.
|
2013-07-30 10:20:23 +00:00
|
|
|
-- * received a HUP, TERM or INT signal.
|
2010-10-23 12:36:55 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
function runner.cycle(
|
|
|
|
timestamp -- the current kernel time (in jiffies)
|
|
|
|
)
|
2016-12-14 13:25:20 +00:00
|
|
|
log( 'Function', 'cycle( ', timestamp, ' )' )
|
|
|
|
|
2016-11-25 13:55:59 +00:00
|
|
|
if lsyncdStatus == 'fade'
|
|
|
|
then
|
|
|
|
if processCount > 0
|
|
|
|
then
|
2012-10-23 12:31:54 +00:00
|
|
|
if
|
|
|
|
lastReportedWaiting == false or
|
|
|
|
timestamp >= lastReportedWaiting + 60
|
|
|
|
then
|
|
|
|
lastReportedWaiting = timestamp
|
|
|
|
|
|
|
|
log(
|
|
|
|
'Normal',
|
|
|
|
'waiting for ',
|
|
|
|
processCount,
|
|
|
|
' more child processes.'
|
|
|
|
)
|
|
|
|
end
|
2012-10-05 07:41:46 +00:00
|
|
|
|
2010-11-14 09:11:09 +00:00
|
|
|
return true
|
|
|
|
else
|
2022-03-16 00:12:42 +00:00
|
|
|
Tunnels.killAll()
|
2010-11-14 09:11:09 +00:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-14 13:25:20 +00:00
|
|
|
if lsyncdStatus ~= 'run'
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
error( 'runner.cycle() called while not running!' )
|
2010-11-14 09:11:09 +00:00
|
|
|
end
|
|
|
|
|
2022-03-11 06:11:39 +00:00
|
|
|
-- check and start tunnels
|
|
|
|
if not uSettings.maxProcesses
|
|
|
|
or processCount < uSettings.maxProcesses
|
|
|
|
then
|
|
|
|
Tunnels.invoke( timestamp )
|
|
|
|
end
|
|
|
|
|
2021-12-10 14:05:30 +00:00
|
|
|
if uSettings.onepass
|
|
|
|
then
|
|
|
|
local allDone = true
|
|
|
|
for i, s in Syncs.iwalk( )
|
|
|
|
do
|
|
|
|
if s.initDone == true
|
|
|
|
then
|
|
|
|
s.disabled = true
|
|
|
|
else
|
|
|
|
allDone = false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if allDone and processCount == 0 then
|
|
|
|
log( 'Info', 'onepass active and all syncs finished. Exiting successfully')
|
|
|
|
os.exit(0)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
|
|
|
-- goes through all syncs and spawns more actions
|
|
|
|
-- if possibly. But only let Syncs invoke actions if
|
|
|
|
-- not at global limit
|
|
|
|
--
|
2016-12-14 13:25:20 +00:00
|
|
|
if not uSettings.maxProcesses
|
|
|
|
or processCount < uSettings.maxProcesses
|
2012-10-03 07:23:18 +00:00
|
|
|
then
|
|
|
|
local start = Syncs.getRound( )
|
2012-10-05 07:41:46 +00:00
|
|
|
|
2011-08-18 13:29:18 +00:00
|
|
|
local ir = start
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2011-08-18 13:29:18 +00:00
|
|
|
repeat
|
2012-10-03 07:23:18 +00:00
|
|
|
local s = Syncs.get( ir )
|
2016-12-14 13:25:20 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
s:invokeActions( timestamp )
|
2016-12-14 13:25:20 +00:00
|
|
|
|
2011-08-18 13:29:18 +00:00
|
|
|
ir = ir + 1
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-11-25 13:55:59 +00:00
|
|
|
if ir > Syncs.size( )
|
|
|
|
then
|
2011-08-18 13:29:18 +00:00
|
|
|
ir = 1
|
|
|
|
end
|
|
|
|
until ir == start
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
Syncs.nextRound( )
|
2010-11-08 12:14:10 +00:00
|
|
|
end
|
2010-11-30 23:14:17 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
UserAlarms.invoke( timestamp )
|
2010-11-30 23:14:17 +00:00
|
|
|
|
2016-11-25 13:55:59 +00:00
|
|
|
if uSettings.statusFile
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
StatusFile.write( timestamp )
|
2010-11-05 18:04:29 +00:00
|
|
|
end
|
2010-11-14 09:11:09 +00:00
|
|
|
|
|
|
|
return true
|
2010-10-22 23:14:11 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
|
|
|
-- Called by core if '-help' or '--help' is in
|
2010-10-27 09:06:13 +00:00
|
|
|
-- the arguments.
|
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
function runner.help(_arg0)
|
2010-10-27 19:34:56 +00:00
|
|
|
io.stdout:write(
|
2022-10-28 12:07:17 +00:00
|
|
|
'lsyncd version: ' .. lsyncd_version ..
|
2010-11-04 13:43:57 +00:00
|
|
|
[[
|
2010-11-13 21:50:21 +00:00
|
|
|
|
2022-10-28 12:07:17 +00:00
|
|
|
|
2012-01-27 11:08:10 +00:00
|
|
|
USAGE:
|
2010-11-13 21:50:21 +00:00
|
|
|
runs a config file:
|
2010-11-04 13:43:57 +00:00
|
|
|
lsyncd [OPTIONS] [CONFIG-FILE]
|
|
|
|
|
|
|
|
default rsync behaviour:
|
2012-01-27 11:08:10 +00:00
|
|
|
lsyncd [OPTIONS] -rsync [SOURCE] [TARGET]
|
|
|
|
|
2010-11-14 09:37:31 +00:00
|
|
|
default rsync with mv's through ssh:
|
|
|
|
lsyncd [OPTIONS] -rsyncssh [SOURCE] [HOST] [TARGETDIR]
|
2012-01-27 11:08:10 +00:00
|
|
|
|
2011-02-08 14:14:07 +00:00
|
|
|
default local copying mechanisms (cp|mv|rm):
|
|
|
|
lsyncd [OPTIONS] -direct [SOURCE] [TARGETDIR]
|
2010-11-04 13:43:57 +00:00
|
|
|
|
|
|
|
OPTIONS:
|
2010-11-28 20:16:56 +00:00
|
|
|
-delay SECS Overrides default delay times
|
2010-11-04 13:43:57 +00:00
|
|
|
-help Shows this
|
2011-08-18 13:29:18 +00:00
|
|
|
-insist Continues startup even if it cannot connect
|
2010-11-13 21:50:21 +00:00
|
|
|
-log all Logs everything (debug)
|
2010-11-04 13:43:57 +00:00
|
|
|
-log scarce Logs errors only
|
2010-11-04 14:23:34 +00:00
|
|
|
-log [Category] Turns on logging for a debug category
|
2010-11-13 21:50:21 +00:00
|
|
|
-logfile FILE Writes log to FILE (DEFAULT: uses syslog)
|
|
|
|
-nodaemon Does not detach and logs to stdout/stderr
|
2018-12-05 06:05:18 +00:00
|
|
|
-onepass Sync once and exit
|
2010-11-17 11:14:36 +00:00
|
|
|
-pidfile FILE Writes Lsyncds PID into FILE
|
2012-01-27 11:08:10 +00:00
|
|
|
-runner FILE Loads Lsyncds lua part from FILE
|
2021-12-08 17:26:11 +00:00
|
|
|
-script FILE Script to load before execting runner (ADVANCED)
|
2023-03-02 16:22:01 +00:00
|
|
|
-sshopts Additional ssh command options when using rsyncssh
|
2010-11-13 21:50:21 +00:00
|
|
|
-version Prints versions and exits
|
2010-11-04 13:43:57 +00:00
|
|
|
|
|
|
|
LICENSE:
|
|
|
|
GPLv2 or any later version.
|
|
|
|
|
|
|
|
SEE:
|
|
|
|
`man lsyncd` for further information.
|
|
|
|
|
2010-10-27 09:06:13 +00:00
|
|
|
]])
|
2010-11-28 10:47:57 +00:00
|
|
|
|
|
|
|
--
|
2012-01-27 11:08:10 +00:00
|
|
|
-- -monitor NAME Uses operating systems event montior NAME
|
2010-11-28 10:47:57 +00:00
|
|
|
-- (inotify/fanotify/fsevents)
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
os.exit( -1 )
|
2010-10-27 09:06:13 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
2010-11-03 21:02:14 +00:00
|
|
|
-- Called from core to parse the command line arguments
|
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- returns a string as user script to load.
|
|
|
|
-- or simply 'true' if running with rsync bevaiour
|
|
|
|
--
|
|
|
|
-- terminates on invalid arguments.
|
|
|
|
--
|
|
|
|
function runner.configure( args, monitors )
|
2010-11-28 09:37:43 +00:00
|
|
|
|
2012-10-07 19:40:05 +00:00
|
|
|
Monitors.initialize( monitors )
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2012-10-08 07:10:03 +00:00
|
|
|
--
|
2012-10-03 07:23:18 +00:00
|
|
|
-- a list of all valid options
|
|
|
|
--
|
|
|
|
-- first paramter is the number of parameters an option takes
|
2012-10-03 15:37:49 +00:00
|
|
|
-- if < 0 the called function has to check the presence of
|
|
|
|
-- optional arguments.
|
2012-10-03 07:23:18 +00:00
|
|
|
--
|
|
|
|
-- second paramter is the function to call
|
2010-11-28 09:37:43 +00:00
|
|
|
--
|
2018-03-01 14:08:26 +00:00
|
|
|
local options =
|
|
|
|
{
|
2010-11-03 21:02:14 +00:00
|
|
|
-- log is handled by core already.
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
delay =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
1,
|
2018-03-01 14:19:30 +00:00
|
|
|
function
|
|
|
|
(
|
|
|
|
secs
|
|
|
|
)
|
2018-03-01 14:08:26 +00:00
|
|
|
clSettings.delay = secs + 0
|
|
|
|
end
|
|
|
|
},
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
insist =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
0,
|
2018-03-01 14:19:30 +00:00
|
|
|
function
|
|
|
|
( )
|
2018-03-01 14:08:26 +00:00
|
|
|
clSettings.insist = true
|
|
|
|
end
|
|
|
|
},
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
log =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
1,
|
|
|
|
nil
|
|
|
|
},
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
logfile =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
1,
|
2018-03-01 14:19:30 +00:00
|
|
|
function
|
|
|
|
(
|
|
|
|
file
|
|
|
|
)
|
2018-03-01 14:08:26 +00:00
|
|
|
clSettings.logfile = file
|
|
|
|
end
|
|
|
|
},
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2012-01-27 11:08:10 +00:00
|
|
|
monitor =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
-1,
|
2018-03-01 14:19:30 +00:00
|
|
|
function
|
|
|
|
(
|
|
|
|
monitor
|
|
|
|
)
|
|
|
|
if not monitor
|
|
|
|
then
|
2018-03-01 14:08:26 +00:00
|
|
|
io.stdout:write( 'This Lsyncd supports these monitors:\n' )
|
2018-03-01 14:19:30 +00:00
|
|
|
for _, v in ipairs( Monitors.list )
|
|
|
|
do
|
|
|
|
io.stdout:write( ' ', v, '\n' )
|
2018-03-01 14:08:26 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
io.stdout:write('\n')
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2018-03-01 14:19:30 +00:00
|
|
|
lsyncd.terminate( -1 )
|
2018-03-01 14:08:26 +00:00
|
|
|
else
|
|
|
|
clSettings.monitor = monitor
|
2010-11-28 09:37:43 +00:00
|
|
|
end
|
2018-03-01 14:08:26 +00:00
|
|
|
end
|
|
|
|
},
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2012-01-27 11:08:10 +00:00
|
|
|
nodaemon =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
0,
|
2018-03-01 14:19:30 +00:00
|
|
|
function
|
|
|
|
( )
|
2018-03-01 14:08:26 +00:00
|
|
|
clSettings.nodaemon = true
|
|
|
|
end
|
|
|
|
},
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-12-05 06:05:18 +00:00
|
|
|
onepass =
|
|
|
|
{
|
|
|
|
0,
|
|
|
|
function
|
2018-12-05 21:41:53 +00:00
|
|
|
( )
|
2018-12-05 06:05:18 +00:00
|
|
|
clSettings.onepass = true
|
|
|
|
end
|
|
|
|
},
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
pidfile =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
1,
|
2018-03-01 14:19:30 +00:00
|
|
|
function
|
|
|
|
(
|
|
|
|
file
|
|
|
|
)
|
2018-03-01 14:08:26 +00:00
|
|
|
clSettings.pidfile=file
|
|
|
|
end
|
|
|
|
},
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2021-12-08 17:21:16 +00:00
|
|
|
sshopts =
|
|
|
|
{
|
|
|
|
1,
|
|
|
|
function
|
|
|
|
(
|
|
|
|
options
|
|
|
|
)
|
|
|
|
clSettings.ssh_extras = splitQuotedString(options)
|
|
|
|
end
|
|
|
|
},
|
|
|
|
|
2021-12-08 17:26:11 +00:00
|
|
|
script =
|
|
|
|
{
|
|
|
|
1,
|
|
|
|
function
|
|
|
|
(
|
|
|
|
file
|
|
|
|
)
|
|
|
|
clSettings.scripts = clSettings.scripts or {}
|
|
|
|
table.insert(clSettings.scripts, file)
|
|
|
|
end
|
|
|
|
},
|
|
|
|
|
2021-12-08 17:21:16 +00:00
|
|
|
rsync =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
2,
|
2018-03-01 14:19:30 +00:00
|
|
|
function
|
|
|
|
(
|
|
|
|
src,
|
|
|
|
trg
|
|
|
|
)
|
2018-03-01 14:08:26 +00:00
|
|
|
clSettings.syncs = clSettings.syncs or { }
|
2018-03-01 14:19:30 +00:00
|
|
|
table.insert( clSettings.syncs, { 'rsync', src, trg } )
|
2018-03-01 14:08:26 +00:00
|
|
|
end
|
|
|
|
},
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2012-01-27 11:08:10 +00:00
|
|
|
rsyncssh =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
3,
|
2018-03-01 14:19:30 +00:00
|
|
|
function
|
|
|
|
(
|
|
|
|
src,
|
|
|
|
host,
|
|
|
|
tdir
|
|
|
|
)
|
2018-03-01 14:08:26 +00:00
|
|
|
clSettings.syncs = clSettings.syncs or { }
|
2018-03-01 14:19:30 +00:00
|
|
|
|
|
|
|
table.insert( clSettings.syncs, { 'rsyncssh', src, host, tdir } )
|
2018-03-01 14:08:26 +00:00
|
|
|
end
|
|
|
|
},
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2012-01-27 11:08:10 +00:00
|
|
|
direct =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
2,
|
2018-03-01 14:19:30 +00:00
|
|
|
function
|
|
|
|
(
|
|
|
|
src,
|
|
|
|
trg
|
|
|
|
)
|
2018-03-01 14:08:26 +00:00
|
|
|
clSettings.syncs = clSettings.syncs or { }
|
2018-03-01 14:19:30 +00:00
|
|
|
|
|
|
|
table.insert( clSettings.syncs, { 'direct', src, trg } )
|
2018-03-01 14:08:26 +00:00
|
|
|
end
|
|
|
|
},
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
version =
|
2018-03-01 14:08:26 +00:00
|
|
|
{
|
|
|
|
0,
|
2018-03-01 14:19:30 +00:00
|
|
|
function
|
|
|
|
( )
|
2018-03-01 14:08:26 +00:00
|
|
|
io.stdout:write( 'Version: ', lsyncd_version, '\n' )
|
2018-03-01 14:19:30 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
os.exit( 0 )
|
|
|
|
end
|
|
|
|
}
|
2010-11-03 21:02:14 +00:00
|
|
|
}
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
-- non-opts is filled with all args that were no part dash options
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2012-10-03 07:23:18 +00:00
|
|
|
local nonopts = { }
|
2012-10-03 15:37:49 +00:00
|
|
|
|
|
|
|
local i = 1
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
while i <= #args
|
|
|
|
do
|
2012-10-03 15:37:49 +00:00
|
|
|
local a = args[ i ]
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
if a:sub( 1, 1 ) ~= '-'
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
table.insert( nonopts, args[ i ] )
|
2010-11-03 21:02:14 +00:00
|
|
|
else
|
2018-03-01 14:08:26 +00:00
|
|
|
if a:sub( 1, 2 ) == '--'
|
|
|
|
then
|
2012-10-03 07:23:18 +00:00
|
|
|
a = a:sub( 3 )
|
2010-11-03 21:02:14 +00:00
|
|
|
else
|
2012-10-03 07:23:18 +00:00
|
|
|
a = a:sub( 2 )
|
2010-11-03 21:02:14 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
|
|
|
local o = options[ a ]
|
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
if not o
|
|
|
|
then
|
2018-03-01 14:08:26 +00:00
|
|
|
log( 'Error', 'unknown option command line option ', args[ i ] )
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
os.exit( -1 )
|
2010-11-03 21:02:14 +00:00
|
|
|
end
|
2012-10-03 07:23:18 +00:00
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
if o[ 1 ] >= 0 and i + o[ 1 ] > #args
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
log( 'Error', a ,' needs ', o[ 1 ],' arguments' )
|
2016-12-01 11:52:09 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
os.exit( -1 )
|
2016-12-01 11:52:09 +00:00
|
|
|
elseif o[1] < 0
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
o[ 1 ] = -o[ 1 ]
|
|
|
|
end
|
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
if o[ 2 ]
|
|
|
|
then
|
|
|
|
if o[ 1 ] == 0
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
o[ 2 ]( )
|
2016-12-01 11:52:09 +00:00
|
|
|
elseif o[ 1 ] == 1
|
|
|
|
then
|
|
|
|
o[ 2 ]( args[ i + 1] )
|
|
|
|
elseif o[ 1 ] == 2
|
|
|
|
then
|
|
|
|
o[ 2 ]( args[ i + 1], args[ i + 2] )
|
|
|
|
elseif o[ 1 ] == 3
|
|
|
|
then
|
|
|
|
o[ 2 ]( args[ i + 1], args[ i + 2], args[ i + 3] )
|
2010-11-28 20:16:56 +00:00
|
|
|
end
|
|
|
|
end
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2010-11-28 20:16:56 +00:00
|
|
|
i = i + o[1]
|
2010-11-03 21:02:14 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
i = i + 1
|
2010-11-03 21:02:14 +00:00
|
|
|
end
|
|
|
|
|
2022-10-28 12:07:17 +00:00
|
|
|
log( 'Debug', 'lsyncd version: '.. lsyncd_version .. ' starting.' )
|
|
|
|
log( 'Debug', 'module search path: '.. package.path)
|
|
|
|
|
2021-12-08 17:26:11 +00:00
|
|
|
if clSettings.scripts then
|
|
|
|
for _, file in ipairs(clSettings.scripts) do
|
|
|
|
log( 'Info', 'Run addition script: ' .. file )
|
|
|
|
dofile(file)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
if clSettings.syncs
|
|
|
|
then
|
|
|
|
if #nonopts ~= 0
|
|
|
|
then
|
2018-03-01 14:08:26 +00:00
|
|
|
log( 'Error', 'There cannot be command line syncs and a config file together.' )
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
os.exit( -1 )
|
2010-11-13 20:47:45 +00:00
|
|
|
end
|
|
|
|
else
|
2016-12-01 11:52:09 +00:00
|
|
|
if #nonopts == 0
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
runner.help( args[ 0 ] )
|
2016-12-01 11:52:09 +00:00
|
|
|
elseif #nonopts == 1
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
return nonopts[ 1 ]
|
2012-01-27 11:08:10 +00:00
|
|
|
else
|
2012-10-03 15:37:49 +00:00
|
|
|
-- TODO make this possible
|
2018-03-01 14:08:26 +00:00
|
|
|
log( 'Error', 'There can only be one config file in the command line.' )
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
os.exit( -1 )
|
2010-11-13 20:47:45 +00:00
|
|
|
end
|
2010-11-03 21:02:14 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2010-10-17 15:24:55 +00:00
|
|
|
-- Called from core on init or restart after user configuration.
|
2011-08-29 09:21:40 +00:00
|
|
|
--
|
2012-10-03 15:37:49 +00:00
|
|
|
-- firstTime:
|
|
|
|
-- true when Lsyncd startups the first time,
|
|
|
|
-- false on resets, due to HUP signal or monitor queue overflow.
|
2012-01-27 11:08:10 +00:00
|
|
|
--
|
2012-10-03 15:37:49 +00:00
|
|
|
function runner.initialize( firstTime )
|
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
-- Checks if user overwrote the settings function.
|
|
|
|
-- ( was Lsyncd <2.1 style )
|
|
|
|
if settings ~= settingsSafe
|
|
|
|
then
|
2012-10-08 07:10:03 +00:00
|
|
|
log(
|
2016-12-01 11:52:09 +00:00
|
|
|
'Error',
|
|
|
|
'Do not use settings = { ... }\n'..
|
2018-03-01 14:08:26 +00:00
|
|
|
' please use settings{ ... } ( without the equal sign )'
|
2012-10-08 07:10:03 +00:00
|
|
|
)
|
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
os.exit( -1 )
|
2012-10-08 07:10:03 +00:00
|
|
|
end
|
2012-01-27 11:08:10 +00:00
|
|
|
|
2012-10-23 12:31:54 +00:00
|
|
|
lastReportedWaiting = false
|
|
|
|
|
2012-10-05 07:41:46 +00:00
|
|
|
--
|
2010-10-25 14:55:40 +00:00
|
|
|
-- From this point on, no globals may be created anymore
|
2012-10-05 07:41:46 +00:00
|
|
|
--
|
|
|
|
lockGlobals( )
|
2010-10-25 14:55:40 +00:00
|
|
|
|
2012-10-06 11:43:55 +00:00
|
|
|
--
|
2010-11-17 11:14:36 +00:00
|
|
|
-- all command line settings overwrite config file settings
|
2012-10-06 11:43:55 +00:00
|
|
|
--
|
2016-12-01 11:52:09 +00:00
|
|
|
for k, v in pairs( clSettings )
|
|
|
|
do
|
|
|
|
if k ~= 'syncs'
|
|
|
|
then
|
2012-10-08 07:10:03 +00:00
|
|
|
uSettings[ k ] = v
|
2010-11-13 21:50:21 +00:00
|
|
|
end
|
|
|
|
end
|
2012-02-15 15:47:18 +00:00
|
|
|
|
2012-10-06 11:43:55 +00:00
|
|
|
--
|
|
|
|
-- implicitly forces 'insist' on Lsyncd resets.
|
|
|
|
--
|
2016-12-01 11:52:09 +00:00
|
|
|
if not firstTime
|
|
|
|
then
|
2012-10-08 07:10:03 +00:00
|
|
|
uSettings.insist = true
|
2011-08-29 09:21:40 +00:00
|
|
|
end
|
2010-11-13 21:50:21 +00:00
|
|
|
|
2012-10-06 11:43:55 +00:00
|
|
|
--
|
2010-11-13 21:50:21 +00:00
|
|
|
-- adds syncs specified by command line.
|
2012-10-06 11:43:55 +00:00
|
|
|
--
|
2016-12-01 11:52:09 +00:00
|
|
|
if clSettings.syncs
|
|
|
|
then
|
|
|
|
for _, s in ipairs( clSettings.syncs )
|
|
|
|
do
|
|
|
|
if s[ 1 ] == 'rsync'
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
sync{
|
|
|
|
default.rsync,
|
|
|
|
source = s[ 2 ],
|
|
|
|
target = s[ 3 ]
|
|
|
|
}
|
2016-12-01 11:52:09 +00:00
|
|
|
elseif s[ 1 ] == 'rsyncssh'
|
|
|
|
then
|
2021-12-08 17:21:16 +00:00
|
|
|
local opts = {
|
2012-10-03 15:37:49 +00:00
|
|
|
default.rsyncssh,
|
|
|
|
source = s[ 2 ],
|
|
|
|
host = s[ 3 ],
|
|
|
|
targetdir=s[ 4 ]
|
|
|
|
}
|
2021-12-08 17:21:16 +00:00
|
|
|
if clSettings.ssh_extras ~= nil
|
|
|
|
then
|
|
|
|
opts.ssh = {_extra = clSettings.ssh_extras}
|
|
|
|
end
|
|
|
|
sync(opts)
|
2016-12-01 11:52:09 +00:00
|
|
|
elseif s[ 1 ] == 'direct'
|
|
|
|
then
|
2012-10-06 11:43:55 +00:00
|
|
|
sync{
|
|
|
|
default.direct,
|
|
|
|
source=s[ 2 ],
|
|
|
|
target=s[ 3 ]
|
|
|
|
}
|
2010-11-13 21:50:21 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
if uSettings.nodaemon
|
|
|
|
then
|
2012-10-05 07:41:46 +00:00
|
|
|
lsyncd.configure( 'nodaemon' )
|
2010-11-13 21:50:21 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
if uSettings.logfile
|
|
|
|
then
|
2012-10-08 07:10:03 +00:00
|
|
|
lsyncd.configure( 'logfile', uSettings.logfile )
|
2010-11-13 21:50:21 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
if uSettings.logident
|
|
|
|
then
|
2012-10-08 07:10:03 +00:00
|
|
|
lsyncd.configure( 'logident', uSettings.logident )
|
2011-03-01 14:57:26 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
if uSettings.logfacility
|
|
|
|
then
|
2012-10-08 07:10:03 +00:00
|
|
|
lsyncd.configure( 'logfacility', uSettings.logfacility )
|
2011-03-01 14:57:26 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2016-12-01 11:52:09 +00:00
|
|
|
if uSettings.pidfile
|
|
|
|
then
|
2012-10-08 07:10:03 +00:00
|
|
|
lsyncd.configure( 'pidfile', uSettings.pidfile )
|
2011-02-28 14:36:23 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2012-10-08 07:10:03 +00:00
|
|
|
-- Transfers some defaults to uSettings
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2016-12-01 11:52:09 +00:00
|
|
|
if uSettings.statusInterval == nil
|
|
|
|
then
|
2012-10-08 07:10:03 +00:00
|
|
|
uSettings.statusInterval = default.statusInterval
|
2010-10-27 09:06:13 +00:00
|
|
|
end
|
2010-10-25 21:41:45 +00:00
|
|
|
|
2012-01-27 11:08:10 +00:00
|
|
|
-- makes sure the user gave Lsyncd anything to do
|
2016-12-01 11:52:09 +00:00
|
|
|
if Syncs.size() == 0
|
|
|
|
then
|
2022-03-16 00:12:42 +00:00
|
|
|
log( 'Error', 'Nothing to watch!' )
|
2012-10-03 15:37:49 +00:00
|
|
|
|
|
|
|
os.exit( -1 )
|
2010-10-21 12:37:27 +00:00
|
|
|
end
|
|
|
|
|
2010-11-03 11:37:25 +00:00
|
|
|
-- from now on use logging as configured instead of stdout/err.
|
2012-01-30 14:01:18 +00:00
|
|
|
lsyncdStatus = 'run';
|
2012-10-05 07:41:46 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
lsyncd.configure( 'running' );
|
2012-01-27 11:08:10 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
local ufuncs =
|
|
|
|
{
|
2012-10-03 15:37:49 +00:00
|
|
|
'onAttrib',
|
|
|
|
'onCreate',
|
|
|
|
'onDelete',
|
|
|
|
'onModify',
|
|
|
|
'onMove',
|
|
|
|
'onStartup',
|
2010-11-13 13:44:51 +00:00
|
|
|
}
|
2012-01-27 11:08:10 +00:00
|
|
|
|
2010-11-13 13:44:51 +00:00
|
|
|
-- translates layer 3 scripts
|
2016-12-12 18:53:44 +00:00
|
|
|
for _, s in Syncs.iwalk()
|
|
|
|
do
|
2010-11-13 13:44:51 +00:00
|
|
|
-- checks if any user functions is a layer 3 string.
|
|
|
|
local config = s.config
|
2012-10-05 07:41:46 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
for _, fn in ipairs( ufuncs )
|
|
|
|
do
|
|
|
|
if type(config[fn]) == 'string'
|
|
|
|
then
|
|
|
|
local ft = functionWriter.translate( config[ fn ] )
|
2022-06-07 19:28:18 +00:00
|
|
|
if _LUA_VERSION_MAJOR <= 5 and _LUA_VERSION_MINOR < 2 then
|
|
|
|
-- lua 5.1 and older
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line deprecated
|
2022-06-07 19:28:18 +00:00
|
|
|
config[ fn ] = assert( loadstring( 'return '..ft ) )( )
|
|
|
|
else
|
|
|
|
config[ fn ] = assert( load( 'return '..ft ) )( )
|
|
|
|
end
|
2010-11-13 13:44:51 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2010-11-07 09:53:39 +00:00
|
|
|
|
2010-11-17 18:52:55 +00:00
|
|
|
-- runs through the Syncs created by users
|
2016-12-01 12:25:49 +00:00
|
|
|
for _, s in Syncs.iwalk( )
|
|
|
|
do
|
|
|
|
if s.config.monitor == 'inotify'
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
Inotify.addSync( s, s.source )
|
2016-12-01 12:25:49 +00:00
|
|
|
elseif s.config.monitor == 'fsevents'
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
Fsevents.addSync( s, s.source )
|
2010-11-28 10:47:57 +00:00
|
|
|
else
|
2012-10-03 15:37:49 +00:00
|
|
|
error(
|
|
|
|
'sync ' ..
|
|
|
|
s.config.name ..
|
|
|
|
' has no known event monitor interface.'
|
|
|
|
)
|
2010-11-28 10:47:57 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
|
|
|
-- if the sync has an init function, the init delay
|
|
|
|
-- is stacked which causes the init function to be called.
|
2016-12-01 12:25:49 +00:00
|
|
|
if s.config.init
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
s:addInitDelay( )
|
2010-10-22 10:35:26 +00:00
|
|
|
end
|
|
|
|
end
|
2010-10-17 15:24:55 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
|
|
|
-- Called by core to query the soonest alarm.
|
2010-10-19 10:12:11 +00:00
|
|
|
--
|
2016-11-25 13:55:59 +00:00
|
|
|
-- @return false ... no alarm, core can go in untimed sleep
|
2010-11-08 12:14:10 +00:00
|
|
|
-- true ... immediate action
|
2010-11-05 18:20:33 +00:00
|
|
|
-- times ... the alarm time (only read if number is 1)
|
|
|
|
--
|
2016-12-14 13:25:20 +00:00
|
|
|
function runner.getAlarm
|
|
|
|
( )
|
|
|
|
log( 'Function', 'getAlarm( )' )
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
if lsyncdStatus ~= 'run' then return false end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2010-11-05 18:20:33 +00:00
|
|
|
local alarm = false
|
2022-03-30 21:03:12 +00:00
|
|
|
local alarmSource = ""
|
2012-10-03 15:37:49 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Checks if 'a' is sooner than the 'alarm' up-value.
|
2010-11-06 21:29:22 +00:00
|
|
|
--
|
2016-12-14 13:25:20 +00:00
|
|
|
local function checkAlarm
|
|
|
|
(
|
2022-03-30 21:03:12 +00:00
|
|
|
a, -- alarm time
|
|
|
|
src -- name of subsystem
|
2016-12-14 13:25:20 +00:00
|
|
|
)
|
2018-03-01 14:08:26 +00:00
|
|
|
if a == nil then error( 'got nil alarm' ) end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2022-11-11 19:05:09 +00:00
|
|
|
if (type(alarm) == "boolean" and alarm == true) or not a
|
2016-11-25 13:55:59 +00:00
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
-- 'alarm' is already immediate or
|
|
|
|
-- a not a new alarm
|
2010-12-01 13:25:05 +00:00
|
|
|
return
|
2010-11-06 21:29:22 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
|
|
|
-- sets 'alarm' to a if a is sooner
|
2016-11-25 13:55:59 +00:00
|
|
|
if not alarm or a < alarm
|
|
|
|
then
|
2010-12-01 13:25:05 +00:00
|
|
|
alarm = a
|
2022-03-30 21:03:12 +00:00
|
|
|
alarmSource = src
|
2010-10-24 16:41:58 +00:00
|
|
|
end
|
|
|
|
end
|
2010-11-06 21:29:22 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
|
|
|
-- checks all syncs for their earliest alarm,
|
2011-08-18 13:29:18 +00:00
|
|
|
-- but only if the global process limit is not yet reached.
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2022-03-30 21:03:12 +00:00
|
|
|
|
2016-12-14 13:25:20 +00:00
|
|
|
if not uSettings.maxProcesses
|
|
|
|
or processCount < uSettings.maxProcesses
|
2012-10-03 15:37:49 +00:00
|
|
|
then
|
2016-12-14 13:25:20 +00:00
|
|
|
for _, s in Syncs.iwalk( )
|
|
|
|
do
|
2022-03-30 21:03:12 +00:00
|
|
|
checkAlarm( s:getAlarm( ), s.config.name )
|
2011-08-18 13:29:18 +00:00
|
|
|
end
|
|
|
|
else
|
2012-10-03 15:37:49 +00:00
|
|
|
log(
|
|
|
|
'Alarm',
|
|
|
|
'at global process limit.'
|
|
|
|
)
|
2010-11-06 10:10:57 +00:00
|
|
|
end
|
2022-03-11 06:11:39 +00:00
|
|
|
-- checks for tunnel alarm
|
2022-03-30 21:03:12 +00:00
|
|
|
checkAlarm( Tunnels.getAlarm( ), "Tunnels" )
|
2011-08-18 13:29:18 +00:00
|
|
|
|
2010-11-06 21:29:22 +00:00
|
|
|
-- checks if a statusfile write has been delayed
|
2022-03-30 21:03:12 +00:00
|
|
|
checkAlarm( StatusFile.getAlarm( ), "StatusFile" )
|
2010-11-30 23:14:17 +00:00
|
|
|
-- checks for an userAlarm
|
2022-03-30 21:03:12 +00:00
|
|
|
checkAlarm( UserAlarms.getAlarm( ), "UserAlarms" )
|
|
|
|
log( 'Alarm', 'runner.getAlarm returns: ', alarm, " Source:", alarmSource )
|
2010-11-06 10:10:57 +00:00
|
|
|
|
2010-11-05 18:20:33 +00:00
|
|
|
return alarm
|
2010-10-19 10:12:11 +00:00
|
|
|
end
|
2010-10-17 15:24:55 +00:00
|
|
|
|
2010-11-10 15:57:37 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
|
|
|
-- Called when an file system monitor events arrive
|
2010-11-26 16:19:56 +00:00
|
|
|
--
|
|
|
|
runner.inotifyEvent = Inotify.event
|
2010-12-10 13:28:10 +00:00
|
|
|
runner.fsEventsEvent = Fsevents.event
|
2010-10-21 12:37:27 +00:00
|
|
|
|
|
|
|
--
|
2012-10-03 15:37:49 +00:00
|
|
|
-- Collector for every child process that finished in startup phase
|
2010-10-21 12:37:27 +00:00
|
|
|
--
|
2017-01-09 12:13:05 +00:00
|
|
|
function runner.collector
|
|
|
|
(
|
2012-10-03 15:37:49 +00:00
|
|
|
pid, -- pid of the child process
|
|
|
|
exitcode -- exitcode of the child process
|
|
|
|
)
|
2016-12-01 12:25:49 +00:00
|
|
|
if exitcode ~= 0
|
|
|
|
then
|
2018-03-01 14:08:26 +00:00
|
|
|
log( 'Error', 'Startup process', pid, ' failed' )
|
2016-12-01 12:25:49 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
terminate( -1 )
|
2010-10-20 13:01:26 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2010-10-21 12:37:27 +00:00
|
|
|
return 0
|
2010-10-20 10:25:34 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2010-11-10 15:57:37 +00:00
|
|
|
-- Called by core when an overflow happened.
|
|
|
|
--
|
2018-03-01 14:08:26 +00:00
|
|
|
function runner.overflow
|
|
|
|
( )
|
|
|
|
log( 'Normal', '--- OVERFLOW in event queue ---' )
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2012-01-30 14:01:18 +00:00
|
|
|
lsyncdStatus = 'fade'
|
2010-11-14 09:11:09 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2010-11-14 09:11:09 +00:00
|
|
|
-- Called by core on a hup signal.
|
|
|
|
--
|
2018-03-01 14:08:26 +00:00
|
|
|
function runner.hup
|
|
|
|
( )
|
|
|
|
log( 'Normal', '--- HUP signal, resetting ---' )
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2012-01-30 14:01:18 +00:00
|
|
|
lsyncdStatus = 'fade'
|
2010-11-14 09:11:09 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2010-11-14 09:11:09 +00:00
|
|
|
-- Called by core on a term signal.
|
|
|
|
--
|
2018-03-01 14:08:26 +00:00
|
|
|
function runner.term
|
|
|
|
(
|
|
|
|
sigcode -- signal code
|
|
|
|
)
|
|
|
|
local sigtexts =
|
|
|
|
{
|
|
|
|
[ 2 ] = 'INT',
|
|
|
|
[ 15 ] = 'TERM'
|
2013-07-30 10:20:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
local sigtext = sigtexts[ sigcode ];
|
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
if not sigtext then sigtext = 'UNKNOWN' end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
log( 'Normal', '--- ', sigtext, ' signal, fading ---' )
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2012-01-30 14:01:18 +00:00
|
|
|
lsyncdStatus = 'fade'
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2010-11-10 15:57:37 +00:00
|
|
|
end
|
2010-10-21 12:37:27 +00:00
|
|
|
|
2022-03-23 22:41:02 +00:00
|
|
|
--
|
|
|
|
-- Called by core on a term signal.
|
|
|
|
--
|
|
|
|
function runner.teardown
|
|
|
|
(
|
|
|
|
exitCode -- exitcode that will be returned
|
|
|
|
)
|
|
|
|
-- ensure we will all stray tunnels when we hard exit
|
|
|
|
Tunnels.killAll()
|
|
|
|
|
|
|
|
return exitCode
|
|
|
|
end
|
Implement tunnel pool mode.
In this mode, multiple tunnel processes are started and connection a load
balanced on the pool of connections.
Example config:
...
sync {
default.rsync,
tunnel = tunnel {
command = {"ssh", "-N", "-L", "localhost:${localport}:localhost:873", "user@testmachine"},
mode = "pool",
parallel = 2,
},
target = "rsync://localhost:${localport}/test",
...
}
2022-03-23 22:44:19 +00:00
|
|
|
|
2010-10-25 17:38:57 +00:00
|
|
|
--============================================================================
|
2012-10-03 15:37:49 +00:00
|
|
|
-- Lsyncd runner's user interface
|
2010-10-25 17:38:57 +00:00
|
|
|
--============================================================================
|
2010-10-17 15:24:55 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2010-11-05 15:18:01 +00:00
|
|
|
-- Main utility to create new observations.
|
|
|
|
--
|
2012-10-03 15:37:49 +00:00
|
|
|
-- Returns an Inlet to that sync.
|
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line: lowercase-global
|
2018-03-01 10:26:12 +00:00
|
|
|
function sync
|
|
|
|
(
|
|
|
|
opts
|
|
|
|
)
|
|
|
|
if lsyncdStatus ~= 'init'
|
|
|
|
then
|
|
|
|
error( 'Sync can only be created during initialization.', 2 )
|
2010-11-05 15:18:01 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
|
|
|
return Syncs.add( opts ).inlet
|
2010-11-05 15:18:01 +00:00
|
|
|
end
|
2010-10-17 15:24:55 +00:00
|
|
|
|
2010-10-19 16:40:49 +00:00
|
|
|
|
2010-10-27 11:31:18 +00:00
|
|
|
--
|
2012-10-03 15:37:49 +00:00
|
|
|
-- Spawns a new child process.
|
2010-11-07 01:06:08 +00:00
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line: lowercase-global
|
2012-10-03 15:37:49 +00:00
|
|
|
function spawn(
|
|
|
|
agent, -- the reason why a process is spawned.
|
|
|
|
-- a delay or delay list for a sync
|
|
|
|
-- it will mark the related files as blocked.
|
|
|
|
binary, -- binary to call
|
|
|
|
... -- arguments
|
|
|
|
)
|
2018-03-01 14:08:26 +00:00
|
|
|
if agent == nil
|
|
|
|
or type( agent ) ~= 'table'
|
2012-10-03 15:37:49 +00:00
|
|
|
then
|
2018-03-01 14:08:26 +00:00
|
|
|
error( 'spawning with an invalid agent', 2 )
|
2010-11-11 15:17:22 +00:00
|
|
|
end
|
2012-02-16 07:28:40 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
if lsyncdStatus == 'fade'
|
|
|
|
then
|
|
|
|
log( 'Normal', 'ignored process spawning while fading' )
|
2012-01-30 14:01:18 +00:00
|
|
|
return
|
2010-11-14 09:11:09 +00:00
|
|
|
end
|
2012-02-16 07:28:40 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
if type( binary ) ~= 'string'
|
|
|
|
then
|
|
|
|
error( 'calling spawn(agent, binary, ...): binary is not a string', 2 )
|
2010-12-03 19:47:33 +00:00
|
|
|
end
|
2012-02-16 07:28:40 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
local dol = InletFactory.getDelayOrList( agent )
|
2011-02-08 10:34:39 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
if not dol
|
|
|
|
then
|
|
|
|
error( 'spawning with an unknown agent', 2 )
|
2012-10-03 15:37:49 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- checks if a spawn is called on an already active event
|
|
|
|
--
|
2016-12-12 18:53:44 +00:00
|
|
|
if dol.status
|
|
|
|
then
|
2012-10-03 15:37:49 +00:00
|
|
|
-- is an event
|
|
|
|
|
2016-12-21 12:11:55 +00:00
|
|
|
if dol.status ~= 'wait'
|
|
|
|
then
|
2012-01-30 14:01:18 +00:00
|
|
|
error('spawn() called on an non-waiting event', 2)
|
2011-02-08 10:34:39 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
else
|
|
|
|
-- is a list
|
2016-12-12 18:53:44 +00:00
|
|
|
for _, d in ipairs( dol )
|
|
|
|
do
|
|
|
|
if d.status ~= 'wait'
|
|
|
|
and d.status ~= 'block'
|
|
|
|
then
|
|
|
|
error( 'spawn() called on an non-waiting event list', 2 )
|
2011-02-08 10:34:39 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
|
|
|
-- tries to spawn the process
|
|
|
|
--
|
|
|
|
local pid = lsyncd.exec( binary, ... )
|
2011-02-08 10:34:39 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
if pid and pid > 0
|
|
|
|
then
|
2011-08-18 13:29:18 +00:00
|
|
|
processCount = processCount + 1
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2018-03-01 14:08:26 +00:00
|
|
|
if uSettings.maxProcesses
|
|
|
|
and processCount > uSettings.maxProcesses
|
2012-10-03 15:37:49 +00:00
|
|
|
then
|
|
|
|
error( 'Spawned too much processes!' )
|
2011-08-18 13:29:18 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
|
|
|
local sync = InletFactory.getSync( agent )
|
|
|
|
|
2010-11-30 22:56:34 +00:00
|
|
|
-- delay or list
|
2016-12-12 18:53:44 +00:00
|
|
|
if dol.status
|
|
|
|
then
|
2010-11-30 22:56:34 +00:00
|
|
|
-- is a delay
|
2016-12-21 12:11:55 +00:00
|
|
|
dol:setActive( )
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
sync.processes[ pid ] = dol
|
2012-02-15 15:47:18 +00:00
|
|
|
else
|
2010-11-30 22:56:34 +00:00
|
|
|
-- is a list
|
2016-12-12 18:53:44 +00:00
|
|
|
for _, d in ipairs( dol )
|
|
|
|
do
|
2016-12-21 12:11:55 +00:00
|
|
|
d:setActive( )
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
2012-10-03 15:37:49 +00:00
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
sync.processes[ pid ] = dol
|
2010-11-12 18:52:43 +00:00
|
|
|
end
|
2010-11-07 01:06:08 +00:00
|
|
|
end
|
2010-11-05 13:34:02 +00:00
|
|
|
end
|
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2011-03-21 08:33:37 +00:00
|
|
|
-- Spawns a child process using the default shell.
|
2010-11-07 01:06:08 +00:00
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line: lowercase-global
|
2016-12-21 12:11:55 +00:00
|
|
|
function spawnShell
|
|
|
|
(
|
2012-10-03 15:37:49 +00:00
|
|
|
agent, -- the delay(list) to spawn the command for
|
|
|
|
command, -- the shell command
|
|
|
|
... -- additonal arguments
|
|
|
|
)
|
2022-01-12 19:46:41 +00:00
|
|
|
return spawn( agent, 'sh', '-c', command, 'sh', ... )
|
2010-10-27 11:31:18 +00:00
|
|
|
end
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2016-12-02 15:24:07 +00:00
|
|
|
--
|
|
|
|
-- Observes a filedescriptor.
|
2010-12-01 12:19:17 +00:00
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line: lowercase-global
|
2016-12-21 12:11:55 +00:00
|
|
|
function observefd
|
|
|
|
(
|
2012-10-03 15:37:49 +00:00
|
|
|
fd, -- file descriptor
|
|
|
|
ready, -- called when fd is ready to be read
|
|
|
|
writey -- called when fd is ready to be written
|
|
|
|
)
|
2018-03-01 14:08:26 +00:00
|
|
|
return lsyncd.observe_fd( fd, ready, writey )
|
2010-12-01 12:19:17 +00:00
|
|
|
end
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2010-12-01 12:19:17 +00:00
|
|
|
--
|
2016-12-02 15:24:07 +00:00
|
|
|
-- Stops observeing a filedescriptor.
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line: lowercase-global
|
2016-12-21 12:11:55 +00:00
|
|
|
function nonobservefd
|
|
|
|
(
|
2012-10-03 15:37:49 +00:00
|
|
|
fd -- file descriptor
|
|
|
|
)
|
|
|
|
return lsyncd.nonobserve_fd( fd )
|
2010-12-01 12:19:17 +00:00
|
|
|
end
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2010-11-30 23:14:17 +00:00
|
|
|
-- Calls func at timestamp.
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2010-11-30 23:14:17 +00:00
|
|
|
-- Use now() to receive current timestamp
|
2012-10-03 15:37:49 +00:00
|
|
|
-- add seconds with '+' to it
|
2010-11-30 23:14:17 +00:00
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line: lowercase-global
|
2010-11-30 23:14:17 +00:00
|
|
|
alarm = UserAlarms.alarm
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2010-11-10 11:23:26 +00:00
|
|
|
-- Comfort routine also for user.
|
|
|
|
-- Returns true if 'String' starts with 'Start'
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
function string.starts
|
|
|
|
(
|
|
|
|
String,
|
|
|
|
Start
|
|
|
|
)
|
2012-10-03 15:37:49 +00:00
|
|
|
return string.sub( String, 1, #Start )==Start
|
2010-11-10 11:23:26 +00:00
|
|
|
end
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2010-11-10 11:23:26 +00:00
|
|
|
-- Comfort routine also for user.
|
|
|
|
-- Returns true if 'String' ends with 'End'
|
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
function string.ends
|
|
|
|
(
|
|
|
|
String,
|
|
|
|
End
|
|
|
|
)
|
2012-10-03 15:37:49 +00:00
|
|
|
return End == '' or string.sub( String, -#End ) == End
|
2010-11-10 11:23:26 +00:00
|
|
|
end
|
|
|
|
|
2016-12-12 18:53:44 +00:00
|
|
|
|
2010-11-28 20:16:56 +00:00
|
|
|
--
|
2016-12-13 13:41:35 +00:00
|
|
|
-- The settings call
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2022-11-10 03:20:54 +00:00
|
|
|
--- @diagnostic disable-next-line: lowercase-global
|
2016-12-13 13:41:35 +00:00
|
|
|
function settings
|
|
|
|
(
|
|
|
|
a1 -- a string for getting a setting
|
|
|
|
-- or a table of key/value pairs to set these settings
|
|
|
|
)
|
2016-12-01 12:25:49 +00:00
|
|
|
|
2012-11-09 19:15:42 +00:00
|
|
|
-- if a1 is a string this is a get operation
|
2016-12-01 12:25:49 +00:00
|
|
|
if type( a1 ) == 'string'
|
|
|
|
then
|
2012-11-09 19:15:42 +00:00
|
|
|
return uSettings[ a1 ]
|
|
|
|
end
|
|
|
|
|
|
|
|
-- if its a table it sets all the value of the bale
|
2016-12-01 12:25:49 +00:00
|
|
|
for k, v in pairs( a1 )
|
|
|
|
do
|
|
|
|
if type( k ) ~= 'number'
|
|
|
|
then
|
|
|
|
if not settingsCheckgauge[ k ]
|
|
|
|
then
|
2018-03-01 14:08:26 +00:00
|
|
|
error( 'setting "'..k..'" unknown.', 2 )
|
2016-12-01 12:25:49 +00:00
|
|
|
end
|
|
|
|
|
2012-10-08 07:10:03 +00:00
|
|
|
uSettings[ k ] = v
|
|
|
|
else
|
2016-12-01 12:25:49 +00:00
|
|
|
if not settingsCheckgauge[ v ]
|
|
|
|
then
|
2018-03-01 14:08:26 +00:00
|
|
|
error( 'setting "'..v..'" unknown.', 2 )
|
2016-12-01 12:25:49 +00:00
|
|
|
end
|
|
|
|
|
2012-10-08 07:10:03 +00:00
|
|
|
uSettings[ v ] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-12-01 11:52:09 +00:00
|
|
|
|
2012-10-08 07:10:03 +00:00
|
|
|
settingsSafe = settings
|
2010-11-28 20:16:56 +00:00
|
|
|
|
2012-10-03 15:37:49 +00:00
|
|
|
--
|
2010-11-11 15:17:22 +00:00
|
|
|
-- Returns the core the runners function interface.
|
|
|
|
--
|
2010-11-10 15:57:37 +00:00
|
|
|
return runner
|