7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
25 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
26 * Copyright (c) 2013 Steven Hartland. All rights reserved.
27 */
28
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <libintl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <strings.h>
36 #include <unistd.h>
37 #include <stddef.h>
38 #include <fcntl.h>
39 #include <sys/mount.h>
40 #include <pthread.h>
41 #include <umem.h>
42 #include <time.h>
43
44 #include <libzfs.h>
45 #include <libzfs_core.h>
46
47 #include "zfs_namecheck.h"
48 #include "zfs_prop.h"
49 #include "zfs_fletcher.h"
50 #include "libzfs_impl.h"
51 #include <zlib.h>
52 #include <sha2.h>
53 #include <sys/zio_checksum.h>
54 #include <sys/ddt.h>
55
56 /* in libzfs_dataset.c */
57 extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
58
59 static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
60 recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
61 uint64_t *);
62 static int guid_to_name(libzfs_handle_t *, const char *,
63 uint64_t, boolean_t, char *);
64
65 static const zio_cksum_t zero_cksum = { 0 };
66
67 typedef struct dedup_arg {
68 int inputfd;
69 int outputfd;
70 libzfs_handle_t *dedup_hdl;
71 } dedup_arg_t;
72
73 typedef struct progress_arg {
74 zfs_handle_t *pa_zhp;
75 int pa_fd;
76 boolean_t pa_parsable;
77 } progress_arg_t;
78
79 typedef struct dataref {
80 uint64_t ref_guid;
81 uint64_t ref_object;
2544 nvlist_free(local_nv);
2545
2546 if (needagain && progress) {
2547 /* do another pass to fix up temporary names */
2548 if (flags->verbose)
2549 (void) printf("another pass:\n");
2550 goto again;
2551 }
2552
2553 return (needagain);
2554 }
2555
2556 static int
2557 zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
2558 recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
2559 char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
2560 {
2561 nvlist_t *stream_nv = NULL;
2562 avl_tree_t *stream_avl = NULL;
2563 char *fromsnap = NULL;
2564 char *cp;
2565 char tofs[ZFS_MAXNAMELEN];
2566 char sendfs[ZFS_MAXNAMELEN];
2567 char errbuf[1024];
2568 dmu_replay_record_t drre;
2569 int error;
2570 boolean_t anyerr = B_FALSE;
2571 boolean_t softerr = B_FALSE;
2572 boolean_t recursive;
2573
2574 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2575 "cannot receive"));
2576
2577 assert(drr->drr_type == DRR_BEGIN);
2578 assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);
2579 assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==
2580 DMU_COMPOUNDSTREAM);
2581
2582 /*
2583 * Read in the nvlist from the stream.
2692 zfs_close(zhp);
2693 if (clp != NULL) {
2694 softerr |=
2695 changelist_prefix(clp);
2696 changelist_free(clp);
2697 }
2698 }
2699 }
2700
2701 nvlist_free(renamed);
2702 }
2703 }
2704
2705 /*
2706 * Get the fs specified by the first path in the stream (the top level
2707 * specified by 'zfs send') and pass it to each invocation of
2708 * zfs_receive_one().
2709 */
2710 (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
2711 ZFS_MAXNAMELEN);
2712 if ((cp = strchr(sendfs, '@')) != NULL)
2713 *cp = '\0';
2714
2715 /* Finally, receive each contained stream */
2716 do {
2717 /*
2718 * we should figure out if it has a recoverable
2719 * error, in which case do a recv_skip() and drive on.
2720 * Note, if we fail due to already having this guid,
2721 * zfs_receive_one() will take care of it (ie,
2722 * recv_skip() and return 0).
2723 */
2724 error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
2725 sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
2726 action_handlep);
2727 if (error == ENODATA) {
2728 error = 0;
2729 break;
2730 }
2731 anyerr |= error;
2732 } while (error == 0);
2733
2734 if (drr->drr_payloadlen != 0 && fromsnap != NULL) {
2735 /*
2736 * Now that we have the fs's they sent us, try the
2737 * renames again.
2738 */
2739 softerr = recv_incremental_replication(hdl, tofs, flags,
2740 stream_nv, stream_avl, NULL);
2741 }
2742
2743 out:
2744 fsavl_destroy(stream_avl);
2745 if (stream_nv)
2746 nvlist_free(stream_nv);
2870 token_buf, sizeof (token_buf),
2871 NULL, NULL, 0, B_TRUE);
2872 if (error == 0) {
2873 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2874 "checksum mismatch or incomplete stream.\n"
2875 "Partially received snapshot is saved.\n"
2876 "A resuming stream can be generated on the sending "
2877 "system by running:\n"
2878 " zfs send -t %s"),
2879 token_buf);
2880 }
2881 zfs_close(zhp);
2882 }
2883
2884 /*
2885 * Restores a backup of tosnap from the file descriptor specified by infd.
2886 */
2887 static int
2888 zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
2889 const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
2890 dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,
2891 avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
2892 uint64_t *action_handlep)
2893 {
2894 zfs_cmd_t zc = { 0 };
2895 time_t begin_time;
2896 int ioctl_err, ioctl_errno, err;
2897 char *cp;
2898 struct drr_begin *drrb = &drr->drr_u.drr_begin;
2899 char errbuf[1024];
2900 char prop_errbuf[1024];
2901 const char *chopprefix;
2902 boolean_t newfs = B_FALSE;
2903 boolean_t stream_wantsnewfs;
2904 uint64_t parent_snapguid = 0;
2905 prop_changelist_t *clp = NULL;
2906 nvlist_t *snapprops_nvlist = NULL;
2907 zprop_errflags_t prop_errflags;
2908 boolean_t recursive;
2909
2910 begin_time = time(NULL);
2911
2912 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2913 "cannot receive"));
2914
2915 recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
2916 ENOENT);
2917
2918 if (stream_avl != NULL) {
2919 char *snapname;
2920 nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
2921 &snapname);
2922 nvlist_t *props;
2923 int ret;
2924
2925 (void) nvlist_lookup_uint64(fs, "parentfromsnap",
2926 &parent_snapguid);
2927 err = nvlist_lookup_nvlist(fs, "props", &props);
2928 if (err)
2929 VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
2930
2931 if (flags->canmountoff) {
2932 VERIFY(0 == nvlist_add_uint64(props,
2933 zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
2934 }
2935 ret = zcmd_write_src_nvlist(hdl, &zc, props);
2936 if (err)
2937 nvlist_free(props);
2938
2939 if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {
2940 VERIFY(0 == nvlist_lookup_nvlist(props,
2941 snapname, &snapprops_nvlist));
2942 }
2943
2944 if (ret != 0)
2945 return (-1);
2946 }
2947
2948 cp = NULL;
2949
2950 /*
2951 * Determine how much of the snapshot name stored in the stream
2952 * we are going to tack on to the name they specified on the
2953 * command line, and how much we are going to chop off.
2954 *
2955 * If they specified a snapshot, chop the entire name stored in
2956 * the stream.
2987 * everything but the first element of the sent snapshot path
2988 * (all but the pool name).
2989 */
2990 if (strchr(tosnap, '@')) {
2991 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
2992 "argument - snapshot not allowed with -d"));
2993 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2994 }
2995
2996 chopprefix = strchr(drrb->drr_toname, '/');
2997 if (chopprefix == NULL)
2998 chopprefix = strchr(drrb->drr_toname, '@');
2999 } else if (strchr(tosnap, '@') == NULL) {
3000 /*
3001 * If a filesystem was specified without -d or -e, we want to
3002 * tack on everything after the fs specified by 'zfs send'.
3003 */
3004 chopprefix = drrb->drr_toname + strlen(sendfs);
3005 } else {
3006 /* A snapshot was specified as an exact path (no -d or -e). */
3007 if (recursive) {
3008 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3009 "cannot specify snapshot name for multi-snapshot "
3010 "stream"));
3011 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3012 }
3013 chopprefix = drrb->drr_toname + strlen(drrb->drr_toname);
3014 }
3015
3016 ASSERT(strstr(drrb->drr_toname, sendfs) == drrb->drr_toname);
3017 ASSERT(chopprefix > drrb->drr_toname);
3018 ASSERT(chopprefix <= drrb->drr_toname + strlen(drrb->drr_toname));
3019 ASSERT(chopprefix[0] == '/' || chopprefix[0] == '@' ||
3020 chopprefix[0] == '\0');
3021
3022 /*
3023 * Determine name of destination snapshot, store in zc_value.
3024 */
3025 (void) strcpy(zc.zc_value, tosnap);
3026 (void) strncat(zc.zc_value, chopprefix, sizeof (zc.zc_value));
3027 free(cp);
3431 char buf1[64];
3432 char buf2[64];
3433 uint64_t bytes = zc.zc_cookie;
3434 time_t delta = time(NULL) - begin_time;
3435 if (delta == 0)
3436 delta = 1;
3437 zfs_nicenum(bytes, buf1, sizeof (buf1));
3438 zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
3439
3440 (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
3441 buf1, delta, buf2);
3442 }
3443
3444 return (0);
3445 }
3446
3447 static int
3448 zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
3449 const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
3450 nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
3451 uint64_t *action_handlep)
3452 {
3453 int err;
3454 dmu_replay_record_t drr, drr_noswap;
3455 struct drr_begin *drrb = &drr.drr_u.drr_begin;
3456 char errbuf[1024];
3457 zio_cksum_t zcksum = { 0 };
3458 uint64_t featureflags;
3459 int hdrtype;
3460
3461 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3462 "cannot receive"));
3463
3464 if (flags->isprefix &&
3465 !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
3466 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
3467 "(%s) does not exist"), tosnap);
3468 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3469 }
3470 if (originsnap &&
3471 !zfs_dataset_exists(hdl, originsnap, ZFS_TYPE_DATASET)) {
3527
3528 if (strchr(drrb->drr_toname, '@') == NULL) {
3529 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
3530 "stream (bad snapshot name)"));
3531 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3532 }
3533
3534 if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {
3535 char nonpackage_sendfs[ZFS_MAXNAMELEN];
3536 if (sendfs == NULL) {
3537 /*
3538 * We were not called from zfs_receive_package(). Get
3539 * the fs specified by 'zfs send'.
3540 */
3541 char *cp;
3542 (void) strlcpy(nonpackage_sendfs,
3543 drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
3544 if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
3545 *cp = '\0';
3546 sendfs = nonpackage_sendfs;
3547 }
3548 return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
3549 &drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,
3550 cleanup_fd, action_handlep));
3551 } else {
3552 assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
3553 DMU_COMPOUNDSTREAM);
3554 return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
3555 &zcksum, top_zfs, cleanup_fd, action_handlep));
3556 }
3557 }
3558
3559 /*
3560 * Restores a backup of tosnap from the file descriptor specified by infd.
3561 * Return 0 on total success, -2 if some things couldn't be
3562 * destroyed/renamed/promoted, -1 if some things couldn't be received.
3563 * (-1 will override -2, if -1 and the resumable flag was specified the
3564 * transfer can be resumed if the sending side supports it).
3565 */
3566 int
3567 zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
3568 recvflags_t *flags, int infd, avl_tree_t *stream_avl)
3569 {
3570 char *top_zfs = NULL;
3571 int err;
3572 int cleanup_fd;
3573 uint64_t action_handle = 0;
3574 char *originsnap = NULL;
3575 if (props) {
3576 err = nvlist_lookup_string(props, "origin", &originsnap);
3577 if (err && err != ENOENT)
3578 return (err);
3579 }
3580
3581 cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
3582 VERIFY(cleanup_fd >= 0);
3583
3584 err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
3585 stream_avl, &top_zfs, cleanup_fd, &action_handle);
3586
3587 VERIFY(0 == close(cleanup_fd));
3588
3589 if (err == 0 && !flags->nomount && top_zfs) {
3590 zfs_handle_t *zhp;
3591 prop_changelist_t *clp;
3592
3593 zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
3594 if (zhp != NULL) {
3595 clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
3596 CL_GATHER_MOUNT_ALWAYS, 0);
3597 zfs_close(zhp);
3598 if (clp != NULL) {
3599 /* mount and share received datasets */
3600 err = changelist_postfix(clp);
3601 changelist_free(clp);
3602 }
3603 }
3604 if (zhp == NULL || clp == NULL || err)
3605 err = -1;
|
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
25 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
26 * Copyright (c) 2013 Steven Hartland. All rights reserved.
27 * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
28 */
29
30 #include <assert.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <libintl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <strings.h>
37 #include <unistd.h>
38 #include <stddef.h>
39 #include <fcntl.h>
40 #include <sys/mount.h>
41 #include <pthread.h>
42 #include <umem.h>
43 #include <time.h>
44
45 #include <libzfs.h>
46 #include <libzfs_core.h>
47
48 #include "zfs_namecheck.h"
49 #include "zfs_prop.h"
50 #include "zfs_fletcher.h"
51 #include "libzfs_impl.h"
52 #include <zlib.h>
53 #include <sha2.h>
54 #include <sys/zio_checksum.h>
55 #include <sys/ddt.h>
56
57 /* in libzfs_dataset.c */
58 extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
59
60 static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
61 recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
62 uint64_t *, const char *);
63 static int guid_to_name(libzfs_handle_t *, const char *,
64 uint64_t, boolean_t, char *);
65
66 static const zio_cksum_t zero_cksum = { 0 };
67
68 typedef struct dedup_arg {
69 int inputfd;
70 int outputfd;
71 libzfs_handle_t *dedup_hdl;
72 } dedup_arg_t;
73
74 typedef struct progress_arg {
75 zfs_handle_t *pa_zhp;
76 int pa_fd;
77 boolean_t pa_parsable;
78 } progress_arg_t;
79
80 typedef struct dataref {
81 uint64_t ref_guid;
82 uint64_t ref_object;
2545 nvlist_free(local_nv);
2546
2547 if (needagain && progress) {
2548 /* do another pass to fix up temporary names */
2549 if (flags->verbose)
2550 (void) printf("another pass:\n");
2551 goto again;
2552 }
2553
2554 return (needagain);
2555 }
2556
2557 static int
2558 zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
2559 recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
2560 char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
2561 {
2562 nvlist_t *stream_nv = NULL;
2563 avl_tree_t *stream_avl = NULL;
2564 char *fromsnap = NULL;
2565 char *sendsnap = NULL;
2566 char *cp;
2567 char tofs[ZFS_MAXNAMELEN];
2568 char sendfs[ZFS_MAXNAMELEN];
2569 char errbuf[1024];
2570 dmu_replay_record_t drre;
2571 int error;
2572 boolean_t anyerr = B_FALSE;
2573 boolean_t softerr = B_FALSE;
2574 boolean_t recursive;
2575
2576 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2577 "cannot receive"));
2578
2579 assert(drr->drr_type == DRR_BEGIN);
2580 assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);
2581 assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==
2582 DMU_COMPOUNDSTREAM);
2583
2584 /*
2585 * Read in the nvlist from the stream.
2694 zfs_close(zhp);
2695 if (clp != NULL) {
2696 softerr |=
2697 changelist_prefix(clp);
2698 changelist_free(clp);
2699 }
2700 }
2701 }
2702
2703 nvlist_free(renamed);
2704 }
2705 }
2706
2707 /*
2708 * Get the fs specified by the first path in the stream (the top level
2709 * specified by 'zfs send') and pass it to each invocation of
2710 * zfs_receive_one().
2711 */
2712 (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
2713 ZFS_MAXNAMELEN);
2714 if ((cp = strchr(sendfs, '@')) != NULL) {
2715 *cp = '\0';
2716 /*
2717 * Find the "sendsnap", the final snapshot in a replication
2718 * stream, so zfs_receive_one() can set filesystem properties
2719 * ONLY when receiving that final snapshot.
2720 */
2721 sendsnap = (cp + 1);
2722 }
2723
2724 /* Finally, receive each contained stream */
2725 do {
2726 /*
2727 * we should figure out if it has a recoverable
2728 * error, in which case do a recv_skip() and drive on.
2729 * Note, if we fail due to already having this guid,
2730 * zfs_receive_one() will take care of it (ie,
2731 * recv_skip() and return 0).
2732 */
2733 error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
2734 sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
2735 action_handlep, sendsnap);
2736 if (error == ENODATA) {
2737 error = 0;
2738 break;
2739 }
2740 anyerr |= error;
2741 } while (error == 0);
2742
2743 if (drr->drr_payloadlen != 0 && fromsnap != NULL) {
2744 /*
2745 * Now that we have the fs's they sent us, try the
2746 * renames again.
2747 */
2748 softerr = recv_incremental_replication(hdl, tofs, flags,
2749 stream_nv, stream_avl, NULL);
2750 }
2751
2752 out:
2753 fsavl_destroy(stream_avl);
2754 if (stream_nv)
2755 nvlist_free(stream_nv);
2879 token_buf, sizeof (token_buf),
2880 NULL, NULL, 0, B_TRUE);
2881 if (error == 0) {
2882 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2883 "checksum mismatch or incomplete stream.\n"
2884 "Partially received snapshot is saved.\n"
2885 "A resuming stream can be generated on the sending "
2886 "system by running:\n"
2887 " zfs send -t %s"),
2888 token_buf);
2889 }
2890 zfs_close(zhp);
2891 }
2892
2893 /*
2894 * Restores a backup of tosnap from the file descriptor specified by infd.
2895 */
2896 static int
2897 zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
2898 const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
2899 dmu_replay_record_t *drr_noswap, const char *sendfs,
2900 avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
2901 uint64_t *action_handlep, const char *finalsnap)
2902 {
2903 zfs_cmd_t zc = { 0 };
2904 time_t begin_time;
2905 int ioctl_err, ioctl_errno, err;
2906 char *cp;
2907 struct drr_begin *drrb = &drr->drr_u.drr_begin;
2908 char errbuf[1024];
2909 char prop_errbuf[1024];
2910 const char *chopprefix;
2911 boolean_t newfs = B_FALSE;
2912 boolean_t stream_wantsnewfs;
2913 uint64_t parent_snapguid = 0;
2914 prop_changelist_t *clp = NULL;
2915 nvlist_t *snapprops_nvlist = NULL;
2916 zprop_errflags_t prop_errflags;
2917
2918 begin_time = time(NULL);
2919
2920 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2921 "cannot receive"));
2922
2923 if (stream_avl != NULL) {
2924 char *snapname;
2925 nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
2926 &snapname);
2927 nvlist_t *props;
2928 int ret;
2929 boolean_t is_finalsnap;
2930
2931 VERIFY(fs != NULL);
2932 (void) nvlist_lookup_uint64(fs, "parentfromsnap",
2933 &parent_snapguid);
2934 /*
2935 * Can safely use strcmp because at least "snapname" has been
2936 * verified.
2937 */
2938 is_finalsnap = (strcmp(snapname, finalsnap) == 0);
2939
2940 if (is_finalsnap)
2941 err = nvlist_lookup_nvlist(fs, "props", &props);
2942 if (!is_finalsnap || err)
2943 VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
2944
2945 if (flags->canmountoff) {
2946 VERIFY(0 == nvlist_add_uint64(props,
2947 zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
2948 }
2949 ret = zcmd_write_src_nvlist(hdl, &zc, props);
2950 if (!is_finalsnap || err)
2951 nvlist_free(props);
2952
2953 if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {
2954 VERIFY(0 == nvlist_lookup_nvlist(props,
2955 snapname, &snapprops_nvlist));
2956 }
2957
2958 if (ret != 0)
2959 return (-1);
2960 }
2961
2962 cp = NULL;
2963
2964 /*
2965 * Determine how much of the snapshot name stored in the stream
2966 * we are going to tack on to the name they specified on the
2967 * command line, and how much we are going to chop off.
2968 *
2969 * If they specified a snapshot, chop the entire name stored in
2970 * the stream.
3001 * everything but the first element of the sent snapshot path
3002 * (all but the pool name).
3003 */
3004 if (strchr(tosnap, '@')) {
3005 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
3006 "argument - snapshot not allowed with -d"));
3007 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3008 }
3009
3010 chopprefix = strchr(drrb->drr_toname, '/');
3011 if (chopprefix == NULL)
3012 chopprefix = strchr(drrb->drr_toname, '@');
3013 } else if (strchr(tosnap, '@') == NULL) {
3014 /*
3015 * If a filesystem was specified without -d or -e, we want to
3016 * tack on everything after the fs specified by 'zfs send'.
3017 */
3018 chopprefix = drrb->drr_toname + strlen(sendfs);
3019 } else {
3020 /* A snapshot was specified as an exact path (no -d or -e). */
3021 if (flags->recursive) {
3022 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3023 "cannot specify snapshot name for multi-snapshot "
3024 "stream"));
3025 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3026 }
3027 chopprefix = drrb->drr_toname + strlen(drrb->drr_toname);
3028 }
3029
3030 ASSERT(strstr(drrb->drr_toname, sendfs) == drrb->drr_toname);
3031 ASSERT(chopprefix > drrb->drr_toname);
3032 ASSERT(chopprefix <= drrb->drr_toname + strlen(drrb->drr_toname));
3033 ASSERT(chopprefix[0] == '/' || chopprefix[0] == '@' ||
3034 chopprefix[0] == '\0');
3035
3036 /*
3037 * Determine name of destination snapshot, store in zc_value.
3038 */
3039 (void) strcpy(zc.zc_value, tosnap);
3040 (void) strncat(zc.zc_value, chopprefix, sizeof (zc.zc_value));
3041 free(cp);
3445 char buf1[64];
3446 char buf2[64];
3447 uint64_t bytes = zc.zc_cookie;
3448 time_t delta = time(NULL) - begin_time;
3449 if (delta == 0)
3450 delta = 1;
3451 zfs_nicenum(bytes, buf1, sizeof (buf1));
3452 zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
3453
3454 (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
3455 buf1, delta, buf2);
3456 }
3457
3458 return (0);
3459 }
3460
3461 static int
3462 zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
3463 const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
3464 nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
3465 uint64_t *action_handlep, const char *finalsnap)
3466 {
3467 int err;
3468 dmu_replay_record_t drr, drr_noswap;
3469 struct drr_begin *drrb = &drr.drr_u.drr_begin;
3470 char errbuf[1024];
3471 zio_cksum_t zcksum = { 0 };
3472 uint64_t featureflags;
3473 int hdrtype;
3474
3475 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3476 "cannot receive"));
3477
3478 if (flags->isprefix &&
3479 !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
3480 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
3481 "(%s) does not exist"), tosnap);
3482 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3483 }
3484 if (originsnap &&
3485 !zfs_dataset_exists(hdl, originsnap, ZFS_TYPE_DATASET)) {
3541
3542 if (strchr(drrb->drr_toname, '@') == NULL) {
3543 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
3544 "stream (bad snapshot name)"));
3545 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3546 }
3547
3548 if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {
3549 char nonpackage_sendfs[ZFS_MAXNAMELEN];
3550 if (sendfs == NULL) {
3551 /*
3552 * We were not called from zfs_receive_package(). Get
3553 * the fs specified by 'zfs send'.
3554 */
3555 char *cp;
3556 (void) strlcpy(nonpackage_sendfs,
3557 drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
3558 if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
3559 *cp = '\0';
3560 sendfs = nonpackage_sendfs;
3561 VERIFY(finalsnap == NULL);
3562 }
3563 flags->recursive =
3564 (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
3565 ENOENT);
3566 err = zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
3567 &drr, &drr_noswap, sendfs, stream_avl, top_zfs,
3568 cleanup_fd, action_handlep, finalsnap);
3569 /* Clear out internal-only flags. */
3570 flags->recursive = B_FALSE;
3571 return (err);
3572 } else {
3573 assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
3574 DMU_COMPOUNDSTREAM);
3575 return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
3576 &zcksum, top_zfs, cleanup_fd, action_handlep));
3577 }
3578 }
3579
3580 /*
3581 * Restores a backup of tosnap from the file descriptor specified by infd.
3582 * Return 0 on total success, -2 if some things couldn't be
3583 * destroyed/renamed/promoted, -1 if some things couldn't be received.
3584 * (-1 will override -2, if -1 and the resumable flag was specified the
3585 * transfer can be resumed if the sending side supports it).
3586 */
3587 int
3588 zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
3589 recvflags_t *flags, int infd, avl_tree_t *stream_avl)
3590 {
3591 char *top_zfs = NULL;
3592 int err;
3593 int cleanup_fd;
3594 uint64_t action_handle = 0;
3595 char *originsnap = NULL;
3596 if (props) {
3597 err = nvlist_lookup_string(props, "origin", &originsnap);
3598 if (err && err != ENOENT)
3599 return (err);
3600 }
3601
3602 cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
3603 VERIFY(cleanup_fd >= 0);
3604
3605 err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
3606 stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
3607
3608 VERIFY(0 == close(cleanup_fd));
3609
3610 if (err == 0 && !flags->nomount && top_zfs) {
3611 zfs_handle_t *zhp;
3612 prop_changelist_t *clp;
3613
3614 zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
3615 if (zhp != NULL) {
3616 clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
3617 CL_GATHER_MOUNT_ALWAYS, 0);
3618 zfs_close(zhp);
3619 if (clp != NULL) {
3620 /* mount and share received datasets */
3621 err = changelist_postfix(clp);
3622 changelist_free(clp);
3623 }
3624 }
3625 if (zhp == NULL || clp == NULL || err)
3626 err = -1;
|