From f9185203ee03152001530db5624a2b8c93e1ea94 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 7 Nov 2009 00:39:50 -0800 Subject: [PATCH] Added notifications about error-exit values: - The receiver notifies the generator if it is exiting with an error, and then, if it is a server, waits around for the generator to die. This ensures that the client side has time to read the error. - The generator or sender will notifiy the other side of the transfer of an error-exit value if protocol 31 is in effect. This will get rid of some "connection unexpectedly closed" errors that are really expected events due to a fatal exit on the other side. --- cleanup.c | 20 ++++++++++++++++++-- errcode.h | 2 ++ io.c | 22 +++++++++++++++++++++- log.c | 3 ++- rsync.h | 3 ++- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/cleanup.c b/cleanup.c index 19ef072c..4ff5b9c0 100644 --- a/cleanup.c +++ b/cleanup.c @@ -24,9 +24,12 @@ extern int am_server; extern int am_daemon; +extern int am_sender; +extern int am_generator; extern int io_error; extern int keep_partial; extern int got_xfer_error; +extern int protocol_version; extern int output_needs_newline; extern char *partial_dir; extern char *logfile_name; @@ -127,6 +130,17 @@ NORETURN void _exit_cleanup(int code, const char *file, int line) code, file, line); } + /* FALLTHROUGH */ +#include "case_N.h" + + if (exit_code && exit_code != RERR_RCVR_ERROR + && exit_code != RERR_STREAMIO && exit_code != RERR_SIGNAL1 + && (protocol_version >= 31 || (!am_sender && !am_generator))) { + send_msg_int(MSG_ERROR_EXIT, exit_code); + if (am_server && !am_sender && !am_generator) + noop_io_until_death(); + } + /* FALLTHROUGH */ #include "case_N.h" @@ -160,7 +174,8 @@ NORETURN void _exit_cleanup(int code, const char *file, int line) /* FALLTHROUGH */ #include "case_N.h" - io_flush(FULL_FLUSH); + if (!code || am_server || (!am_sender && !am_generator)) + io_flush(FULL_FLUSH); /* FALLTHROUGH */ #include "case_N.h" @@ -184,7 +199,8 @@ NORETURN void _exit_cleanup(int code, const char *file, int line) code = exit_code = RERR_PARTIAL; } - if (code || am_daemon || (logfile_name && (am_server || !INFO_GTE(STATS, 1)))) + if ((code && code != RERR_RCVR_ERROR) + || am_daemon || (logfile_name && (am_server || !INFO_GTE(STATS, 1)))) log_exit(code, file, line); /* FALLTHROUGH */ diff --git a/errcode.h b/errcode.h index 41c55432..bae7700c 100644 --- a/errcode.h +++ b/errcode.h @@ -47,6 +47,8 @@ #define RERR_TIMEOUT 30 /* timeout in data send/receive */ #define RERR_CONTIMEOUT 35 /* timeout waiting for daemon connection */ +#define RERR_RCVR_ERROR 42 /* receiver is exiting with an error */ + /* Although it doesn't seem to be specified anywhere, * ssh and the shell seem to return these values: * diff --git a/io.c b/io.c index e7cb76e3..1e2f2187 100644 --- a/io.c +++ b/io.c @@ -752,7 +752,7 @@ static char *perform_io(size_t needed, int flags) /* Don't write errors on a dead socket. */ msgs2stderr = 1; out->len = iobuf.raw_flushing_ends_before = out->pos = 0; - rsyserr(FERROR_SOCKET, errno, "write error"); + rsyserr(FERROR_SOCKET, errno, "[%s] write error", who_am_i()); exit_cleanup(RERR_STREAMIO); } } @@ -802,6 +802,16 @@ static char *perform_io(size_t needed, int flags) return data; } +void noop_io_until_death(void) +{ + char buf[1024]; + + kluge_around_eof = 1; + + while (1) + read_buf(iobuf.in_fd, buf, sizeof buf); +} + /* Buffer a message for the multiplexed output stream. Is never used for MSG_DATA. */ int send_msg(enum msgcode code, const char *buf, size_t len, int convert) { @@ -1426,6 +1436,16 @@ static void read_a_msg(void) first_message = 0; } break; + case MSG_ERROR_EXIT: + if (msg_bytes != 4) + goto invalid_msg; + data = perform_io(4, PIO_INPUT_AND_CONSUME); + val = IVAL(data, 0); + if (am_generator && protocol_version >= 31) + send_msg_int(MSG_ERROR_EXIT, val); + if (am_generator) + val = RERR_RCVR_ERROR; /* avoids duplicate errors */ + exit_cleanup(val); default: rprintf(FERROR, "unexpected tag %d [%s%s]\n", tag, who_am_i(), inc_recurse ? "/inc" : ""); diff --git a/log.c b/log.c index 4e20c2c8..5b4773fb 100644 --- a/log.c +++ b/log.c @@ -97,13 +97,14 @@ struct { { RERR_MALLOC , "error allocating core memory buffers" }, { RERR_PARTIAL , "some files/attrs were not transferred (see previous errors)" }, { RERR_VANISHED , "some files vanished before they could be transferred" }, + { RERR_DEL_LIMIT , "the --max-delete limit stopped deletions" }, { RERR_TIMEOUT , "timeout in data send/receive" }, { RERR_CONTIMEOUT , "timeout waiting for daemon connection" }, + { RERR_RCVR_ERROR , "exiting due to receiver error" }, { RERR_CMD_FAILED , "remote shell failed" }, { RERR_CMD_KILLED , "remote shell killed" }, { RERR_CMD_RUN , "remote command could not be run" }, { RERR_CMD_NOTFOUND,"remote command not found" }, - { RERR_DEL_LIMIT , "the --max-delete limit stopped deletions" }, { 0, NULL } }; diff --git a/rsync.h b/rsync.h index 522ffc50..61f1c47c 100644 --- a/rsync.h +++ b/rsync.h @@ -98,7 +98,7 @@ /* This is used when working on a new protocol version in CVS, and should * be a new non-zero value for each CVS change that affects the protocol. * It must ALWAYS be 0 when the protocol goes final (and NEVER before)! */ -#define SUBPROTOCOL_VERSION 10 +#define SUBPROTOCOL_VERSION 11 /* We refuse to interoperate with versions that are not in this range. * Note that we assume we'll work with later versions: the onus is on @@ -233,6 +233,7 @@ enum msgcode { MSG_IO_ERROR=22,/* the sending side had an I/O error */ MSG_IO_TIMEOUT=33,/* tell client about a daemon's timeout value */ MSG_NOOP=42, /* a do-nothing message */ + MSG_ERROR_EXIT=86, /* used by siblings and by protocol-31 */ MSG_SUCCESS=100,/* successfully updated indicated flist index */ MSG_DELETED=101,/* successfully deleted a file on receiving side */ MSG_NO_SEND=102,/* sender failed to open a file we wanted */ -- 2.34.1