The following patch fixes exit codes, which became confused in the
switch from returning a Boolean and an exit code.  I actually prefer for
these to become an enum to avoid further confusion, but this just gets
it fixed.

It also documents the return values in each function and unifies the
protocol incompatibility error message.
? rsync-error-codes.diff
Index: client.c
===================================================================
RCS file: /cvs/src/usr.bin/rsync/client.c,v
retrieving revision 1.12
diff -u -p -r1.12 client.c
--- client.c	18 Mar 2019 15:33:21 -0000	1.12
+++ client.c	22 Mar 2019 14:31:53 -0000
@@ -30,17 +30,14 @@
  * It can either be in sender or receiver mode.
  * In the former, it synchronises local files from a remote sink.
  * In the latter, the remote sink synchronses to the local files.
- *
- * Pledges: stdio, rpath, wpath, cpath, unveil, fattr, chown.
- *
- * Pledges (dry-run): -cpath, -wpath, -fattr, chown.
- * Pledges (!preserve_times): -fattr.
+ * Returns exit code 0 on success, 1 on failure, 2 on failure with
+ * incompatible protocols.
  */
 int
 rsync_client(const struct opts *opts, int fd, const struct fargs *f)
 {
 	struct sess	 sess;
-	int		 rc = 0;
+	int		 rc = 1;
 
 	/* Standard rsync preamble, sender side. */
 
@@ -64,10 +61,10 @@ rsync_client(const struct opts *opts, in
 	}
 
 	if (sess.rver < sess.lver) {
-		ERRX(&sess, "remote protocol is older "
-			"than our own (%" PRId32 " < %" PRId32 "): "
-			"this is not supported",
-			sess.rver, sess.lver);
+		ERRX(&sess,
+		    "remote protocol %d is older than our own %d: unsupported",
+		    sess.rver, sess.lver);
+		rc = 2;
 		goto out;
 	}
 
@@ -105,7 +102,7 @@ rsync_client(const struct opts *opts, in
 		WARNX(&sess, "data remains in read pipe");
 #endif
 
-	rc = 1;
+	rc = 0;
 out:
 	return rc;
 }
Index: main.c
===================================================================
RCS file: /cvs/src/usr.bin/rsync/main.c,v
retrieving revision 1.33
diff -u -p -r1.33 main.c
--- main.c	18 Mar 2019 08:11:11 -0000	1.33
+++ main.c	22 Mar 2019 14:31:54 -0000
@@ -273,7 +273,7 @@ main(int argc, char *argv[])
 {
 	struct opts	 opts;
 	pid_t		 child;
-	int		 fds[2], rc = 0, c, st, i;
+	int		 fds[2], rc, c, st, i;
 	struct sess	  sess;
 	struct fargs	*fargs;
 	char		**args;
@@ -478,13 +478,23 @@ main(int argc, char *argv[])
 	 * So close the connection here so that they don't hang.
 	 */
 
-	if (!rc)
+	if (rc)
 		close(fds[0]);
 
 	if (waitpid(child, &st, 0) == -1)
 		err(1, "waitpid");
-	if (!(WIFEXITED(st) && WEXITSTATUS(st) == 0))
-		rc = 0;
+
+	/*
+	 * If we don't already have an error (rc == 0), then inherit the
+	 * error code of rsync_server() if it has exited.
+	 * If it hasn't exited, it overrides our return value.
+	 */
+
+	if (WIFEXITED(st) && rc == 0)
+		rc = WEXITSTATUS(st);
+	else if (!WIFEXITED(st))
+		rc = 1;
+
 	exit(rc);
 usage:
 	fprintf(stderr, "usage: %s [-aDglnoprtv] [-e program] [--archive] [--delete] [--devices]\n"
Index: server.c
===================================================================
RCS file: /cvs/src/usr.bin/rsync/server.c,v
retrieving revision 1.8
diff -u -p -r1.8 server.c
--- server.c	6 Mar 2019 18:37:22 -0000	1.8
+++ server.c	22 Mar 2019 14:31:54 -0000
@@ -45,18 +45,15 @@ fcntl_nonblock(struct sess *sess, int fd
  * The server (remote) side of the system.
  * This parses the arguments given it by the remote shell then moves
  * into receiver or sender mode depending upon those arguments.
- *
- * Pledges: unveil rpath, cpath, wpath, stdio, fattr.
- *
- * Pledges (dry-run): -cpath, -wpath, -fattr.
- * Pledges (!preserve_times): -fattr.
+ * Returns exit code 0 on success, 1 on failure, 2 on failure with
+ * incompatible protocols.
  */
 int
 rsync_server(const struct opts *opts, size_t argc, char *argv[])
 {
 	struct sess	 sess;
 	int		 fdin = STDIN_FILENO,
-			 fdout = STDOUT_FILENO, rc = 0;
+			 fdout = STDOUT_FILENO, rc = 1;
 
 	if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil",
 	    NULL) == -1)
@@ -161,7 +158,7 @@ rsync_server(const struct opts *opts, si
 		WARNX(&sess, "data remains in read pipe");
 #endif
 
-	rc = 1;
+	rc = 0;
 out:
 	return rc;
 }
Index: socket.c
===================================================================
RCS file: /cvs/src/usr.bin/rsync/socket.c,v
retrieving revision 1.19
diff -u -p -r1.19 socket.c
--- socket.c	6 Mar 2019 18:37:22 -0000	1.19
+++ socket.c	22 Mar 2019 14:31:54 -0000
@@ -232,10 +232,9 @@ protocol_line(struct sess *sess, const c
 }
 
 /*
- * Pledges: dns, inet, unix, unveil, rpath, cpath, wpath, stdio, fattr, chown.
- *
- * Pledges (dry-run): -unix, -cpath, -wpath, -fattr, -chown.
- * Pledges (!preserve_times): -fattr.
+ * Talk to a remote rsync://-enabled server sender.
+ * Returns exit code 0 on success, 1 on failure, 2 on failure with
+ * incompatible protocols.
  */
 int
 rsync_socket(const struct opts *opts, const struct fargs *f)
@@ -243,7 +242,7 @@ rsync_socket(const struct opts *opts, co
 	struct sess	  sess;
 	struct source	 *src = NULL;
 	size_t		  i, srcsz = 0;
-	int		  sd = -1, rc = 0;
+	int		  sd = -1, rc = 1, c;
 	char		**args, buf[BUFSIZ];
 	uint8_t		  byte;
 
@@ -286,11 +285,11 @@ rsync_socket(const struct opts *opts, co
 
 	assert(srcsz);
 	for (i = 0; i < srcsz; i++) {
-		rc = inet_connect(&sess, &sd, &src[i], f->host);
-		if (rc < 0) {
+		c = inet_connect(&sess, &sd, &src[i], f->host);
+		if (c < 0) {
 			ERRX1(&sess, "inet_connect");
 			goto out;
-		} else if (rc > 0)
+		} else if (c > 0)
 			break;
 	}
 
@@ -357,10 +356,10 @@ rsync_socket(const struct opts *opts, co
 		if (buf[i - 1] == '\r')
 			buf[i - 1] = '\0';
 
-		if ((rc = protocol_line(&sess, f->host, buf)) < 0) {
+		if ((c = protocol_line(&sess, f->host, buf)) < 0) {
 			ERRX1(&sess, "protocol_line");
 			goto out;
-		} else if (rc > 0)
+		} else if (c > 0)
 			break;
 	}
 
@@ -407,6 +406,7 @@ rsync_socket(const struct opts *opts, co
 			"than our own (%" PRId32 " < %" PRId32 "): "
 			"this is not supported",
 			sess.rver, sess.lver);
+		rc = 2;
 		goto out;
 	}
 
@@ -431,7 +431,7 @@ rsync_socket(const struct opts *opts, co
 		WARNX(&sess, "data remains in read pipe");
 #endif
 
-	rc = 1;
+	rc = 0;
 out:
 	free(src);
 	free(args);

Reply via email to