This commit is contained in:
Axel Kittenberger 2010-10-28 17:56:33 +00:00
parent 9976269bfb
commit d823e8b580
3 changed files with 125 additions and 33 deletions

View File

@ -5,8 +5,8 @@
-- --
settings = { settings = {
-- logfile = "/tmp/lsyncd", -- logfile = "/tmp/lsyncd",
nodaemon, -- nodaemon,
statuspipe = "/tmp/lsyncd.stat", statusfile = "/tmp/lsyncd.stat",
loglevel = DEBUG, loglevel = DEBUG,
} }

115
lsyncd.c
View File

@ -24,6 +24,7 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <signal.h> #include <signal.h>
#include <stdbool.h> #include <stdbool.h>
@ -100,7 +101,7 @@ static int inotify_fd;
/** /**
* TODO allow configure. * TODO allow configure.
*/ */
static const uint32_t standard_event_mask = static const uint32_t standard_event_mask =
IN_ATTRIB | IN_CLOSE_WRITE | IN_CREATE | IN_ATTRIB | IN_CLOSE_WRITE | IN_CREATE |
IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM | IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM |
IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR; IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR;
@ -131,11 +132,19 @@ enum loglevel {
* configuration parameters * configuration parameters
*/ */
static struct settings { static struct settings {
/**
* threshold for log messages
*/
enum loglevel loglevel; enum loglevel loglevel;
char * statuspipe;
/**
* lsyncd will periodically write its status in this
* file if configured so. (for special observing only)
*/
char * statusfile;
} settings = { } settings = {
.loglevel = DEBUG, .loglevel = DEBUG,
.statuspipe = NULL, .statusfile = NULL,
}; };
/** /**
@ -443,6 +452,7 @@ l_addto_clock(lua_State *L)
lua_pushinteger(L, c1 + c2 * clocks_per_sec); lua_pushinteger(L, c1 + c2 * clocks_per_sec);
return 1; return 1;
} }
/** /**
* Executes a subprocess. Does not wait for it to return. * Executes a subprocess. Does not wait for it to return.
* *
@ -468,17 +478,20 @@ l_exec(lua_State *L)
pid = fork(); pid = fork();
if (pid == 0) { if (pid == 0) {
// TODO /* if lsyncd runs as a daemon and has a logfile it will redirect
//if (!log->flag_nodaemon && log->logfile) { stdout/stderr of child processes to the logfile. */
// if (!freopen(log->logfile, "a", stdout)) { if (is_daemon && logfile) {
// printlogf(log, ERROR, "cannot redirect stdout to [%s].", log->logfile); if (!freopen(logfile, "a", stdout)) {
// } printlogf(L, ERROR,
// if (!freopen(log->logfile, "a", stderr)) { "cannot redirect stdout to '%s'.", logfile);
// printlogf(log, ERROR, "cannot redirect stderr to [%s].", log->logfile); }
// } if (!freopen(logfile, "a", stderr)) {
//} printlogf(L, ERROR,
"cannot redirect stderr to '%s'.", logfile);
}
}
execv(binary, (char **)argv); execv(binary, (char **)argv);
// in a sane world execv does not return! /* in a sane world execv does not return! */
printlogf(L, ERROR, "Failed executing [%s]!", binary); printlogf(L, ERROR, "Failed executing [%s]!", binary);
exit(-1); // ERRNO exit(-1); // ERRNO
} }
@ -511,10 +524,16 @@ l_real_dir(lua_State *L)
{ {
/* makes sure its a directory */ /* makes sure its a directory */
struct stat st; struct stat st;
stat(cbuf, &st); if (stat(cbuf, &st)) {
printlogf(L, ERROR,
"cannot get absolute path of dir '%s': %s",
rdir, strerror(errno));
return 0;
}
if (!S_ISDIR(st.st_mode)) { if (!S_ISDIR(st.st_mode)) {
printlogf(L, ERROR, printlogf(L, ERROR,
"failure in real_dir '%s' is not a directory", rdir); "cannot get absolute path of dir '%s': is not a directory",
rdir);
free(cbuf); free(cbuf);
return 0; return 0;
} }
@ -617,6 +636,21 @@ l_sub_dirs (lua_State *L)
return 1; return 1;
} }
/**
* Writes a string to a file descriptor
*
* @param (Lua Stack) file descriptor
* @param (Lua Stack) string.
*/
int
l_writefd(lua_State *L)
{
int fd = luaL_checkinteger(L, 1);
const char *s = luaL_checkstring(L, 2);
write(fd, s, strlen(s));
return 0;
}
/** /**
* Terminates lsyncd daemon. * Terminates lsyncd daemon.
* *
@ -740,13 +774,12 @@ static int
l_configure(lua_State *L) l_configure(lua_State *L)
{ {
const char * command = luaL_checkstring(L, 1); const char * command = luaL_checkstring(L, 1);
if (!strcmp(command, "statuspipe")) { if (!strcmp(command, "statusfile")) {
/* configures the status pipe lsyncd will dump /* configures the status file lsyncd will dump its status to */
* its status to if opened*/ if (settings.statusfile) {
if (settings.statuspipe) { free(settings.statusfile);
free(settings.statuspipe);
} }
settings.statuspipe = s_strdup(luaL_checkstring(L, 2)); settings.statusfile = s_strdup(luaL_checkstring(L, 2));
} else if (!strcmp(command, "loglevel")) { } else if (!strcmp(command, "loglevel")) {
settings.loglevel = luaL_checkinteger(L, 2); settings.loglevel = luaL_checkinteger(L, 2);
} else if (!strcmp(command, "running")) { } else if (!strcmp(command, "running")) {
@ -773,6 +806,7 @@ static const luaL_reg lsyncdlib[] = {
{"exec", l_exec }, {"exec", l_exec },
{"log", l_log }, {"log", l_log },
{"now", l_now }, {"now", l_now },
{"writefd", l_writefd },
{"real_dir", l_real_dir }, {"real_dir", l_real_dir },
{"stackdump", l_stackdump }, {"stackdump", l_stackdump },
{"sub_dirs", l_sub_dirs }, {"sub_dirs", l_sub_dirs },
@ -813,8 +847,15 @@ printlogf(lua_State *L,
* Lsyncd buffers MOVE_FROM events to check if * Lsyncd buffers MOVE_FROM events to check if
*/ */
struct inotify_event * move_event_buf = NULL; struct inotify_event * move_event_buf = NULL;
/**
* Memory allocated for move_event_buf
*/
size_t move_event_buf_size = 0; size_t move_event_buf_size = 0;
/* true if the buffer is used.*/
/**
* true if the buffer is used.
*/
bool move_event = false; bool move_event = false;
/** /**
@ -826,6 +867,7 @@ void handle_event(lua_State *L, struct inotify_event *event) {
/* used to execute two events in case of unmatched MOVE_FROM buffer */ /* used to execute two events in case of unmatched MOVE_FROM buffer */
struct inotify_event *after_buf = NULL; struct inotify_event *after_buf = NULL;
logstring(DEBUG, "got an event");
if (reset) { if (reset) {
return; return;
@ -1015,7 +1057,7 @@ masterloop(lua_State *L)
handle_event(L, NULL); handle_event(L, NULL);
} }
/* collect zombified child processes */ /* collects zombified child processes */
while(1) { while(1) {
int status; int status;
pid_t pid = waitpid(0, &status, WNOHANG); pid_t pid = waitpid(0, &status, WNOHANG);
@ -1028,7 +1070,29 @@ masterloop(lua_State *L)
lua_call(L, 2, 0); lua_call(L, 2, 0);
} }
/* let the runner spawn new processes */ /* writes status of lsyncd in a file */
/* this is not a real loop, it will only be runned once max.
* this is just using break as comfortable jump down. */
while (settings.statusfile) {
int fd = open(settings.statusfile, O_WRONLY | O_CREAT | O_TRUNC);
if (fd < 0) {
printlogf(L, ERROR,
"Cannot open statusfile '%s' for writing.",
settings.statusfile);
break;
}
/* calls the lua runner to write the status. */
lua_getglobal(L, "lsyncd_status_report");
lua_pushinteger(L, fd);
lua_call(L, 1, 0);
/* TODO */
fsync(fd);
close(fd);
break;
}
/* lets the runner spawn new processes */
lua_getglobal(L, "lsyncd_alarm"); lua_getglobal(L, "lsyncd_alarm");
lua_pushinteger(L, times(NULL)); lua_pushinteger(L, times(NULL));
lua_call(L, 1, 0); lua_call(L, 1, 0);
@ -1036,7 +1100,7 @@ masterloop(lua_State *L)
} }
/** /**
* Prints a minimal help if e.g. config_file is missing * Prints a minimal help if e.g. config_file is missing.
*/ */
void minihelp(char *arg0) void minihelp(char *arg0)
{ {
@ -1045,7 +1109,6 @@ void minihelp(char *arg0)
fprintf(stderr, " Specify -help for more help.\n"); fprintf(stderr, " Specify -help for more help.\n");
} }
/** /**
* Main * Main
*/ */

View File

@ -188,7 +188,9 @@ end
---- ----
-- Table of all root directories to sync, -- origins
--
-- table of all root directories to sync.
-- filled during initialization. -- filled during initialization.
-- --
-- [#] { -- [#] {
@ -212,11 +214,19 @@ end
-- } -- }
-- --
local origins = new_array() local origins = new_array()
local proto_origin = {actions=true, source=true, targetident=true, processes=true, delays=true, delaywd=true} local proto_origin = {
local proto_delay = {atype =true, alarm=true, wd=true, sync=true, filename=true, movepeer=true} actions=true, source=true, targetident=true,
processes=true, delays=true, delaywd=true
}
local proto_delay = {
atype =true, alarm=true, wd=true,
sync=true, filename=true, movepeer=true
}
----- -----
-- all watches -- watches
--
-- contains all inotify watches.
-- --
-- structure: -- structure:
-- [wd] = { -- [wd] = {
@ -439,6 +449,25 @@ local function invoke_action(delay)
end end
----
-- Called from core to get a status report written into a file descriptor
--
function lsyncd_status_report(fd)
local w = lsyncd.writefd
w(fd, "Lsyncd status report at "..os.date().."\n\n")
w(fd, "Watching "..watches.size.." directories\n")
for i, v in pairs(watches) do
w(fd, " "..i..": ")
if i ~= v.wd then
w(fd, "[Error: wd/v.wd "..i.."~="..v.wd.."]")
end
for _, s in pairs(v.syncs) do
w(fd, "("..s.origin.source.."//"..s.origin.path..")")
end
w(fd, "\n")
end
end
---- ----
-- Called from core everytime at the latest of an -- Called from core everytime at the latest of an
-- expired alarm (or more often) -- expired alarm (or more often)
@ -511,7 +540,7 @@ function lsyncd_initialize(args)
terminate(-1); -- ERRNO terminate(-1); -- ERRNO
end end
end}, end},
statuspipe = {1, nil}, statusfile = {1, nil},
} }
-- check all entries in the settings table -- check all entries in the settings table