Added notifications about error-exit values:
authorWayne Davison <wayned@samba.org>
Sat, 7 Nov 2009 08:39:50 +0000 (00:39 -0800)
committerWayne Davison <wayned@samba.org>
Sat, 7 Nov 2009 09:22:11 +0000 (01:22 -0800)
- 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
errcode.h
io.c
log.c
rsync.h

index 19ef072..4ff5b9c 100644 (file)
--- a/cleanup.c
+++ b/cleanup.c
 
 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 */
index 41c5543..bae7700 100644 (file)
--- 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 e7cb76e..1e2f218 100644 (file)
--- 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 4e20c2c..5b4773f 100644 (file)
--- 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 522ffc5..61f1c47 100644 (file)
--- 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 */