summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorTom Erickson <Tom.Erickson@Sun.COM>2010-01-08 16:55:38 -0800
committerTom Erickson <Tom.Erickson@Sun.COM>2010-01-08 16:55:38 -0800
commitf64930f5a99dc5cadc013502deedef5a6ef3971f (patch)
tree5d0ca0f906e6ea9474bde4fc01b1c7d869ffa03d /usr/src
parentb72c368a02e0464faeef362bc5a1cf0fc69981da (diff)
downloadillumos-gate-f64930f5a99dc5cadc013502deedef5a6ef3971f.tar.gz
PSARC 2009/663 zfs receive -e
6885138 Would like ability to specify exact receive path when receiving "zfs send -R" stream 6644648 want "zfs send -R a/b/c@snap|zfs recv d/e" to create d/e/c[/...]
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/zfs/zfs_main.c8
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h6
-rw-r--r--usr/src/lib/libzfs/common/libzfs_sendrecv.c32
3 files changed, 24 insertions, 22 deletions
diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c
index a0d0a59118..9c800d2861 100644
--- a/usr/src/cmd/zfs/zfs_main.c
+++ b/usr/src/cmd/zfs/zfs_main.c
@@ -2684,7 +2684,7 @@ zfs_do_send(int argc, char **argv)
}
/*
- * zfs receive [-dnvF] <fs@snap>
+ * zfs receive [-denvF] <fs@snap>
*
* Restore a backup stream from stdin.
*/
@@ -2695,11 +2695,15 @@ zfs_do_receive(int argc, char **argv)
recvflags_t flags = { 0 };
/* check options */
- while ((c = getopt(argc, argv, ":dnuvF")) != -1) {
+ while ((c = getopt(argc, argv, ":denuvF")) != -1) {
switch (c) {
case 'd':
flags.isprefix = B_TRUE;
break;
+ case 'e':
+ flags.isprefix = B_TRUE;
+ flags.istail = B_TRUE;
+ break;
case 'n':
flags.dryrun = B_TRUE;
break;
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index e6bd268291..4d0aef344f 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -544,6 +544,12 @@ typedef struct recvflags {
/* the destination is a prefix, not the exact fs (ie, -d) */
int isprefix : 1;
+ /*
+ * Only the tail of the sent snapshot path is appended to the
+ * destination to determine the received snapshot name (ie, -e).
+ */
+ int istail : 1;
+
/* do not actually do the recv, just check if it would work (ie, -n) */
int dryrun : 1;
diff --git a/usr/src/lib/libzfs/common/libzfs_sendrecv.c b/usr/src/lib/libzfs/common/libzfs_sendrecv.c
index 4d507aaf58..65f9b66b60 100644
--- a/usr/src/lib/libzfs/common/libzfs_sendrecv.c
+++ b/usr/src/lib/libzfs/common/libzfs_sendrecv.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1921,24 +1921,12 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
* Read in the nvlist from the stream.
*/
if (drr->drr_payloadlen != 0) {
- boolean_t recursive;
-
error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen,
&stream_nv, flags.byteswap, zc);
if (error) {
error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
goto out;
}
-
- recursive = (nvlist_lookup_boolean(stream_nv,
- "not_recursive") == ENOENT);
-
- if (recursive && !flags.isprefix) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must use -d to receive replication "
- "(send -R) stream"));
- return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
- }
}
/*
@@ -2189,23 +2177,27 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
(void) strcpy(chopprefix, drrb->drr_toname);
if (flags.isprefix) {
/*
- * They specified a fs with -d, we want to tack on
- * everything but the pool name stored in the stream
+ * They specified a fs with -d or -e. We want to tack on
+ * everything but the first element of the sent snapshot path
+ * (all but the pool name) in the case of -d, or only the tail
+ * of the sent snapshot path in the case of -e.
*/
if (strchr(tosnap, '@')) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
- "argument - snapshot not allowed with -d"));
+ "argument - snapshot not allowed with %s"),
+ (flags.istail ? "-e" : "-d"));
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
}
- cp = strchr(chopprefix, '/');
+ cp = (flags.istail ? strrchr(chopprefix, '/') :
+ strchr(chopprefix, '/'));
if (cp == NULL)
cp = strchr(chopprefix, '@');
*cp = '\0';
} else if (strchr(tosnap, '@') == NULL) {
/*
- * If they specified a filesystem without -d, we want to
- * tack on everything after the fs specified in the
- * first name from the stream.
+ * If they specified a filesystem without -d or -e, we want to
+ * tack on everything after the fs specified in the first name
+ * from the stream.
*/
cp = strchr(chopprefix, '@');
*cp = '\0';