diff options
author | Sebastian Benoit <benno@cvs.openbsd.org> | 2019-02-18 21:55:28 +0000 |
---|---|---|
committer | Sebastian Benoit <benno@cvs.openbsd.org> | 2019-02-18 21:55:28 +0000 |
commit | 9bb0da04d46a25150c43281f9df758c060567427 (patch) | |
tree | 6a59467b56f448ca7660a0262fda0b7690b11243 /usr.bin/rsync | |
parent | bde034a382776f3c396eef446206fe579292673e (diff) |
revert previous
Diffstat (limited to 'usr.bin/rsync')
-rw-r--r-- | usr.bin/rsync/TODO.md | 6 | ||||
-rw-r--r-- | usr.bin/rsync/blocks.c | 23 | ||||
-rw-r--r-- | usr.bin/rsync/child.c | 10 | ||||
-rw-r--r-- | usr.bin/rsync/client.c | 10 | ||||
-rw-r--r-- | usr.bin/rsync/downloader.c | 10 | ||||
-rw-r--r-- | usr.bin/rsync/extern.h | 18 | ||||
-rw-r--r-- | usr.bin/rsync/io.c | 5 | ||||
-rw-r--r-- | usr.bin/rsync/log.c | 22 | ||||
-rw-r--r-- | usr.bin/rsync/main.c | 100 | ||||
-rw-r--r-- | usr.bin/rsync/mktemp.c | 125 | ||||
-rw-r--r-- | usr.bin/rsync/receiver.c | 6 | ||||
-rw-r--r-- | usr.bin/rsync/rsync.5 | 4 | ||||
-rw-r--r-- | usr.bin/rsync/sender.c | 376 | ||||
-rw-r--r-- | usr.bin/rsync/server.c | 16 | ||||
-rw-r--r-- | usr.bin/rsync/socket.c | 16 | ||||
-rw-r--r-- | usr.bin/rsync/uploader.c | 176 |
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; |