mirror of
https://github.com/octoleo/lsyncd.git
synced 2024-09-27 22:49:02 +00:00
move rsync actions into a script, this way rsync options are easily configureable, and the admin can freely change rsync behavior as well as add additional actions after rsyncs.
This commit is contained in:
parent
e1e6940146
commit
ad0a7398dd
60
lsyncd-action
Executable file
60
lsyncd-action
Executable file
@ -0,0 +1,60 @@
|
||||
#!/bin/bash
|
||||
|
||||
###
|
||||
# lsyncd-action
|
||||
#
|
||||
# This script will be called by lsyncd whenever it wants to sync something.
|
||||
# It is supposed to be configured or even completly exchanged by you, to fit your needs.
|
||||
#
|
||||
# First parameter is "startup" in case lsyncd startups, "change" in normal operation.
|
||||
# Second parameter is rsync source
|
||||
# Third parameter is rsync destition.
|
||||
#
|
||||
# When this script returns a non-zero error code, lsyncd will either die
|
||||
# or in the current implementation call it again with the parant directory if not in startup mode.
|
||||
#
|
||||
# This script is GPLv2 or later licensed like everything here.
|
||||
#
|
||||
set -e
|
||||
|
||||
###
|
||||
# You can add additional options you want to call rsync here.
|
||||
#
|
||||
RSYNC_OPTIONS="--delete -lt";
|
||||
|
||||
###
|
||||
# Adds -r (recursive) option in case of startup, or "-d" in case of normal operations.
|
||||
#
|
||||
case $1 in
|
||||
"startup") SCOPE="r";;
|
||||
"change") SCOPE="d";;
|
||||
*) echo "Unknown action reason option ($1)"; exit 1;;
|
||||
esac
|
||||
|
||||
###
|
||||
# The environment variable EXCLUDE_FILE will be set by lsyncd if an exclude file is configured.
|
||||
#
|
||||
if test $EXCLUDE_FILE != ""; then
|
||||
EXCLUDE_FILE="--exclude-from $EXCLUDE_FILE"
|
||||
fi
|
||||
|
||||
while true; do
|
||||
EXITVAL=0
|
||||
echo /usr/bin/rsync $RSYNC_OPTIONS$SCOPE $EXCLUDE_FILE $2 $3 || EXITVAL=$?
|
||||
/usr/bin/rsync $RSYNC_OPTIONS$SCOPE $EXCLUDE_FILE $2 $3 || EXITVAL=$?
|
||||
case $EXITVAL in
|
||||
0) # everything okay
|
||||
break;;
|
||||
5|10|12) # on temporary errors recall rsync
|
||||
echo "recalling rsync on non-fatal error ($EXITVAL)"
|
||||
sleep 10
|
||||
;;
|
||||
*) # really bad error
|
||||
exit $EXITVAL;;
|
||||
esac
|
||||
done
|
||||
|
||||
###
|
||||
# If you want to add some actions to be performed after rsync you can do here...
|
||||
#
|
||||
|
103
lsyncd.c
103
lsyncd.c
@ -41,7 +41,7 @@
|
||||
int loglevel = LOG_NORMAL;
|
||||
|
||||
/**
|
||||
* Option: if true rsync will not be actually called.
|
||||
* Option: if true action will not be actually called.
|
||||
*/
|
||||
int flag_dryrun = 0;
|
||||
|
||||
@ -63,7 +63,7 @@ char * option_target = NULL;
|
||||
/**
|
||||
* Option: rsync binary to call.
|
||||
*/
|
||||
char * rsync_binary = "/usr/bin/rsync";
|
||||
char * action_binary = "./lsyncd-action";
|
||||
|
||||
/**
|
||||
* Option: the exclude-file to pass to rsync.
|
||||
@ -83,7 +83,6 @@ char * pidfile = NULL;
|
||||
/**
|
||||
* Structure to store the directory watches of the deamon.
|
||||
*/
|
||||
|
||||
struct dir_watch {
|
||||
/**
|
||||
* The watch descriptor returned by kernel.
|
||||
@ -172,18 +171,26 @@ char * logfile = "/var/log/lsyncd";
|
||||
int inotf;
|
||||
|
||||
/**
|
||||
* Possible Exit codes for this application
|
||||
* Possible exit codes for this application.
|
||||
*/
|
||||
enum lsyncd_exit_code
|
||||
{
|
||||
LSYNCD_SUCCESS = 0,
|
||||
LSYNCD_OUTOFMEMORY = 1, /* out-of memory */
|
||||
LSYNCD_FILENOTFOUND = 2, /* file was not found, or failed to write */
|
||||
LSYNCD_EXECRSYNCFAIL = 3, /* rsync execution somehow failed */
|
||||
LSYNCD_EXECFAIL = 3, /* action execution somehow failed */
|
||||
LSYNCD_NOTENOUGHARGUMENTS = 4, /* Not enough command-line arguments were given to lsyncd invocation */
|
||||
LSYNCD_TOOMANYDIRECTORYEXCLUDES = 5, /* Too many excludes files were specified */
|
||||
};
|
||||
|
||||
/**
|
||||
* Reason why calling the action script.
|
||||
*/
|
||||
enum action_reason
|
||||
{
|
||||
ACTION_STARTUP = 0,
|
||||
ACTION_CHANGE
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -356,44 +363,31 @@ char *realdir(const char * dir)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls rsync to sync from src to dest.
|
||||
* Calls the action script to sync from src to dest.
|
||||
* Returns after rsync has finished.
|
||||
*
|
||||
* @param state Reason why action is called, 0: startup, 1: change
|
||||
* @param src Source string.
|
||||
* @param dest Destination string,
|
||||
* @param recursive If true -r will be handled on, -d (single directory) otherwise
|
||||
* @return true if successful, false if not.
|
||||
*/
|
||||
bool rsync(char const * src, const char * dest, bool recursive)
|
||||
bool action(int reason, char * src, char * dest)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
char const * opts = recursive ? "-ltr" : "-ltd";
|
||||
const int MAX_ARGS = 100;
|
||||
char * argv[MAX_ARGS];
|
||||
int argc=0;
|
||||
int i;
|
||||
int status = 0;
|
||||
//char const * opts = recursive ? "-ltr" : "-ltd";
|
||||
const int MAX_ARGS = 10;
|
||||
char * const argv[] = {action_binary,
|
||||
reason == ACTION_STARTUP ? "startup" : "change",
|
||||
src,
|
||||
dest,
|
||||
NULL};
|
||||
|
||||
argv[argc++] = s_strdup(rsync_binary);
|
||||
argv[argc++] = s_strdup("--delete");
|
||||
argv[argc++] = s_strdup(opts);
|
||||
if (exclude_file) {
|
||||
argv[argc++] = s_strdup("--exclude-from");
|
||||
argv[argc++] = s_strdup(exclude_file);
|
||||
}
|
||||
argv[argc++] = s_strdup(src);
|
||||
argv[argc++] = s_strdup(dest);
|
||||
argv[argc++] = NULL;
|
||||
|
||||
if (argc > MAX_ARGS) { /* check for error condition */
|
||||
printlogf(LOG_ERROR, "Internal error: too many (%i) options passed", argc);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* debug dump of command-line options */
|
||||
for (i=0; i<argc; ++i) {
|
||||
printlogf(LOG_DEBUG, "exec parameter %i:%s", i, argv[i]);
|
||||
}
|
||||
//argv[argc++] = s_strdup("--delete");
|
||||
//if (exclude_file) {
|
||||
// argv[argc++] = s_strdup("--exclude-from");
|
||||
// argv[argc++] = s_strdup(exclude_file);
|
||||
//}
|
||||
|
||||
if (flag_dryrun) {
|
||||
return true;
|
||||
@ -407,22 +401,18 @@ bool rsync(char const * src, const char * dest, bool recursive)
|
||||
freopen(logfile, "a", stderr);
|
||||
}
|
||||
|
||||
execv(rsync_binary, argv);
|
||||
setenv("EXCLUDE_FILE", exclude_file, 1);
|
||||
execv(action_binary, argv);
|
||||
|
||||
printlogf(LOG_ERROR, "Failed executing [%s]", rsync_binary);
|
||||
|
||||
exit(LSYNCD_EXECRSYNCFAIL);
|
||||
}
|
||||
|
||||
for (i=0; i<argc; ++i) {
|
||||
if (argv[i])
|
||||
free(argv[i]);
|
||||
printlogf(LOG_ERROR, "Failed executing [%s]", action_binary);
|
||||
exit(LSYNCD_EXECFAIL);
|
||||
}
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
assert(WIFEXITED(status));
|
||||
|
||||
if (WEXITSTATUS(status)){
|
||||
printlogf(LOG_NORMAL, "Forked rsync process returned non-zero return code: %i", WEXITSTATUS(status));
|
||||
printlogf(LOG_ERROR, "Action process returned non-zero, non-repeat error code: %i", WEXITSTATUS(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -757,7 +747,7 @@ bool handle_event(struct inotify_event *event)
|
||||
// call rsync to propagate changes in the directory
|
||||
if ((IN_CREATE | IN_CLOSE_WRITE | IN_DELETE | IN_MOVED_TO | IN_MOVED_FROM) & event->mask) {
|
||||
printlogf(LOG_NORMAL, "%s of %s in %s --> %s", masktext, event->name, pathname, destname);
|
||||
if (!rsync(pathname, destname, false)) {
|
||||
if (!action(ACTION_CHANGE, pathname, destname)) {
|
||||
// if error on partial rsync, retry with parent dir rsync
|
||||
if (dir_watches[i].parent != -1) {
|
||||
buildpath(pathname, sizeof(pathname), dir_watches[i].parent, NULL, NULL);
|
||||
@ -765,9 +755,9 @@ bool handle_event(struct inotify_event *event)
|
||||
|
||||
printlogf(LOG_NORMAL, "Retry Directory resync with %s to %s",
|
||||
pathname, destname);
|
||||
if (!rsync(pathname, destname, true)) {
|
||||
if (!action(ACTION_CHANGE, pathname, destname)) {
|
||||
printlogf(LOG_ERROR, "Retry of rsync from %s to %s failed", pathname, destname);
|
||||
exit(LSYNCD_EXECRSYNCFAIL);
|
||||
exit(LSYNCD_EXECFAIL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -861,8 +851,7 @@ void print_help(char *arg0)
|
||||
printf(" --logfile FILE Put log here (DEFAULT: %s)\n",
|
||||
logfile);
|
||||
printf(" --no-daemon Do not detach, log to stdout/stderr\n");
|
||||
printf(" --rsync-binary FILE Call this binary to sync (DEFAULT: %s)\n",
|
||||
rsync_binary);
|
||||
printf(" --action-binary FILE Call this binary to sync (DEFAULT: %s)\n", action_binary);
|
||||
printf(" --pidfile FILE Create a file containing pid of the daemon\n");
|
||||
printf(" --scarce Only log errors\n");
|
||||
printf(" --version Print version an exit.\n");
|
||||
@ -895,7 +884,7 @@ bool parse_options(int argc, char **argv)
|
||||
{"help", 0, NULL, 0},
|
||||
{"logfile", 1, NULL, 0},
|
||||
{"no-daemon", 0, &flag_nodaemon, 1},
|
||||
{"rsync-binary", 1, NULL, 0},
|
||||
{"action-binary", 1, NULL, 0},
|
||||
{"pidfile", 1, NULL, 0},
|
||||
{"scarce", 0, &loglevel, 3},
|
||||
{"version", 0, NULL, 0},
|
||||
@ -934,18 +923,16 @@ bool parse_options(int argc, char **argv)
|
||||
exclude_file = s_strdup(optarg);
|
||||
}
|
||||
|
||||
if (!strcmp("rsync-binary", long_options[oi].name)) {
|
||||
rsync_binary = s_strdup(optarg);
|
||||
if (!strcmp("action-binary", long_options[oi].name)) {
|
||||
action_binary = s_strdup(optarg);
|
||||
}
|
||||
|
||||
if (!strcmp("pidfile", long_options[oi].name)) {
|
||||
pidfile = s_strdup(optarg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (optind + 2 != argc) {
|
||||
printf("Error: please specify SOURCE and TARGET (see --help)\n");
|
||||
exit(LSYNCD_NOTENOUGHARGUMENTS);
|
||||
@ -1061,6 +1048,8 @@ int main(int argc, char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
action_binary = realpath(action_binary, NULL);
|
||||
|
||||
if (exclude_file) {
|
||||
parse_exclude_file();
|
||||
}
|
||||
@ -1088,9 +1077,9 @@ int main(int argc, char **argv)
|
||||
|
||||
printlogf(LOG_NORMAL, "watching %s", option_source);
|
||||
add_dirwatch(option_source, "", true, -1);
|
||||
if (!rsync(option_source, option_target, true)) {
|
||||
printlogf(LOG_ERROR, "Initial rsync from %s to %s failed", option_source, option_target);
|
||||
exit(LSYNCD_EXECRSYNCFAIL);
|
||||
if (!action(ACTION_STARTUP, option_source, option_target)) {
|
||||
printlogf(LOG_ERROR, "Initial sync action from %s to %s failed", option_source, option_target);
|
||||
exit(LSYNCD_EXECFAIL);
|
||||
}
|
||||
|
||||
printlogf(LOG_NORMAL, "--- Entering normal operation with [%d] monitored directories ---", dir_watch_num);
|
||||
|
Loading…
Reference in New Issue
Block a user