summaryrefslogtreecommitdiff
path: root/usr.bin/rsync
diff options
context:
space:
mode:
authorSebastian Benoit <benno@cvs.openbsd.org>2019-02-18 21:55:28 +0000
committerSebastian Benoit <benno@cvs.openbsd.org>2019-02-18 21:55:28 +0000
commit9bb0da04d46a25150c43281f9df758c060567427 (patch)
tree6a59467b56f448ca7660a0262fda0b7690b11243 /usr.bin/rsync
parentbde034a382776f3c396eef446206fe579292673e (diff)
revert previous
Diffstat (limited to 'usr.bin/rsync')
-rw-r--r--usr.bin/rsync/TODO.md6
-rw-r--r--usr.bin/rsync/blocks.c23
-rw-r--r--usr.bin/rsync/child.c10
-rw-r--r--usr.bin/rsync/client.c10
-rw-r--r--usr.bin/rsync/downloader.c10
-rw-r--r--usr.bin/rsync/extern.h18
-rw-r--r--usr.bin/rsync/io.c5
-rw-r--r--usr.bin/rsync/log.c22
-rw-r--r--usr.bin/rsync/main.c100
-rw-r--r--usr.bin/rsync/mktemp.c125
-rw-r--r--usr.bin/rsync/receiver.c6
-rw-r--r--usr.bin/rsync/rsync.54
-rw-r--r--usr.bin/rsync/sender.c376
-rw-r--r--usr.bin/rsync/server.c16
-rw-r--r--usr.bin/rsync/socket.c16
-rw-r--r--usr.bin/rsync/uploader.c176
16 files changed, 414 insertions, 509 deletions
diff --git a/usr.bin/rsync/TODO.md b/usr.bin/rsync/TODO.md
index 4ba1dca3403..b98c674b4e5 100644
--- a/usr.bin/rsync/TODO.md
+++ b/usr.bin/rsync/TODO.md
@@ -47,6 +47,12 @@ I would rate this as easy/medium.
- Hard: the same, but for Linux.
+- Hard: make the sender loop use an event handler on incoming and
+ outgoing I/O. Right now it moves in lockstep and can be considerably
+ more responsive to requests by reading them in immediately instead of
+ having them sit in the receiver queue while it waits for disc IO.
+ This isn't *that* hard.
+
- Hard: once the sender loop is optimised, the uploader can also queue
up block metadata to send on-demand instead of reading in the file
then sending, then reading again, then sending.
diff --git a/usr.bin/rsync/blocks.c b/usr.bin/rsync/blocks.c
index a65ea84da69..1a71eca95d2 100644
--- a/usr.bin/rsync/blocks.c
+++ b/usr.bin/rsync/blocks.c
@@ -1,4 +1,4 @@
-/* $Id: blocks.c,v 1.11 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: blocks.c,v 1.12 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -201,14 +201,16 @@ blk_match(struct sess *sess, const struct blkset *blks,
}
/*
- * Buffer the message from sender to the receiver indicating that the
- * block set has been received.
+ * Sent from the sender to the receiver to indicate that the block set
+ * has been received.
* Symmetrises blk_send_ack().
+ * Returns zero on failure, non-zero on success.
*/
-void
-blk_recv_ack(struct sess *sess, char buf[20],
- const struct blkset *blocks, int32_t idx)
+int
+blk_recv_ack(struct sess *sess,
+ int fd, const struct blkset *blocks, int32_t idx)
{
+ char buf[20];
size_t pos = 0, sz;
sz = sizeof(int32_t) + /* index */
@@ -216,7 +218,7 @@ blk_recv_ack(struct sess *sess, char buf[20],
sizeof(int32_t) + /* block length */
sizeof(int32_t) + /* checksum length */
sizeof(int32_t); /* block remainder */
- assert(sz == 20);
+ assert(sz <= sizeof(buf));
io_buffer_int(sess, buf, &pos, sz, idx);
io_buffer_int(sess, buf, &pos, sz, blocks->blksz);
@@ -224,6 +226,13 @@ blk_recv_ack(struct sess *sess, char buf[20],
io_buffer_int(sess, buf, &pos, sz, blocks->csum);
io_buffer_int(sess, buf, &pos, sz, blocks->rem);
assert(pos == sz);
+
+ if (!io_write_buf(sess, fd, buf, sz)) {
+ ERRX1(sess, "io_write_buf");
+ return 0;
+ }
+
+ return 1;
}
/*
diff --git a/usr.bin/rsync/child.c b/usr.bin/rsync/child.c
index 2b9427b7cbe..2b3985afd44 100644
--- a/usr.bin/rsync/child.c
+++ b/usr.bin/rsync/child.c
@@ -1,4 +1,4 @@
-/* $Id: child.c,v 1.6 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: child.c,v 1.7 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -46,7 +46,7 @@ rsync_child(const struct opts *opts, int fd, const struct fargs *f)
if ((args = fargs_cmdline(&sess, f)) == NULL) {
ERRX1(&sess, "fargs_cmdline");
- exit(EXIT_FAILURE);
+ exit(1);
}
for (i = 0; args[i] != NULL; i++)
@@ -56,10 +56,10 @@ rsync_child(const struct opts *opts, int fd, const struct fargs *f)
if (dup2(fd, STDIN_FILENO) == -1) {
ERR(&sess, "dup2");
- exit(EXIT_FAILURE);
+ exit(1);
} if (dup2(fd, STDOUT_FILENO) == -1) {
ERR(&sess, "dup2");
- exit(EXIT_FAILURE);
+ exit(1);
}
/* Here we go... */
@@ -67,6 +67,6 @@ rsync_child(const struct opts *opts, int fd, const struct fargs *f)
execvp(args[0], args);
ERR(&sess, "%s: execvp", args[0]);
- exit(EXIT_FAILURE);
+ exit(1);
/* NOTREACHED */
}
diff --git a/usr.bin/rsync/client.c b/usr.bin/rsync/client.c
index fd1deea624c..1066229723b 100644
--- a/usr.bin/rsync/client.c
+++ b/usr.bin/rsync/client.c
@@ -1,4 +1,4 @@
-/* $Id: client.c,v 1.8 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: client.c,v 1.9 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -59,10 +59,10 @@ rsync_client(const struct opts *opts, int fd, const struct fargs *f)
}
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 own %d: unsupported\n",
+ sess.rver, sess.lver);
+ rc = 2; /* Protocol incompatibility*/
goto out;
}
diff --git a/usr.bin/rsync/downloader.c b/usr.bin/rsync/downloader.c
index 3c5652e29f3..eba81d0a63a 100644
--- a/usr.bin/rsync/downloader.c
+++ b/usr.bin/rsync/downloader.c
@@ -1,4 +1,4 @@
-/* $Id: downloader.c,v 1.15 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: downloader.c,v 1.16 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -414,14 +414,14 @@ rsync_downloader(struct download *p, struct sess *sess, int *ofd)
/* Create the temporary file. */
- if (mktemplate(sess, &p->fname,
- f->path, sess->opts->recursive) == -1) {
- ERRX1(sess, "mktemplate");
+ if (mktemplate(&p->fname, f->path, sess->opts->recursive)
+ == -1) {
+ ERR(sess, "asprintf");
goto out;
}
if ((p->fd = mkstempat(p->rootfd, p->fname)) == -1) {
- ERR(sess, "mkstempat");
+ ERR(sess, "%s: openat", p->fname);
goto out;
}
diff --git a/usr.bin/rsync/extern.h b/usr.bin/rsync/extern.h
index a395a4e7cf5..d4cdcc25de8 100644
--- a/usr.bin/rsync/extern.h
+++ b/usr.bin/rsync/extern.h
@@ -1,4 +1,4 @@
-/* $Id: extern.h,v 1.19 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: extern.h,v 1.20 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -23,11 +23,6 @@
#define RSYNC_PROTOCOL (27)
/*
- * The default service (see services(5)) for rsync.
- */
-#define RSYNC_SERVICE "rsync"
-
-/*
* Maximum amount of file data sent over the wire at once.
*/
#define MAX_CHUNK (32 * 1024)
@@ -140,12 +135,11 @@ struct blk {
enum blkstatst {
BLKSTAT_NONE = 0,
- BLKSTAT_NEXT,
+ BLKSTAT_DATASZ,
BLKSTAT_DATA,
BLKSTAT_TOK,
BLKSTAT_HASH,
- BLKSTAT_DONE,
- BLKSTAT_PHASE,
+ BLKSTAT_DONE
};
/*
@@ -331,8 +325,8 @@ struct upload *upload_alloc(struct sess *, const char *, int, int, size_t,
void upload_free(struct upload *);
struct blkset *blk_recv(struct sess *, int, const char *);
-void blk_recv_ack(struct sess *,
- char [20], const struct blkset *, int32_t);
+int blk_recv_ack(struct sess *,
+ int, const struct blkset *, int32_t);
void blk_match(struct sess *, const struct blkset *,
const char *, struct blkstat *);
int blk_send(struct sess *, int, size_t,
@@ -352,7 +346,7 @@ char *mkstemplinkat(char*, int, char *);
char *mkstempfifoat(int, char *);
char *mkstempnodat(int, char *, mode_t, dev_t);
char *mkstempsock(const char *, char *);
-int mktemplate(struct sess *, char **, const char *, int);
+int mktemplate(char **, const char *, int);
char *symlink_read(struct sess *, const char *);
char *symlinkat_read(struct sess *, int, const char *);
diff --git a/usr.bin/rsync/io.c b/usr.bin/rsync/io.c
index edd413ab2c4..806fb56a230 100644
--- a/usr.bin/rsync/io.c
+++ b/usr.bin/rsync/io.c
@@ -1,4 +1,4 @@
-/* $Id: io.c,v 1.10 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: io.c,v 1.11 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -304,7 +304,8 @@ io_read_flush(struct sess *sess, int fd)
} else if (sess->mplex_read_remain == 0)
return 1;
- if (!io_read_blocking(sess, fd, mpbuf, sess->mplex_read_remain)) {
+ if (!io_read_blocking(sess, fd,
+ mpbuf, sess->mplex_read_remain)) {
ERRX1(sess, "io_read_blocking");
return 0;
}
diff --git a/usr.bin/rsync/log.c b/usr.bin/rsync/log.c
index 77c537a473b..7719cb60677 100644
--- a/usr.bin/rsync/log.c
+++ b/usr.bin/rsync/log.c
@@ -1,4 +1,4 @@
-/* $Id: log.c,v 1.4 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: log.c,v 1.5 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -77,8 +77,8 @@ rsync_errx(struct sess *sess, const char *fname,
}
fprintf(stderr, "%s:%zu: error%s%s\n", fname, line,
- (buf != NULL) ? ": " : "",
- (buf != NULL) ? buf : "");
+ buf != NULL ? ": " : "",
+ buf != NULL ? buf : "");
free(buf);
}
@@ -104,8 +104,8 @@ rsync_err(struct sess *sess, const char *fname,
}
fprintf(stderr, "%s:%zu: error%s%s: %s\n", fname, line,
- (buf != NULL) ? ": " : "",
- (buf != NULL) ? buf : "", strerror(er));
+ buf != NULL ? ": " : "",
+ buf != NULL ? buf : "", strerror(er));
free(buf);
}
@@ -133,8 +133,8 @@ rsync_errx1(struct sess *sess, const char *fname,
}
fprintf(stderr, "%s:%zu: error%s%s\n", fname, line,
- (buf != NULL) ? ": " : "",
- (buf != NULL) ? buf : "");
+ buf != NULL ? ": " : "",
+ buf != NULL ? buf : "");
free(buf);
}
@@ -158,8 +158,8 @@ rsync_warnx(struct sess *sess, const char *fname,
}
fprintf(stderr, "%s:%zu: warning%s%s\n", fname, line,
- (buf != NULL) ? ": " : "",
- (buf != NULL) ? buf : "");
+ buf != NULL ? ": " : "",
+ buf != NULL ? buf : "");
free(buf);
}
@@ -188,7 +188,7 @@ rsync_warn(struct sess *sess, int level,
}
fprintf(stderr, "%s:%zu: warning%s%s: %s\n", fname, line,
- (buf != NULL) ? ": " : "",
- (buf != NULL) ? buf : "", strerror(er));
+ buf != NULL ? ": " : "",
+ buf != NULL ? buf : "", strerror(er));
free(buf);
}
diff --git a/usr.bin/rsync/main.c b/usr.bin/rsync/main.c
index f72bbcde936..cdd6b8586af 100644
--- a/usr.bin/rsync/main.c
+++ b/usr.bin/rsync/main.c
@@ -1,4 +1,4 @@
-/* $Id: main.c,v 1.28 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: main.c,v 1.29 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -98,18 +98,18 @@ fargs_parse(size_t argc, char *argv[], struct opts *opts)
/* Allocations. */
if ((f = calloc(1, sizeof(struct fargs))) == NULL)
- err(EXIT_FAILURE, "calloc");
+ err(1, "calloc");
f->sourcesz = argc - 1;
if ((f->sources = calloc(f->sourcesz, sizeof(char *))) == NULL)
- err(EXIT_FAILURE, "calloc");
+ err(1, "calloc");
for (i = 0; i < argc - 1; i++)
if ((f->sources[i] = strdup(argv[i])) == NULL)
- err(EXIT_FAILURE, "strdup");
+ err(1, "strdup");
if ((f->sink = strdup(argv[i])) == NULL)
- err(EXIT_FAILURE, "strdup");
+ err(1, "strdup");
/*
* Test files for its locality.
@@ -124,32 +124,32 @@ fargs_parse(size_t argc, char *argv[], struct opts *opts)
if (fargs_is_remote(f->sink)) {
f->mode = FARGS_SENDER;
if ((f->host = strdup(f->sink)) == NULL)
- err(EXIT_FAILURE, "strdup");
+ err(1, "strdup");
}
if (fargs_is_remote(f->sources[0])) {
if (f->host != NULL)
- errx(EXIT_FAILURE, "both source and "
+ errx(1, "both source and "
"destination cannot be remote files");
f->mode = FARGS_RECEIVER;
if ((f->host = strdup(f->sources[0])) == NULL)
- err(EXIT_FAILURE, "strdup");
+ err(1, "strdup");
}
if (f->host != NULL) {
if (strncasecmp(f->host, "rsync://", 8) == 0) {
- /* rsync://host[:port]/module[/path] */
+ /* rsync://host/module[/path] */
f->remote = 1;
len = strlen(f->host) - 8 + 1;
memmove(f->host, f->host + 8, len);
if ((cp = strchr(f->host, '/')) == NULL)
- errx(EXIT_FAILURE, "rsync protocol "
+ errx(1, "rsync protocol "
"requires a module name");
*cp++ = '\0';
f->module = cp;
if ((cp = strchr(f->module, '/')) != NULL)
*cp = '\0';
- if ((cp = strchr(f->host, ':')) != NULL) {
+ if ((cp = strchr(f->host, ':'))) {
/* host:port --> extract port */
*cp++ = '\0';
opts->port = cp;
@@ -169,9 +169,9 @@ fargs_parse(size_t argc, char *argv[], struct opts *opts)
}
}
if ((len = strlen(f->host)) == 0)
- errx(EXIT_FAILURE, "empty remote host");
+ errx(1, "empty remote host");
if (f->remote && strlen(f->module) == 0)
- errx(EXIT_FAILURE, "empty remote module");
+ errx(1, "empty remote module");
}
/* Make sure we have the same "hostspec" for all files. */
@@ -181,7 +181,7 @@ fargs_parse(size_t argc, char *argv[], struct opts *opts)
for (i = 0; i < f->sourcesz; i++) {
if (!fargs_is_remote(f->sources[i]))
continue;
- errx(EXIT_FAILURE, "remote file in "
+ errx(1, "remote file in "
"list of local sources: %s",
f->sources[i]);
}
@@ -191,22 +191,22 @@ fargs_parse(size_t argc, char *argv[], struct opts *opts)
!fargs_is_daemon(f->sources[i]))
continue;
if (fargs_is_daemon(f->sources[i]))
- errx(EXIT_FAILURE, "remote "
+ errx(1, "remote "
"daemon in list of "
"remote sources: %s",
f->sources[i]);
- errx(EXIT_FAILURE, "local file in "
+ errx(1, "local file in "
"list of remote sources: %s",
f->sources[i]);
}
} else {
if (f->mode != FARGS_RECEIVER)
- errx(EXIT_FAILURE, "sender mode for remote "
+ errx(1, "sender mode for remote "
"daemon receivers not yet supported");
for (i = 0; i < f->sourcesz; i++) {
if (fargs_is_daemon(f->sources[i]))
continue;
- errx(EXIT_FAILURE, "non-remote daemon file "
+ errx(1, "non-remote daemon file "
"in list of remote daemon sources: "
"%s", f->sources[i]);
}
@@ -248,18 +248,11 @@ fargs_parse(size_t argc, char *argv[], struct opts *opts)
strncasecmp(cp, "rsync://", 8) == 0) {
/* rsync://path */
cp += 8;
-
- /*
- * FIXME: broken.
- * URIs can allow colons too.
- * Fix this after merge.
- */
-
- if ((ccp = strchr(cp, ':')) != NULL) /* skip :port */
+ if ((ccp = strchr(cp, ':'))) /* skip :port */
*ccp = '\0';
if (strncmp(cp, f->host, len) ||
(cp[len] != '/' && cp[len] != '\0'))
- errx(EXIT_FAILURE, "different remote "
+ errx(1, "different remote "
"host: %s", f->sources[i]);
memmove(f->sources[i],
f->sources[i] + len + 8 + 1,
@@ -272,7 +265,7 @@ fargs_parse(size_t argc, char *argv[], struct opts *opts)
/* host::path */
if (strncmp(cp, f->host, len) ||
(cp[len] != ':' && cp[len] != '\0'))
- errx(EXIT_FAILURE, "different remote "
+ errx(1, "different remote "
"host: %s", f->sources[i]);
memmove(f->sources[i], f->sources[i] + len + 2,
j - len - 1);
@@ -283,7 +276,7 @@ fargs_parse(size_t argc, char *argv[], struct opts *opts)
/* host:path */
if (strncmp(cp, f->host, len) ||
(cp[len] != ':' && cp[len] != '\0'))
- errx(EXIT_FAILURE, "different remote "
+ errx(1, "different remote "
"host: %s", f->sources[i]);
memmove(f->sources[i],
f->sources[i] + len + 1, j - len);
@@ -298,7 +291,7 @@ main(int argc, char *argv[])
{
struct opts opts;
pid_t child;
- int fds[2], c, st;
+ int fds[2], rc = 0, c, st;
struct fargs *fargs;
struct option lopts[] = {
{ "port", required_argument, NULL, 3 },
@@ -336,7 +329,7 @@ main(int argc, char *argv[])
if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw proc exec unveil",
NULL) == -1)
- err(EXIT_FAILURE, "pledge");
+ err(1, "pledge");
memset(&opts, 0, sizeof(struct opts));
@@ -358,7 +351,6 @@ main(int argc, char *argv[])
break;
case 'e':
opts.ssh_prog = optarg;
- /* Ignore. */
break;
case 'g':
opts.preserve_gids = 1;
@@ -412,7 +404,7 @@ main(int argc, char *argv[])
goto usage;
if (opts.port == NULL)
- opts.port = RSYNC_SERVICE;
+ opts.port = "rsync";
/*
* This is what happens when we're started with the "hidden"
@@ -422,9 +414,8 @@ main(int argc, char *argv[])
if (opts.server) {
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1)
- err(EXIT_FAILURE, "pledge");
- c = rsync_server(&opts, (size_t)argc, argv);
- return c ? EXIT_SUCCESS : EXIT_FAILURE;
+ err(1, "pledge");
+ return rsync_server(&opts, (size_t)argc, argv);
}
/*
@@ -450,39 +441,39 @@ main(int argc, char *argv[])
assert(fargs->mode == FARGS_RECEIVER);
if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw unveil",
NULL) == -1)
- err(EXIT_FAILURE, "pledge");
- c = rsync_socket(&opts, fargs);
+ err(1, "pledge");
+ rc = rsync_socket(&opts, fargs);
fargs_free(fargs);
- return c ? EXIT_SUCCESS : EXIT_FAILURE;
+ return rc;
}
/* Drop the dns/inet possibility. */
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw proc exec unveil",
NULL) == -1)
- err(EXIT_FAILURE, "pledge");
+ err(1, "pledge");
/* Create a bidirectional socket and start our child. */
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds) == -1)
- err(EXIT_FAILURE, "socketpair");
+ err(1, "socketpair");
if ((child = fork()) == -1) {
close(fds[0]);
close(fds[1]);
- err(EXIT_FAILURE, "fork");
+ err(1, "fork");
}
/* Drop the fork possibility. */
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw exec unveil", NULL) == -1)
- err(EXIT_FAILURE, "pledge");
+ err(1, "pledge");
if (child == 0) {
close(fds[0]);
fds[0] = -1;
if (pledge("stdio exec", NULL) == -1)
- err(EXIT_FAILURE, "pledge");
+ err(1, "pledge");
rsync_child(&opts, fds[1], fargs);
/* NOTREACHED */
}
@@ -490,8 +481,8 @@ main(int argc, char *argv[])
close(fds[1]);
fds[1] = -1;
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1)
- err(EXIT_FAILURE, "pledge");
- c = rsync_client(&opts, fds[0], fargs);
+ err(1, "pledge");
+ rc = rsync_client(&opts, fds[0], fargs);
fargs_free(fargs);
/*
@@ -500,23 +491,22 @@ main(int argc, char *argv[])
* So close the connection here so that they don't hang.
*/
- if (!c) {
+ if (!rc) {
close(fds[0]);
fds[0] = -1;
}
if (waitpid(child, &st, 0) == -1)
- err(EXIT_FAILURE, "waitpid");
- if (!(WIFEXITED(st) && WEXITSTATUS(st) == EXIT_SUCCESS))
- c = 0;
+ err(1, "waitpid");
+ if (!(WIFEXITED(st) && WEXITSTATUS(st) == 0))
+ rc = 0;
if (fds[0] != -1)
close(fds[0]);
- return c ? EXIT_SUCCESS : EXIT_FAILURE;
+ return rc;
usage:
- fprintf(stderr, "usage: %s [-Daghlnoprtv] "
- "[-e ssh-prog] [--delete] "
- "[--port=port] [--rsync-path=prog] src ... dst\n",
+ fprintf(stderr, "usage: %s [-Daglnoprtv] "
+ "[-e ssh-prog] [--delete] [--rsync-path=prog] src ... dst\n",
getprogname());
- return EXIT_FAILURE;
+ return 1;
}
diff --git a/usr.bin/rsync/mktemp.c b/usr.bin/rsync/mktemp.c
index 0e132e1ef07..15a3a46e824 100644
--- a/usr.bin/rsync/mktemp.c
+++ b/usr.bin/rsync/mktemp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mktemp.c,v 1.5 2019/02/18 21:34:54 benno Exp $ */
+/* $OpenBSD: mktemp.c,v 1.6 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 1996-1998, 2008 Theo de Raadt
* Copyright (c) 1997, 2008-2009 Todd C. Miller
@@ -16,71 +16,50 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
-
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
-#include "extern.h"
-
-/*
- * The type of temporary files we can create.
- */
-enum tmpmode {
- MKTEMP_NAME,
- MKTEMP_FILE,
- MKTEMP_DIR,
- MKTEMP_LINK,
- MKTEMP_FIFO,
- MKTEMP_NOD,
- MKTEMP_SOCK
-};
+#define MKTEMP_NAME 0
+#define MKTEMP_FILE 1
+#define MKTEMP_DIR 2
+#define MKTEMP_LINK 3
+#define MKTEMP_FIFO 4
+#define MKTEMP_NOD 5
+#define MKTEMP_SOCK 6
-/*
- * Characters we'll use for replacement in the template string.
- */
#define TEMPCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
#define NUM_CHARS (sizeof(TEMPCHARS) - 1)
-
-/*
- * The number of template replacement values (foo.XXXXXX = 6) that we
- * require as a minimum for the filename.
- */
#define MIN_X 6
-/*
- * The only flags we'll accept for creation of the temporary file.
- */
#define MKOTEMP_FLAGS (O_APPEND | O_CLOEXEC | O_DSYNC | O_RSYNC | O_SYNC)
#ifndef nitems
-# define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
-/*
- * Adapted from libc/stdio/mktemp.c.
- */
+/* adapted from libc/stdio/mktemp.c */
static int
-mktemp_internalat(int pfd, char *path, int slen, enum tmpmode mode,
- int flags, const char *link, mode_t dev_type, dev_t dev)
+mktemp_internalat(int pfd, char *path, int slen, int mode, int flags,
+ const char *link, mode_t dev_type, dev_t dev)
{
- char *start, *cp, *ep;
- const char tempchars[] = TEMPCHARS;
- unsigned int tries;
- struct stat sb;
+ char *start, *cp, *ep;
+ const char tempchars[] = TEMPCHARS;
+ unsigned int tries;
+ struct stat sb;
struct sockaddr_un sun;
- size_t len;
- int fd, saved_errno;
+ size_t len;
+ int fd, saved_errno;
len = strlen(path);
if (len < MIN_X || slen < 0 || (size_t)slen > len - MIN_X) {
@@ -90,8 +69,7 @@ mktemp_internalat(int pfd, char *path, int slen, enum tmpmode mode,
ep = path + len - slen;
for (start = ep; start > path && start[-1] == 'X'; start--)
- /* continue */ ;
-
+ ;
if (ep - start < MIN_X) {
errno = EINVAL;
return(-1);
@@ -205,74 +183,69 @@ mktemp_internalat(int pfd, char *path, int slen, enum tmpmode mode,
* A combination of mkstemp(3) and openat(2).
* On success returns a file descriptor and trailing Xs are overwritten in
* path to create a unique file name.
- * Returns -1 on failure and sets errno.
+ * Returns -1 on failure.
*/
int
mkstempat(int fd, char *path)
{
-
- return mktemp_internalat(fd, path, 0, MKTEMP_FILE, 0, NULL, 0, 0);
+ return(mktemp_internalat(fd, path, 0, MKTEMP_FILE, 0, NULL, 0, 0));
}
/*
* A combination of mkstemp(3) and symlinkat(2).
* On success returns path with trailing Xs overwritten to create a unique
* file name.
- * Returns NULL on failure and sets errno.
+ * Returns NULL on failure.
*/
-char *
+char*
mkstemplinkat(char *link, int fd, char *path)
{
-
if (mktemp_internalat(fd, path, 0, MKTEMP_LINK, 0, link, 0, 0) == -1)
- return NULL;
- return path;
+ return(NULL);
+ return(path);
}
/*
* A combination of mkstemp(3) and mkfifoat(2).
* On success returns path with trailing Xs overwritten to create a unique
* file name.
- * Returns NULL on failure and sets errno.
+ * Returns NULL on failure.
*/
-char *
+char*
mkstempfifoat(int fd, char *path)
{
-
if (mktemp_internalat(fd, path, 0, MKTEMP_FIFO, 0, NULL, 0, 0) == -1)
- return NULL;
- return path;
+ return(NULL);
+ return(path);
}
/*
* A combination of mkstemp(3) and mknodat(2).
* On success returns path with trailing Xs overwritten to create a unique
* file name.
- * Returns NULL on failure and sets errno.
+ * Returns NULL on failure.
*/
-char *
+char*
mkstempnodat(int fd, char *path, mode_t mode, dev_t dev)
{
-
- if (mktemp_internalat(fd, path, 0,
- MKTEMP_NOD, 0, NULL, mode, dev) == -1)
- return NULL;
- return path;
+ if (mktemp_internalat(fd, path, 0, MKTEMP_NOD, 0, NULL, mode, dev) ==
+ -1)
+ return(NULL);
+ return(path);
}
/*
* A combination of mkstemp(3) and bind(2) on a unix domain socket.
* On success returns path with trailing Xs overwritten to create a unique
* file name.
- * Returns NULL on failure and sets errno.
+ * Returns NULL on failure.
*/
-char *
+char*
mkstempsock(const char *root, char *path)
{
-
if (mktemp_internalat(0, path, 0, MKTEMP_SOCK, 0, root, 0, 0) == -1)
- return NULL;
- return path;
+ return(NULL);
+ return(path);
}
/*
@@ -283,23 +256,19 @@ mkstempsock(const char *root, char *path)
* (excluding the final '\0').
*/
int
-mktemplate(struct sess *sess, char **ret, const char *path, int recursive)
+mktemplate(char **ret, const char *path, int recursive)
{
int n, dirlen;
const char *cp;
if (recursive && (cp = strrchr(path, '/')) != NULL) {
dirlen = cp - path;
- n = asprintf(ret, "%.*s/.%s.XXXXXXXXXX",
- dirlen, path, path + dirlen + 1);
- if (n < 0) {
- ERR(sess, "asprintf");
+ if ((n = asprintf(ret, "%.*s/.%s.XXXXXXXXXX", dirlen, path,
+ path + dirlen + 1)) == -1)
+ *ret = NULL;
+ } else {
+ if ((n = asprintf(ret, ".%s.XXXXXXXXXX", path)) == -1)
*ret = NULL;
- }
- } else if ((n = asprintf(ret, ".%s.XXXXXXXXXX", path)) < 0) {
- ERR(sess, "asprintf");
- *ret = NULL;
}
-
- return n;
+ return(n);
}
diff --git a/usr.bin/rsync/receiver.c b/usr.bin/rsync/receiver.c
index 54d0ddb6382..a4bfe1827bc 100644
--- a/usr.bin/rsync/receiver.c
+++ b/usr.bin/rsync/receiver.c
@@ -1,4 +1,4 @@
-/* $Id: receiver.c,v 1.18 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: receiver.c,v 1.19 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -199,7 +199,7 @@ rsync_receiver(struct sess *sess, int fdin, int fdout, const char *root)
if (!io_read_size(sess, fdin, &excl)) {
ERRX1(sess, "io_read_size");
goto out;
- } else if (0 != excl) {
+ } else if (excl != 0) {
ERRX(sess, "exclusion list is non-empty");
goto out;
}
@@ -220,7 +220,7 @@ rsync_receiver(struct sess *sess, int fdin, int fdout, const char *root)
if (!io_read_int(sess, fdin, &ioerror)) {
ERRX1(sess, "io_read_int");
goto out;
- } else if (0 != ioerror) {
+ } else if (ioerror != 0) {
ERRX1(sess, "io_error is non-zero");
goto out;
}
diff --git a/usr.bin/rsync/rsync.5 b/usr.bin/rsync/rsync.5
index a27f856986f..b675982c1bb 100644
--- a/usr.bin/rsync/rsync.5
+++ b/usr.bin/rsync/rsync.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: rsync.5,v 1.9 2019/02/18 21:34:54 benno Exp $
+.\" $OpenBSD: rsync.5,v 1.10 2019/02/18 21:55:27 benno Exp $
.\"
.\" Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
@@ -234,7 +234,7 @@ the group id (integer)
.It
if a special file and
.Fl D ,
-the device
+the device
.Dq rdev
type (integer)
.It
diff --git a/usr.bin/rsync/sender.c b/usr.bin/rsync/sender.c
index bb2c148538e..fd94908e756 100644
--- a/usr.bin/rsync/sender.c
+++ b/usr.bin/rsync/sender.c
@@ -1,4 +1,4 @@
-/* $Id: sender.c,v 1.14 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: sender.c,v 1.15 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -34,7 +34,7 @@
* A request from the receiver to download updated file data.
*/
struct send_dl {
- int32_t idx; /* index in our file list */
+ int32_t idx; /* index in our file list */
struct blkset *blks; /* the sender's block information */
TAILQ_ENTRY(send_dl) entries;
};
@@ -46,6 +46,7 @@ struct send_dl {
struct send_up {
struct send_dl *cur; /* file being updated or NULL */
struct blkstat stat; /* status of file being updated */
+ int primed; /* blk_recv_ack() was called */
};
TAILQ_HEAD(send_dlq, send_dl);
@@ -86,189 +87,7 @@ send_up_reset(struct send_up *p)
p->stat.offs = 0;
p->stat.hint = 0;
p->stat.curst = BLKSTAT_NONE;
-}
-
-/*
- * This is the bulk of the sender work.
- * Here we tend to an output buffer that responds to receiver requests
- * for data.
- * This does not act upon the output descriptor itself so as to avoid
- * blocking, which otherwise would deadlock the protocol.
- * Returns zero on failure, non-zero on success.
- */
-static int
-send_up_fsm(struct sess *sess, size_t *phase,
- struct send_up *up, void **wb, size_t *wbsz, size_t *wbmax,
- const struct flist *fl)
-{
- size_t pos = 0, isz = sizeof(int32_t),
- dsz = MD4_DIGEST_LENGTH;
- unsigned char fmd[MD4_DIGEST_LENGTH];
- off_t sz;
- char buf[20];
-
- switch (up->stat.curst) {
- case BLKSTAT_DATA:
- /*
- * A data segment to be written: buffer both the length
- * and the data.
- * If we've finished the transfer, move on to the token;
- * otherwise, keep sending data.
- */
-
- sz = MINIMUM(MAX_CHUNK,
- up->stat.curlen - up->stat.curpos);
- if (!io_lowbuffer_alloc(sess, wb, wbsz, wbmax, isz)) {
- ERRX1(sess, "io_lowbuffer_alloc");
- return 0;
- }
- io_lowbuffer_int(sess, *wb, &pos, *wbsz, sz);
- if (!io_lowbuffer_alloc(sess, wb, wbsz, wbmax, sz)) {
- ERRX1(sess, "io_lowbuffer_alloc");
- return 0;
- }
- io_lowbuffer_buf(sess, *wb, &pos, *wbsz,
- up->stat.map + up->stat.curpos, sz);
-
- up->stat.curpos += sz;
- if (up->stat.curpos == up->stat.curlen)
- up->stat.curst = BLKSTAT_TOK;
- return 1;
- case BLKSTAT_TOK:
- /*
- * The data token following (maybe) a data segment.
- * These can also come standalone if, say, the file's
- * being fully written.
- * It's followed by a hash or another data segment,
- * depending on the token.
- */
-
- if (!io_lowbuffer_alloc(sess, wb, wbsz, wbmax, isz)) {
- ERRX1(sess, "io_lowbuffer_alloc");
- return 0;
- }
- io_lowbuffer_int(sess, *wb,
- &pos, *wbsz, up->stat.curtok);
- up->stat.curst = up->stat.curtok ?
- BLKSTAT_NEXT : BLKSTAT_HASH;
- return 1;
- case BLKSTAT_HASH:
- /*
- * The hash following transmission of all file contents.
- * This is always followed by the state that we're
- * finished with the file.
- */
-
- hash_file(up->stat.map, up->stat.mapsz, fmd, sess);
- if (!io_lowbuffer_alloc(sess, wb, wbsz, wbmax, dsz)) {
- ERRX1(sess, "io_lowbuffer_alloc");
- return 0;
- }
- io_lowbuffer_buf(sess, *wb, &pos, *wbsz, fmd, dsz);
- up->stat.curst = BLKSTAT_DONE;
- return 1;
- case BLKSTAT_DONE:
- /*
- * The data has been written.
- * Clear our current send file and allow the block below
- * to find another.
- */
-
- LOG3(sess, "%s: flushed %jd KB total, %.2f%% uploaded",
- fl[up->cur->idx].path,
- (intmax_t)up->stat.total / 1024,
- 100.0 * up->stat.dirty / up->stat.total);
- send_up_reset(up);
- return 1;
- case BLKSTAT_PHASE:
- /*
- * This is where we actually stop the algorithm: we're
- * already at the second phase.
- */
-
- send_up_reset(up);
- (*phase)++;
- return 1;
- case BLKSTAT_NEXT:
- /*
- * Our last case: we need to find the
- * next block (and token) to transmit to
- * the receiver.
- * These will drive the finite state
- * machine in the first few conditional
- * blocks of this set.
- */
-
- assert(up->stat.fd != -1);
- blk_match(sess, up->cur->blks,
- fl[up->cur->idx].path, &up->stat);
- return 1;
- case BLKSTAT_NONE:
- break;
- }
-
- assert(BLKSTAT_NONE == up->stat.curst);
-
- /*
- * We've either hit the phase change following the last file (or
- * start, or prior phase change), or we need to prime the next
- * file for transmission.
- * We special-case dry-run mode.
- */
-
- if (up->cur->idx < 0) {
- if (!io_lowbuffer_alloc(sess, wb, wbsz, wbmax, isz)) {
- ERRX1(sess, "io_lowbuffer_alloc");
- return 0;
- }
- io_lowbuffer_int(sess, *wb, &pos, *wbsz, -1);
-
- if (sess->opts->server && sess->rver > 27) {
- if (!io_lowbuffer_alloc(sess,
- wb, wbsz, wbmax, isz)) {
- ERRX1(sess, "io_lowbuffer_alloc");
- return 0;
- }
- io_lowbuffer_int(sess, *wb, &pos, *wbsz, -1);
- }
- up->stat.curst = BLKSTAT_PHASE;
- } else if (sess->opts->dry_run) {
- if (!sess->opts->server)
- LOG1(sess, "%s", fl[up->cur->idx].wpath);
-
- if (!io_lowbuffer_alloc(sess, wb, wbsz, wbmax, isz)) {
- ERRX1(sess, "io_lowbuffer_alloc");
- return 0;
- }
- io_lowbuffer_int(sess, *wb, &pos, *wbsz, up->cur->idx);
- up->stat.curst = BLKSTAT_NEXT;
- } else {
- assert(up->stat.fd != -1);
-
- /*
- * FIXME: use the nice output of log_file() and so on in
- * downloader.c, which means moving this into
- * BLKSTAT_DONE instead of having it be here.
- */
-
- if (!sess->opts->server)
- LOG1(sess, "%s", fl[up->cur->idx].wpath);
-
- if (!io_lowbuffer_alloc(sess, wb, wbsz, wbmax, 20)) {
- ERRX1(sess, "io_lowbuffer_alloc");
- return 0;
- }
- assert(sizeof(buf) == 20);
- blk_recv_ack(sess, buf, up->cur->blks, up->cur->idx);
- io_lowbuffer_buf(sess, *wb, &pos, *wbsz, buf, 20);
-
- LOG3(sess, "%s: primed for %jd B total",
- fl[up->cur->idx].path,
- (intmax_t)up->cur->blks->size);
- up->stat.curst = BLKSTAT_NEXT;
- }
-
- return 1;
+ p->primed = 0;
}
/*
@@ -284,7 +103,7 @@ send_dl_enqueue(struct sess *sess, struct send_dlq *q,
int32_t idx, const struct flist *fl, size_t flsz, int fd)
{
struct send_dl *s;
-
+
/* End-of-phase marker. */
if (idx == -1) {
@@ -299,7 +118,7 @@ send_dl_enqueue(struct sess *sess, struct send_dlq *q,
}
/* Validate the index. */
-
+
if (idx < 0 || (uint32_t)idx >= flsz) {
ERRX(sess, "file index out of bounds: invalid %"
PRId32 " out of %zu", idx, flsz);
@@ -359,6 +178,7 @@ rsync_sender(struct sess *sess, int fdin,
struct flist *fl = NULL;
const struct flist *f;
size_t i, flsz = 0, phase = 0, excl;
+ off_t sz;
int rc = 0, c;
int32_t idx;
struct pollfd pfd[3];
@@ -366,8 +186,9 @@ rsync_sender(struct sess *sess, int fdin,
struct send_dl *dl;
struct send_up up;
struct stat st;
+ unsigned char filemd[MD4_DIGEST_LENGTH];
void *wbuf = NULL;
- size_t wbufpos = 0, wbufsz = 0, wbufmax = 0;
+ size_t wbufpos = 0, pos, wbufsz = 0, wbufmax = 0;
ssize_t ssz;
if (pledge("stdio getpw rpath unveil", NULL) == -1) {
@@ -394,7 +215,7 @@ rsync_sender(struct sess *sess, int fdin,
/* Client sends zero-length exclusions if deleting. */
if (!sess->opts->server && sess->opts->del &&
- !io_write_int(sess, fdout, 0)) {
+ !io_write_int(sess, fdout, 0)) {
ERRX1(sess, "io_write_int");
goto out;
}
@@ -563,20 +384,170 @@ rsync_sender(struct sess *sess, int fdin,
sess->total_write += ssz;
}
- /*
- * Engage the FSM for the current transfer.
- * If our phase changes, stop processing.
- */
-
- if (pfd[1].revents & POLLOUT && up.cur != NULL) {
+ if (pfd[1].revents & POLLOUT) {
assert(pfd[2].fd == -1);
assert(wbufpos == 0 && wbufsz == 0);
- if (!send_up_fsm(sess, &phase,
- &up, &wbuf, &wbufsz, &wbufmax, fl)) {
- ERRX1(sess, "send_up_fsm");
- goto out;
- } else if (phase > 1)
- break;
+
+ /*
+ * If we have data to write, do it now according
+ * to the data finite state machine.
+ * If we receive an invalid index (-1), then
+ * we're either promoted to the second phase or
+ * it's time to exit, depending upon which phase
+ * we're in.
+ * Otherwise, we either start a transfer
+ * sequence (if not primed) or continue one.
+ */
+
+ pos = 0;
+ if (BLKSTAT_DATA == up.stat.curst) {
+ /*
+ * A data segment to be written: buffer
+ * both the length and the data, then
+ * put is in the token phase.
+ */
+
+ sz = MINIMUM(MAX_CHUNK,
+ up.stat.curlen - up.stat.curpos);
+ if (!io_lowbuffer_alloc(sess, &wbuf,
+ &wbufsz, &wbufmax, sizeof(int32_t))) {
+ ERRX1(sess, "io_lowbuffer_alloc");
+ goto out;
+ }
+ io_lowbuffer_int(sess,
+ wbuf, &pos, wbufsz, sz);
+ if (!io_lowbuffer_alloc(sess, &wbuf,
+ &wbufsz, &wbufmax, sz)) {
+ ERRX1(sess, "io_lowbuffer_alloc");
+ goto out;
+ }
+ io_lowbuffer_buf(sess, wbuf, &pos, wbufsz,
+ up.stat.map + up.stat.curpos, sz);
+ up.stat.curpos += sz;
+ if (up.stat.curpos == up.stat.curlen)
+ up.stat.curst = BLKSTAT_TOK;
+ } else if (BLKSTAT_TOK == up.stat.curst) {
+ /*
+ * The data token following (maybe) a
+ * data segment.
+ * These can also come standalone if,
+ * say, the file's being fully written.
+ * It's followed by a hash or another
+ * data segment, depending on the token.
+ */
+
+ if (!io_lowbuffer_alloc(sess, &wbuf,
+ &wbufsz, &wbufmax, sizeof(int32_t))) {
+ ERRX1(sess, "io_lowbuffer_alloc");
+ goto out;
+ }
+ io_lowbuffer_int(sess, wbuf,
+ &pos, wbufsz, up.stat.curtok);
+ up.stat.curst = up.stat.curtok ?
+ BLKSTAT_NONE : BLKSTAT_HASH;
+ } else if (BLKSTAT_HASH == up.stat.curst) {
+ /*
+ * The hash following transmission of
+ * all file contents.
+ * This is always followed by the state
+ * that we're finished with the file.
+ */
+
+ hash_file(up.stat.map,
+ up.stat.mapsz, filemd, sess);
+ if (!io_lowbuffer_alloc(sess, &wbuf,
+ &wbufsz, &wbufmax, MD4_DIGEST_LENGTH)) {
+ ERRX1(sess, "io_lowbuffer_alloc");
+ goto out;
+ }
+ io_lowbuffer_buf(sess, wbuf, &pos,
+ wbufsz, filemd, MD4_DIGEST_LENGTH);
+ up.stat.curst = BLKSTAT_DONE;
+ } else if (BLKSTAT_DONE == up.stat.curst) {
+ /*
+ * The data has been written.
+ * Clear our current send file and allow
+ * the block below to find another.
+ */
+
+ LOG3(sess, "%s: flushed %jd KB total, "
+ "%.2f%% uploaded",
+ fl[up.cur->idx].path,
+ (intmax_t)up.stat.total / 1024,
+ 100.0 * up.stat.dirty / up.stat.total);
+ send_up_reset(&up);
+ } else if (up.cur != NULL && up.cur->idx < 0) {
+ /*
+ * We've hit the phase change following
+ * the last file (or start, or prior
+ * phase change).
+ * Simply acknowledge it.
+ * FIXME: use buffering.
+ */
+
+ if (!io_write_int(sess, fdout, -1)) {
+ ERRX1(sess, "io_write_int");
+ goto out;
+ }
+ if (sess->opts->server && sess->rver > 27 &&
+ !io_write_int(sess, fdout, -1)) {
+ ERRX1(sess, "io_write_int");
+ goto out;
+ }
+ send_up_reset(&up);
+
+ /*
+ * This is where we actually stop the
+ * algorithm: we're already at the
+ * second phase.
+ */
+
+ if (phase++)
+ break;
+ } else if (up.cur != NULL && up.primed == 0) {
+ /*
+ * We're getting ready to send the file
+ * contents to the receiver.
+ * FIXME: use buffering.
+ */
+
+ if (!sess->opts->server)
+ LOG1(sess, "%s", fl[up.cur->idx].wpath);
+
+ /* Dry-running does nothing but a response. */
+
+ if (sess->opts->dry_run &&
+ !io_write_int(sess, fdout, up.cur->idx)) {
+ ERRX1(sess, "io_write_int");
+ goto out;
+ }
+
+ /* Actually perform the block send. */
+
+ assert(up.stat.fd != -1);
+ if (!blk_recv_ack(sess, fdout,
+ up.cur->blks, up.cur->idx)) {
+ ERRX1(sess, "blk_recv_ack");
+ goto out;
+ }
+ LOG3(sess, "%s: primed for %jd B total",
+ fl[up.cur->idx].path,
+ (intmax_t)up.cur->blks->size);
+ up.primed = 1;
+ } else if (up.cur != NULL) {
+ /*
+ * Our last case: we need to find the
+ * next block (and token) to transmit to
+ * the receiver.
+ * These will drive the finite state
+ * machine in the first few conditional
+ * blocks of this set.
+ */
+
+ assert(up.stat.fd != -1);
+ blk_match(sess, up.cur->blks,
+ fl[up.cur->idx].path, &up.stat);
+ }
}
/*
@@ -615,7 +586,7 @@ rsync_sender(struct sess *sess, int fdin,
pfd[1].fd = fdout;
continue;
}
-
+
/*
* Non-blocking open of file.
* This will be picked up in the state machine
@@ -657,7 +628,6 @@ rsync_sender(struct sess *sess, int fdin,
out:
send_up_reset(&up);
while ((dl = TAILQ_FIRST(&sdlq)) != NULL) {
- TAILQ_REMOVE(&sdlq, dl, entries);
free(dl->blks);
free(dl);
}
diff --git a/usr.bin/rsync/server.c b/usr.bin/rsync/server.c
index 234d9c05c3b..2d8bdf1adb0 100644
--- a/usr.bin/rsync/server.c
+++ b/usr.bin/rsync/server.c
@@ -1,4 +1,4 @@
-/* $Id: server.c,v 1.6 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: server.c,v 1.7 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -55,7 +55,7 @@ rsync_server(const struct opts *opts, size_t argc, char *argv[])
{
struct sess sess;
int fdin = STDIN_FILENO,
- fdout = STDOUT_FILENO, c = 0;
+ fdout = STDOUT_FILENO, rc = 0;
memset(&sess, 0, sizeof(struct sess));
sess.opts = opts;
@@ -87,10 +87,10 @@ rsync_server(const struct opts *opts, size_t argc, char *argv[])
sess.mplex_writes = 1;
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;
}
@@ -156,7 +156,7 @@ rsync_server(const struct opts *opts, size_t argc, char *argv[])
WARNX(&sess, "data remains in read pipe");
#endif
- c = 1;
+ rc = 1;
out:
- return c;
+ return rc;
}
diff --git a/usr.bin/rsync/socket.c b/usr.bin/rsync/socket.c
index 7f9b41491ae..7b96d3b0130 100644
--- a/usr.bin/rsync/socket.c
+++ b/usr.bin/rsync/socket.c
@@ -1,4 +1,4 @@
-/* $Id: socket.c,v 1.16 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: socket.c,v 1.17 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -121,12 +121,12 @@ inet_resolve(struct sess *sess, const char *host, size_t *sz)
LOG2(sess, "resolving: %s", host);
if (error == EAI_AGAIN || error == EAI_NONAME) {
- ERRX(sess, "could not resolve hostname %s: %s",
+ ERRX(sess, "Could not resolve hostname %s: %s",
host, gai_strerror(error));
return NULL;
} else if (error == EAI_SERVICE) {
- ERRX(sess, "could not resolve service rsync: %s",
- gai_strerror(error));
+ ERRX(sess, "Could not resolve service '%s': %s",
+ sess->opts->port, gai_strerror(error));
return NULL;
} else if (error) {
ERRX(sess, "getaddrinfo: %s: %s", host, gai_strerror(error));
@@ -396,10 +396,10 @@ rsync_socket(const struct opts *opts, const struct fargs *f)
/* Now we've completed the handshake. */
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 own %d: unsupported\n",
+ sess.rver, sess.lver);
+ rc = 2; /* Protocol incompatibility*/
goto out;
}
diff --git a/usr.bin/rsync/uploader.c b/usr.bin/rsync/uploader.c
index 66ddc6f2c35..1f84025200e 100644
--- a/usr.bin/rsync/uploader.c
+++ b/usr.bin/rsync/uploader.c
@@ -1,4 +1,4 @@
-/* $Id: uploader.c,v 1.15 2019/02/18 21:34:54 benno Exp $ */
+/* $Id: uploader.c,v 1.16 2019/02/18 21:55:27 benno Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2019 Florian Obser <florian@openbsd.org>
@@ -163,10 +163,6 @@ init_blk(struct blk *p, const struct blkset *set, off_t offs,
}
/*
- * Handle a symbolic link.
- * If we encounter directories existing in the symbolic link's place,
- * then try to unlink the directory.
- * Otherwise, simply overwrite with the symbolic link by renaming.
* Return <0 on failure 0 on success.
*/
static int
@@ -188,24 +184,20 @@ pre_link(struct upload *p, struct sess *sess)
return 0;
}
- /*
- * See if the symlink already exists.
- * If it's a directory, then try to unlink the directory prior
- * to overwriting with a symbolic link.
- * If it's a non-directory, we just overwrite it.
- */
+ /* See if the symlink already exists. */
assert(p->rootfd != -1);
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
if (rc != -1 && !S_ISLNK(st.st_mode)) {
- if (S_ISDIR(st.st_mode) &&
- unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
- ERR(sess, "%s: unlinkat", f->path);
- return -1;
+ if (S_ISDIR(st.st_mode)) {
+ if (unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
+ WARN(sess, "%s", f->path);
+ return -1;
+ }
}
- rc = -1;
+ rc = -1; /* overwrite object with symlink */
} else if (rc == -1 && errno != ENOENT) {
- ERR(sess, "%s: fstatat", f->path);
+ WARN(sess, "%s: fstatat", f->path);
return -1;
}
@@ -217,7 +209,7 @@ pre_link(struct upload *p, struct sess *sess)
if (rc != -1) {
b = symlinkat_read(sess, p->rootfd, f->path);
if (b == NULL) {
- ERRX1(sess, "symlinkat_read");
+ ERRX1(sess, "%s: symlinkat_read", f->path);
return -1;
}
if (strcmp(f->link, b)) {
@@ -231,29 +223,24 @@ pre_link(struct upload *p, struct sess *sess)
b = NULL;
}
- /*
- * Create the temporary file as a symbolic link, then rename the
- * temporary file as the real one, overwriting anything there.
- */
-
if (rc == -1 || updatelink) {
LOG3(sess, "%s: creating "
"symlink: %s", f->path, f->link);
- if (mktemplate(sess, &temp,
- f->path, sess->opts->recursive) == -1) {
- ERRX1(sess, "mktemplate");
+
+ if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
+ ERR(sess, "asprintf");
return -1;
}
if (mkstemplinkat(f->link, p->rootfd, temp) == NULL) {
- ERR(sess, "mkstemplinkat");
+ WARN(sess, "%s: symlinkat", temp);
free(temp);
return -1;
}
newlink = 1;
}
- rsync_set_metadata_at(sess, newlink,
- p->rootfd, f, newlink ? temp : f->path);
+ rsync_set_metadata_at(sess, newlink, p->rootfd, f,
+ newlink ? temp : f->path);
if (newlink) {
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
@@ -270,8 +257,6 @@ pre_link(struct upload *p, struct sess *sess)
}
/*
- * See pre_link(), but for devices.
- * FIXME: this is very similar to the other pre_xxx() functions.
* Return <0 on failure 0 on success.
*/
static int
@@ -293,55 +278,53 @@ pre_dev(struct upload *p, struct sess *sess)
return 0;
}
- /*
- * See if the dev already exists.
- * If a non-device exists in its place, we'll replace that.
- * If it replaces a directory, remove the directory first.
- */
-
+ /* See if the dev already exists */
assert(p->rootfd != -1);
+
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
if (rc != -1 && !(S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) {
- if (S_ISDIR(st.st_mode) &&
- unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
- ERR(sess, "%s: unlinkat", f->path);
- return -1;
+ if (S_ISDIR(st.st_mode)) {
+ if (unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
+ WARN(sess, "%s", f->path);
+ return -1;
+ }
}
- rc = -1;
+ rc = -1; /* overwrite object with dev */
} else if (rc == -1 && errno != ENOENT) {
- ERR(sess, "%s: fstatat", f->path);
+ WARN(sess, "%s: fstatat", f->path);
return -1;
}
- /* Make sure existing device is of the correct type. */
+ /*
+ * If the device already exists make sure it is of the correct type.
+ */
if (rc != -1) {
if ((f->st.mode & (S_IFCHR|S_IFBLK)) !=
- (st.st_mode & (S_IFCHR|S_IFBLK)) ||
- f->st.rdev != st.st_rdev) {
- LOG3(sess, "%s: updating device", f->path);
+ (st.st_mode & (S_IFCHR|S_IFBLK)) || f->st.rdev !=
+ st.st_rdev) {
+ LOG3(sess, "%s: updating dev", f->path);
updatedev = 1;
}
}
if (rc == -1 || updatedev) {
newdev = 1;
- if (mktemplate(sess, &temp, f->path,
- sess->opts->recursive) == -1) {
- ERRX1(sess, "mktemplate");
+ if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
+ ERR(sess, "asprintf");
return -1;
}
- if (mkstempnodat(p->rootfd, temp,
- f->st.mode & (S_IFCHR|S_IFBLK), f->st.rdev) == NULL) {
- ERR(sess, "mkstempnodat");
+ if (mkstempnodat(p->rootfd, temp, f->st.mode &
+ (S_IFCHR|S_IFBLK), f->st.rdev) == NULL) {
+ WARN(sess, "%s: mknodat", temp);
free(temp);
return -1;
}
}
- rsync_set_metadata_at(sess, newdev,
- p->rootfd, f, newdev ? temp : f->path);
+ rsync_set_metadata_at(sess, newdev, p->rootfd, f,
+ newdev ? temp : f->path);
if (newdev) {
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
@@ -352,14 +335,11 @@ pre_dev(struct upload *p, struct sess *sess)
}
free(temp);
}
-
log_file(sess, f);
return 0;
}
/*
- * See pre_link(), but for FIFOs.
- * FIXME: this is very similar to the other pre_xxx() functions.
* Return <0 on failure 0 on success.
*/
static int
@@ -381,43 +361,39 @@ pre_fifo(struct upload *p, struct sess *sess)
return 0;
}
- /*
- * See if the fifo already exists.
- * If it exists as a non-FIFO, unlink it (if a directory) then
- * mark it from replacement.
- */
-
+ /* See if the fifo already exists */
assert(p->rootfd != -1);
+
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
if (rc != -1 && !S_ISFIFO(st.st_mode)) {
- if (S_ISDIR(st.st_mode) &&
- unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
- ERR(sess, "%s: unlinkat", f->path);
- return -1;
+ if (S_ISDIR(st.st_mode)) {
+ if (unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
+ WARN(sess, "%s", f->path);
+ return -1;
+ }
}
- rc = -1;
+ rc = -1; /* overwrite object with fifo */
} else if (rc == -1 && errno != ENOENT) {
- ERR(sess, "%s: fstatat", f->path);
+ WARN(sess, "%s: fstatat", f->path);
return -1;
}
if (rc == -1) {
newfifo = 1;
- if (mktemplate(sess, &temp, f->path,
- sess->opts->recursive) == -1) {
- ERRX1(sess, "mktemplate");
+ if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
+ ERR(sess, "asprintf");
return -1;
}
if (mkstempfifoat(p->rootfd, temp) == NULL) {
- ERR(sess, "mkstempfifoat");
+ WARN(sess, "%s: mkfifoat", temp);
free(temp);
return -1;
}
}
- rsync_set_metadata_at(sess, newfifo,
- p->rootfd, f, newfifo ? temp : f->path);
+ rsync_set_metadata_at(sess, newfifo, p->rootfd, f,
+ newfifo ? temp : f->path);
if (newfifo) {
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
@@ -428,14 +404,11 @@ pre_fifo(struct upload *p, struct sess *sess)
}
free(temp);
}
-
log_file(sess, f);
return 0;
}
/*
- * See pre_link(), but for socket files.
- * FIXME: this is very similar to the other pre_xxx() functions.
* Return <0 on failure 0 on success.
*/
static int
@@ -457,43 +430,38 @@ pre_sock(struct upload *p, struct sess *sess)
return 0;
}
- /*
- * See if the fifo already exists.
- * If it exists as a non-FIFO, unlink it (if a directory) then
- * mark it from replacement.
- */
-
- assert(-1 != p->rootfd);
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
if (rc != -1 && !S_ISSOCK(st.st_mode)) {
- if (S_ISDIR(st.st_mode) &&
- unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
- ERR(sess, "%s: unlinkat", f->path);
- return -1;
+ if (S_ISDIR(st.st_mode)) {
+ if (unlinkat(p->rootfd, f->path, AT_REMOVEDIR) == -1) {
+ WARN(sess, "%s", f->path);
+ return -1;
+ }
}
- rc = -1;
+ rc = -1; /* overwrite object with sock */
} else if (rc == -1 && errno != ENOENT) {
- ERR(sess, "%s: fstatat", f->path);
+ WARN(sess, "%s: fstatat", f->path);
return -1;
}
if (rc == -1) {
newsock = 1;
- if (mktemplate(sess, &temp, f->path,
- sess->opts->recursive) == -1) {
- ERRX1(sess, "mktemplate");
+
+ if (mktemplate(&temp, f->path, sess->opts->recursive) == -1) {
+ ERR(sess, "asprintf");
return -1;
}
+
if (mkstempsock(p->root, temp) == NULL) {
- ERR(sess, "mkstempsock");
+ WARN(sess, "%s: mksockat", temp);
free(temp);
return -1;
}
}
- rsync_set_metadata_at(sess, newsock,
- p->rootfd, f, newsock ? temp : f->path);
+ rsync_set_metadata_at(sess, newsock, p->rootfd, f,
+ newsock ? temp : f->path);
if (newsock) {
if (renameat(p->rootfd, temp, p->rootfd, f->path) == -1) {
@@ -504,7 +472,6 @@ pre_sock(struct upload *p, struct sess *sess)
}
free(temp);
}
-
log_file(sess, f);
return 0;
}
@@ -534,12 +501,11 @@ pre_dir(const struct upload *p, struct sess *sess)
assert(p->rootfd != -1);
rc = fstatat(p->rootfd, f->path, &st, AT_SYMLINK_NOFOLLOW);
-
if (rc == -1 && errno != ENOENT) {
- ERR(sess, "%s: fstatat", f->path);
+ WARN(sess, "%s: fstatat", f->path);
return -1;
} else if (rc != -1 && !S_ISDIR(st.st_mode)) {
- ERRX(sess, "%s: not a directory", f->path);
+ WARNX(sess, "%s: not a directory", f->path);
return -1;
} else if (rc != -1) {
/*
@@ -560,7 +526,7 @@ pre_dir(const struct upload *p, struct sess *sess)
LOG3(sess, "%s: creating directory", f->path);
if (mkdirat(p->rootfd, f->path, 0777 & ~p->oumask) == -1) {
- ERR(sess, "%s: mkdirat", f->path);
+ WARN(sess, "%s: mkdirat", f->path);
return -1;
}
@@ -858,7 +824,7 @@ rsync_uploader(struct upload *u, int *fileinfd,
/* Go back to the event loop, if necessary. */
u->state = (*fileinfd == -1) ?
- UPLOAD_WRITE_LOCAL : UPLOAD_READ_LOCAL;
+ UPLOAD_WRITE_LOCAL : UPLOAD_READ_LOCAL;
if (u->state == UPLOAD_READ_LOCAL)
return 1;
}
@@ -919,7 +885,7 @@ rsync_uploader(struct upload *u, int *fileinfd,
mapsz = st.st_size;
map = mmap(NULL, mapsz, PROT_READ, MAP_SHARED, *fileinfd, 0);
if (map == MAP_FAILED) {
- ERR(sess, "%s: mmap", u->fl[u->idx].path);
+ WARN(sess, "%s: mmap", u->fl[u->idx].path);
close(*fileinfd);
*fileinfd = -1;
return -1;