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]

Reply via email to