769 *nvlp = sd.fss; |
770 *nvlp = sd.fss; |
770 return (0); |
771 return (0); |
771 } |
772 } |
772 |
773 |
773 /* |
774 /* |
774 * Routines for dealing with the sorted snapshot functionality |
|
775 */ |
|
776 typedef struct zfs_node { |
|
777 zfs_handle_t *zn_handle; |
|
778 avl_node_t zn_avlnode; |
|
779 } zfs_node_t; |
|
780 |
|
781 static int |
|
782 zfs_sort_snaps(zfs_handle_t *zhp, void *data) |
|
783 { |
|
784 avl_tree_t *avl = data; |
|
785 zfs_node_t *node; |
|
786 zfs_node_t search; |
|
787 |
|
788 search.zn_handle = zhp; |
|
789 node = avl_find(avl, &search, NULL); |
|
790 if (node) { |
|
791 /* |
|
792 * If this snapshot was renamed while we were creating the |
|
793 * AVL tree, it's possible that we already inserted it under |
|
794 * its old name. Remove the old handle before adding the new |
|
795 * one. |
|
796 */ |
|
797 zfs_close(node->zn_handle); |
|
798 avl_remove(avl, node); |
|
799 free(node); |
|
800 } |
|
801 |
|
802 node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t)); |
|
803 node->zn_handle = zhp; |
|
804 avl_add(avl, node); |
|
805 |
|
806 return (0); |
|
807 } |
|
808 |
|
809 static int |
|
810 zfs_snapshot_compare(const void *larg, const void *rarg) |
|
811 { |
|
812 zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle; |
|
813 zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle; |
|
814 uint64_t lcreate, rcreate; |
|
815 |
|
816 /* |
|
817 * Sort them according to creation time. We use the hidden |
|
818 * CREATETXG property to get an absolute ordering of snapshots. |
|
819 */ |
|
820 lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG); |
|
821 rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG); |
|
822 |
|
823 if (lcreate < rcreate) |
|
824 return (-1); |
|
825 else if (lcreate > rcreate) |
|
826 return (+1); |
|
827 else |
|
828 return (0); |
|
829 } |
|
830 |
|
831 int |
|
832 zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data) |
|
833 { |
|
834 int ret = 0; |
|
835 zfs_node_t *node; |
|
836 avl_tree_t avl; |
|
837 void *cookie = NULL; |
|
838 |
|
839 avl_create(&avl, zfs_snapshot_compare, |
|
840 sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode)); |
|
841 |
|
842 ret = zfs_iter_snapshots(zhp, zfs_sort_snaps, &avl); |
|
843 |
|
844 for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node)) |
|
845 ret |= callback(node->zn_handle, data); |
|
846 |
|
847 while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL) |
|
848 free(node); |
|
849 |
|
850 avl_destroy(&avl); |
|
851 |
|
852 return (ret); |
|
853 } |
|
854 |
|
855 /* |
|
856 * Routines specific to "zfs send" |
775 * Routines specific to "zfs send" |
857 */ |
776 */ |
858 typedef struct send_dump_data { |
777 typedef struct send_dump_data { |
859 /* these are all just the short snapname (the part after the @) */ |
778 /* these are all just the short snapname (the part after the @) */ |
860 const char *fromsnap; |
779 const char *fromsnap; |
861 const char *tosnap; |
780 const char *tosnap; |
862 char prevsnap[ZFS_MAXNAMELEN]; |
781 char prevsnap[ZFS_MAXNAMELEN]; |
863 uint64_t prevsnap_obj; |
782 uint64_t prevsnap_obj; |
864 boolean_t seenfrom, seento, replicate, doall, fromorigin; |
783 boolean_t seenfrom, seento, replicate, doall, fromorigin; |
865 boolean_t verbose; |
784 boolean_t verbose, dryrun, parsable; |
866 int outfd; |
785 int outfd; |
867 boolean_t err; |
786 boolean_t err; |
868 nvlist_t *fss; |
787 nvlist_t *fss; |
869 avl_tree_t *fsavl; |
788 avl_tree_t *fsavl; |
870 snapfilter_cb_t *filter_cb; |
789 snapfilter_cb_t *filter_cb; |
871 void *filter_cb_arg; |
790 void *filter_cb_arg; |
872 nvlist_t *debugnv; |
791 nvlist_t *debugnv; |
873 char holdtag[ZFS_MAXNAMELEN]; |
792 char holdtag[ZFS_MAXNAMELEN]; |
874 int cleanup_fd; |
793 int cleanup_fd; |
|
794 uint64_t size; |
875 } send_dump_data_t; |
795 } send_dump_data_t; |
876 |
796 |
877 /* |
|
878 * Dumps a backup of the given snapshot (incremental from fromsnap if it's not |
|
879 * NULL) to the file descriptor specified by outfd. |
|
880 */ |
|
881 static int |
797 static int |
882 dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj, |
798 estimate_ioctl(zfs_handle_t *zhp, uint64_t fromsnap_obj, |
883 boolean_t fromorigin, int outfd, nvlist_t *debugnv) |
799 boolean_t fromorigin, uint64_t *sizep) |
884 { |
800 { |
885 zfs_cmd_t zc = { 0 }; |
801 zfs_cmd_t zc = { 0 }; |
886 libzfs_handle_t *hdl = zhp->zfs_hdl; |
802 libzfs_handle_t *hdl = zhp->zfs_hdl; |
887 nvlist_t *thisdbg; |
|
888 |
803 |
889 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); |
804 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); |
890 assert(fromsnap_obj == 0 || !fromorigin); |
805 assert(fromsnap_obj == 0 || !fromorigin); |
891 |
806 |
892 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); |
807 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); |
893 zc.zc_cookie = outfd; |
|
894 zc.zc_obj = fromorigin; |
808 zc.zc_obj = fromorigin; |
895 zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID); |
809 zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID); |
896 zc.zc_fromobj = fromsnap_obj; |
810 zc.zc_fromobj = fromsnap_obj; |
897 |
811 zc.zc_guid = 1; /* estimate flag */ |
898 VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0)); |
812 |
899 if (fromsnap && fromsnap[0] != '\0') { |
813 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) { |
900 VERIFY(0 == nvlist_add_string(thisdbg, |
|
901 "fromsnap", fromsnap)); |
|
902 } |
|
903 |
|
904 if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SEND, &zc) != 0) { |
|
905 char errbuf[1024]; |
814 char errbuf[1024]; |
906 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, |
815 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, |
907 "warning: cannot send '%s'"), zhp->zfs_name); |
816 "warning: cannot estimate space for '%s'"), zhp->zfs_name); |
908 |
|
909 VERIFY(0 == nvlist_add_uint64(thisdbg, "error", errno)); |
|
910 if (debugnv) { |
|
911 VERIFY(0 == nvlist_add_nvlist(debugnv, |
|
912 zhp->zfs_name, thisdbg)); |
|
913 } |
|
914 nvlist_free(thisdbg); |
|
915 |
817 |
916 switch (errno) { |
818 switch (errno) { |
917 |
|
918 case EXDEV: |
819 case EXDEV: |
919 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
820 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
920 "not an earlier snapshot from the same fs")); |
821 "not an earlier snapshot from the same fs")); |
921 return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); |
822 return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); |
922 |
823 |
946 default: |
847 default: |
947 return (zfs_standard_error(hdl, errno, errbuf)); |
848 return (zfs_standard_error(hdl, errno, errbuf)); |
948 } |
849 } |
949 } |
850 } |
950 |
851 |
|
852 *sizep = zc.zc_objset_type; |
|
853 |
|
854 return (0); |
|
855 } |
|
856 |
|
857 /* |
|
858 * Dumps a backup of the given snapshot (incremental from fromsnap if it's not |
|
859 * NULL) to the file descriptor specified by outfd. |
|
860 */ |
|
861 static int |
|
862 dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj, |
|
863 boolean_t fromorigin, int outfd, nvlist_t *debugnv) |
|
864 { |
|
865 zfs_cmd_t zc = { 0 }; |
|
866 libzfs_handle_t *hdl = zhp->zfs_hdl; |
|
867 nvlist_t *thisdbg; |
|
868 |
|
869 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); |
|
870 assert(fromsnap_obj == 0 || !fromorigin); |
|
871 |
|
872 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); |
|
873 zc.zc_cookie = outfd; |
|
874 zc.zc_obj = fromorigin; |
|
875 zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID); |
|
876 zc.zc_fromobj = fromsnap_obj; |
|
877 |
|
878 VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0)); |
|
879 if (fromsnap && fromsnap[0] != '\0') { |
|
880 VERIFY(0 == nvlist_add_string(thisdbg, |
|
881 "fromsnap", fromsnap)); |
|
882 } |
|
883 |
|
884 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) { |
|
885 char errbuf[1024]; |
|
886 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, |
|
887 "warning: cannot send '%s'"), zhp->zfs_name); |
|
888 |
|
889 VERIFY(0 == nvlist_add_uint64(thisdbg, "error", errno)); |
|
890 if (debugnv) { |
|
891 VERIFY(0 == nvlist_add_nvlist(debugnv, |
|
892 zhp->zfs_name, thisdbg)); |
|
893 } |
|
894 nvlist_free(thisdbg); |
|
895 |
|
896 switch (errno) { |
|
897 case EXDEV: |
|
898 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
|
899 "not an earlier snapshot from the same fs")); |
|
900 return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); |
|
901 |
|
902 case ENOENT: |
|
903 if (zfs_dataset_exists(hdl, zc.zc_name, |
|
904 ZFS_TYPE_SNAPSHOT)) { |
|
905 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
|
906 "incremental source (@%s) does not exist"), |
|
907 zc.zc_value); |
|
908 } |
|
909 return (zfs_error(hdl, EZFS_NOENT, errbuf)); |
|
910 |
|
911 case EDQUOT: |
|
912 case EFBIG: |
|
913 case EIO: |
|
914 case ENOLINK: |
|
915 case ENOSPC: |
|
916 case ENOSTR: |
|
917 case ENXIO: |
|
918 case EPIPE: |
|
919 case ERANGE: |
|
920 case EFAULT: |
|
921 case EROFS: |
|
922 zfs_error_aux(hdl, strerror(errno)); |
|
923 return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); |
|
924 |
|
925 default: |
|
926 return (zfs_standard_error(hdl, errno, errbuf)); |
|
927 } |
|
928 } |
|
929 |
951 if (debugnv) |
930 if (debugnv) |
952 VERIFY(0 == nvlist_add_nvlist(debugnv, zhp->zfs_name, thisdbg)); |
931 VERIFY(0 == nvlist_add_nvlist(debugnv, zhp->zfs_name, thisdbg)); |
953 nvlist_free(thisdbg); |
932 nvlist_free(thisdbg); |
954 |
933 |
955 return (0); |
934 return (0); |
1072 err = 0; |
1054 err = 0; |
1073 zfs_close(zhp); |
1055 zfs_close(zhp); |
1074 return (err); |
1056 return (err); |
1075 } |
1057 } |
1076 |
1058 |
1077 /* send it */ |
1059 fromorigin = sdd->prevsnap[0] == '\0' && |
|
1060 (sdd->fromorigin || sdd->replicate); |
|
1061 |
1078 if (sdd->verbose) { |
1062 if (sdd->verbose) { |
1079 (void) fprintf(stderr, "sending from @%s to %s\n", |
1063 uint64_t size; |
1080 sdd->prevsnap, zhp->zfs_name); |
1064 err = estimate_ioctl(zhp, sdd->prevsnap_obj, |
1081 } |
1065 fromorigin, &size); |
1082 |
1066 |
1083 err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj, |
1067 if (sdd->parsable) { |
1084 sdd->prevsnap[0] == '\0' && (sdd->fromorigin || sdd->replicate), |
1068 if (sdd->prevsnap[0] != '\0') { |
1085 sdd->outfd, sdd->debugnv); |
1069 (void) fprintf(stderr, "incremental\t%s\t%s", |
|
1070 sdd->prevsnap, zhp->zfs_name); |
|
1071 } else { |
|
1072 (void) fprintf(stderr, "full\t%s", |
|
1073 zhp->zfs_name); |
|
1074 } |
|
1075 } else { |
|
1076 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, |
|
1077 "send from @%s to %s"), |
|
1078 sdd->prevsnap, zhp->zfs_name); |
|
1079 } |
|
1080 if (err == 0) { |
|
1081 if (sdd->parsable) { |
|
1082 (void) fprintf(stderr, "\t%llu\n", |
|
1083 (longlong_t)size); |
|
1084 } else { |
|
1085 char buf[16]; |
|
1086 zfs_nicenum(size, buf, sizeof (buf)); |
|
1087 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, |
|
1088 " estimated size is %s\n"), buf); |
|
1089 } |
|
1090 sdd->size += size; |
|
1091 } else { |
|
1092 (void) fprintf(stderr, "\n"); |
|
1093 } |
|
1094 } |
|
1095 |
|
1096 if (!sdd->dryrun) { |
|
1097 err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj, |
|
1098 fromorigin, sdd->outfd, sdd->debugnv); |
|
1099 } |
1086 |
1100 |
1087 (void) strcpy(sdd->prevsnap, thissnap); |
1101 (void) strcpy(sdd->prevsnap, thissnap); |
1088 sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID); |
1102 sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID); |
1089 zfs_close(zhp); |
1103 zfs_close(zhp); |
1090 return (err); |
1104 return (err); |
1129 if (sdd->fromsnap == NULL || missingfrom) |
1143 if (sdd->fromsnap == NULL || missingfrom) |
1130 sdd->seenfrom = B_TRUE; |
1144 sdd->seenfrom = B_TRUE; |
1131 |
1145 |
1132 rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg); |
1146 rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg); |
1133 if (!sdd->seenfrom) { |
1147 if (!sdd->seenfrom) { |
1134 (void) fprintf(stderr, |
1148 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, |
1135 "WARNING: could not send %s@%s:\n" |
1149 "WARNING: could not send %s@%s:\n" |
1136 "incremental source (%s@%s) does not exist\n", |
1150 "incremental source (%s@%s) does not exist\n"), |
1137 zhp->zfs_name, sdd->tosnap, |
1151 zhp->zfs_name, sdd->tosnap, |
1138 zhp->zfs_name, sdd->fromsnap); |
1152 zhp->zfs_name, sdd->fromsnap); |
1139 sdd->err = B_TRUE; |
1153 sdd->err = B_TRUE; |
1140 } else if (!sdd->seento) { |
1154 } else if (!sdd->seento) { |
1141 if (sdd->fromsnap) { |
1155 if (sdd->fromsnap) { |
1142 (void) fprintf(stderr, |
1156 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, |
1143 "WARNING: could not send %s@%s:\n" |
1157 "WARNING: could not send %s@%s:\n" |
1144 "incremental source (%s@%s) " |
1158 "incremental source (%s@%s) " |
1145 "is not earlier than it\n", |
1159 "is not earlier than it\n"), |
1146 zhp->zfs_name, sdd->tosnap, |
1160 zhp->zfs_name, sdd->tosnap, |
1147 zhp->zfs_name, sdd->fromsnap); |
1161 zhp->zfs_name, sdd->fromsnap); |
1148 } else { |
1162 } else { |
1149 (void) fprintf(stderr, "WARNING: " |
1163 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, |
1150 "could not send %s@%s: does not exist\n", |
1164 "WARNING: " |
|
1165 "could not send %s@%s: does not exist\n"), |
1151 zhp->zfs_name, sdd->tosnap); |
1166 zhp->zfs_name, sdd->tosnap); |
1152 } |
1167 } |
1153 sdd->err = B_TRUE; |
1168 sdd->err = B_TRUE; |
1154 } |
1169 } |
1155 |
1170 |
1191 } |
1206 } |
1192 again: |
1207 again: |
1193 needagain = progress = B_FALSE; |
1208 needagain = progress = B_FALSE; |
1194 for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair; |
1209 for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair; |
1195 fspair = nvlist_next_nvpair(sdd->fss, fspair)) { |
1210 fspair = nvlist_next_nvpair(sdd->fss, fspair)) { |
1196 nvlist_t *fslist; |
1211 nvlist_t *fslist, *parent_nv; |
1197 char *fsname; |
1212 char *fsname; |
1198 zfs_handle_t *zhp; |
1213 zfs_handle_t *zhp; |
1199 int err; |
1214 int err; |
1200 uint64_t origin_guid = 0; |
1215 uint64_t origin_guid = 0; |
|
1216 uint64_t parent_guid = 0; |
1201 |
1217 |
1202 VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0); |
1218 VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0); |
1203 if (nvlist_lookup_boolean(fslist, "sent") == 0) |
1219 if (nvlist_lookup_boolean(fslist, "sent") == 0) |
1204 continue; |
1220 continue; |
1205 |
1221 |
1206 VERIFY(nvlist_lookup_string(fslist, "name", &fsname) == 0); |
1222 VERIFY(nvlist_lookup_string(fslist, "name", &fsname) == 0); |
1207 (void) nvlist_lookup_uint64(fslist, "origin", &origin_guid); |
1223 (void) nvlist_lookup_uint64(fslist, "origin", &origin_guid); |
|
1224 (void) nvlist_lookup_uint64(fslist, "parentfromsnap", |
|
1225 &parent_guid); |
|
1226 |
|
1227 if (parent_guid != 0) { |
|
1228 parent_nv = fsavl_find(sdd->fsavl, parent_guid, NULL); |
|
1229 if (!nvlist_exists(parent_nv, "sent")) { |
|
1230 /* parent has not been sent; skip this one */ |
|
1231 needagain = B_TRUE; |
|
1232 continue; |
|
1233 } |
|
1234 } |
1208 |
1235 |
1209 if (origin_guid != 0) { |
1236 if (origin_guid != 0) { |
1210 nvlist_t *origin_nv = fsavl_find(sdd->fsavl, |
1237 nvlist_t *origin_nv = fsavl_find(sdd->fsavl, |
1211 origin_guid, NULL); |
1238 origin_guid, NULL); |
1212 if (origin_nv != NULL && |
1239 if (origin_nv != NULL && |
1213 nvlist_lookup_boolean(origin_nv, |
1240 !nvlist_exists(origin_nv, "sent")) { |
1214 "sent") == ENOENT) { |
|
1215 /* |
1241 /* |
1216 * origin has not been sent yet; |
1242 * origin has not been sent yet; |
1217 * skip this clone. |
1243 * skip this clone. |
1218 */ |
1244 */ |
1219 needagain = B_TRUE; |
1245 needagain = B_TRUE; |
1312 return (zfs_error(zhp->zfs_hdl, |
1348 return (zfs_error(zhp->zfs_hdl, |
1313 EZFS_THREADCREATEFAILED, errbuf)); |
1349 EZFS_THREADCREATEFAILED, errbuf)); |
1314 } |
1350 } |
1315 } |
1351 } |
1316 |
1352 |
1317 if (flags.replicate || flags.doall || flags.props) { |
1353 if (flags->replicate || flags->doall || flags->props) { |
1318 dmu_replay_record_t drr = { 0 }; |
1354 dmu_replay_record_t drr = { 0 }; |
1319 char *packbuf = NULL; |
1355 char *packbuf = NULL; |
1320 size_t buflen = 0; |
1356 size_t buflen = 0; |
1321 zio_cksum_t zc = { 0 }; |
1357 zio_cksum_t zc = { 0 }; |
1322 |
1358 |
1323 if (flags.replicate || flags.props) { |
1359 if (flags->replicate || flags->props) { |
1324 nvlist_t *hdrnv; |
1360 nvlist_t *hdrnv; |
1325 |
1361 |
1326 VERIFY(0 == nvlist_alloc(&hdrnv, NV_UNIQUE_NAME, 0)); |
1362 VERIFY(0 == nvlist_alloc(&hdrnv, NV_UNIQUE_NAME, 0)); |
1327 if (fromsnap) { |
1363 if (fromsnap) { |
1328 VERIFY(0 == nvlist_add_string(hdrnv, |
1364 VERIFY(0 == nvlist_add_string(hdrnv, |
1329 "fromsnap", fromsnap)); |
1365 "fromsnap", fromsnap)); |
1330 } |
1366 } |
1331 VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap)); |
1367 VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap)); |
1332 if (!flags.replicate) { |
1368 if (!flags->replicate) { |
1333 VERIFY(0 == nvlist_add_boolean(hdrnv, |
1369 VERIFY(0 == nvlist_add_boolean(hdrnv, |
1334 "not_recursive")); |
1370 "not_recursive")); |
1335 } |
1371 } |
1336 |
1372 |
1337 err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name, |
1373 err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name, |
1338 fromsnap, tosnap, flags.replicate, &fss, &fsavl); |
1374 fromsnap, tosnap, flags->replicate, &fss, &fsavl); |
1339 if (err) |
1375 if (err) |
1340 goto err_out; |
1376 goto err_out; |
1341 VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss)); |
1377 VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss)); |
1342 err = nvlist_pack(hdrnv, &packbuf, &buflen, |
1378 err = nvlist_pack(hdrnv, &packbuf, &buflen, |
1343 NV_ENCODE_XDR, 0); |
1379 NV_ENCODE_XDR, 0); |
1350 nvlist_free(fss); |
1386 nvlist_free(fss); |
1351 goto stderr_out; |
1387 goto stderr_out; |
1352 } |
1388 } |
1353 } |
1389 } |
1354 |
1390 |
1355 /* write first begin record */ |
1391 if (!flags->dryrun) { |
1356 drr.drr_type = DRR_BEGIN; |
1392 /* write first begin record */ |
1357 drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; |
1393 drr.drr_type = DRR_BEGIN; |
1358 DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.drr_versioninfo, |
1394 drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; |
1359 DMU_COMPOUNDSTREAM); |
1395 DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin. |
1360 DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.drr_versioninfo, |
1396 drr_versioninfo, DMU_COMPOUNDSTREAM); |
1361 featureflags); |
1397 DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin. |
1362 (void) snprintf(drr.drr_u.drr_begin.drr_toname, |
1398 drr_versioninfo, featureflags); |
1363 sizeof (drr.drr_u.drr_begin.drr_toname), |
1399 (void) snprintf(drr.drr_u.drr_begin.drr_toname, |
1364 "%s@%s", zhp->zfs_name, tosnap); |
1400 sizeof (drr.drr_u.drr_begin.drr_toname), |
1365 drr.drr_payloadlen = buflen; |
1401 "%s@%s", zhp->zfs_name, tosnap); |
1366 err = cksum_and_write(&drr, sizeof (drr), &zc, outfd); |
1402 drr.drr_payloadlen = buflen; |
1367 |
1403 err = cksum_and_write(&drr, sizeof (drr), &zc, outfd); |
1368 /* write header nvlist */ |
1404 |
1369 if (err != -1 && packbuf != NULL) { |
1405 /* write header nvlist */ |
1370 err = cksum_and_write(packbuf, buflen, &zc, outfd); |
1406 if (err != -1 && packbuf != NULL) { |
1371 } |
1407 err = cksum_and_write(packbuf, buflen, &zc, |
1372 free(packbuf); |
1408 outfd); |
1373 if (err == -1) { |
1409 } |
1374 fsavl_destroy(fsavl); |
1410 free(packbuf); |
1375 nvlist_free(fss); |
1411 if (err == -1) { |
1376 err = errno; |
1412 fsavl_destroy(fsavl); |
1377 goto stderr_out; |
1413 nvlist_free(fss); |
1378 } |
1414 err = errno; |
1379 |
1415 goto stderr_out; |
1380 /* write end record */ |
1416 } |
1381 if (err != -1) { |
1417 |
|
1418 /* write end record */ |
1382 bzero(&drr, sizeof (drr)); |
1419 bzero(&drr, sizeof (drr)); |
1383 drr.drr_type = DRR_END; |
1420 drr.drr_type = DRR_END; |
1384 drr.drr_u.drr_end.drr_checksum = zc; |
1421 drr.drr_u.drr_end.drr_checksum = zc; |
1385 err = write(outfd, &drr, sizeof (drr)); |
1422 err = write(outfd, &drr, sizeof (drr)); |
1386 if (err == -1) { |
1423 if (err == -1) { |
1387 fsavl_destroy(fsavl); |
1424 fsavl_destroy(fsavl); |
1388 nvlist_free(fss); |
1425 nvlist_free(fss); |
1389 err = errno; |
1426 err = errno; |
1390 goto stderr_out; |
1427 goto stderr_out; |
1391 } |
1428 } |
|
1429 |
|
1430 err = 0; |
1392 } |
1431 } |
1393 } |
1432 } |
1394 |
1433 |
1395 /* dump each stream */ |
1434 /* dump each stream */ |
1396 sdd.fromsnap = fromsnap; |
1435 sdd.fromsnap = fromsnap; |
1397 sdd.tosnap = tosnap; |
1436 sdd.tosnap = tosnap; |
1398 if (flags.dedup) |
1437 if (flags->dedup) |
1399 sdd.outfd = pipefd[0]; |
1438 sdd.outfd = pipefd[0]; |
1400 else |
1439 else |
1401 sdd.outfd = outfd; |
1440 sdd.outfd = outfd; |
1402 sdd.replicate = flags.replicate; |
1441 sdd.replicate = flags->replicate; |
1403 sdd.doall = flags.doall; |
1442 sdd.doall = flags->doall; |
1404 sdd.fromorigin = flags.fromorigin; |
1443 sdd.fromorigin = flags->fromorigin; |
1405 sdd.fss = fss; |
1444 sdd.fss = fss; |
1406 sdd.fsavl = fsavl; |
1445 sdd.fsavl = fsavl; |
1407 sdd.verbose = flags.verbose; |
1446 sdd.verbose = flags->verbose; |
|
1447 sdd.parsable = flags->parsable; |
|
1448 sdd.dryrun = flags->dryrun; |
1408 sdd.filter_cb = filter_func; |
1449 sdd.filter_cb = filter_func; |
1409 sdd.filter_cb_arg = cb_arg; |
1450 sdd.filter_cb_arg = cb_arg; |
1410 if (debugnvp) |
1451 if (debugnvp) |
1411 sdd.debugnv = *debugnvp; |
1452 sdd.debugnv = *debugnvp; |
1412 if (holdsnaps) { |
1453 if (holdsnaps) { |
1419 goto stderr_out; |
1460 goto stderr_out; |
1420 } |
1461 } |
1421 } else { |
1462 } else { |
1422 sdd.cleanup_fd = -1; |
1463 sdd.cleanup_fd = -1; |
1423 } |
1464 } |
|
1465 if (flags->verbose) { |
|
1466 /* |
|
1467 * Do a verbose no-op dry run to get all the verbose output |
|
1468 * before generating any data. Then do a non-verbose real |
|
1469 * run to generate the streams. |
|
1470 */ |
|
1471 sdd.dryrun = B_TRUE; |
|
1472 err = dump_filesystems(zhp, &sdd); |
|
1473 sdd.dryrun = flags->dryrun; |
|
1474 sdd.verbose = B_FALSE; |
|
1475 if (flags->parsable) { |
|
1476 (void) fprintf(stderr, "size\t%llu\n", |
|
1477 (longlong_t)sdd.size); |
|
1478 } else { |
|
1479 char buf[16]; |
|
1480 zfs_nicenum(sdd.size, buf, sizeof (buf)); |
|
1481 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, |
|
1482 "total estimated size is %s\n"), buf); |
|
1483 } |
|
1484 } |
1424 err = dump_filesystems(zhp, &sdd); |
1485 err = dump_filesystems(zhp, &sdd); |
1425 fsavl_destroy(fsavl); |
1486 fsavl_destroy(fsavl); |
1426 nvlist_free(fss); |
1487 nvlist_free(fss); |
1427 |
1488 |
1428 if (flags.dedup) { |
1489 if (flags->dedup) { |
1429 (void) close(pipefd[0]); |
1490 (void) close(pipefd[0]); |
1430 (void) pthread_join(tid, NULL); |
1491 (void) pthread_join(tid, NULL); |
1431 } |
1492 } |
1432 |
1493 |
1433 if (sdd.cleanup_fd != -1) { |
1494 if (sdd.cleanup_fd != -1) { |
1434 VERIFY(0 == close(sdd.cleanup_fd)); |
1495 VERIFY(0 == close(sdd.cleanup_fd)); |
1435 sdd.cleanup_fd = -1; |
1496 sdd.cleanup_fd = -1; |
1436 } |
1497 } |
1437 |
1498 |
1438 if (flags.replicate || flags.doall || flags.props) { |
1499 if (!flags->dryrun && (flags->replicate || flags->doall || |
|
1500 flags->props)) { |
1439 /* |
1501 /* |
1440 * write final end record. NB: want to do this even if |
1502 * write final end record. NB: want to do this even if |
1441 * there was some error, because it might not be totally |
1503 * there was some error, because it might not be totally |
1442 * failed. |
1504 * failed. |
1443 */ |
1505 */ |
1572 (void) strncpy(newname, name, baselen); |
1634 (void) strncpy(newname, name, baselen); |
1573 (void) snprintf(newname+baselen, ZFS_MAXNAMELEN-baselen, |
1635 (void) snprintf(newname+baselen, ZFS_MAXNAMELEN-baselen, |
1574 "recv-%u-%u", getpid(), seq); |
1636 "recv-%u-%u", getpid(), seq); |
1575 (void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value)); |
1637 (void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value)); |
1576 |
1638 |
1577 if (flags.verbose) { |
1639 if (flags->verbose) { |
1578 (void) printf("failed - trying rename %s to %s\n", |
1640 (void) printf("failed - trying rename %s to %s\n", |
1579 zc.zc_name, zc.zc_value); |
1641 zc.zc_name, zc.zc_value); |
1580 } |
1642 } |
1581 err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc); |
1643 err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc); |
1582 if (err == 0) |
1644 if (err == 0) |
1583 changelist_rename(clp, name, newname); |
1645 changelist_rename(clp, name, newname); |
1584 if (err && flags.verbose) { |
1646 if (err && flags->verbose) { |
1585 (void) printf("failed (%u) - " |
1647 (void) printf("failed (%u) - " |
1586 "will try again on next pass\n", errno); |
1648 "will try again on next pass\n", errno); |
1587 } |
1649 } |
1588 err = EAGAIN; |
1650 err = EAGAIN; |
1589 } else if (flags.verbose) { |
1651 } else if (flags->verbose) { |
1590 if (err == 0) |
1652 if (err == 0) |
1591 (void) printf("success\n"); |
1653 (void) printf("success\n"); |
1592 else |
1654 else |
1593 (void) printf("failed (%u)\n", errno); |
1655 (void) printf("failed (%u)\n", errno); |
1594 } |
1656 } |
1655 } |
1717 } |
1656 |
1718 |
1657 typedef struct guid_to_name_data { |
1719 typedef struct guid_to_name_data { |
1658 uint64_t guid; |
1720 uint64_t guid; |
1659 char *name; |
1721 char *name; |
|
1722 char *skip; |
1660 } guid_to_name_data_t; |
1723 } guid_to_name_data_t; |
1661 |
1724 |
1662 static int |
1725 static int |
1663 guid_to_name_cb(zfs_handle_t *zhp, void *arg) |
1726 guid_to_name_cb(zfs_handle_t *zhp, void *arg) |
1664 { |
1727 { |
1665 guid_to_name_data_t *gtnd = arg; |
1728 guid_to_name_data_t *gtnd = arg; |
1666 int err; |
1729 int err; |
|
1730 |
|
1731 if (gtnd->skip != NULL && |
|
1732 strcmp(zhp->zfs_name, gtnd->skip) == 0) { |
|
1733 return (0); |
|
1734 } |
1667 |
1735 |
1668 if (zhp->zfs_dmustats.dds_guid == gtnd->guid) { |
1736 if (zhp->zfs_dmustats.dds_guid == gtnd->guid) { |
1669 (void) strcpy(gtnd->name, zhp->zfs_name); |
1737 (void) strcpy(gtnd->name, zhp->zfs_name); |
1670 zfs_close(zhp); |
1738 zfs_close(zhp); |
1671 return (EEXIST); |
1739 return (EEXIST); |
1672 } |
1740 } |
|
1741 |
1673 err = zfs_iter_children(zhp, guid_to_name_cb, gtnd); |
1742 err = zfs_iter_children(zhp, guid_to_name_cb, gtnd); |
1674 zfs_close(zhp); |
1743 zfs_close(zhp); |
1675 return (err); |
1744 return (err); |
1676 } |
1745 } |
1677 |
1746 |
|
1747 /* |
|
1748 * Attempt to find the local dataset associated with this guid. In the case of |
|
1749 * multiple matches, we attempt to find the "best" match by searching |
|
1750 * progressively larger portions of the hierarchy. This allows one to send a |
|
1751 * tree of datasets individually and guarantee that we will find the source |
|
1752 * guid within that hierarchy, even if there are multiple matches elsewhere. |
|
1753 */ |
1678 static int |
1754 static int |
1679 guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid, |
1755 guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid, |
1680 char *name) |
1756 char *name) |
1681 { |
1757 { |
1682 /* exhaustive search all local snapshots */ |
1758 /* exhaustive search all local snapshots */ |
|
1759 char pname[ZFS_MAXNAMELEN]; |
1683 guid_to_name_data_t gtnd; |
1760 guid_to_name_data_t gtnd; |
1684 int err = 0; |
1761 int err = 0; |
1685 zfs_handle_t *zhp; |
1762 zfs_handle_t *zhp; |
1686 char *cp; |
1763 char *cp; |
1687 |
1764 |
1688 gtnd.guid = guid; |
1765 gtnd.guid = guid; |
1689 gtnd.name = name; |
1766 gtnd.name = name; |
1690 |
1767 gtnd.skip = NULL; |
1691 if (strchr(parent, '@') == NULL) { |
1768 |
1692 zhp = make_dataset_handle(hdl, parent); |
1769 (void) strlcpy(pname, parent, sizeof (pname)); |
1693 if (zhp != NULL) { |
1770 |
1694 err = zfs_iter_children(zhp, guid_to_name_cb, >nd); |
1771 /* |
1695 zfs_close(zhp); |
1772 * Search progressively larger portions of the hierarchy. This will |
1696 if (err == EEXIST) |
1773 * select the "most local" version of the origin snapshot in the case |
1697 return (0); |
1774 * that there are multiple matching snapshots in the system. |
1698 } |
1775 */ |
1699 } |
1776 while ((cp = strrchr(pname, '/')) != NULL) { |
1700 |
1777 |
1701 cp = strchr(parent, '/'); |
1778 /* Chop off the last component and open the parent */ |
1702 if (cp) |
|
1703 *cp = '\0'; |
1779 *cp = '\0'; |
1704 zhp = make_dataset_handle(hdl, parent); |
1780 zhp = make_dataset_handle(hdl, pname); |
1705 if (cp) |
1781 |
1706 *cp = '/'; |
1782 if (zhp == NULL) |
1707 |
1783 continue; |
1708 if (zhp) { |
1784 |
1709 err = zfs_iter_children(zhp, guid_to_name_cb, >nd); |
1785 err = zfs_iter_children(zhp, guid_to_name_cb, >nd); |
1710 zfs_close(zhp); |
1786 zfs_close(zhp); |
1711 } |
1787 if (err == EEXIST) |
1712 |
1788 return (0); |
1713 return (err == EEXIST ? 0 : ENOENT); |
1789 |
1714 |
1790 /* |
|
1791 * Remember the dataset that we already searched, so we |
|
1792 * skip it next time through. |
|
1793 */ |
|
1794 gtnd.skip = pname; |
|
1795 } |
|
1796 |
|
1797 return (ENOENT); |
1715 } |
1798 } |
1716 |
1799 |
1717 /* |
1800 /* |
1718 * Return true if dataset guid1 is created before guid2. |
1801 * Return +1 if guid1 is before guid2, 0 if they are the same, and -1 if |
|
1802 * guid1 is after guid2. |
1719 */ |
1803 */ |
1720 static int |
1804 static int |
1721 created_before(libzfs_handle_t *hdl, avl_tree_t *avl, |
1805 created_before(libzfs_handle_t *hdl, avl_tree_t *avl, |
1722 uint64_t guid1, uint64_t guid2) |
1806 uint64_t guid1, uint64_t guid2) |
1723 { |
1807 { |
1724 nvlist_t *nvfs; |
1808 nvlist_t *nvfs; |
1725 char *fsname, *snapname; |
1809 char *fsname, *snapname; |
1726 char buf[ZFS_MAXNAMELEN]; |
1810 char buf[ZFS_MAXNAMELEN]; |
1727 int rv; |
1811 int rv; |
1728 zfs_node_t zn1, zn2; |
1812 zfs_handle_t *guid1hdl, *guid2hdl; |
|
1813 uint64_t create1, create2; |
1729 |
1814 |
1730 if (guid2 == 0) |
1815 if (guid2 == 0) |
1731 return (0); |
1816 return (0); |
1732 if (guid1 == 0) |
1817 if (guid1 == 0) |
1733 return (1); |
1818 return (1); |
1734 |
1819 |
1735 nvfs = fsavl_find(avl, guid1, &snapname); |
1820 nvfs = fsavl_find(avl, guid1, &snapname); |
1736 VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); |
1821 VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); |
1737 (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname); |
1822 (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname); |
1738 zn1.zn_handle = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); |
1823 guid1hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); |
1739 if (zn1.zn_handle == NULL) |
1824 if (guid1hdl == NULL) |
1740 return (-1); |
1825 return (-1); |
1741 |
1826 |
1742 nvfs = fsavl_find(avl, guid2, &snapname); |
1827 nvfs = fsavl_find(avl, guid2, &snapname); |
1743 VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); |
1828 VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); |
1744 (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname); |
1829 (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname); |
1745 zn2.zn_handle = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); |
1830 guid2hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); |
1746 if (zn2.zn_handle == NULL) { |
1831 if (guid2hdl == NULL) { |
1747 zfs_close(zn2.zn_handle); |
1832 zfs_close(guid1hdl); |
1748 return (-1); |
1833 return (-1); |
1749 } |
1834 } |
1750 |
1835 |
1751 rv = (zfs_snapshot_compare(&zn1, &zn2) == -1); |
1836 create1 = zfs_prop_get_int(guid1hdl, ZFS_PROP_CREATETXG); |
1752 |
1837 create2 = zfs_prop_get_int(guid2hdl, ZFS_PROP_CREATETXG); |
1753 zfs_close(zn1.zn_handle); |
1838 |
1754 zfs_close(zn2.zn_handle); |
1839 if (create1 < create2) |
|
1840 rv = -1; |
|
1841 else if (create1 > create2) |
|
1842 rv = +1; |
|
1843 else |
|
1844 rv = 0; |
|
1845 |
|
1846 zfs_close(guid1hdl); |
|
1847 zfs_close(guid2hdl); |
1755 |
1848 |
1756 return (rv); |
1849 return (rv); |
1757 } |
1850 } |
1758 |
1851 |
1759 static int |
1852 static int |
1760 recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs, |
1853 recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs, |
1761 recvflags_t flags, nvlist_t *stream_nv, avl_tree_t *stream_avl, |
1854 recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl, |
1762 nvlist_t *renamed) |
1855 nvlist_t *renamed) |
1763 { |
1856 { |
1764 nvlist_t *local_nv; |
1857 nvlist_t *local_nv; |
1765 avl_tree_t *local_avl; |
1858 avl_tree_t *local_avl; |
1766 nvpair_t *fselem, *nextfselem; |
1859 nvpair_t *fselem, *nextfselem; |
2028 fsavl_destroy(local_avl); |
2121 fsavl_destroy(local_avl); |
2029 nvlist_free(local_nv); |
2122 nvlist_free(local_nv); |
2030 |
2123 |
2031 if (needagain && progress) { |
2124 if (needagain && progress) { |
2032 /* do another pass to fix up temporary names */ |
2125 /* do another pass to fix up temporary names */ |
2033 if (flags.verbose) |
2126 if (flags->verbose) |
2034 (void) printf("another pass:\n"); |
2127 (void) printf("another pass:\n"); |
2035 goto again; |
2128 goto again; |
2036 } |
2129 } |
2037 |
2130 |
2038 return (needagain); |
2131 return (needagain); |
2039 } |
2132 } |
2040 |
2133 |
2041 static int |
2134 static int |
2042 zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, |
2135 zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, |
2043 recvflags_t flags, dmu_replay_record_t *drr, zio_cksum_t *zc, |
2136 recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc, |
2044 char **top_zfs, int cleanup_fd, uint64_t *action_handlep) |
2137 char **top_zfs, int cleanup_fd, uint64_t *action_handlep) |
2045 { |
2138 { |
2046 nvlist_t *stream_nv = NULL; |
2139 nvlist_t *stream_nv = NULL; |
2047 avl_tree_t *stream_avl = NULL; |
2140 avl_tree_t *stream_avl = NULL; |
2048 char *fromsnap = NULL; |
2141 char *fromsnap = NULL; |
2476 |
2569 |
2477 /* |
2570 /* |
2478 * Determine the name of the origin snapshot, store in zc_string. |
2571 * Determine the name of the origin snapshot, store in zc_string. |
2479 */ |
2572 */ |
2480 if (drrb->drr_flags & DRR_FLAG_CLONE) { |
2573 if (drrb->drr_flags & DRR_FLAG_CLONE) { |
2481 if (guid_to_name(hdl, tosnap, |
2574 if (guid_to_name(hdl, zc.zc_value, |
2482 drrb->drr_fromguid, zc.zc_string) != 0) { |
2575 drrb->drr_fromguid, zc.zc_string) != 0) { |
2483 zcmd_free_nvlists(&zc); |
2576 zcmd_free_nvlists(&zc); |
2484 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
2577 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
2485 "local origin for clone %s does not exist"), |
2578 "local origin for clone %s does not exist"), |
2486 zc.zc_value); |
2579 zc.zc_value); |
2487 return (zfs_error(hdl, EZFS_NOENT, errbuf)); |
2580 return (zfs_error(hdl, EZFS_NOENT, errbuf)); |
2488 } |
2581 } |
2489 if (flags.verbose) |
2582 if (flags->verbose) |
2490 (void) printf("found clone origin %s\n", zc.zc_string); |
2583 (void) printf("found clone origin %s\n", zc.zc_string); |
2491 } |
2584 } |
2492 |
2585 |
2493 stream_wantsnewfs = (drrb->drr_fromguid == NULL || |
2586 stream_wantsnewfs = (drrb->drr_fromguid == NULL || |
2494 (drrb->drr_flags & DRR_FLAG_CLONE)); |
2587 (drrb->drr_flags & DRR_FLAG_CLONE)); |
2529 /* |
2622 /* |
2530 * If the exact receive path was specified and this is the |
2623 * If the exact receive path was specified and this is the |
2531 * topmost path in the stream, then if the fs does not exist we |
2624 * topmost path in the stream, then if the fs does not exist we |
2532 * should look no further. |
2625 * should look no further. |
2533 */ |
2626 */ |
2534 if ((flags.isprefix || (*(chopprefix = drrb->drr_toname + |
2627 if ((flags->isprefix || (*(chopprefix = drrb->drr_toname + |
2535 strlen(sendfs)) != '\0' && *chopprefix != '@')) && |
2628 strlen(sendfs)) != '\0' && *chopprefix != '@')) && |
2536 !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { |
2629 !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { |
2537 char snap[ZFS_MAXNAMELEN]; |
2630 char snap[ZFS_MAXNAMELEN]; |
2538 (void) strcpy(snap, strchr(zc.zc_value, '@')); |
2631 (void) strcpy(snap, strchr(zc.zc_value, '@')); |
2539 if (guid_to_name(hdl, tosnap, drrb->drr_fromguid, |
2632 if (guid_to_name(hdl, zc.zc_name, drrb->drr_fromguid, |
2540 zc.zc_value) == 0) { |
2633 zc.zc_value) == 0) { |
2541 *strchr(zc.zc_value, '@') = '\0'; |
2634 *strchr(zc.zc_value, '@') = '\0'; |
2542 (void) strcat(zc.zc_value, snap); |
2635 (void) strcat(zc.zc_value, snap); |
2543 } |
2636 } |
2544 } |
2637 } |
2631 * Trim off the final dataset component so we perform the |
2724 * Trim off the final dataset component so we perform the |
2632 * recvbackup ioctl to the filesystems's parent. |
2725 * recvbackup ioctl to the filesystems's parent. |
2633 */ |
2726 */ |
2634 *cp = '\0'; |
2727 *cp = '\0'; |
2635 |
2728 |
2636 if (flags.isprefix && !flags.istail && !flags.dryrun && |
2729 if (flags->isprefix && !flags->istail && !flags->dryrun && |
2637 create_parents(hdl, zc.zc_value, strlen(tosnap)) != 0) { |
2730 create_parents(hdl, zc.zc_value, strlen(tosnap)) != 0) { |
2638 zcmd_free_nvlists(&zc); |
2731 zcmd_free_nvlists(&zc); |
2639 return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); |
2732 return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); |
2640 } |
2733 } |
2641 |
2734 |
2642 newfs = B_TRUE; |
2735 newfs = B_TRUE; |
2643 } |
2736 } |
2644 |
2737 |
2645 zc.zc_begin_record = drr_noswap->drr_u.drr_begin; |
2738 zc.zc_begin_record = drr_noswap->drr_u.drr_begin; |
2646 zc.zc_cookie = infd; |
2739 zc.zc_cookie = infd; |
2647 zc.zc_guid = flags.force; |
2740 zc.zc_guid = flags->force; |
2648 if (flags.verbose) { |
2741 if (flags->verbose) { |
2649 (void) printf("%s %s stream of %s into %s\n", |
2742 (void) printf("%s %s stream of %s into %s\n", |
2650 flags.dryrun ? "would receive" : "receiving", |
2743 flags->dryrun ? "would receive" : "receiving", |
2651 drrb->drr_fromguid ? "incremental" : "full", |
2744 drrb->drr_fromguid ? "incremental" : "full", |
2652 drrb->drr_toname, zc.zc_value); |
2745 drrb->drr_toname, zc.zc_value); |
2653 (void) fflush(stdout); |
2746 (void) fflush(stdout); |
2654 } |
2747 } |
2655 |
2748 |
2656 if (flags.dryrun) { |
2749 if (flags->dryrun) { |
2657 zcmd_free_nvlists(&zc); |
2750 zcmd_free_nvlists(&zc); |
2658 return (recv_skip(hdl, infd, flags.byteswap)); |
2751 return (recv_skip(hdl, infd, flags->byteswap)); |
2659 } |
2752 } |
2660 |
2753 |
2661 zc.zc_nvlist_dst = (uint64_t)(uintptr_t)prop_errbuf; |
2754 zc.zc_nvlist_dst = (uint64_t)(uintptr_t)prop_errbuf; |
2662 zc.zc_nvlist_dst_size = sizeof (prop_errbuf); |
2755 zc.zc_nvlist_dst_size = sizeof (prop_errbuf); |
2663 zc.zc_cleanup_fd = cleanup_fd; |
2756 zc.zc_cleanup_fd = cleanup_fd; |
2902 } |
2995 } |
2903 |
2996 |
2904 /* the kernel needs the non-byteswapped begin record */ |
2997 /* the kernel needs the non-byteswapped begin record */ |
2905 drr_noswap = drr; |
2998 drr_noswap = drr; |
2906 |
2999 |
2907 flags.byteswap = B_FALSE; |
3000 flags->byteswap = B_FALSE; |
2908 if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { |
3001 if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { |
2909 /* |
3002 /* |
2910 * We computed the checksum in the wrong byteorder in |
3003 * We computed the checksum in the wrong byteorder in |
2911 * recv_read() above; do it again correctly. |
3004 * recv_read() above; do it again correctly. |
2912 */ |
3005 */ |
2913 bzero(&zcksum, sizeof (zio_cksum_t)); |
3006 bzero(&zcksum, sizeof (zio_cksum_t)); |
2914 fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum); |
3007 fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum); |
2915 flags.byteswap = B_TRUE; |
3008 flags->byteswap = B_TRUE; |
2916 |
3009 |
2917 drr.drr_type = BSWAP_32(drr.drr_type); |
3010 drr.drr_type = BSWAP_32(drr.drr_type); |
2918 drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen); |
3011 drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen); |
2919 drrb->drr_magic = BSWAP_64(drrb->drr_magic); |
3012 drrb->drr_magic = BSWAP_64(drrb->drr_magic); |
2920 drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo); |
3013 drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo); |