4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
30 #include <libdevinfo.h>
38 #include <sys/mount.h>
39 #include <sys/mntent.h>
40 #include <sys/mnttab.h>
46 #include "zfs_namecheck.h"
48 #include "libzfs_impl.h"
50 #include <fletcher.c> /* XXX */
52 static int zfs_receive_impl(libzfs_handle_t
*, const char *, recvflags_t
,
53 int, avl_tree_t
*, char **);
56 * Routines for dealing with the AVL tree of fs-nvlists
58 typedef struct fsavl_node
{
66 fsavl_compare(const void *arg1
, const void *arg2
)
68 const fsavl_node_t
*fn1
= arg1
;
69 const fsavl_node_t
*fn2
= arg2
;
71 if (fn1
->fn_guid
> fn2
->fn_guid
)
73 else if (fn1
->fn_guid
< fn2
->fn_guid
)
80 * Given the GUID of a snapshot, find its containing filesystem and
84 fsavl_find(avl_tree_t
*avl
, uint64_t snapguid
, char **snapname
)
89 fn_find
.fn_guid
= snapguid
;
91 fn
= avl_find(avl
, &fn_find
, NULL
);
94 *snapname
= fn
->fn_snapname
;
101 fsavl_destroy(avl_tree_t
*avl
)
110 while ((fn
= avl_destroy_nodes(avl
, &cookie
)) != NULL
)
117 fsavl_create(nvlist_t
*fss
)
120 nvpair_t
*fselem
= NULL
;
122 if ((fsavl
= malloc(sizeof (avl_tree_t
))) == NULL
)
125 avl_create(fsavl
, fsavl_compare
, sizeof (fsavl_node_t
),
126 offsetof(fsavl_node_t
, fn_node
));
128 while ((fselem
= nvlist_next_nvpair(fss
, fselem
)) != NULL
) {
129 nvlist_t
*nvfs
, *snaps
;
130 nvpair_t
*snapelem
= NULL
;
132 VERIFY(0 == nvpair_value_nvlist(fselem
, &nvfs
));
133 VERIFY(0 == nvlist_lookup_nvlist(nvfs
, "snaps", &snaps
));
136 nvlist_next_nvpair(snaps
, snapelem
)) != NULL
) {
140 VERIFY(0 == nvpair_value_uint64(snapelem
, &guid
));
141 if ((fn
= malloc(sizeof (fsavl_node_t
))) == NULL
) {
142 fsavl_destroy(fsavl
);
146 fn
->fn_snapname
= nvpair_name(snapelem
);
150 * Note: if there are multiple snaps with the
151 * same GUID, we ignore all but one.
153 if (avl_find(fsavl
, fn
, NULL
) == NULL
)
164 * Routines for dealing with the giant nvlist of fs-nvlists, etc.
166 typedef struct send_data
{
167 uint64_t parent_fromsnap_guid
;
168 nvlist_t
*parent_snaps
;
171 const char *fromsnap
;
175 * The header nvlist is of the following format:
178 * "fromsnap" -> string (if incremental)
182 * "name" -> string (full name; for debugging)
183 * "parentfromsnap" -> number (guid of fromsnap in parent)
185 * "props" -> { name -> value (only if set here) }
186 * "snaps" -> { name (lastname) -> number (guid) }
187 * "snapprops" -> { name (lastname) -> { name -> value } }
189 * "origin" -> number (guid) (if clone)
190 * "sent" -> boolean (not on-disk)
198 static void send_iterate_prop(zfs_handle_t
*zhp
, nvlist_t
*nv
);
201 send_iterate_snap(zfs_handle_t
*zhp
, void *arg
)
203 send_data_t
*sd
= arg
;
204 uint64_t guid
= zhp
->zfs_dmustats
.dds_guid
;
208 snapname
= strrchr(zhp
->zfs_name
, '@')+1;
210 VERIFY(0 == nvlist_add_uint64(sd
->parent_snaps
, snapname
, guid
));
212 * NB: if there is no fromsnap here (it's a newly created fs in
213 * an incremental replication), we will substitute the tosnap.
215 if ((sd
->fromsnap
&& strcmp(snapname
, sd
->fromsnap
) == 0) ||
216 (sd
->parent_fromsnap_guid
== 0 && sd
->tosnap
&&
217 strcmp(snapname
, sd
->tosnap
) == 0)) {
218 sd
->parent_fromsnap_guid
= guid
;
221 VERIFY(0 == nvlist_alloc(&nv
, NV_UNIQUE_NAME
, 0));
222 send_iterate_prop(zhp
, nv
);
223 VERIFY(0 == nvlist_add_nvlist(sd
->snapprops
, snapname
, nv
));
231 send_iterate_prop(zfs_handle_t
*zhp
, nvlist_t
*nv
)
233 nvpair_t
*elem
= NULL
;
235 while ((elem
= nvlist_next_nvpair(zhp
->zfs_props
, elem
)) != NULL
) {
236 char *propname
= nvpair_name(elem
);
237 zfs_prop_t prop
= zfs_name_to_prop(propname
);
240 if (!zfs_prop_user(propname
) && zfs_prop_readonly(prop
))
243 verify(nvpair_value_nvlist(elem
, &propnv
) == 0);
244 if (prop
== ZFS_PROP_QUOTA
|| prop
== ZFS_PROP_RESERVATION
) {
245 /* these guys are modifyable, but have no source */
247 verify(nvlist_lookup_uint64(propnv
,
248 ZPROP_VALUE
, &value
) == 0);
249 if (zhp
->zfs_type
== ZFS_TYPE_SNAPSHOT
)
253 if (nvlist_lookup_string(propnv
,
254 ZPROP_SOURCE
, &source
) != 0)
256 if (strcmp(source
, zhp
->zfs_name
) != 0)
260 if (zfs_prop_user(propname
) ||
261 zfs_prop_get_type(prop
) == PROP_TYPE_STRING
) {
263 verify(nvlist_lookup_string(propnv
,
264 ZPROP_VALUE
, &value
) == 0);
265 VERIFY(0 == nvlist_add_string(nv
, propname
, value
));
268 verify(nvlist_lookup_uint64(propnv
,
269 ZPROP_VALUE
, &value
) == 0);
270 VERIFY(0 == nvlist_add_uint64(nv
, propname
, value
));
276 send_iterate_fs(zfs_handle_t
*zhp
, void *arg
)
278 send_data_t
*sd
= arg
;
281 uint64_t parent_fromsnap_guid_save
= sd
->parent_fromsnap_guid
;
282 uint64_t guid
= zhp
->zfs_dmustats
.dds_guid
;
285 VERIFY(0 == nvlist_alloc(&nvfs
, NV_UNIQUE_NAME
, 0));
286 VERIFY(0 == nvlist_add_string(nvfs
, "name", zhp
->zfs_name
));
287 VERIFY(0 == nvlist_add_uint64(nvfs
, "parentfromsnap",
288 sd
->parent_fromsnap_guid
));
290 if (zhp
->zfs_dmustats
.dds_origin
[0]) {
291 zfs_handle_t
*origin
= zfs_open(zhp
->zfs_hdl
,
292 zhp
->zfs_dmustats
.dds_origin
, ZFS_TYPE_SNAPSHOT
);
295 VERIFY(0 == nvlist_add_uint64(nvfs
, "origin",
296 origin
->zfs_dmustats
.dds_guid
));
299 /* iterate over props */
300 VERIFY(0 == nvlist_alloc(&nv
, NV_UNIQUE_NAME
, 0));
301 send_iterate_prop(zhp
, nv
);
302 VERIFY(0 == nvlist_add_nvlist(nvfs
, "props", nv
));
305 /* iterate over snaps, and set sd->parent_fromsnap_guid */
306 sd
->parent_fromsnap_guid
= 0;
307 VERIFY(0 == nvlist_alloc(&sd
->parent_snaps
, NV_UNIQUE_NAME
, 0));
308 VERIFY(0 == nvlist_alloc(&sd
->snapprops
, NV_UNIQUE_NAME
, 0));
309 (void) zfs_iter_snapshots(zhp
, send_iterate_snap
, sd
);
310 VERIFY(0 == nvlist_add_nvlist(nvfs
, "snaps", sd
->parent_snaps
));
311 VERIFY(0 == nvlist_add_nvlist(nvfs
, "snapprops", sd
->snapprops
));
312 nvlist_free(sd
->parent_snaps
);
313 nvlist_free(sd
->snapprops
);
315 /* add this fs to nvlist */
316 (void) snprintf(guidstring
, sizeof (guidstring
),
317 "0x%llx", (longlong_t
)guid
);
318 VERIFY(0 == nvlist_add_nvlist(sd
->fss
, guidstring
, nvfs
));
321 /* iterate over children */
322 rv
= zfs_iter_filesystems(zhp
, send_iterate_fs
, sd
);
324 sd
->parent_fromsnap_guid
= parent_fromsnap_guid_save
;
331 gather_nvlist(libzfs_handle_t
*hdl
, const char *fsname
, const char *fromsnap
,
332 const char *tosnap
, nvlist_t
**nvlp
, avl_tree_t
**avlp
)
335 send_data_t sd
= { 0 };
338 zhp
= zfs_open(hdl
, fsname
, ZFS_TYPE_FILESYSTEM
| ZFS_TYPE_VOLUME
);
340 return (EZFS_BADTYPE
);
342 VERIFY(0 == nvlist_alloc(&sd
.fss
, NV_UNIQUE_NAME
, 0));
343 sd
.fromsnap
= fromsnap
;
346 if ((error
= send_iterate_fs(zhp
, &sd
)) != 0) {
354 if (avlp
!= NULL
&& (*avlp
= fsavl_create(sd
.fss
)) == NULL
) {
365 * Routines for dealing with the sorted snapshot functionality
367 typedef struct zfs_node
{
368 zfs_handle_t
*zn_handle
;
369 avl_node_t zn_avlnode
;
373 zfs_sort_snaps(zfs_handle_t
*zhp
, void *data
)
375 avl_tree_t
*avl
= data
;
376 zfs_node_t
*node
= zfs_alloc(zhp
->zfs_hdl
, sizeof (zfs_node_t
));
378 node
->zn_handle
= zhp
;
385 zfs_snapshot_compare(const void *larg
, const void *rarg
)
387 zfs_handle_t
*l
= ((zfs_node_t
*)larg
)->zn_handle
;
388 zfs_handle_t
*r
= ((zfs_node_t
*)rarg
)->zn_handle
;
389 uint64_t lcreate
, rcreate
;
392 * Sort them according to creation time. We use the hidden
393 * CREATETXG property to get an absolute ordering of snapshots.
395 lcreate
= zfs_prop_get_int(l
, ZFS_PROP_CREATETXG
);
396 rcreate
= zfs_prop_get_int(r
, ZFS_PROP_CREATETXG
);
398 if (lcreate
< rcreate
)
400 else if (lcreate
> rcreate
)
407 zfs_iter_snapshots_sorted(zfs_handle_t
*zhp
, zfs_iter_f callback
, void *data
)
414 avl_create(&avl
, zfs_snapshot_compare
,
415 sizeof (zfs_node_t
), offsetof(zfs_node_t
, zn_avlnode
));
417 ret
= zfs_iter_snapshots(zhp
, zfs_sort_snaps
, &avl
);
419 for (node
= avl_first(&avl
); node
!= NULL
; node
= AVL_NEXT(&avl
, node
))
420 ret
|= callback(node
->zn_handle
, data
);
422 while ((node
= avl_destroy_nodes(&avl
, &cookie
)) != NULL
)
431 * Routines specific to "zfs send"
433 typedef struct send_dump_data
{
434 /* these are all just the short snapname (the part after the @) */
435 const char *fromsnap
;
437 char lastsnap
[ZFS_MAXNAMELEN
];
438 boolean_t seenfrom
, seento
, replicate
, doall
, fromorigin
;
447 * Dumps a backup of the given snapshot (incremental from fromsnap if it's not
448 * NULL) to the file descriptor specified by outfd.
451 dump_ioctl(zfs_handle_t
*zhp
, const char *fromsnap
, boolean_t fromorigin
,
454 zfs_cmd_t zc
= { 0 };
455 libzfs_handle_t
*hdl
= zhp
->zfs_hdl
;
457 assert(zhp
->zfs_type
== ZFS_TYPE_SNAPSHOT
);
458 assert(fromsnap
== NULL
|| fromsnap
[0] == '\0' || !fromorigin
);
460 (void) strlcpy(zc
.zc_name
, zhp
->zfs_name
, sizeof (zc
.zc_name
));
462 (void) strlcpy(zc
.zc_value
, fromsnap
, sizeof (zc
.zc_value
));
463 zc
.zc_cookie
= outfd
;
464 zc
.zc_obj
= fromorigin
;
466 if (ioctl(zhp
->zfs_hdl
->libzfs_fd
, ZFS_IOC_SEND
, &zc
) != 0) {
468 (void) snprintf(errbuf
, sizeof (errbuf
), dgettext(TEXT_DOMAIN
,
469 "warning: cannot send '%s'"), zhp
->zfs_name
);
474 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
475 "not an earlier snapshot from the same fs"));
476 return (zfs_error(hdl
, EZFS_CROSSTARGET
, errbuf
));
479 if (zfs_dataset_exists(hdl
, zc
.zc_name
,
480 ZFS_TYPE_SNAPSHOT
)) {
481 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
482 "incremental source (@%s) does not exist"),
485 return (zfs_error(hdl
, EZFS_NOENT
, errbuf
));
498 zfs_error_aux(hdl
, strerror(errno
));
499 return (zfs_error(hdl
, EZFS_BADBACKUP
, errbuf
));
502 return (zfs_standard_error(hdl
, errno
, errbuf
));
510 dump_snapshot(zfs_handle_t
*zhp
, void *arg
)
512 send_dump_data_t
*sdd
= arg
;
513 const char *thissnap
;
516 thissnap
= strchr(zhp
->zfs_name
, '@') + 1;
518 if (sdd
->fromsnap
&& !sdd
->seenfrom
&&
519 strcmp(sdd
->fromsnap
, thissnap
) == 0) {
520 sdd
->seenfrom
= B_TRUE
;
521 (void) strcpy(sdd
->lastsnap
, thissnap
);
526 if (sdd
->seento
|| !sdd
->seenfrom
) {
533 (void) fprintf(stderr
, "sending from @%s to %s\n",
534 sdd
->lastsnap
, zhp
->zfs_name
);
537 err
= dump_ioctl(zhp
, sdd
->lastsnap
,
538 sdd
->lastsnap
[0] == '\0' && (sdd
->fromorigin
|| sdd
->replicate
),
541 if (!sdd
->seento
&& strcmp(sdd
->tosnap
, thissnap
) == 0)
542 sdd
->seento
= B_TRUE
;
544 (void) strcpy(sdd
->lastsnap
, thissnap
);
550 dump_filesystem(zfs_handle_t
*zhp
, void *arg
)
553 send_dump_data_t
*sdd
= arg
;
554 boolean_t missingfrom
= B_FALSE
;
555 zfs_cmd_t zc
= { 0 };
557 (void) snprintf(zc
.zc_name
, sizeof (zc
.zc_name
), "%s@%s",
558 zhp
->zfs_name
, sdd
->tosnap
);
559 if (ioctl(zhp
->zfs_hdl
->libzfs_fd
, ZFS_IOC_OBJSET_STATS
, &zc
) != 0) {
560 (void) fprintf(stderr
, "WARNING: "
561 "could not send %s@%s: does not exist\n",
562 zhp
->zfs_name
, sdd
->tosnap
);
567 if (sdd
->replicate
&& sdd
->fromsnap
) {
569 * If this fs does not have fromsnap, and we're doing
570 * recursive, we need to send a full stream from the
571 * beginning (or an incremental from the origin if this
572 * is a clone). If we're doing non-recursive, then let
573 * them get the error.
575 (void) snprintf(zc
.zc_name
, sizeof (zc
.zc_name
), "%s@%s",
576 zhp
->zfs_name
, sdd
->fromsnap
);
577 if (ioctl(zhp
->zfs_hdl
->libzfs_fd
,
578 ZFS_IOC_OBJSET_STATS
, &zc
) != 0) {
579 missingfrom
= B_TRUE
;
584 sdd
->seenfrom
= sdd
->seento
= sdd
->lastsnap
[0] = 0;
585 if (sdd
->fromsnap
== NULL
|| missingfrom
)
586 sdd
->seenfrom
= B_TRUE
;
588 rv
= zfs_iter_snapshots_sorted(zhp
, dump_snapshot
, arg
);
589 if (!sdd
->seenfrom
) {
590 (void) fprintf(stderr
,
591 "WARNING: could not send %s@%s:\n"
592 "incremental source (%s@%s) does not exist\n",
593 zhp
->zfs_name
, sdd
->tosnap
,
594 zhp
->zfs_name
, sdd
->fromsnap
);
596 } else if (!sdd
->seento
) {
597 (void) fprintf(stderr
,
598 "WARNING: could not send %s@%s:\n"
599 "incremental source (%s@%s) "
600 "is not earlier than it\n",
601 zhp
->zfs_name
, sdd
->tosnap
,
602 zhp
->zfs_name
, sdd
->fromsnap
);
606 zfs_handle_t
*snapzhp
;
607 char snapname
[ZFS_MAXNAMELEN
];
609 (void) snprintf(snapname
, sizeof (snapname
), "%s@%s",
610 zfs_get_name(zhp
), sdd
->tosnap
);
611 snapzhp
= zfs_open(zhp
->zfs_hdl
, snapname
, ZFS_TYPE_SNAPSHOT
);
612 if (snapzhp
== NULL
) {
615 rv
= dump_ioctl(snapzhp
,
616 missingfrom
? NULL
: sdd
->fromsnap
,
617 sdd
->fromorigin
|| missingfrom
,
619 sdd
->seento
= B_TRUE
;
628 dump_filesystems(zfs_handle_t
*rzhp
, void *arg
)
630 send_dump_data_t
*sdd
= arg
;
632 boolean_t needagain
, progress
;
635 return (dump_filesystem(rzhp
, sdd
));
638 needagain
= progress
= B_FALSE
;
639 for (fspair
= nvlist_next_nvpair(sdd
->fss
, NULL
); fspair
;
640 fspair
= nvlist_next_nvpair(sdd
->fss
, fspair
)) {
645 uint64_t origin_guid
= 0;
648 VERIFY(nvpair_value_nvlist(fspair
, &fslist
) == 0);
649 if (nvlist_lookup_boolean(fslist
, "sent") == 0)
652 VERIFY(nvlist_lookup_string(fslist
, "name", &fsname
) == 0);
653 (void) nvlist_lookup_uint64(fslist
, "origin", &origin_guid
);
655 origin_nv
= fsavl_find(sdd
->fsavl
, origin_guid
, NULL
);
657 nvlist_lookup_boolean(origin_nv
, "sent") == ENOENT
) {
659 * origin has not been sent yet;
666 zhp
= zfs_open(rzhp
->zfs_hdl
, fsname
, ZFS_TYPE_DATASET
);
669 err
= dump_filesystem(zhp
, sdd
);
670 VERIFY(nvlist_add_boolean(fslist
, "sent") == 0);
684 * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL.
685 * If 'doall', dump all intermediate snaps.
686 * If 'replicate', dump special header and do recursively.
689 zfs_send(zfs_handle_t
*zhp
, const char *fromsnap
, const char *tosnap
,
690 boolean_t replicate
, boolean_t doall
, boolean_t fromorigin
,
691 boolean_t verbose
, int outfd
)
694 send_dump_data_t sdd
= { 0 };
696 nvlist_t
*fss
= NULL
;
697 avl_tree_t
*fsavl
= NULL
;
699 (void) snprintf(errbuf
, sizeof (errbuf
), dgettext(TEXT_DOMAIN
,
700 "cannot send '%s'"), zhp
->zfs_name
);
702 if (fromsnap
&& fromsnap
[0] == '\0') {
703 zfs_error_aux(zhp
->zfs_hdl
, dgettext(TEXT_DOMAIN
,
704 "zero-length incremental source"));
705 return (zfs_error(zhp
->zfs_hdl
, EZFS_NOENT
, errbuf
));
708 if (replicate
|| doall
) {
709 dmu_replay_record_t drr
= { 0 };
710 char *packbuf
= NULL
;
712 zio_cksum_t zc
= { 0 };
714 assert(fromsnap
|| doall
);
719 VERIFY(0 == nvlist_alloc(&hdrnv
, NV_UNIQUE_NAME
, 0));
721 VERIFY(0 == nvlist_add_string(hdrnv
,
722 "fromsnap", fromsnap
));
724 VERIFY(0 == nvlist_add_string(hdrnv
, "tosnap", tosnap
));
726 err
= gather_nvlist(zhp
->zfs_hdl
, zhp
->zfs_name
,
727 fromsnap
, tosnap
, &fss
, &fsavl
);
730 VERIFY(0 == nvlist_add_nvlist(hdrnv
, "fss", fss
));
731 err
= nvlist_pack(hdrnv
, &packbuf
, &buflen
,
735 fsavl_destroy(fsavl
);
737 return (zfs_standard_error(zhp
->zfs_hdl
,
742 /* write first begin record */
743 drr
.drr_type
= DRR_BEGIN
;
744 drr
.drr_u
.drr_begin
.drr_magic
= DMU_BACKUP_MAGIC
;
745 drr
.drr_u
.drr_begin
.drr_version
= DMU_BACKUP_HEADER_VERSION
;
746 (void) snprintf(drr
.drr_u
.drr_begin
.drr_toname
,
747 sizeof (drr
.drr_u
.drr_begin
.drr_toname
),
748 "%s@%s", zhp
->zfs_name
, tosnap
);
749 drr
.drr_payloadlen
= buflen
;
750 fletcher_4_incremental_native(&drr
, sizeof (drr
), &zc
);
751 err
= write(outfd
, &drr
, sizeof (drr
));
753 /* write header nvlist */
755 fletcher_4_incremental_native(packbuf
, buflen
, &zc
);
756 err
= write(outfd
, packbuf
, buflen
);
760 fsavl_destroy(fsavl
);
762 return (zfs_standard_error(zhp
->zfs_hdl
,
766 /* write end record */
768 bzero(&drr
, sizeof (drr
));
769 drr
.drr_type
= DRR_END
;
770 drr
.drr_u
.drr_end
.drr_checksum
= zc
;
771 err
= write(outfd
, &drr
, sizeof (drr
));
773 fsavl_destroy(fsavl
);
775 return (zfs_standard_error(zhp
->zfs_hdl
,
781 /* dump each stream */
782 sdd
.fromsnap
= fromsnap
;
785 sdd
.replicate
= replicate
;
787 sdd
.fromorigin
= fromorigin
;
790 sdd
.verbose
= verbose
;
791 err
= dump_filesystems(zhp
, &sdd
);
792 fsavl_destroy(fsavl
);
795 if (replicate
|| doall
) {
797 * write final end record. NB: want to do this even if
798 * there was some error, because it might not be totally
801 dmu_replay_record_t drr
= { 0 };
802 drr
.drr_type
= DRR_END
;
803 if (write(outfd
, &drr
, sizeof (drr
)) == -1) {
804 return (zfs_standard_error(zhp
->zfs_hdl
,
809 return (err
|| sdd
.err
);
813 * Routines specific to "zfs recv"
817 recv_read(libzfs_handle_t
*hdl
, int fd
, void *buf
, int ilen
,
818 boolean_t byteswap
, zio_cksum_t
*zc
)
825 rv
= read(fd
, cp
, len
);
830 if (rv
< 0 || len
!= 0) {
831 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
832 "failed to read from stream"));
833 return (zfs_error(hdl
, EZFS_BADSTREAM
, dgettext(TEXT_DOMAIN
,
839 fletcher_4_incremental_byteswap(buf
, ilen
, zc
);
841 fletcher_4_incremental_native(buf
, ilen
, zc
);
847 recv_read_nvlist(libzfs_handle_t
*hdl
, int fd
, int len
, nvlist_t
**nvp
,
848 boolean_t byteswap
, zio_cksum_t
*zc
)
853 buf
= zfs_alloc(hdl
, len
);
857 err
= recv_read(hdl
, fd
, buf
, len
, byteswap
, zc
);
863 err
= nvlist_unpack(buf
, len
, nvp
, 0);
866 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
, "invalid "
867 "stream (malformed nvlist)"));
874 recv_rename(libzfs_handle_t
*hdl
, const char *name
, const char *tryname
,
875 int baselen
, char *newname
, recvflags_t flags
)
878 zfs_cmd_t zc
= { 0 };
880 prop_changelist_t
*clp
;
883 zhp
= zfs_open(hdl
, name
, ZFS_TYPE_DATASET
);
886 clp
= changelist_gather(zhp
, ZFS_PROP_NAME
, 0,
887 flags
.force
? MS_FORCE
: 0);
891 err
= changelist_prefix(clp
);
896 (void) strcpy(newname
, tryname
);
898 zc
.zc_objset_type
= DMU_OST_ZFS
;
899 (void) strlcpy(zc
.zc_name
, name
, sizeof (zc
.zc_name
));
900 (void) strlcpy(zc
.zc_value
, tryname
, sizeof (zc
.zc_value
));
903 (void) printf("attempting rename %s to %s\n",
904 zc
.zc_name
, zc
.zc_value
);
906 err
= ioctl(hdl
->libzfs_fd
, ZFS_IOC_RENAME
, &zc
);
908 changelist_rename(clp
, name
, tryname
);
913 if (err
!= 0 && strncmp(name
+baselen
, "recv-", 5) != 0) {
916 (void) strncpy(newname
, name
, baselen
);
917 (void) snprintf(newname
+baselen
, ZFS_MAXNAMELEN
-baselen
,
918 "recv-%u-%u", getpid(), seq
);
919 (void) strlcpy(zc
.zc_value
, newname
, sizeof (zc
.zc_value
));
922 (void) printf("failed - trying rename %s to %s\n",
923 zc
.zc_name
, zc
.zc_value
);
925 err
= ioctl(hdl
->libzfs_fd
, ZFS_IOC_RENAME
, &zc
);
927 changelist_rename(clp
, name
, newname
);
928 if (err
&& flags
.verbose
) {
929 (void) printf("failed (%u) - "
930 "will try again on next pass\n", errno
);
933 } else if (flags
.verbose
) {
935 (void) printf("success\n");
937 (void) printf("failed (%u)\n", errno
);
940 (void) changelist_postfix(clp
);
941 changelist_free(clp
);
947 recv_destroy(libzfs_handle_t
*hdl
, const char *name
, int baselen
,
948 char *newname
, recvflags_t flags
)
950 zfs_cmd_t zc
= { 0 };
952 prop_changelist_t
*clp
;
955 zhp
= zfs_open(hdl
, name
, ZFS_TYPE_DATASET
);
958 clp
= changelist_gather(zhp
, ZFS_PROP_NAME
, 0,
959 flags
.force
? MS_FORCE
: 0);
963 err
= changelist_prefix(clp
);
967 zc
.zc_objset_type
= DMU_OST_ZFS
;
968 (void) strlcpy(zc
.zc_name
, name
, sizeof (zc
.zc_name
));
971 (void) printf("attempting destroy %s\n", zc
.zc_name
);
972 err
= ioctl(hdl
->libzfs_fd
, ZFS_IOC_DESTROY
, &zc
);
976 (void) printf("success\n");
977 changelist_remove(clp
, zc
.zc_name
);
980 (void) changelist_postfix(clp
);
981 changelist_free(clp
);
984 err
= recv_rename(hdl
, name
, NULL
, baselen
, newname
, flags
);
989 typedef struct guid_to_name_data
{
992 } guid_to_name_data_t
;
995 guid_to_name_cb(zfs_handle_t
*zhp
, void *arg
)
997 guid_to_name_data_t
*gtnd
= arg
;
1000 if (zhp
->zfs_dmustats
.dds_guid
== gtnd
->guid
) {
1001 (void) strcpy(gtnd
->name
, zhp
->zfs_name
);
1004 err
= zfs_iter_children(zhp
, guid_to_name_cb
, gtnd
);
1010 guid_to_name(libzfs_handle_t
*hdl
, const char *parent
, uint64_t guid
,
1013 /* exhaustive search all local snapshots */
1014 guid_to_name_data_t gtnd
;
1022 if (strchr(parent
, '@') == NULL
) {
1023 zhp
= make_dataset_handle(hdl
, parent
);
1025 err
= zfs_iter_children(zhp
, guid_to_name_cb
, >nd
);
1032 cp
= strchr(parent
, '/');
1035 zhp
= make_dataset_handle(hdl
, parent
);
1040 err
= zfs_iter_children(zhp
, guid_to_name_cb
, >nd
);
1044 return (err
== EEXIST
? 0 : ENOENT
);
1049 * Return true if dataset guid1 is created before guid2.
1052 created_before(libzfs_handle_t
*hdl
, avl_tree_t
*avl
,
1053 uint64_t guid1
, uint64_t guid2
)
1056 char *fsname
, *snapname
;
1057 char buf
[ZFS_MAXNAMELEN
];
1059 zfs_node_t zn1
, zn2
;
1066 nvfs
= fsavl_find(avl
, guid1
, &snapname
);
1067 VERIFY(0 == nvlist_lookup_string(nvfs
, "name", &fsname
));
1068 (void) snprintf(buf
, sizeof (buf
), "%s@%s", fsname
, snapname
);
1069 zn1
.zn_handle
= zfs_open(hdl
, buf
, ZFS_TYPE_SNAPSHOT
);
1070 if (zn1
.zn_handle
== NULL
)
1073 nvfs
= fsavl_find(avl
, guid2
, &snapname
);
1074 VERIFY(0 == nvlist_lookup_string(nvfs
, "name", &fsname
));
1075 (void) snprintf(buf
, sizeof (buf
), "%s@%s", fsname
, snapname
);
1076 zn2
.zn_handle
= zfs_open(hdl
, buf
, ZFS_TYPE_SNAPSHOT
);
1077 if (zn2
.zn_handle
== NULL
) {
1078 zfs_close(zn2
.zn_handle
);
1082 rv
= (zfs_snapshot_compare(&zn1
, &zn2
) == -1);
1084 zfs_close(zn1
.zn_handle
);
1085 zfs_close(zn2
.zn_handle
);
1091 recv_incremental_replication(libzfs_handle_t
*hdl
, const char *tofs
,
1092 recvflags_t flags
, nvlist_t
*stream_nv
, avl_tree_t
*stream_avl
)
1095 avl_tree_t
*local_avl
;
1096 nvpair_t
*fselem
, *nextfselem
;
1097 char *tosnap
, *fromsnap
;
1098 char newname
[ZFS_MAXNAMELEN
];
1100 boolean_t needagain
, progress
;
1102 VERIFY(0 == nvlist_lookup_string(stream_nv
, "fromsnap", &fromsnap
));
1103 VERIFY(0 == nvlist_lookup_string(stream_nv
, "tosnap", &tosnap
));
1109 needagain
= progress
= B_FALSE
;
1111 if ((error
= gather_nvlist(hdl
, tofs
, fromsnap
, NULL
,
1112 &local_nv
, &local_avl
)) != 0)
1116 * Process deletes and renames
1118 for (fselem
= nvlist_next_nvpair(local_nv
, NULL
);
1119 fselem
; fselem
= nextfselem
) {
1120 nvlist_t
*nvfs
, *snaps
;
1121 nvlist_t
*stream_nvfs
= NULL
;
1122 nvpair_t
*snapelem
, *nextsnapelem
;
1123 uint64_t fromguid
= 0;
1124 uint64_t originguid
= 0;
1125 uint64_t stream_originguid
= 0;
1126 uint64_t parent_fromsnap_guid
, stream_parent_fromsnap_guid
;
1127 char *fsname
, *stream_fsname
;
1129 nextfselem
= nvlist_next_nvpair(local_nv
, fselem
);
1131 VERIFY(0 == nvpair_value_nvlist(fselem
, &nvfs
));
1132 VERIFY(0 == nvlist_lookup_nvlist(nvfs
, "snaps", &snaps
));
1133 VERIFY(0 == nvlist_lookup_string(nvfs
, "name", &fsname
));
1134 VERIFY(0 == nvlist_lookup_uint64(nvfs
, "parentfromsnap",
1135 &parent_fromsnap_guid
));
1136 (void) nvlist_lookup_uint64(nvfs
, "origin", &originguid
);
1139 * First find the stream's fs, so we can check for
1140 * a different origin (due to "zfs promote")
1142 for (snapelem
= nvlist_next_nvpair(snaps
, NULL
);
1143 snapelem
; snapelem
= nvlist_next_nvpair(snaps
, snapelem
)) {
1146 VERIFY(0 == nvpair_value_uint64(snapelem
, &thisguid
));
1147 stream_nvfs
= fsavl_find(stream_avl
, thisguid
, NULL
);
1149 if (stream_nvfs
!= NULL
)
1153 /* check for promote */
1154 (void) nvlist_lookup_uint64(stream_nvfs
, "origin",
1155 &stream_originguid
);
1156 if (stream_nvfs
&& originguid
!= stream_originguid
) {
1157 switch (created_before(hdl
, local_avl
,
1158 stream_originguid
, originguid
)) {
1161 zfs_cmd_t zc
= { 0 };
1162 nvlist_t
*origin_nvfs
;
1163 char *origin_fsname
;
1166 (void) printf("promoting %s\n", fsname
);
1168 origin_nvfs
= fsavl_find(local_avl
, originguid
,
1170 VERIFY(0 == nvlist_lookup_string(origin_nvfs
,
1171 "name", &origin_fsname
));
1172 (void) strlcpy(zc
.zc_value
, origin_fsname
,
1173 sizeof (zc
.zc_value
));
1174 (void) strlcpy(zc
.zc_name
, fsname
,
1175 sizeof (zc
.zc_name
));
1176 error
= zfs_ioctl(hdl
, ZFS_IOC_PROMOTE
, &zc
);
1184 fsavl_destroy(local_avl
);
1185 nvlist_free(local_nv
);
1189 * We had/have the wrong origin, therefore our
1190 * list of snapshots is wrong. Need to handle
1191 * them on the next pass.
1197 for (snapelem
= nvlist_next_nvpair(snaps
, NULL
);
1198 snapelem
; snapelem
= nextsnapelem
) {
1200 char *stream_snapname
;
1201 nvlist_t
*found
, *props
;
1203 nextsnapelem
= nvlist_next_nvpair(snaps
, snapelem
);
1205 VERIFY(0 == nvpair_value_uint64(snapelem
, &thisguid
));
1206 found
= fsavl_find(stream_avl
, thisguid
,
1209 /* check for delete */
1210 if (found
== NULL
) {
1211 char name
[ZFS_MAXNAMELEN
];
1216 (void) snprintf(name
, sizeof (name
), "%s@%s",
1217 fsname
, nvpair_name(snapelem
));
1219 error
= recv_destroy(hdl
, name
,
1220 strlen(fsname
)+1, newname
, flags
);
1228 stream_nvfs
= found
;
1230 if (0 == nvlist_lookup_nvlist(stream_nvfs
, "snapprops",
1231 &props
) && 0 == nvlist_lookup_nvlist(props
,
1232 stream_snapname
, &props
)) {
1233 zfs_cmd_t zc
= { 0 };
1235 zc
.zc_cookie
= B_TRUE
; /* clear current props */
1236 (void) snprintf(zc
.zc_name
, sizeof (zc
.zc_name
),
1237 "%s@%s", fsname
, nvpair_name(snapelem
));
1238 if (zcmd_write_src_nvlist(hdl
, &zc
,
1240 (void) zfs_ioctl(hdl
,
1241 ZFS_IOC_SET_PROP
, &zc
);
1242 zcmd_free_nvlists(&zc
);
1246 /* check for different snapname */
1247 if (strcmp(nvpair_name(snapelem
),
1248 stream_snapname
) != 0) {
1249 char name
[ZFS_MAXNAMELEN
];
1250 char tryname
[ZFS_MAXNAMELEN
];
1252 (void) snprintf(name
, sizeof (name
), "%s@%s",
1253 fsname
, nvpair_name(snapelem
));
1254 (void) snprintf(tryname
, sizeof (name
), "%s@%s",
1255 fsname
, stream_snapname
);
1257 error
= recv_rename(hdl
, name
, tryname
,
1258 strlen(fsname
)+1, newname
, flags
);
1265 if (strcmp(stream_snapname
, fromsnap
) == 0)
1266 fromguid
= thisguid
;
1269 /* check for delete */
1270 if (stream_nvfs
== NULL
) {
1274 error
= recv_destroy(hdl
, fsname
, strlen(tofs
)+1,
1283 if (fromguid
== 0 && flags
.verbose
) {
1284 (void) printf("local fs %s does not have fromsnap "
1285 "(%s in stream); must have been deleted locally; "
1286 "ignoring\n", fsname
, fromsnap
);
1290 VERIFY(0 == nvlist_lookup_string(stream_nvfs
,
1291 "name", &stream_fsname
));
1292 VERIFY(0 == nvlist_lookup_uint64(stream_nvfs
,
1293 "parentfromsnap", &stream_parent_fromsnap_guid
));
1295 /* check for rename */
1296 if ((stream_parent_fromsnap_guid
!= 0 &&
1297 stream_parent_fromsnap_guid
!= parent_fromsnap_guid
) ||
1298 strcmp(strrchr(fsname
, '/'),
1299 strrchr(stream_fsname
, '/')) != 0) {
1301 char tryname
[ZFS_MAXNAMELEN
];
1303 parent
= fsavl_find(local_avl
,
1304 stream_parent_fromsnap_guid
, NULL
);
1306 * NB: parent might not be found if we used the
1307 * tosnap for stream_parent_fromsnap_guid,
1308 * because the parent is a newly-created fs;
1309 * we'll be able to rename it after we recv the
1312 if (parent
!= NULL
) {
1315 VERIFY(0 == nvlist_lookup_string(parent
, "name",
1317 (void) snprintf(tryname
, sizeof (tryname
),
1318 "%s%s", pname
, strrchr(stream_fsname
, '/'));
1321 if (flags
.verbose
) {
1322 (void) printf("local fs %s new parent "
1323 "not found\n", fsname
);
1327 error
= recv_rename(hdl
, fsname
, tryname
,
1328 strlen(tofs
)+1, newname
, flags
);
1336 fsavl_destroy(local_avl
);
1337 nvlist_free(local_nv
);
1339 if (needagain
&& progress
) {
1340 /* do another pass to fix up temporary names */
1342 (void) printf("another pass:\n");
1350 zfs_receive_package(libzfs_handle_t
*hdl
, int fd
, const char *destname
,
1351 recvflags_t flags
, dmu_replay_record_t
*drr
, zio_cksum_t
*zc
,
1354 nvlist_t
*stream_nv
= NULL
;
1355 avl_tree_t
*stream_avl
= NULL
;
1356 char *fromsnap
= NULL
;
1357 char tofs
[ZFS_MAXNAMELEN
];
1359 dmu_replay_record_t drre
;
1361 boolean_t anyerr
= B_FALSE
;
1362 boolean_t softerr
= B_FALSE
;
1364 (void) snprintf(errbuf
, sizeof (errbuf
), dgettext(TEXT_DOMAIN
,
1367 if (strchr(destname
, '@')) {
1368 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1369 "can not specify snapshot name for multi-snapshot stream"));
1370 return (zfs_error(hdl
, EZFS_BADSTREAM
, errbuf
));
1373 assert(drr
->drr_type
== DRR_BEGIN
);
1374 assert(drr
->drr_u
.drr_begin
.drr_magic
== DMU_BACKUP_MAGIC
);
1375 assert(drr
->drr_u
.drr_begin
.drr_version
== DMU_BACKUP_HEADER_VERSION
);
1378 * Read in the nvlist from the stream.
1380 if (drr
->drr_payloadlen
!= 0) {
1381 if (!flags
.isprefix
) {
1382 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1383 "must use -d to receive replication "
1384 "(send -R) stream"));
1385 return (zfs_error(hdl
, EZFS_BADSTREAM
, errbuf
));
1388 error
= recv_read_nvlist(hdl
, fd
, drr
->drr_payloadlen
,
1389 &stream_nv
, flags
.byteswap
, zc
);
1391 error
= zfs_error(hdl
, EZFS_BADSTREAM
, errbuf
);
1397 * Read in the end record and verify checksum.
1399 if (0 != (error
= recv_read(hdl
, fd
, &drre
, sizeof (drre
),
1400 flags
.byteswap
, NULL
)))
1402 if (flags
.byteswap
) {
1403 drre
.drr_type
= BSWAP_32(drre
.drr_type
);
1404 drre
.drr_u
.drr_end
.drr_checksum
.zc_word
[0] =
1405 BSWAP_64(drre
.drr_u
.drr_end
.drr_checksum
.zc_word
[0]);
1406 drre
.drr_u
.drr_end
.drr_checksum
.zc_word
[1] =
1407 BSWAP_64(drre
.drr_u
.drr_end
.drr_checksum
.zc_word
[1]);
1408 drre
.drr_u
.drr_end
.drr_checksum
.zc_word
[2] =
1409 BSWAP_64(drre
.drr_u
.drr_end
.drr_checksum
.zc_word
[2]);
1410 drre
.drr_u
.drr_end
.drr_checksum
.zc_word
[3] =
1411 BSWAP_64(drre
.drr_u
.drr_end
.drr_checksum
.zc_word
[3]);
1413 if (drre
.drr_type
!= DRR_END
) {
1414 error
= zfs_error(hdl
, EZFS_BADSTREAM
, errbuf
);
1417 if (!ZIO_CHECKSUM_EQUAL(drre
.drr_u
.drr_end
.drr_checksum
, *zc
)) {
1418 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1419 "incorrect header checksum"));
1420 error
= zfs_error(hdl
, EZFS_BADSTREAM
, errbuf
);
1424 (void) nvlist_lookup_string(stream_nv
, "fromsnap", &fromsnap
);
1426 if (drr
->drr_payloadlen
!= 0) {
1427 nvlist_t
*stream_fss
;
1429 VERIFY(0 == nvlist_lookup_nvlist(stream_nv
, "fss",
1431 if ((stream_avl
= fsavl_create(stream_fss
)) == NULL
) {
1432 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1433 "couldn't allocate avl tree"));
1434 error
= zfs_error(hdl
, EZFS_NOMEM
, errbuf
);
1438 if (fromsnap
!= NULL
) {
1439 (void) strlcpy(tofs
, destname
, ZFS_MAXNAMELEN
);
1440 if (flags
.isprefix
) {
1441 int i
= strcspn(drr
->drr_u
.drr_begin
.drr_toname
,
1443 /* zfs_receive_one() will create_parents() */
1444 (void) strlcat(tofs
,
1445 &drr
->drr_u
.drr_begin
.drr_toname
[i
],
1447 *strchr(tofs
, '@') = '\0';
1449 softerr
= recv_incremental_replication(hdl
, tofs
,
1450 flags
, stream_nv
, stream_avl
);
1455 /* Finally, receive each contained stream */
1458 * we should figure out if it has a recoverable
1459 * error, in which case do a recv_skip() and drive on.
1460 * Note, if we fail due to already having this guid,
1461 * zfs_receive_one() will take care of it (ie,
1462 * recv_skip() and return 0).
1464 error
= zfs_receive_impl(hdl
, destname
, flags
, fd
,
1465 stream_avl
, top_zfs
);
1466 if (error
== ENODATA
) {
1471 } while (error
== 0);
1473 if (drr
->drr_payloadlen
!= 0 && fromsnap
!= NULL
) {
1475 * Now that we have the fs's they sent us, try the
1478 softerr
= recv_incremental_replication(hdl
, tofs
, flags
,
1479 stream_nv
, stream_avl
);
1483 fsavl_destroy(stream_avl
);
1485 nvlist_free(stream_nv
);
1494 recv_skip(libzfs_handle_t
*hdl
, int fd
, boolean_t byteswap
)
1496 dmu_replay_record_t
*drr
;
1497 void *buf
= malloc(1<<20);
1499 /* XXX would be great to use lseek if possible... */
1502 while (recv_read(hdl
, fd
, drr
, sizeof (dmu_replay_record_t
),
1503 byteswap
, NULL
) == 0) {
1505 drr
->drr_type
= BSWAP_32(drr
->drr_type
);
1507 switch (drr
->drr_type
) {
1509 /* NB: not to be used on v2 stream packages */
1510 assert(drr
->drr_payloadlen
== 0);
1519 drr
->drr_u
.drr_object
.drr_bonuslen
=
1520 BSWAP_32(drr
->drr_u
.drr_object
.
1523 (void) recv_read(hdl
, fd
, buf
,
1524 P2ROUNDUP(drr
->drr_u
.drr_object
.drr_bonuslen
, 8),
1530 drr
->drr_u
.drr_write
.drr_length
=
1531 BSWAP_64(drr
->drr_u
.drr_write
.drr_length
);
1533 (void) recv_read(hdl
, fd
, buf
,
1534 drr
->drr_u
.drr_write
.drr_length
, B_FALSE
, NULL
);
1537 case DRR_FREEOBJECTS
:
1542 assert(!"invalid record type");
1551 * Restores a backup of tosnap from the file descriptor specified by infd.
1554 zfs_receive_one(libzfs_handle_t
*hdl
, int infd
, const char *tosnap
,
1555 recvflags_t flags
, dmu_replay_record_t
*drr
,
1556 dmu_replay_record_t
*drr_noswap
, avl_tree_t
*stream_avl
,
1559 zfs_cmd_t zc
= { 0 };
1561 int ioctl_err
, ioctl_errno
, err
, choplen
;
1563 struct drr_begin
*drrb
= &drr
->drr_u
.drr_begin
;
1565 char chopprefix
[ZFS_MAXNAMELEN
];
1566 boolean_t newfs
= B_FALSE
;
1567 boolean_t stream_wantsnewfs
;
1568 uint64_t parent_snapguid
= 0;
1569 prop_changelist_t
*clp
= NULL
;
1570 nvlist_t
*snapprops_nvlist
= NULL
;
1572 begin_time
= time(NULL
);
1574 (void) snprintf(errbuf
, sizeof (errbuf
), dgettext(TEXT_DOMAIN
,
1577 if (stream_avl
!= NULL
) {
1579 nvlist_t
*fs
= fsavl_find(stream_avl
, drrb
->drr_toguid
,
1584 (void) nvlist_lookup_uint64(fs
, "parentfromsnap",
1586 err
= nvlist_lookup_nvlist(fs
, "props", &props
);
1588 VERIFY(0 == nvlist_alloc(&props
, NV_UNIQUE_NAME
, 0));
1590 if (flags
.canmountoff
) {
1591 VERIFY(0 == nvlist_add_uint64(props
,
1592 zfs_prop_to_name(ZFS_PROP_CANMOUNT
), 0));
1594 ret
= zcmd_write_src_nvlist(hdl
, &zc
, props
);
1598 if (0 == nvlist_lookup_nvlist(fs
, "snapprops", &props
)) {
1599 VERIFY(0 == nvlist_lookup_nvlist(props
,
1600 snapname
, &snapprops_nvlist
));
1608 * Determine how much of the snapshot name stored in the stream
1609 * we are going to tack on to the name they specified on the
1610 * command line, and how much we are going to chop off.
1612 * If they specified a snapshot, chop the entire name stored in
1615 (void) strcpy(chopprefix
, drrb
->drr_toname
);
1616 if (flags
.isprefix
) {
1618 * They specified a fs with -d, we want to tack on
1619 * everything but the pool name stored in the stream
1621 if (strchr(tosnap
, '@')) {
1622 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
, "invalid "
1623 "argument - snapshot not allowed with -d"));
1624 return (zfs_error(hdl
, EZFS_INVALIDNAME
, errbuf
));
1626 cp
= strchr(chopprefix
, '/');
1628 cp
= strchr(chopprefix
, '@');
1630 } else if (strchr(tosnap
, '@') == NULL
) {
1632 * If they specified a filesystem without -d, we want to
1633 * tack on everything after the fs specified in the
1634 * first name from the stream.
1636 cp
= strchr(chopprefix
, '@');
1639 choplen
= strlen(chopprefix
);
1642 * Determine name of destination snapshot, store in zc_value.
1644 (void) strcpy(zc
.zc_value
, tosnap
);
1645 (void) strncat(zc
.zc_value
, drrb
->drr_toname
+choplen
,
1646 sizeof (zc
.zc_value
));
1647 if (!zfs_name_valid(zc
.zc_value
, ZFS_TYPE_SNAPSHOT
)) {
1648 zcmd_free_nvlists(&zc
);
1649 return (zfs_error(hdl
, EZFS_INVALIDNAME
, errbuf
));
1653 * Determine the name of the origin snapshot, store in zc_string.
1655 if (drrb
->drr_flags
& DRR_FLAG_CLONE
) {
1656 if (guid_to_name(hdl
, tosnap
,
1657 drrb
->drr_fromguid
, zc
.zc_string
) != 0) {
1658 zcmd_free_nvlists(&zc
);
1659 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1660 "local origin for clone %s does not exist"),
1662 return (zfs_error(hdl
, EZFS_NOENT
, errbuf
));
1665 (void) printf("found clone origin %s\n", zc
.zc_string
);
1668 stream_wantsnewfs
= (drrb
->drr_fromguid
== NULL
||
1669 (drrb
->drr_flags
& DRR_FLAG_CLONE
));
1671 if (stream_wantsnewfs
) {
1673 * if the parent fs does not exist, look for it based on
1674 * the parent snap GUID
1676 (void) snprintf(errbuf
, sizeof (errbuf
), dgettext(TEXT_DOMAIN
,
1677 "cannot receive new filesystem stream"));
1679 (void) strcpy(zc
.zc_name
, zc
.zc_value
);
1680 cp
= strrchr(zc
.zc_name
, '/');
1684 !zfs_dataset_exists(hdl
, zc
.zc_name
, ZFS_TYPE_DATASET
)) {
1685 char suffix
[ZFS_MAXNAMELEN
];
1686 (void) strcpy(suffix
, strrchr(zc
.zc_value
, '/'));
1687 if (guid_to_name(hdl
, tosnap
, parent_snapguid
,
1688 zc
.zc_value
) == 0) {
1689 *strchr(zc
.zc_value
, '@') = '\0';
1690 (void) strcat(zc
.zc_value
, suffix
);
1695 * if the fs does not exist, look for it based on the
1698 (void) snprintf(errbuf
, sizeof (errbuf
), dgettext(TEXT_DOMAIN
,
1699 "cannot receive incremental stream"));
1701 (void) strcpy(zc
.zc_name
, zc
.zc_value
);
1702 *strchr(zc
.zc_name
, '@') = '\0';
1704 if (!zfs_dataset_exists(hdl
, zc
.zc_name
, ZFS_TYPE_DATASET
)) {
1705 char snap
[ZFS_MAXNAMELEN
];
1706 (void) strcpy(snap
, strchr(zc
.zc_value
, '@'));
1707 if (guid_to_name(hdl
, tosnap
, drrb
->drr_fromguid
,
1708 zc
.zc_value
) == 0) {
1709 *strchr(zc
.zc_value
, '@') = '\0';
1710 (void) strcat(zc
.zc_value
, snap
);
1715 (void) strcpy(zc
.zc_name
, zc
.zc_value
);
1716 *strchr(zc
.zc_name
, '@') = '\0';
1718 if (zfs_dataset_exists(hdl
, zc
.zc_name
, ZFS_TYPE_DATASET
)) {
1721 * Destination fs exists. Therefore this should either
1722 * be an incremental, or the stream specifies a new fs
1723 * (full stream or clone) and they want us to blow it
1724 * away (and have therefore specified -F and removed any
1728 if (stream_wantsnewfs
) {
1730 zcmd_free_nvlists(&zc
);
1731 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1732 "destination '%s' exists\n"
1733 "must specify -F to overwrite it"),
1735 return (zfs_error(hdl
, EZFS_EXISTS
, errbuf
));
1737 if (ioctl(hdl
->libzfs_fd
, ZFS_IOC_SNAPSHOT_LIST_NEXT
,
1739 zcmd_free_nvlists(&zc
);
1740 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1741 "destination has snapshots (eg. %s)\n"
1742 "must destroy them to overwrite it"),
1744 return (zfs_error(hdl
, EZFS_EXISTS
, errbuf
));
1748 if ((zhp
= zfs_open(hdl
, zc
.zc_name
,
1749 ZFS_TYPE_FILESYSTEM
| ZFS_TYPE_VOLUME
)) == NULL
) {
1750 zcmd_free_nvlists(&zc
);
1754 if (stream_wantsnewfs
&&
1755 zhp
->zfs_dmustats
.dds_origin
[0]) {
1756 zcmd_free_nvlists(&zc
);
1758 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1759 "destination '%s' is a clone\n"
1760 "must destroy it to overwrite it"),
1762 return (zfs_error(hdl
, EZFS_EXISTS
, errbuf
));
1765 if (!flags
.dryrun
&& zhp
->zfs_type
== ZFS_TYPE_FILESYSTEM
&&
1766 stream_wantsnewfs
) {
1767 /* We can't do online recv in this case */
1768 clp
= changelist_gather(zhp
, ZFS_PROP_NAME
, 0, 0);
1770 zcmd_free_nvlists(&zc
);
1773 if (changelist_prefix(clp
) != 0) {
1774 changelist_free(clp
);
1775 zcmd_free_nvlists(&zc
);
1779 if (!flags
.dryrun
&& zhp
->zfs_type
== ZFS_TYPE_VOLUME
&&
1780 zvol_remove_link(hdl
, zhp
->zfs_name
) != 0) {
1782 zcmd_free_nvlists(&zc
);
1788 * Destination filesystem does not exist. Therefore we better
1789 * be creating a new filesystem (either from a full backup, or
1790 * a clone). It would therefore be invalid if the user
1791 * specified only the pool name (i.e. if the destination name
1792 * contained no slash character).
1794 if (!stream_wantsnewfs
||
1795 (cp
= strrchr(zc
.zc_name
, '/')) == NULL
) {
1796 zcmd_free_nvlists(&zc
);
1797 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1798 "destination '%s' does not exist"), zc
.zc_name
);
1799 return (zfs_error(hdl
, EZFS_NOENT
, errbuf
));
1803 * Trim off the final dataset component so we perform the
1804 * recvbackup ioctl to the filesystems's parent.
1808 if (flags
.isprefix
&& !flags
.dryrun
&&
1809 create_parents(hdl
, zc
.zc_value
, strlen(tosnap
)) != 0) {
1810 zcmd_free_nvlists(&zc
);
1811 return (zfs_error(hdl
, EZFS_BADRESTORE
, errbuf
));
1817 zc
.zc_begin_record
= drr_noswap
->drr_u
.drr_begin
;
1818 zc
.zc_cookie
= infd
;
1819 zc
.zc_guid
= flags
.force
;
1820 if (flags
.verbose
) {
1821 (void) printf("%s %s stream of %s into %s\n",
1822 flags
.dryrun
? "would receive" : "receiving",
1823 drrb
->drr_fromguid
? "incremental" : "full",
1824 drrb
->drr_toname
, zc
.zc_value
);
1825 (void) fflush(stdout
);
1829 zcmd_free_nvlists(&zc
);
1830 return (recv_skip(hdl
, infd
, flags
.byteswap
));
1833 err
= ioctl_err
= zfs_ioctl(hdl
, ZFS_IOC_RECV
, &zc
);
1834 ioctl_errno
= errno
;
1835 zcmd_free_nvlists(&zc
);
1837 if (err
== 0 && snapprops_nvlist
) {
1838 zfs_cmd_t zc2
= { 0 };
1840 (void) strcpy(zc2
.zc_name
, zc
.zc_value
);
1841 if (zcmd_write_src_nvlist(hdl
, &zc2
, snapprops_nvlist
) == 0) {
1842 (void) zfs_ioctl(hdl
, ZFS_IOC_SET_PROP
, &zc2
);
1843 zcmd_free_nvlists(&zc2
);
1847 if (err
&& (ioctl_errno
== ENOENT
|| ioctl_errno
== ENODEV
)) {
1849 * It may be that this snapshot already exists,
1850 * in which case we want to consume & ignore it
1851 * rather than failing.
1853 avl_tree_t
*local_avl
;
1854 nvlist_t
*local_nv
, *fs
;
1855 char *cp
= strchr(zc
.zc_value
, '@');
1858 * XXX Do this faster by just iterating over snaps in
1859 * this fs. Also if zc_value does not exist, we will
1860 * get a strange "does not exist" error message.
1863 if (gather_nvlist(hdl
, zc
.zc_value
, NULL
, NULL
,
1864 &local_nv
, &local_avl
) == 0) {
1866 fs
= fsavl_find(local_avl
, drrb
->drr_toguid
, NULL
);
1867 fsavl_destroy(local_avl
);
1868 nvlist_free(local_nv
);
1871 if (flags
.verbose
) {
1872 (void) printf("snap %s already exists; "
1873 "ignoring\n", zc
.zc_value
);
1875 ioctl_err
= recv_skip(hdl
, infd
,
1883 if (ioctl_err
!= 0) {
1884 switch (ioctl_errno
) {
1886 cp
= strchr(zc
.zc_value
, '@');
1888 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1889 "most recent snapshot of %s does not\n"
1890 "match incremental source"), zc
.zc_value
);
1891 (void) zfs_error(hdl
, EZFS_BADRESTORE
, errbuf
);
1895 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1896 "destination %s has been modified\n"
1897 "since most recent snapshot"), zc
.zc_name
);
1898 (void) zfs_error(hdl
, EZFS_BADRESTORE
, errbuf
);
1901 cp
= strchr(zc
.zc_value
, '@');
1903 /* it's the containing fs that exists */
1906 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1907 "destination already exists"));
1908 (void) zfs_error_fmt(hdl
, EZFS_EXISTS
,
1909 dgettext(TEXT_DOMAIN
, "cannot restore to %s"),
1914 (void) zfs_error(hdl
, EZFS_BADSTREAM
, errbuf
);
1917 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
1918 "invalid stream (checksum mismatch)"));
1919 (void) zfs_error(hdl
, EZFS_BADSTREAM
, errbuf
);
1922 (void) zfs_standard_error(hdl
, ioctl_errno
, errbuf
);
1927 * Mount or recreate the /dev links for the target filesystem
1928 * (if created, or if we tore them down to do an incremental
1929 * restore), and the /dev links for the new snapshot (if
1930 * created). Also mount any children of the target filesystem
1931 * if we did an incremental receive.
1933 cp
= strchr(zc
.zc_value
, '@');
1934 if (cp
&& (ioctl_err
== 0 || !newfs
)) {
1938 h
= zfs_open(hdl
, zc
.zc_value
,
1939 ZFS_TYPE_FILESYSTEM
| ZFS_TYPE_VOLUME
);
1941 if (h
->zfs_type
== ZFS_TYPE_VOLUME
) {
1943 err
= zvol_create_link(hdl
, h
->zfs_name
);
1944 if (err
== 0 && ioctl_err
== 0)
1945 err
= zvol_create_link(hdl
,
1949 * Track the first/top of hierarchy fs,
1950 * for mounting and sharing later.
1952 if (top_zfs
&& *top_zfs
== NULL
)
1953 *top_zfs
= zfs_strdup(hdl
, zc
.zc_value
);
1961 err
|= changelist_postfix(clp
);
1962 changelist_free(clp
);
1965 if (err
|| ioctl_err
)
1968 if (flags
.verbose
) {
1971 uint64_t bytes
= zc
.zc_cookie
;
1972 time_t delta
= time(NULL
) - begin_time
;
1975 zfs_nicenum(bytes
, buf1
, sizeof (buf1
));
1976 zfs_nicenum(bytes
/delta
, buf2
, sizeof (buf1
));
1978 (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
1986 zfs_receive_impl(libzfs_handle_t
*hdl
, const char *tosnap
, recvflags_t flags
,
1987 int infd
, avl_tree_t
*stream_avl
, char **top_zfs
)
1990 dmu_replay_record_t drr
, drr_noswap
;
1991 struct drr_begin
*drrb
= &drr
.drr_u
.drr_begin
;
1993 zio_cksum_t zcksum
= { 0 };
1995 (void) snprintf(errbuf
, sizeof (errbuf
), dgettext(TEXT_DOMAIN
,
1998 if (flags
.isprefix
&&
1999 !zfs_dataset_exists(hdl
, tosnap
, ZFS_TYPE_DATASET
)) {
2000 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
, "specified fs "
2001 "(%s) does not exist"), tosnap
);
2002 return (zfs_error(hdl
, EZFS_NOENT
, errbuf
));
2005 /* read in the BEGIN record */
2006 if (0 != (err
= recv_read(hdl
, infd
, &drr
, sizeof (drr
), B_FALSE
,
2010 if (drr
.drr_type
== DRR_END
|| drr
.drr_type
== BSWAP_32(DRR_END
)) {
2011 /* It's the double end record at the end of a package */
2015 /* the kernel needs the non-byteswapped begin record */
2018 flags
.byteswap
= B_FALSE
;
2019 if (drrb
->drr_magic
== BSWAP_64(DMU_BACKUP_MAGIC
)) {
2021 * We computed the checksum in the wrong byteorder in
2022 * recv_read() above; do it again correctly.
2024 bzero(&zcksum
, sizeof (zio_cksum_t
));
2025 fletcher_4_incremental_byteswap(&drr
, sizeof (drr
), &zcksum
);
2026 flags
.byteswap
= B_TRUE
;
2028 drr
.drr_type
= BSWAP_32(drr
.drr_type
);
2029 drr
.drr_payloadlen
= BSWAP_32(drr
.drr_payloadlen
);
2030 drrb
->drr_magic
= BSWAP_64(drrb
->drr_magic
);
2031 drrb
->drr_version
= BSWAP_64(drrb
->drr_version
);
2032 drrb
->drr_creation_time
= BSWAP_64(drrb
->drr_creation_time
);
2033 drrb
->drr_type
= BSWAP_32(drrb
->drr_type
);
2034 drrb
->drr_flags
= BSWAP_32(drrb
->drr_flags
);
2035 drrb
->drr_toguid
= BSWAP_64(drrb
->drr_toguid
);
2036 drrb
->drr_fromguid
= BSWAP_64(drrb
->drr_fromguid
);
2039 if (drrb
->drr_magic
!= DMU_BACKUP_MAGIC
|| drr
.drr_type
!= DRR_BEGIN
) {
2040 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
, "invalid "
2041 "stream (bad magic number)"));
2042 return (zfs_error(hdl
, EZFS_BADSTREAM
, errbuf
));
2045 if (strchr(drrb
->drr_toname
, '@') == NULL
) {
2046 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
, "invalid "
2047 "stream (bad snapshot name)"));
2048 return (zfs_error(hdl
, EZFS_BADSTREAM
, errbuf
));
2051 if (drrb
->drr_version
== DMU_BACKUP_STREAM_VERSION
) {
2052 return (zfs_receive_one(hdl
, infd
, tosnap
, flags
,
2053 &drr
, &drr_noswap
, stream_avl
, top_zfs
));
2054 } else if (drrb
->drr_version
== DMU_BACKUP_HEADER_VERSION
) {
2055 return (zfs_receive_package(hdl
, infd
, tosnap
, flags
,
2056 &drr
, &zcksum
, top_zfs
));
2058 zfs_error_aux(hdl
, dgettext(TEXT_DOMAIN
,
2059 "stream is unsupported version %llu"),
2061 return (zfs_error(hdl
, EZFS_BADSTREAM
, errbuf
));
2066 * Restores a backup of tosnap from the file descriptor specified by infd.
2067 * Return 0 on total success, -2 if some things couldn't be
2068 * destroyed/renamed/promoted, -1 if some things couldn't be received.
2069 * (-1 will override -2).
2072 zfs_receive(libzfs_handle_t
*hdl
, const char *tosnap
, recvflags_t flags
,
2073 int infd
, avl_tree_t
*stream_avl
)
2075 char *top_zfs
= NULL
;
2078 err
= zfs_receive_impl(hdl
, tosnap
, flags
, infd
, stream_avl
, &top_zfs
);
2080 if (err
== 0 && top_zfs
) {
2082 prop_changelist_t
*clp
;
2084 zhp
= zfs_open(hdl
, top_zfs
, ZFS_TYPE_FILESYSTEM
);
2086 clp
= changelist_gather(zhp
, ZFS_PROP_MOUNTPOINT
,
2087 CL_GATHER_MOUNT_ALWAYS
, 0);
2090 /* mount and share received datasets */
2091 err
= changelist_postfix(clp
);
2092 changelist_free(clp
);
2095 if (zhp
== NULL
|| clp
== NULL
|| err
)