see Changelog (parallell targets, some bug fixes

This commit is contained in:
Axel Kittenberger 2010-10-04 13:03:08 +00:00
parent 2b70960933
commit 9e66ac3686
2 changed files with 116 additions and 35 deletions

View File

@ -1,3 +1,11 @@
04-10-2010: 1.39
enhancement: call action for multiple targets simultanously
fix: correctly accept <file-filter/> from config xml
fix: correctly close and free the inotify file descriptor in case of restart
due to HUP signal or OVERFLOW condition
fix: when delay=0 a bug always called rsync file filter even when in
directory mode
01-09-2010: 1.38
enhancement: implemented file filters for singular operations
enhancement: added --singular parameter for single file calls

143
lsyncd.c
View File

@ -339,7 +339,8 @@ struct global_options {
* Standard default options to call the binary with.
*/
struct call_option standard_callopts[] = {
{ CO_TEXT, "-lts%r" },
// { CO_TEXT, "-lts%r" }, AXK!
{ CO_TEXT, "-lt%r" },
{ CO_TEXT, "--delete" },
{ CO_EXCLUDE, NULL },
{ CO_FILTER, NULL },
@ -1307,7 +1308,7 @@ get_arg_str(const struct log *log, char **argv, int argc) {
*
* @return true if successful, false if not.
*/
bool
pid_t
action(const struct global_options *opts,
struct dir_conf *dir_conf,
const char *src,
@ -1316,7 +1317,6 @@ action(const struct global_options *opts,
bool recursive)
{
pid_t pid;
int status;
const int MAX_ARGS = 100;
char * argv[MAX_ARGS];
int argc = 0;
@ -1329,9 +1329,7 @@ action(const struct global_options *opts,
// makes a copy of all call parameters
// step 1 binary itself
argv[argc++] = s_strdup(log, dir_conf->binary ? dir_conf->binary : opts->default_binary, "argv");
printlogf(log, NORMAL, " %s %s --> %s%s", argv[0], src, dest, recursive ? " (recursive)" : "");
// now all other parameters
for(; optp->kind != CO_EOL; optp++) {
switch (optp->kind) {
@ -1371,7 +1369,7 @@ action(const struct global_options *opts,
// check for error condition
printlogf(log, ERROR,
"Error: too many (>%i) options passed", argc);
return false;
return 0;
}
}
argv[argc++] = NULL;
@ -1391,7 +1389,7 @@ action(const struct global_options *opts,
s_free(argv[i]);
}
}
return true;
return 0;
}
}
@ -1413,7 +1411,9 @@ action(const struct global_options *opts,
printlogf(log, ERROR, "Failed executing [%s]", binary);
terminate(log, LSYNCD_INTERNALFAIL);
}
printlogf(log, NORMAL, " %s %s --> %s%s [%d]", argv[0], src, dest, recursive ? " (recursive)" : "", pid);
// free the memory from the arguments.
for (i = 0; i < argc; ++i) {
if (argv[i]) {
@ -1421,24 +1421,7 @@ action(const struct global_options *opts,
}
}
waitpid(pid, &status, 0);
assert(WIFEXITED(status));
if (WEXITSTATUS(status) == LSYNCD_INTERNALFAIL){
printlogf(log, ERROR,
"Fork exit code of %i, execv failure",
WEXITSTATUS(status));
return false;
} else if (WEXITSTATUS(status)) {
printlogf(log, NORMAL,
"Forked binary process returned non-zero return code: %i",
WEXITSTATUS(status));
return false;
}
printlogf(log, DEBUG, "Rsync of [%s%s%s] -> [%s] finished", src,
filename ? "/" : "", filename ? filename : "",
dest);
return true;
return pid;
}
/**
@ -1592,6 +1575,60 @@ buildpath(const struct log *log,
return true;
}
/**
* Waits for n children to return.
* Returns true if all had 0 exit code.
*/
bool
waitchildren(const struct log *log,
pid_t *children,
int n)
{
int nr; // amount of children returned
bool retval = true;
for(nr = 0; nr < n;) {
int status, i;
pid_t pid = wait(&status); // wait for a child.
if (!keep_going) {
// canceled.
return false;
}
for (i = 0; i < n; i++) {
if (children[i] == pid) { // found child in the list
children[i] = 0;
break;
}
}
if (i >= n) {
printlogf(log, DEBUG, "unknown child %d returned!", pid);
continue;
}
nr++;
assert(WIFEXITED(status));
if (WEXITSTATUS(status) == LSYNCD_INTERNALFAIL){
printlogf(log, ERROR,
"Fork exit code of %i, execv failure",
WEXITSTATUS(status));
retval = false;
continue;
} else if (WEXITSTATUS(status)) {
printlogf(log, NORMAL,
"Forked binary process returned non-zero return code: %i",
WEXITSTATUS(status));
retval = false;
continue;
}
printlogf(log, DEBUG, "Rsync of pid %d finished", pid);
if (nr + 1 < n) {
printlogf(log, DEBUG, "Waiting for another %d child(ren).", n - nr - 1);
}
}
printlogf(log, DEBUG, "Finished waiting for all children");
return retval;
}
/**
* Syncs a directory.
* TODO: make better error handling (differ between
@ -1613,9 +1650,9 @@ rsync_dir(const struct global_options *opts,
{
char pathname[PATH_MAX+1];
char destname[PATH_MAX+1];
bool status = true;
char ** target;
const struct log *log = &opts->log;
int ntarget = 0;
if (!buildpath(log, pathname, sizeof(pathname), watch, NULL, NULL)) {
return false;
@ -1627,18 +1664,47 @@ rsync_dir(const struct global_options *opts,
printlogf(log, NORMAL, "%s: acting for %s.", event_text, pathname);
}
// count the amount of targets
for (target = watch->dir_conf->targets; *target; target++) {
if (!buildpath(log, destname, sizeof(destname), watch, NULL, *target)) {
status = false;
continue;
ntarget++;
}
if (ntarget == 1) {
pid_t child;
if (!buildpath(log, destname, sizeof(destname), watch, NULL, *watch->dir_conf->targets)) {
return false;
}
// call the action to propagate changes in the directory
if (!action(opts, watch->dir_conf, pathname, destname, filename, false)) {
child = action(opts, watch->dir_conf, pathname, destname, filename, false);
if (!child) {
printlogf(log, ERROR, "Action %s --> %s has failed.", pathname, destname);
return false;
}
return waitchildren(log, &child, 1);
} else {
bool status = true;
int ci = 0; // position of children started.
pid_t *children = s_calloc(log, ntarget, sizeof(pid_t), "children pid list");
for (target = watch->dir_conf->targets; *target; target++) {
if (!buildpath(log, destname, sizeof(destname), watch, NULL, *target)) {
status = false;
ntarget--;
continue;
}
// call the action to propagate changes in the directory
children[ci] = action(opts, watch->dir_conf, pathname, destname, filename, false);
if (!children[ci]) {
printlogf(log, ERROR, "Action %s --> %s has failed.", pathname, destname);
status = false;
}
ci++;
}
if (!waitchildren(log, children, ntarget)) {
status = false;
}
s_free(children);
return status;
}
return status;
}
/**
@ -1667,7 +1733,11 @@ delay_or_act_dir(const struct global_options *opts,
char pathname[PATH_MAX+1];
if (!delay) {
rsync_dir(opts, watch, filename, event_text);
if (opts->flag_singular) {
rsync_dir(opts, watch, filename, event_text);
} else {
rsync_dir(opts, watch, NULL, event_text);
}
} else {
bool ret;
if (!buildpath(log, pathname, sizeof(pathname), watch, NULL, NULL)) {
@ -2295,6 +2365,7 @@ parse_callopts(struct global_options *opts, xmlNodePtr node) {
}
if (xmlStrcmp(cnode->name, BAD_CAST "option") &&
xmlStrcmp(cnode->name, BAD_CAST "exclude-file") &&
xmlStrcmp(cnode->name, BAD_CAST "file-filter") &&
xmlStrcmp(cnode->name, BAD_CAST "source") &&
xmlStrcmp(cnode->name, BAD_CAST "destination")
) {
@ -2957,8 +3028,10 @@ one_main(int argc, char **argv)
for (i = 0; i < opts.dir_conf_n; i++) {
char **target;
for (target = opts.dir_confs[i].targets; *target; ++target) {
pid_t child;
printlogf(log, NORMAL, "Initial recursive sync for %s -> %s", opts.dir_confs[i].source, *target);
if (!action(&opts, &opts.dir_confs[i], opts.dir_confs[i].source, *target, NULL, true)) {
child = action(&opts, &opts.dir_confs[i], opts.dir_confs[i].source, *target, NULL, true);
if (!child || !waitchildren(log, &child, 1)) {
printlogf(log, ERROR, "Initial rsync from %s -> %s failed%s",
opts.dir_confs[i].source, *target,
opts.flag_stubborn ? ", but continuing because being stubborn." : ".");