summaryrefslogtreecommitdiff
path: root/usr.bin/rsync
diff options
context:
space:
mode:
authorbket <bket@cvs.openbsd.org>2019-04-04 04:19:55 +0000
committerbket <bket@cvs.openbsd.org>2019-04-04 04:19:55 +0000
commit378cd07b6358ce26d9787f640e067db143afbab9 (patch)
tree24a7edea91ddbdd72e11443ec85cd0abaf91ef7e /usr.bin/rsync
parentac781e5d0070a5fccc462e858dafaf804c3a46fa (diff)
Add support for not crossing filesystem boundaries (-x) to rsync. Option
and behaviour is the same as GPL rsync. Initial diff received feedback from benno@, schwarze@, deraadt@ and florian@. Thanks! OK deraadt@
Diffstat (limited to 'usr.bin/rsync')
-rw-r--r--usr.bin/rsync/extern.h3
-rw-r--r--usr.bin/rsync/fargs.c6
-rw-r--r--usr.bin/rsync/flist.c78
-rw-r--r--usr.bin/rsync/main.c9
-rw-r--r--usr.bin/rsync/rsync.111
5 files changed, 95 insertions, 12 deletions
diff --git a/usr.bin/rsync/extern.h b/usr.bin/rsync/extern.h
index 9ae08e7515e..305821be579 100644
--- a/usr.bin/rsync/extern.h
+++ b/usr.bin/rsync/extern.h
@@ -1,4 +1,4 @@
-/* $Id: extern.h,v 1.27 2019/04/02 05:32:08 deraadt Exp $ */
+/* $Id: extern.h,v 1.28 2019/04/04 04:19:54 bket Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -117,6 +117,7 @@ struct opts {
int devices; /* --devices */
int specials; /* --specials */
int numeric_ids; /* --numeric-ids */
+ int one_file_system; /* -x */
char *rsync_path; /* --rsync-path */
char *ssh_prog; /* --rsh or -e */
char *port; /* --port */
diff --git a/usr.bin/rsync/fargs.c b/usr.bin/rsync/fargs.c
index 55bf1b4b8af..59dadc856c7 100644
--- a/usr.bin/rsync/fargs.c
+++ b/usr.bin/rsync/fargs.c
@@ -1,4 +1,4 @@
-/* $Id: fargs.c,v 1.15 2019/04/02 05:32:08 deraadt Exp $ */
+/* $Id: fargs.c,v 1.16 2019/04/04 04:19:54 bket Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -106,6 +106,10 @@ fargs_cmdline(struct sess *sess, const struct fargs *f, size_t *skip)
addargs(&args, "-v");
if (sess->opts->verbose > 0)
addargs(&args, "-v");
+ if (sess->opts->one_file_system > 1)
+ addargs(&args, "-x");
+ if (sess->opts->one_file_system > 0)
+ addargs(&args, "-x");
if (sess->opts->specials && !sess->opts->devices)
addargs(&args, "--specials");
if (!sess->opts->specials && sess->opts->devices)
diff --git a/usr.bin/rsync/flist.c b/usr.bin/rsync/flist.c
index b39599583e3..ac29ad47098 100644
--- a/usr.bin/rsync/flist.c
+++ b/usr.bin/rsync/flist.c
@@ -1,4 +1,4 @@
-/* $Id: flist.c,v 1.23 2019/03/31 09:26:05 deraadt Exp $ */
+/* $Id: flist.c,v 1.24 2019/04/04 04:19:54 bket Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2019 Florian Obser <florian@openbsd.org>
@@ -804,11 +804,12 @@ flist_gen_dirent(struct sess *sess, char *root, struct flist **fl, size_t *sz,
size_t *max)
{
char *cargv[2], *cp;
- int rc = 0;
+ int rc = 0, nxdev = 0, flag, i;
FTS *fts;
FTSENT *ent;
struct flist *f;
size_t flsz = 0, stripdir;
+ dev_t *xdev;
struct stat st;
cargv[0] = root;
@@ -913,6 +914,48 @@ flist_gen_dirent(struct sess *sess, char *root, struct flist **fl, size_t *sz,
continue;
}
+ /*
+ * If rsync is told to avoid crossing a filesystem
+ * boundary when recursing, then replace all mount point
+ * directories with empty directories. The latter is
+ * prevented by telling rsync multiple times to avoid
+ * crossing a filesystem boundary when recursing.
+ * Replacing mount point directories is tricky. We need
+ * to sort out which directories to include. As such,
+ * keep track of unique device inodes, and use these for
+ * comparison.
+ */
+
+ if (sess->opts->one_file_system &&
+ ent->fts_statp->st_dev != st.st_dev) {
+ if (sess->opts->one_file_system > 1 ||
+ !S_ISDIR(ent->fts_statp->st_mode))
+ continue;
+
+ if ((xdev = malloc(sizeof(dev_t))) == NULL) {
+ ERRX1(sess, "malloc");
+ goto out;
+ }
+
+ flag = 0;
+ for (i = 0; i < nxdev; i++)
+ if (xdev[i] == ent->fts_statp->st_dev) {
+ flag = 1;
+ break;
+ }
+ if (flag)
+ continue;
+
+ if (nxdev)
+ if ((xdev = realloc(xdev, sizeof(dev_t))) ==
+ NULL) {
+ ERRX1(sess, "realloc");
+ goto out;
+ }
+ xdev[nxdev] = ent->fts_statp->st_dev;
+ nxdev++;
+ }
+
/* Allocate a new file entry. */
if (!flist_realloc(sess, fl, sz, max)) {
@@ -966,6 +1009,8 @@ flist_gen_dirent(struct sess *sess, char *root, struct flist **fl, size_t *sz,
rc = 1;
out:
fts_close(fts);
+ if (sess->opts->one_file_system)
+ free(xdev);
return rc;
}
@@ -1129,10 +1174,11 @@ flist_gen_dels(struct sess *sess, const char *root, struct flist **fl,
size_t *sz, const struct flist *wfl, size_t wflsz)
{
char **cargv = NULL;
- int rc = 0, c;
+ int rc = 0, c, flag;
FTS *fts = NULL;
FTSENT *ent;
struct flist *f;
+ struct stat st;
size_t cargvs = 0, i, j, max = 0, stripdir;
ENTRY hent;
ENTRY *hentp;
@@ -1253,6 +1299,31 @@ flist_gen_dels(struct sess *sess, const char *root, struct flist **fl,
} else if (stripdir >= ent->fts_pathlen)
continue;
+ assert(ent->fts_statp != NULL);
+
+ /*
+ * If rsync is told to avoid crossing a filesystem
+ * boundary when recursing, then exclude all entries
+ * from the list with a device inode, which does not
+ * match that of one of the top-level directories.
+ */
+
+ if (sess->opts->one_file_system) {
+ flag = 0;
+ for (i = 0; i < wflsz; i++) {
+ if (stat(wfl[i].path, &st) == -1) {
+ ERR(sess, "%s: stat", wfl[i].path);
+ goto out;
+ }
+ if (ent->fts_statp->st_dev == st.st_dev) {
+ flag = 1;
+ break;
+ }
+ }
+ if (!flag)
+ continue;
+ }
+
/* Look up in hashtable. */
memset(&hent, 0, sizeof(ENTRY));
@@ -1273,7 +1344,6 @@ flist_gen_dels(struct sess *sess, const char *root, struct flist **fl,
goto out;
}
f->wpath = f->path + stripdir;
- assert(ent->fts_statp != NULL);
flist_copy_stat(f, ent->fts_statp);
errno = 0;
}
diff --git a/usr.bin/rsync/main.c b/usr.bin/rsync/main.c
index dd598d93eb2..4f0b386e0bf 100644
--- a/usr.bin/rsync/main.c
+++ b/usr.bin/rsync/main.c
@@ -1,4 +1,4 @@
-/* $Id: main.c,v 1.43 2019/04/01 13:04:51 schwarze Exp $ */
+/* $Id: main.c,v 1.44 2019/04/04 04:19:54 bket Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -315,7 +315,7 @@ main(int argc, char *argv[])
memset(&opts, 0, sizeof(struct opts));
- while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvz", lopts, NULL))
+ while ((c = getopt_long(argc, argv, "Dae:ghlnoprtvxz", lopts, NULL))
!= -1) {
switch (c) {
case 'D':
@@ -359,6 +359,9 @@ main(int argc, char *argv[])
case 'v':
opts.verbose++;
break;
+ case 'x':
+ opts.one_file_system++;
+ break;
case 'z':
fprintf(stderr, "%s: -z not supported yet\n", getprogname());
break;
@@ -505,7 +508,7 @@ main(int argc, char *argv[])
exit(rc);
usage:
fprintf(stderr, "usage: %s"
- " [-aDglnoprtv] [-e program] [--del] [--numeric-ids]\n"
+ " [-aDglnoprtvx] [-e program] [--del] [--numeric-ids]\n"
"\t[--port=portnumber] [--rsync-path=program] [--version]\n"
"\tsource ... directory\n",
getprogname());
diff --git a/usr.bin/rsync/rsync.1 b/usr.bin/rsync/rsync.1
index c16168fff8f..3747a3fe70e 100644
--- a/usr.bin/rsync/rsync.1
+++ b/usr.bin/rsync/rsync.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: rsync.1,v 1.16 2019/04/01 13:04:51 schwarze Exp $
+.\" $OpenBSD: rsync.1,v 1.17 2019/04/04 04:19:54 bket Exp $
.\"
.\" Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: April 1 2019 $
+.Dd $Mdocdate: April 4 2019 $
.Dt OPENRSYNC 1
.Os
.Sh NAME
@@ -22,7 +22,7 @@
.Nd synchronise local and remote files
.Sh SYNOPSIS
.Nm openrsync
-.Op Fl aDglnoprtv
+.Op Fl aDglnoprtvx
.Op Fl e Ar program
.Op Fl -del
.Op Fl -numeric-ids
@@ -141,6 +141,11 @@ Increase verbosity.
Specify once for files being transferred, twice for specific status,
thrice for per-file transfer information, and four times for per-file
breakdowns.
+.It Fl x
+Do not cross filesystem boundaries.
+If this option is repeated, all mount point directories from the copy are
+omitted.
+Otherwise, it includes an empty directory at each mount point it encounters.
.It Fl -version
Print version and exit.
.El