Revert "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 reverts commit e4727016c88bce6330cb944b8fa7e15a20ddea48.
This commit is contained in:
Junichi Uekawa 2008-11-03 13:09:40 +00:00
parent 4820dbbc49
commit b85f94bf43
2 changed files with 71 additions and 120 deletions

View File

@ -1,60 +0,0 @@
#!/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...
#

131
lsyncd.c
View File

@ -41,7 +41,7 @@
int loglevel = LOG_NORMAL;
/**
* Option: if true action will not be actually called.
* Option: if true rsync will not be actually called.
*/
int flag_dryrun = 0;
@ -63,7 +63,7 @@ char * option_target = NULL;
/**
* Option: rsync binary to call.
*/
char * action_binary = "./lsyncd-action";
char * rsync_binary = "/usr/bin/rsync";
/**
* Option: the exclude-file to pass to rsync.
@ -83,6 +83,7 @@ char * pidfile = NULL;
/**
* Structure to store the directory watches of the deamon.
*/
struct dir_watch {
/**
* The watch descriptor returned by kernel.
@ -171,27 +172,19 @@ 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_EXECFAIL = 3, /* action execution somehow failed */
LSYNCD_NOTENOUGHARGUMENTS = 4, /* Not enough command-line arguments were given to lsyncd invocation */
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_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
};
/**
@ -363,31 +356,44 @@ char *realdir(const char * dir)
}
/**
* Calls the action script to sync from src to dest.
* Calls rsync 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 action(int reason, char * src, char * dest)
bool rsync(char const * src, const char * dest, bool recursive)
{
pid_t pid;
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};
int status;
char const * opts = recursive ? "-ltr" : "-ltd";
const int MAX_ARGS = 100;
char * argv[MAX_ARGS];
int argc=0;
int i;
//argv[argc++] = s_strdup("--delete");
//if (exclude_file) {
// argv[argc++] = s_strdup("--exclude-from");
// argv[argc++] = s_strdup(exclude_file);
//}
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]);
}
if (flag_dryrun) {
return true;
@ -400,19 +406,23 @@ bool action(int reason, char * src, char * dest)
freopen(logfile, "a", stdout);
freopen(logfile, "a", stderr);
}
setenv("EXCLUDE_FILE", exclude_file, 1);
execv(action_binary, argv);
printlogf(LOG_ERROR, "Failed executing [%s]", action_binary);
exit(LSYNCD_EXECFAIL);
execv(rsync_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]);
}
waitpid(pid, &status, 0);
assert(WIFEXITED(status));
if (WEXITSTATUS(status)){
printlogf(LOG_ERROR, "Action process returned non-zero, non-repeat error code: %i", WEXITSTATUS(status));
printlogf(LOG_NORMAL, "Forked rsync process returned non-zero return code: %i", WEXITSTATUS(status));
return false;
}
@ -747,7 +757,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 (!action(ACTION_CHANGE, pathname, destname)) {
if (!rsync(pathname, destname, false)) {
// 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);
@ -755,9 +765,9 @@ bool handle_event(struct inotify_event *event)
printlogf(LOG_NORMAL, "Retry Directory resync with %s to %s",
pathname, destname);
if (!action(ACTION_CHANGE, pathname, destname)) {
if (!rsync(pathname, destname, true)) {
printlogf(LOG_ERROR, "Retry of rsync from %s to %s failed", pathname, destname);
exit(LSYNCD_EXECFAIL);
exit(LSYNCD_EXECRSYNCFAIL);
}
}
}
@ -851,7 +861,8 @@ 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(" --action-binary FILE Call this binary to sync (DEFAULT: %s)\n", action_binary);
printf(" --rsync-binary FILE Call this binary to sync (DEFAULT: %s)\n",
rsync_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");
@ -878,16 +889,16 @@ bool parse_options(int argc, char **argv)
{
static struct option long_options[] = {
{"debug", 0, &loglevel, 1},
{"dryrun", 0, &flag_dryrun, 1},
{"exclude-from", 1, NULL, 0},
{"help", 0, NULL, 0},
{"logfile", 1, NULL, 0},
{"no-daemon", 0, &flag_nodaemon, 1},
{"action-binary", 1, NULL, 0},
{"pidfile", 1, NULL, 0},
{"scarce", 0, &loglevel, 3},
{"version", 0, NULL, 0},
{"debug", 0, &loglevel, 1},
{"dryrun", 0, &flag_dryrun, 1},
{"exclude-from", 1, NULL, 0},
{"help", 0, NULL, 0},
{"logfile", 1, NULL, 0},
{"no-daemon", 0, &flag_nodaemon, 1},
{"rsync-binary", 1, NULL, 0},
{"pidfile", 1, NULL, 0},
{"scarce", 0, &loglevel, 3},
{"version", 0, NULL, 0},
{0, 0, 0, 0}
};
@ -923,16 +934,18 @@ bool parse_options(int argc, char **argv)
exclude_file = s_strdup(optarg);
}
if (!strcmp("action-binary", long_options[oi].name)) {
action_binary = s_strdup(optarg);
if (!strcmp("rsync-binary", long_options[oi].name)) {
rsync_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);
@ -1048,8 +1061,6 @@ int main(int argc, char **argv)
return -1;
}
action_binary = realpath(action_binary, NULL);
if (exclude_file) {
parse_exclude_file();
}
@ -1077,9 +1088,9 @@ int main(int argc, char **argv)
printlogf(LOG_NORMAL, "watching %s", option_source);
add_dirwatch(option_source, "", true, -1);
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);
if (!rsync(option_source, option_target, true)) {
printlogf(LOG_ERROR, "Initial rsync from %s to %s failed", option_source, option_target);
exit(LSYNCD_EXECRSYNCFAIL);
}
printlogf(LOG_NORMAL, "--- Entering normal operation with [%d] monitored directories ---", dir_watch_num);