GPL rsync allows tunneling an rsync:// connection to a daemon through
an explicitly given -e command. Specifically, you can rsync the
repository from sthen@'s mirror through ssh this way:
$ rsync -av --del -e 'ssh -W localhost:rsync -lanoncvs' \
rsync://anoncvs.spacehopper.org/OpenBSD-CVS/ /cvs
The patch below adds to OpenRsync this ability to combine rsync://
and -e by splitting rsync_socket() into two functions, rsync_connect()
to establish a TCP connection to the remote daemon and rsync_socket()
to run the actual protocol.
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.bin/rsync/extern.h,v
retrieving revision 1.24
diff -u -p -r1.24 extern.h
--- extern.h 6 Mar 2019 18:37:22 -0000 1.24
+++ extern.h 31 Mar 2019 03:21:38 -0000
@@ -266,7 +266,7 @@ int flist_gen_dels(struct sess *, con
struct flist **, size_t *,
const struct flist *, size_t);
-char **fargs_cmdline(struct sess *, const struct fargs *);
+char **fargs_cmdline(struct sess *, const struct fargs *, size_t *);
int io_read_buf(struct sess *, int, void *, size_t);
int io_read_byte(struct sess *, int, uint8_t *);
@@ -304,7 +304,9 @@ void io_unbuffer_buf(struct sess *, c
int rsync_receiver(struct sess *, int, int, const char *);
int rsync_sender(struct sess *, int, int, size_t, char **);
int rsync_client(const struct opts *, int, const struct fargs *);
-int rsync_socket(const struct opts *, const struct fargs *);
+int rsync_connect(const struct opts *, int *,
+ const struct fargs *);
+int rsync_socket(const struct opts *, int, const struct fargs *);
int rsync_server(const struct opts *, size_t, char *[]);
int rsync_downloader(struct download *, struct sess *, int *);
int rsync_set_metadata(struct sess *, int, int,
Index: fargs.c
===================================================================
RCS file: /cvs/src/usr.bin/rsync/fargs.c,v
retrieving revision 1.13
diff -u -p -r1.13 fargs.c
--- fargs.c 21 Feb 2019 22:06:26 -0000 1.13
+++ fargs.c 31 Mar 2019 03:21:24 -0000
@@ -26,7 +26,7 @@
#define RSYNC_PATH "rsync"
char **
-fargs_cmdline(struct sess *sess, const struct fargs *f)
+fargs_cmdline(struct sess *sess, const struct fargs *f, size_t *skip)
{
char **args = NULL, **new;
size_t i = 0, n = 1, j, argsz = 0;
@@ -52,8 +52,6 @@ fargs_cmdline(struct sess *sess, const s
goto out;
if (f->host != NULL) {
- assert(f->host != NULL);
-
/*
* Splice arguments from -e "foo bar baz" into array
* elements required for execve(2).
@@ -89,6 +87,8 @@ fargs_cmdline(struct sess *sess, const s
args[i++] = f->host;
args[i++] = rsync_path;
+ if (skip)
+ *skip = i;
args[i++] = "--server";
if (f->mode == FARGS_RECEIVER)
args[i++] = "--sender";
Index: main.c
===================================================================
RCS file: /cvs/src/usr.bin/rsync/main.c,v
retrieving revision 1.40
diff -u -p -r1.40 main.c
--- main.c 30 Mar 2019 23:48:24 -0000 1.40
+++ main.c 31 Mar 2019 03:31:27 -0000
@@ -269,7 +269,7 @@ main(int argc, char *argv[])
{
struct opts opts;
pid_t child;
- int fds[2], rc, c, st, i;
+ int fds[2], sd, rc, c, st, i;
struct sess sess;
struct fargs *fargs;
char **args;
@@ -417,12 +417,15 @@ main(int argc, char *argv[])
/*
* If we're contacting an rsync:// daemon, then we don't need to
* fork, because we won't start a server ourselves.
- * Route directly into the socket code, in that case.
+ * Route directly into the socket code, unless a remote shell
+ * has explicitly been specified.
*/
- if (fargs->remote) {
+ if (fargs->remote && opts.ssh_prog == NULL) {
assert(fargs->mode == FARGS_RECEIVER);
- exit(rsync_socket(&opts, fargs));
+ if ((rc = rsync_connect(&opts, &sd, fargs)) == 0)
+ rc = rsync_socket(&opts, sd, fargs);
+ exit(rc);
}
/* Drop the dns/inet possibility. */
@@ -447,7 +450,7 @@ main(int argc, char *argv[])
memset(&sess, 0, sizeof(struct sess));
sess.opts = &opts;
- if ((args = fargs_cmdline(&sess, fargs)) == NULL) {
+ if ((args = fargs_cmdline(&sess, fargs, NULL)) == NULL) {
ERRX1(&sess, "fargs_cmdline");
_exit(1);
}
@@ -469,7 +472,10 @@ main(int argc, char *argv[])
/* NOTREACHED */
default:
close(fds[1]);
- rc = rsync_client(&opts, fds[0], fargs);
+ if (!fargs->remote)
+ rc = rsync_client(&opts, fds[0], fargs);
+ else
+ rc = rsync_socket(&opts, fds[0], fargs);
break;
}
Index: socket.c
===================================================================
RCS file: /cvs/src/usr.bin/rsync/socket.c,v
retrieving revision 1.21
diff -u -p -r1.21 socket.c
--- socket.c 23 Mar 2019 16:04:28 -0000 1.21
+++ socket.c 31 Mar 2019 03:24:55 -0000
@@ -232,41 +232,30 @@ protocol_line(struct sess *sess, const c
}
/*
- * Talk to a remote rsync://-enabled server sender.
- * Returns exit code 0 on success, 1 on failure, 2 on failure with
- * incompatible protocols.
+ * Connect to a remote rsync://-enabled server sender.
+ * Returns exit code 0 on success, 1 on failure.
*/
int
-rsync_socket(const struct opts *opts, const struct fargs *f)
+rsync_connect(const struct opts *opts, int *sd, const struct fargs *f)
{
struct sess sess;
struct source *src = NULL;
size_t i, srcsz = 0;
- int sd = -1, rc = 1, c;
- char **args, buf[BUFSIZ];
- uint8_t byte;
+ int c, rc = 1;
if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns
getpw unveil",
NULL) == -1)
err(1, "pledge");
memset(&sess, 0, sizeof(struct sess));
- sess.lver = RSYNC_PROTOCOL;
sess.opts = opts;
assert(f->host != NULL);
- assert(f->module != NULL);
-
- if ((args = fargs_cmdline(&sess, f)) == NULL) {
- ERRX1(&sess, "fargs_cmdline");
- exit(1);
- }
/* Resolve all IP addresses from the host. */
if ((src = inet_resolve(&sess, f->host, &srcsz)) == NULL) {
ERRX1(&sess, "inet_resolve");
- free(args);
exit(1);
}
@@ -285,7 +274,7 @@ rsync_socket(const struct opts *opts, co
assert(srcsz);
for (i = 0; i < srcsz; i++) {
- c = inet_connect(&sess, &sd, &src[i], f->host);
+ c = inet_connect(&sess, sd, &src[i], f->host);
if (c < 0) {
ERRX1(&sess, "inet_connect");
goto out;
@@ -305,10 +294,49 @@ rsync_socket(const struct opts *opts, co
goto out;
}
- /* Initiate with the rsyncd version and module request. */
-
LOG2(&sess, "connected: %s, %s", src[i].ip, f->host);
+ free(src);
+ return 0;
+out:
+ free(src);
+ if (*sd != -1)
+ close(*sd);
+ return rc;
+}
+
+/*
+ * 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, int sd, const struct fargs *f)
+{
+ struct sess sess;
+ size_t i, skip;
+ int c, rc = 1;
+ char **args, buf[BUFSIZ];
+ uint8_t byte;
+
+ if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw
unveil",
+ NULL) == -1)
+ err(1, "pledge");
+
+ memset(&sess, 0, sizeof(struct sess));
+ sess.lver = RSYNC_PROTOCOL;
+ sess.opts = opts;
+
+ assert(f->host != NULL);
+ assert(f->module != NULL);
+
+ if ((args = fargs_cmdline(&sess, f, &skip)) == NULL) {
+ ERRX1(&sess, "fargs_cmdline");
+ exit(1);
+ }
+
+ /* Initiate with the rsyncd version and module request. */
+
(void)snprintf(buf, sizeof(buf), "@RSYNCD: %d", sess.lver);
if (!io_write_line(&sess, sd, buf)) {
ERRX1(&sess, "io_write_line");
@@ -372,12 +400,7 @@ rsync_socket(const struct opts *opts, co
* Emit a standalone newline afterward.
*/
- if (f->mode == FARGS_RECEIVER || f->mode == FARGS_SENDER)
- i = 3; /* ssh host rsync... */
- else
- i = 1; /* rsync... */
-
- for ( ; args[i] != NULL; i++)
+ for (i = skip ; args[i] != NULL; i++)
if (!io_write_line(&sess, sd, args[i])) {
ERRX1(&sess, "io_write_line");
goto out;
@@ -431,9 +454,7 @@ rsync_socket(const struct opts *opts, co
rc = 0;
out:
- free(src);
free(args);
- if (sd != -1)
- close(sd);
+ close(sd);
return rc;
}
--
Christian "naddy" Weisgerber [email protected]