1*5367Sahrens /* 2*5367Sahrens * CDDL HEADER START 3*5367Sahrens * 4*5367Sahrens * The contents of this file are subject to the terms of the 5*5367Sahrens * Common Development and Distribution License (the "License"). 6*5367Sahrens * You may not use this file except in compliance with the License. 7*5367Sahrens * 8*5367Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5367Sahrens * or http://www.opensolaris.org/os/licensing. 10*5367Sahrens * See the License for the specific language governing permissions 11*5367Sahrens * and limitations under the License. 12*5367Sahrens * 13*5367Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14*5367Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5367Sahrens * If applicable, add the following below this CDDL HEADER, with the 16*5367Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17*5367Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18*5367Sahrens * 19*5367Sahrens * CDDL HEADER END 20*5367Sahrens */ 21*5367Sahrens 22*5367Sahrens /* 23*5367Sahrens * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*5367Sahrens * Use is subject to license terms. 25*5367Sahrens */ 26*5367Sahrens 27*5367Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28*5367Sahrens 29*5367Sahrens #include <assert.h> 30*5367Sahrens #include <ctype.h> 31*5367Sahrens #include <errno.h> 32*5367Sahrens #include <libdevinfo.h> 33*5367Sahrens #include <libintl.h> 34*5367Sahrens #include <stdio.h> 35*5367Sahrens #include <stdlib.h> 36*5367Sahrens #include <strings.h> 37*5367Sahrens #include <unistd.h> 38*5367Sahrens #include <stddef.h> 39*5367Sahrens #include <fcntl.h> 40*5367Sahrens #include <sys/mount.h> 41*5367Sahrens #include <sys/mntent.h> 42*5367Sahrens #include <sys/mnttab.h> 43*5367Sahrens #include <sys/avl.h> 44*5367Sahrens #include <stddef.h> 45*5367Sahrens 46*5367Sahrens #include <libzfs.h> 47*5367Sahrens 48*5367Sahrens #include "zfs_namecheck.h" 49*5367Sahrens #include "zfs_prop.h" 50*5367Sahrens #include "libzfs_impl.h" 51*5367Sahrens 52*5367Sahrens #include <fletcher.c> /* XXX */ 53*5367Sahrens 54*5367Sahrens /* 55*5367Sahrens * Routines for dealing with the AVL tree of fs-nvlists 56*5367Sahrens */ 57*5367Sahrens typedef struct fsavl_node { 58*5367Sahrens avl_node_t fn_node; 59*5367Sahrens nvlist_t *fn_nvfs; 60*5367Sahrens char *fn_snapname; 61*5367Sahrens uint64_t fn_guid; 62*5367Sahrens } fsavl_node_t; 63*5367Sahrens 64*5367Sahrens static int 65*5367Sahrens fsavl_compare(const void *arg1, const void *arg2) 66*5367Sahrens { 67*5367Sahrens const fsavl_node_t *fn1 = arg1; 68*5367Sahrens const fsavl_node_t *fn2 = arg2; 69*5367Sahrens 70*5367Sahrens if (fn1->fn_guid > fn2->fn_guid) 71*5367Sahrens return (+1); 72*5367Sahrens else if (fn1->fn_guid < fn2->fn_guid) 73*5367Sahrens return (-1); 74*5367Sahrens else 75*5367Sahrens return (0); 76*5367Sahrens } 77*5367Sahrens 78*5367Sahrens /* 79*5367Sahrens * Given the GUID of a snapshot, find its containing filesystem and 80*5367Sahrens * (optionally) name. 81*5367Sahrens */ 82*5367Sahrens static nvlist_t * 83*5367Sahrens fsavl_find(avl_tree_t *avl, uint64_t snapguid, char **snapname) 84*5367Sahrens { 85*5367Sahrens fsavl_node_t fn_find; 86*5367Sahrens fsavl_node_t *fn; 87*5367Sahrens 88*5367Sahrens fn_find.fn_guid = snapguid; 89*5367Sahrens 90*5367Sahrens fn = avl_find(avl, &fn_find, NULL); 91*5367Sahrens if (fn) { 92*5367Sahrens if (snapname) 93*5367Sahrens *snapname = fn->fn_snapname; 94*5367Sahrens return (fn->fn_nvfs); 95*5367Sahrens } 96*5367Sahrens return (NULL); 97*5367Sahrens } 98*5367Sahrens 99*5367Sahrens static avl_tree_t * 100*5367Sahrens fsavl_create(nvlist_t *fss) 101*5367Sahrens { 102*5367Sahrens avl_tree_t *fsavl; 103*5367Sahrens nvpair_t *fselem = NULL; 104*5367Sahrens 105*5367Sahrens fsavl = malloc(sizeof (avl_tree_t)); 106*5367Sahrens avl_create(fsavl, fsavl_compare, sizeof (fsavl_node_t), 107*5367Sahrens offsetof(fsavl_node_t, fn_node)); 108*5367Sahrens 109*5367Sahrens while ((fselem = nvlist_next_nvpair(fss, fselem)) != NULL) { 110*5367Sahrens nvlist_t *nvfs, *snaps; 111*5367Sahrens nvpair_t *snapelem = NULL; 112*5367Sahrens 113*5367Sahrens VERIFY(0 == nvpair_value_nvlist(fselem, &nvfs)); 114*5367Sahrens VERIFY(0 == nvlist_lookup_nvlist(nvfs, "snaps", &snaps)); 115*5367Sahrens 116*5367Sahrens while ((snapelem = 117*5367Sahrens nvlist_next_nvpair(snaps, snapelem)) != NULL) { 118*5367Sahrens fsavl_node_t *fn; 119*5367Sahrens uint64_t guid; 120*5367Sahrens 121*5367Sahrens VERIFY(0 == nvpair_value_uint64(snapelem, &guid)); 122*5367Sahrens fn = malloc(sizeof (fsavl_node_t)); 123*5367Sahrens fn->fn_nvfs = nvfs; 124*5367Sahrens fn->fn_snapname = nvpair_name(snapelem); 125*5367Sahrens fn->fn_guid = guid; 126*5367Sahrens 127*5367Sahrens /* 128*5367Sahrens * Note: if there are multiple snaps with the 129*5367Sahrens * same GUID, we ignore all but one. 130*5367Sahrens */ 131*5367Sahrens if (avl_find(fsavl, fn, NULL) == NULL) 132*5367Sahrens avl_add(fsavl, fn); 133*5367Sahrens else 134*5367Sahrens free(fn); 135*5367Sahrens } 136*5367Sahrens } 137*5367Sahrens 138*5367Sahrens return (fsavl); 139*5367Sahrens } 140*5367Sahrens 141*5367Sahrens static void 142*5367Sahrens fsavl_destroy(avl_tree_t *avl) 143*5367Sahrens { 144*5367Sahrens fsavl_node_t *fn; 145*5367Sahrens void *cookie; 146*5367Sahrens 147*5367Sahrens if (avl == NULL) 148*5367Sahrens return; 149*5367Sahrens 150*5367Sahrens cookie = NULL; 151*5367Sahrens while ((fn = avl_destroy_nodes(avl, &cookie)) != NULL) 152*5367Sahrens free(fn); 153*5367Sahrens avl_destroy(avl); 154*5367Sahrens } 155*5367Sahrens 156*5367Sahrens /* 157*5367Sahrens * Routines for dealing with the giant nvlist of fs-nvlists, etc. 158*5367Sahrens */ 159*5367Sahrens typedef struct send_data { 160*5367Sahrens uint64_t parent_fromsnap_guid; 161*5367Sahrens nvlist_t *parent_snaps; 162*5367Sahrens nvlist_t *fss; 163*5367Sahrens const char *fromsnap; 164*5367Sahrens const char *tosnap; 165*5367Sahrens 166*5367Sahrens /* 167*5367Sahrens * The header nvlist is of the following format: 168*5367Sahrens * { 169*5367Sahrens * "tosnap" -> string 170*5367Sahrens * "fromsnap" -> string (if incremental) 171*5367Sahrens * "fss" -> { 172*5367Sahrens * id -> { 173*5367Sahrens * 174*5367Sahrens * "name" -> string (full name; for debugging) 175*5367Sahrens * "parentfromsnap" -> number (guid of fromsnap in parent) 176*5367Sahrens * 177*5367Sahrens * "props" -> { name -> value (only if set here) } 178*5367Sahrens * "snaps" -> { name (lastname) -> number (guid) } 179*5367Sahrens * 180*5367Sahrens * "origin" -> number (guid) (if clone) 181*5367Sahrens * "sent" -> boolean (not on-disk) 182*5367Sahrens * } 183*5367Sahrens * } 184*5367Sahrens * } 185*5367Sahrens * 186*5367Sahrens */ 187*5367Sahrens } send_data_t; 188*5367Sahrens 189*5367Sahrens static int 190*5367Sahrens send_iterate_snap(zfs_handle_t *zhp, void *arg) 191*5367Sahrens { 192*5367Sahrens send_data_t *sd = arg; 193*5367Sahrens uint64_t guid = zhp->zfs_dmustats.dds_guid; 194*5367Sahrens char *snapname; 195*5367Sahrens 196*5367Sahrens snapname = strrchr(zhp->zfs_name, '@')+1; 197*5367Sahrens 198*5367Sahrens VERIFY(0 == nvlist_add_uint64(sd->parent_snaps, snapname, guid)); 199*5367Sahrens /* 200*5367Sahrens * NB: if there is no fromsnap here (it's a newly created fs in 201*5367Sahrens * an incremental replication), we will substitute the tosnap. 202*5367Sahrens */ 203*5367Sahrens if ((sd->fromsnap && strcmp(snapname, sd->fromsnap) == 0) || 204*5367Sahrens (sd->parent_fromsnap_guid == 0 && sd->tosnap && 205*5367Sahrens strcmp(snapname, sd->tosnap) == 0)) { 206*5367Sahrens sd->parent_fromsnap_guid = guid; 207*5367Sahrens } 208*5367Sahrens 209*5367Sahrens zfs_close(zhp); 210*5367Sahrens return (0); 211*5367Sahrens } 212*5367Sahrens 213*5367Sahrens static void 214*5367Sahrens send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv) 215*5367Sahrens { 216*5367Sahrens nvpair_t *elem = NULL; 217*5367Sahrens 218*5367Sahrens while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) { 219*5367Sahrens char *propname = nvpair_name(elem); 220*5367Sahrens zfs_prop_t prop = zfs_name_to_prop(propname); 221*5367Sahrens nvlist_t *propnv; 222*5367Sahrens 223*5367Sahrens if (!zfs_prop_user(propname) && zfs_prop_readonly(prop)) 224*5367Sahrens continue; 225*5367Sahrens 226*5367Sahrens verify(nvpair_value_nvlist(elem, &propnv) == 0); 227*5367Sahrens if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION) { 228*5367Sahrens /* these guys are modifyable, but have no source */ 229*5367Sahrens uint64_t value; 230*5367Sahrens verify(nvlist_lookup_uint64(propnv, 231*5367Sahrens ZPROP_VALUE, &value) == 0); 232*5367Sahrens } else { 233*5367Sahrens char *source; 234*5367Sahrens if (nvlist_lookup_string(propnv, 235*5367Sahrens ZPROP_SOURCE, &source) != 0) 236*5367Sahrens continue; 237*5367Sahrens if (strcmp(source, zhp->zfs_name) != 0) 238*5367Sahrens continue; 239*5367Sahrens } 240*5367Sahrens 241*5367Sahrens if (zfs_prop_user(propname) || 242*5367Sahrens zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 243*5367Sahrens char *value; 244*5367Sahrens verify(nvlist_lookup_string(propnv, 245*5367Sahrens ZPROP_VALUE, &value) == 0); 246*5367Sahrens VERIFY(0 == nvlist_add_string(nv, propname, value)); 247*5367Sahrens } else { 248*5367Sahrens uint64_t value; 249*5367Sahrens verify(nvlist_lookup_uint64(propnv, 250*5367Sahrens ZPROP_VALUE, &value) == 0); 251*5367Sahrens VERIFY(0 == nvlist_add_uint64(nv, propname, value)); 252*5367Sahrens } 253*5367Sahrens } 254*5367Sahrens } 255*5367Sahrens 256*5367Sahrens static int 257*5367Sahrens send_iterate_fs(zfs_handle_t *zhp, void *arg) 258*5367Sahrens { 259*5367Sahrens send_data_t *sd = arg; 260*5367Sahrens nvlist_t *nvfs, *nv; 261*5367Sahrens int rv; 262*5367Sahrens uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid; 263*5367Sahrens uint64_t guid = zhp->zfs_dmustats.dds_guid; 264*5367Sahrens char guidstring[64]; 265*5367Sahrens 266*5367Sahrens VERIFY(0 == nvlist_alloc(&nvfs, NV_UNIQUE_NAME, 0)); 267*5367Sahrens VERIFY(0 == nvlist_add_string(nvfs, "name", zhp->zfs_name)); 268*5367Sahrens VERIFY(0 == nvlist_add_uint64(nvfs, "parentfromsnap", 269*5367Sahrens sd->parent_fromsnap_guid)); 270*5367Sahrens 271*5367Sahrens if (zhp->zfs_dmustats.dds_origin[0]) { 272*5367Sahrens zfs_handle_t *origin = zfs_open(zhp->zfs_hdl, 273*5367Sahrens zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT); 274*5367Sahrens if (origin == NULL) 275*5367Sahrens return (-1); 276*5367Sahrens VERIFY(0 == nvlist_add_uint64(nvfs, "origin", 277*5367Sahrens origin->zfs_dmustats.dds_guid)); 278*5367Sahrens } 279*5367Sahrens 280*5367Sahrens /* iterate over props */ 281*5367Sahrens VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0)); 282*5367Sahrens send_iterate_prop(zhp, nv); 283*5367Sahrens VERIFY(0 == nvlist_add_nvlist(nvfs, "props", nv)); 284*5367Sahrens nvlist_free(nv); 285*5367Sahrens 286*5367Sahrens /* iterate over snaps, and set sd->parent_fromsnap_guid */ 287*5367Sahrens sd->parent_fromsnap_guid = 0; 288*5367Sahrens VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0)); 289*5367Sahrens (void) zfs_iter_snapshots(zhp, send_iterate_snap, sd); 290*5367Sahrens VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps)); 291*5367Sahrens nvlist_free(sd->parent_snaps); 292*5367Sahrens 293*5367Sahrens /* add this fs to nvlist */ 294*5367Sahrens (void) snprintf(guidstring, sizeof (guidstring), 295*5367Sahrens "0x%llx", (longlong_t)guid); 296*5367Sahrens VERIFY(0 == nvlist_add_nvlist(sd->fss, guidstring, nvfs)); 297*5367Sahrens nvlist_free(nvfs); 298*5367Sahrens 299*5367Sahrens /* iterate over children */ 300*5367Sahrens rv = zfs_iter_filesystems(zhp, send_iterate_fs, sd); 301*5367Sahrens 302*5367Sahrens sd->parent_fromsnap_guid = parent_fromsnap_guid_save; 303*5367Sahrens 304*5367Sahrens zfs_close(zhp); 305*5367Sahrens return (rv); 306*5367Sahrens } 307*5367Sahrens 308*5367Sahrens static int 309*5367Sahrens gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, 310*5367Sahrens const char *tosnap, nvlist_t **nvlp, avl_tree_t **avlp) 311*5367Sahrens { 312*5367Sahrens zfs_handle_t *zhp; 313*5367Sahrens send_data_t sd = { 0 }; 314*5367Sahrens int error; 315*5367Sahrens 316*5367Sahrens zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 317*5367Sahrens if (zhp == NULL) 318*5367Sahrens return (EZFS_BADTYPE); 319*5367Sahrens 320*5367Sahrens VERIFY(0 == nvlist_alloc(&sd.fss, NV_UNIQUE_NAME, 0)); 321*5367Sahrens sd.fromsnap = fromsnap; 322*5367Sahrens sd.tosnap = tosnap; 323*5367Sahrens error = send_iterate_fs(zhp, &sd); 324*5367Sahrens 325*5367Sahrens *nvlp = sd.fss; 326*5367Sahrens if (avlp) 327*5367Sahrens *avlp = fsavl_create(sd.fss); 328*5367Sahrens return (error); 329*5367Sahrens } 330*5367Sahrens 331*5367Sahrens /* 332*5367Sahrens * Routines for dealing with the sorted snapshot functionality 333*5367Sahrens */ 334*5367Sahrens typedef struct zfs_node { 335*5367Sahrens zfs_handle_t *zn_handle; 336*5367Sahrens avl_node_t zn_avlnode; 337*5367Sahrens } zfs_node_t; 338*5367Sahrens 339*5367Sahrens static int 340*5367Sahrens zfs_sort_snaps(zfs_handle_t *zhp, void *data) 341*5367Sahrens { 342*5367Sahrens avl_tree_t *avl = data; 343*5367Sahrens zfs_node_t *node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t)); 344*5367Sahrens 345*5367Sahrens node->zn_handle = zhp; 346*5367Sahrens avl_add(avl, node); 347*5367Sahrens return (0); 348*5367Sahrens } 349*5367Sahrens 350*5367Sahrens /* ARGSUSED */ 351*5367Sahrens static int 352*5367Sahrens zfs_snapshot_compare(const void *larg, const void *rarg) 353*5367Sahrens { 354*5367Sahrens zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle; 355*5367Sahrens zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle; 356*5367Sahrens uint64_t lcreate, rcreate; 357*5367Sahrens 358*5367Sahrens /* 359*5367Sahrens * Sort them according to creation time. We use the hidden 360*5367Sahrens * CREATETXG property to get an absolute ordering of snapshots. 361*5367Sahrens */ 362*5367Sahrens lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG); 363*5367Sahrens rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG); 364*5367Sahrens 365*5367Sahrens if (lcreate < rcreate) 366*5367Sahrens return (-1); 367*5367Sahrens else if (lcreate > rcreate) 368*5367Sahrens return (+1); 369*5367Sahrens else 370*5367Sahrens return (0); 371*5367Sahrens } 372*5367Sahrens 373*5367Sahrens static int 374*5367Sahrens zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data) 375*5367Sahrens { 376*5367Sahrens int ret = 0; 377*5367Sahrens zfs_node_t *node; 378*5367Sahrens avl_tree_t avl; 379*5367Sahrens void *cookie = NULL; 380*5367Sahrens 381*5367Sahrens avl_create(&avl, zfs_snapshot_compare, 382*5367Sahrens sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode)); 383*5367Sahrens 384*5367Sahrens ret = zfs_iter_snapshots(zhp, zfs_sort_snaps, &avl); 385*5367Sahrens 386*5367Sahrens for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node)) 387*5367Sahrens ret |= callback(node->zn_handle, data); 388*5367Sahrens 389*5367Sahrens while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL) 390*5367Sahrens free(node); 391*5367Sahrens 392*5367Sahrens avl_destroy(&avl); 393*5367Sahrens 394*5367Sahrens return (ret); 395*5367Sahrens } 396*5367Sahrens 397*5367Sahrens /* 398*5367Sahrens * Routines specific to "zfs send" 399*5367Sahrens */ 400*5367Sahrens typedef struct send_dump_data { 401*5367Sahrens /* these are all just the short snapname (the part after the @) */ 402*5367Sahrens const char *fromsnap; 403*5367Sahrens const char *tosnap; 404*5367Sahrens char lastsnap[ZFS_MAXNAMELEN]; 405*5367Sahrens boolean_t seenfrom, seento, replicate, doall, fromorigin; 406*5367Sahrens boolean_t verbose; 407*5367Sahrens int outfd; 408*5367Sahrens boolean_t err; 409*5367Sahrens nvlist_t *fss; 410*5367Sahrens avl_tree_t *fsavl; 411*5367Sahrens } send_dump_data_t; 412*5367Sahrens 413*5367Sahrens /* 414*5367Sahrens * Dumps a backup of the given snapshot (incremental from fromsnap if it's not 415*5367Sahrens * NULL) to the file descriptor specified by outfd. 416*5367Sahrens */ 417*5367Sahrens static int 418*5367Sahrens dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, boolean_t fromorigin, 419*5367Sahrens int outfd) 420*5367Sahrens { 421*5367Sahrens zfs_cmd_t zc = { 0 }; 422*5367Sahrens libzfs_handle_t *hdl = zhp->zfs_hdl; 423*5367Sahrens 424*5367Sahrens assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 425*5367Sahrens assert(fromsnap == NULL || fromsnap[0] == '\0' || !fromorigin); 426*5367Sahrens 427*5367Sahrens (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 428*5367Sahrens if (fromsnap) 429*5367Sahrens (void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name)); 430*5367Sahrens zc.zc_cookie = outfd; 431*5367Sahrens zc.zc_obj = fromorigin; 432*5367Sahrens 433*5367Sahrens if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SEND, &zc) != 0) { 434*5367Sahrens char errbuf[1024]; 435*5367Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 436*5367Sahrens "warning: cannot send '%s'"), zhp->zfs_name); 437*5367Sahrens 438*5367Sahrens switch (errno) { 439*5367Sahrens 440*5367Sahrens case EXDEV: 441*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 442*5367Sahrens "not an earlier snapshot from the same fs")); 443*5367Sahrens return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 444*5367Sahrens 445*5367Sahrens case ENOENT: 446*5367Sahrens if (zfs_dataset_exists(hdl, zc.zc_name, 447*5367Sahrens ZFS_TYPE_SNAPSHOT)) { 448*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 449*5367Sahrens "incremental source (@%s) does not exist"), 450*5367Sahrens zc.zc_value); 451*5367Sahrens } 452*5367Sahrens return (zfs_error(hdl, EZFS_NOENT, errbuf)); 453*5367Sahrens 454*5367Sahrens case EDQUOT: 455*5367Sahrens case EFBIG: 456*5367Sahrens case EIO: 457*5367Sahrens case ENOLINK: 458*5367Sahrens case ENOSPC: 459*5367Sahrens case ENOSTR: 460*5367Sahrens case ENXIO: 461*5367Sahrens case EPIPE: 462*5367Sahrens case ERANGE: 463*5367Sahrens case EFAULT: 464*5367Sahrens case EROFS: 465*5367Sahrens zfs_error_aux(hdl, strerror(errno)); 466*5367Sahrens return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 467*5367Sahrens 468*5367Sahrens default: 469*5367Sahrens return (zfs_standard_error(hdl, errno, errbuf)); 470*5367Sahrens } 471*5367Sahrens } 472*5367Sahrens 473*5367Sahrens return (0); 474*5367Sahrens } 475*5367Sahrens 476*5367Sahrens static int 477*5367Sahrens dump_snapshot(zfs_handle_t *zhp, void *arg) 478*5367Sahrens { 479*5367Sahrens send_dump_data_t *sdd = arg; 480*5367Sahrens const char *thissnap; 481*5367Sahrens int err; 482*5367Sahrens 483*5367Sahrens thissnap = strchr(zhp->zfs_name, '@') + 1; 484*5367Sahrens 485*5367Sahrens if (sdd->fromsnap && !sdd->seenfrom && 486*5367Sahrens strcmp(sdd->fromsnap, thissnap) == 0) { 487*5367Sahrens sdd->seenfrom = B_TRUE; 488*5367Sahrens (void) strcpy(sdd->lastsnap, thissnap); 489*5367Sahrens zfs_close(zhp); 490*5367Sahrens return (0); 491*5367Sahrens } 492*5367Sahrens 493*5367Sahrens if (sdd->seento || !sdd->seenfrom) { 494*5367Sahrens zfs_close(zhp); 495*5367Sahrens return (0); 496*5367Sahrens } 497*5367Sahrens 498*5367Sahrens /* send it */ 499*5367Sahrens if (sdd->verbose) { 500*5367Sahrens (void) fprintf(stderr, "sending from @%s to %s\n", 501*5367Sahrens sdd->lastsnap, zhp->zfs_name); 502*5367Sahrens } 503*5367Sahrens 504*5367Sahrens err = dump_ioctl(zhp, sdd->lastsnap, 505*5367Sahrens sdd->lastsnap[0] == '\0' && (sdd->fromorigin || sdd->replicate), 506*5367Sahrens sdd->outfd); 507*5367Sahrens 508*5367Sahrens if (!sdd->seento && strcmp(sdd->tosnap, thissnap) == 0) 509*5367Sahrens sdd->seento = B_TRUE; 510*5367Sahrens 511*5367Sahrens (void) strcpy(sdd->lastsnap, thissnap); 512*5367Sahrens zfs_close(zhp); 513*5367Sahrens return (err); 514*5367Sahrens } 515*5367Sahrens 516*5367Sahrens static int 517*5367Sahrens dump_filesystem(zfs_handle_t *zhp, void *arg) 518*5367Sahrens { 519*5367Sahrens int rv = 0; 520*5367Sahrens send_dump_data_t *sdd = arg; 521*5367Sahrens boolean_t missingfrom = B_FALSE; 522*5367Sahrens zfs_cmd_t zc = { 0 }; 523*5367Sahrens 524*5367Sahrens (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s", 525*5367Sahrens zhp->zfs_name, sdd->tosnap); 526*5367Sahrens if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 527*5367Sahrens (void) fprintf(stderr, "WARNING: " 528*5367Sahrens "could not send %s@%s: does not exist\n", 529*5367Sahrens zhp->zfs_name, sdd->tosnap); 530*5367Sahrens sdd->err = B_TRUE; 531*5367Sahrens return (0); 532*5367Sahrens } 533*5367Sahrens 534*5367Sahrens if (sdd->replicate && sdd->fromsnap) { 535*5367Sahrens /* 536*5367Sahrens * If this fs does not have fromsnap, and we're doing 537*5367Sahrens * recursive, we need to send a full stream from the 538*5367Sahrens * beginning (or an incremental from the origin if this 539*5367Sahrens * is a clone). If we're doing non-recursive, then let 540*5367Sahrens * them get the error. 541*5367Sahrens */ 542*5367Sahrens (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s", 543*5367Sahrens zhp->zfs_name, sdd->fromsnap); 544*5367Sahrens if (ioctl(zhp->zfs_hdl->libzfs_fd, 545*5367Sahrens ZFS_IOC_OBJSET_STATS, &zc) != 0) { 546*5367Sahrens missingfrom = B_TRUE; 547*5367Sahrens } 548*5367Sahrens } 549*5367Sahrens 550*5367Sahrens if (sdd->doall) { 551*5367Sahrens sdd->seenfrom = sdd->seento = sdd->lastsnap[0] = 0; 552*5367Sahrens if (sdd->fromsnap == NULL || missingfrom) 553*5367Sahrens sdd->seenfrom = B_TRUE; 554*5367Sahrens 555*5367Sahrens rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg); 556*5367Sahrens if (!sdd->seenfrom) { 557*5367Sahrens (void) fprintf(stderr, 558*5367Sahrens "WARNING: could not send %s@%s:\n" 559*5367Sahrens "incremental source (%s@%s) does not exist\n", 560*5367Sahrens zhp->zfs_name, sdd->tosnap, 561*5367Sahrens zhp->zfs_name, sdd->fromsnap); 562*5367Sahrens sdd->err = B_TRUE; 563*5367Sahrens } else if (!sdd->seento) { 564*5367Sahrens (void) fprintf(stderr, 565*5367Sahrens "WARNING: could not send %s@%s:\n" 566*5367Sahrens "incremental source (%s@%s) " 567*5367Sahrens "is not earlier than it\n", 568*5367Sahrens zhp->zfs_name, sdd->tosnap, 569*5367Sahrens zhp->zfs_name, sdd->fromsnap); 570*5367Sahrens sdd->err = B_TRUE; 571*5367Sahrens } 572*5367Sahrens } else { 573*5367Sahrens zfs_handle_t *snapzhp; 574*5367Sahrens char snapname[ZFS_MAXNAMELEN]; 575*5367Sahrens 576*5367Sahrens (void) snprintf(snapname, sizeof (snapname), "%s@%s", 577*5367Sahrens zfs_get_name(zhp), sdd->tosnap); 578*5367Sahrens snapzhp = zfs_open(zhp->zfs_hdl, snapname, ZFS_TYPE_SNAPSHOT); 579*5367Sahrens rv = dump_ioctl(snapzhp, 580*5367Sahrens missingfrom ? NULL : sdd->fromsnap, 581*5367Sahrens sdd->fromorigin || missingfrom, 582*5367Sahrens sdd->outfd); 583*5367Sahrens sdd->seento = B_TRUE; 584*5367Sahrens zfs_close(snapzhp); 585*5367Sahrens } 586*5367Sahrens 587*5367Sahrens return (rv); 588*5367Sahrens } 589*5367Sahrens 590*5367Sahrens static int 591*5367Sahrens dump_filesystems(zfs_handle_t *rzhp, void *arg) 592*5367Sahrens { 593*5367Sahrens send_dump_data_t *sdd = arg; 594*5367Sahrens nvpair_t *fspair; 595*5367Sahrens boolean_t needagain, progress; 596*5367Sahrens 597*5367Sahrens if (!sdd->replicate) 598*5367Sahrens return (dump_filesystem(rzhp, sdd)); 599*5367Sahrens 600*5367Sahrens again: 601*5367Sahrens needagain = progress = B_FALSE; 602*5367Sahrens for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair; 603*5367Sahrens fspair = nvlist_next_nvpair(sdd->fss, fspair)) { 604*5367Sahrens nvlist_t *fslist; 605*5367Sahrens char *fsname; 606*5367Sahrens zfs_handle_t *zhp; 607*5367Sahrens int err; 608*5367Sahrens uint64_t origin_guid = 0; 609*5367Sahrens nvlist_t *origin_nv; 610*5367Sahrens 611*5367Sahrens VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0); 612*5367Sahrens if (nvlist_lookup_boolean(fslist, "sent") == 0) 613*5367Sahrens continue; 614*5367Sahrens 615*5367Sahrens VERIFY(nvlist_lookup_string(fslist, "name", &fsname) == 0); 616*5367Sahrens (void) nvlist_lookup_uint64(fslist, "origin", &origin_guid); 617*5367Sahrens 618*5367Sahrens origin_nv = fsavl_find(sdd->fsavl, origin_guid, NULL); 619*5367Sahrens if (origin_nv && 620*5367Sahrens nvlist_lookup_boolean(origin_nv, "sent") == ENOENT) { 621*5367Sahrens /* 622*5367Sahrens * origin has not been sent yet; 623*5367Sahrens * skip this clone. 624*5367Sahrens */ 625*5367Sahrens needagain = B_TRUE; 626*5367Sahrens continue; 627*5367Sahrens } 628*5367Sahrens 629*5367Sahrens zhp = zfs_open(rzhp->zfs_hdl, fsname, ZFS_TYPE_DATASET); 630*5367Sahrens err = dump_filesystem(zhp, sdd); 631*5367Sahrens VERIFY(nvlist_add_boolean(fslist, "sent") == 0); 632*5367Sahrens progress = B_TRUE; 633*5367Sahrens zfs_close(zhp); 634*5367Sahrens if (err) 635*5367Sahrens return (err); 636*5367Sahrens } 637*5367Sahrens if (needagain) { 638*5367Sahrens assert(progress); 639*5367Sahrens goto again; 640*5367Sahrens } 641*5367Sahrens return (0); 642*5367Sahrens } 643*5367Sahrens 644*5367Sahrens /* 645*5367Sahrens * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 646*5367Sahrens * If 'doall', dump all intermediate snaps. 647*5367Sahrens * If 'replicate', dump special header and do recursively. 648*5367Sahrens */ 649*5367Sahrens int 650*5367Sahrens zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, 651*5367Sahrens boolean_t replicate, boolean_t doall, boolean_t fromorigin, 652*5367Sahrens boolean_t verbose, int outfd) 653*5367Sahrens { 654*5367Sahrens char errbuf[1024]; 655*5367Sahrens send_dump_data_t sdd = { 0 }; 656*5367Sahrens int err; 657*5367Sahrens nvlist_t *fss = NULL; 658*5367Sahrens avl_tree_t *fsavl = NULL; 659*5367Sahrens 660*5367Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 661*5367Sahrens "cannot send '%s'"), zhp->zfs_name); 662*5367Sahrens 663*5367Sahrens if (fromsnap && fromsnap[0] == '\0') { 664*5367Sahrens zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 665*5367Sahrens "zero-length incremental source")); 666*5367Sahrens return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 667*5367Sahrens } 668*5367Sahrens 669*5367Sahrens if (replicate || doall) { 670*5367Sahrens dmu_replay_record_t drr = { 0 }; 671*5367Sahrens char *packbuf = NULL; 672*5367Sahrens size_t buflen = 0; 673*5367Sahrens zio_cksum_t zc = { 0 }; 674*5367Sahrens 675*5367Sahrens assert(fromsnap || doall); 676*5367Sahrens 677*5367Sahrens if (replicate) { 678*5367Sahrens nvlist_t *hdrnv; 679*5367Sahrens 680*5367Sahrens VERIFY(0 == nvlist_alloc(&hdrnv, NV_UNIQUE_NAME, 0)); 681*5367Sahrens if (fromsnap) { 682*5367Sahrens VERIFY(0 == nvlist_add_string(hdrnv, 683*5367Sahrens "fromsnap", fromsnap)); 684*5367Sahrens } 685*5367Sahrens VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap)); 686*5367Sahrens 687*5367Sahrens err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name, 688*5367Sahrens fromsnap, tosnap, &fss, &fsavl); 689*5367Sahrens if (err) 690*5367Sahrens return (err); 691*5367Sahrens VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss)); 692*5367Sahrens err = nvlist_pack(hdrnv, &packbuf, &buflen, 693*5367Sahrens NV_ENCODE_XDR, 0); 694*5367Sahrens nvlist_free(hdrnv); 695*5367Sahrens if (err) { 696*5367Sahrens fsavl_destroy(fsavl); 697*5367Sahrens nvlist_free(fss); 698*5367Sahrens return (zfs_standard_error(zhp->zfs_hdl, 699*5367Sahrens err, errbuf)); 700*5367Sahrens } 701*5367Sahrens } 702*5367Sahrens 703*5367Sahrens /* write first begin record */ 704*5367Sahrens drr.drr_type = DRR_BEGIN; 705*5367Sahrens drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 706*5367Sahrens drr.drr_u.drr_begin.drr_version = DMU_BACKUP_HEADER_VERSION; 707*5367Sahrens (void) snprintf(drr.drr_u.drr_begin.drr_toname, 708*5367Sahrens sizeof (drr.drr_u.drr_begin.drr_toname), 709*5367Sahrens "%s@%s", zhp->zfs_name, tosnap); 710*5367Sahrens drr.drr_payloadlen = buflen; 711*5367Sahrens fletcher_4_incremental_native(&drr, sizeof (drr), &zc); 712*5367Sahrens err = write(outfd, &drr, sizeof (drr)); 713*5367Sahrens 714*5367Sahrens /* write header nvlist */ 715*5367Sahrens if (err != -1) { 716*5367Sahrens fletcher_4_incremental_native(packbuf, buflen, &zc); 717*5367Sahrens err = write(outfd, packbuf, buflen); 718*5367Sahrens } 719*5367Sahrens free(packbuf); 720*5367Sahrens if (err == -1) { 721*5367Sahrens fsavl_destroy(fsavl); 722*5367Sahrens nvlist_free(fss); 723*5367Sahrens return (zfs_standard_error(zhp->zfs_hdl, 724*5367Sahrens errno, errbuf)); 725*5367Sahrens } 726*5367Sahrens 727*5367Sahrens /* write end record */ 728*5367Sahrens if (err != -1) { 729*5367Sahrens bzero(&drr, sizeof (drr)); 730*5367Sahrens drr.drr_type = DRR_END; 731*5367Sahrens drr.drr_u.drr_end.drr_checksum = zc; 732*5367Sahrens err = write(outfd, &drr, sizeof (drr)); 733*5367Sahrens if (err == -1) { 734*5367Sahrens fsavl_destroy(fsavl); 735*5367Sahrens nvlist_free(fss); 736*5367Sahrens return (zfs_standard_error(zhp->zfs_hdl, 737*5367Sahrens errno, errbuf)); 738*5367Sahrens } 739*5367Sahrens } 740*5367Sahrens } 741*5367Sahrens 742*5367Sahrens /* dump each stream */ 743*5367Sahrens sdd.fromsnap = fromsnap; 744*5367Sahrens sdd.tosnap = tosnap; 745*5367Sahrens sdd.outfd = outfd; 746*5367Sahrens sdd.replicate = replicate; 747*5367Sahrens sdd.doall = doall; 748*5367Sahrens sdd.fromorigin = fromorigin; 749*5367Sahrens sdd.fss = fss; 750*5367Sahrens sdd.fsavl = fsavl; 751*5367Sahrens sdd.verbose = verbose; 752*5367Sahrens err = dump_filesystems(zhp, &sdd); 753*5367Sahrens fsavl_destroy(fsavl); 754*5367Sahrens nvlist_free(fss); 755*5367Sahrens 756*5367Sahrens if (replicate || doall) { 757*5367Sahrens /* 758*5367Sahrens * write final end record. NB: want to do this even if 759*5367Sahrens * there was some error, because it might not be totally 760*5367Sahrens * failed. 761*5367Sahrens */ 762*5367Sahrens dmu_replay_record_t drr = { 0 }; 763*5367Sahrens drr.drr_type = DRR_END; 764*5367Sahrens if (write(outfd, &drr, sizeof (drr)) == -1) { 765*5367Sahrens return (zfs_standard_error(zhp->zfs_hdl, 766*5367Sahrens errno, errbuf)); 767*5367Sahrens } 768*5367Sahrens } 769*5367Sahrens 770*5367Sahrens return (err || sdd.err); 771*5367Sahrens } 772*5367Sahrens 773*5367Sahrens /* 774*5367Sahrens * Routines specific to "zfs recv" 775*5367Sahrens */ 776*5367Sahrens 777*5367Sahrens static int 778*5367Sahrens recv_read(libzfs_handle_t *hdl, int fd, void *buf, int ilen, 779*5367Sahrens boolean_t byteswap, zio_cksum_t *zc) 780*5367Sahrens { 781*5367Sahrens char *cp = buf; 782*5367Sahrens int rv; 783*5367Sahrens int len = ilen; 784*5367Sahrens 785*5367Sahrens do { 786*5367Sahrens rv = read(fd, cp, len); 787*5367Sahrens cp += rv; 788*5367Sahrens len -= rv; 789*5367Sahrens } while (rv > 0); 790*5367Sahrens 791*5367Sahrens if (rv < 0 || len != 0) { 792*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 793*5367Sahrens "failed to read from stream")); 794*5367Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, dgettext(TEXT_DOMAIN, 795*5367Sahrens "cannot receive"))); 796*5367Sahrens } 797*5367Sahrens 798*5367Sahrens if (zc) { 799*5367Sahrens if (byteswap) 800*5367Sahrens fletcher_4_incremental_byteswap(buf, ilen, zc); 801*5367Sahrens else 802*5367Sahrens fletcher_4_incremental_native(buf, ilen, zc); 803*5367Sahrens } 804*5367Sahrens return (0); 805*5367Sahrens } 806*5367Sahrens 807*5367Sahrens static int 808*5367Sahrens recv_read_nvlist(libzfs_handle_t *hdl, int fd, int len, nvlist_t **nvp, 809*5367Sahrens boolean_t byteswap, zio_cksum_t *zc) 810*5367Sahrens { 811*5367Sahrens char *buf; 812*5367Sahrens int err; 813*5367Sahrens 814*5367Sahrens buf = zfs_alloc(hdl, len); 815*5367Sahrens if (buf == NULL) 816*5367Sahrens return (ENOMEM); 817*5367Sahrens 818*5367Sahrens err = recv_read(hdl, fd, buf, len, byteswap, zc); 819*5367Sahrens if (err != 0) { 820*5367Sahrens free(buf); 821*5367Sahrens return (err); 822*5367Sahrens } 823*5367Sahrens 824*5367Sahrens err = nvlist_unpack(buf, len, nvp, 0); 825*5367Sahrens free(buf); 826*5367Sahrens if (err != 0) { 827*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 828*5367Sahrens "stream (malformed nvlist)")); 829*5367Sahrens return (EINVAL); 830*5367Sahrens } 831*5367Sahrens return (0); 832*5367Sahrens } 833*5367Sahrens 834*5367Sahrens static int 835*5367Sahrens recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname, 836*5367Sahrens int baselen, char *newname, recvflags_t flags) 837*5367Sahrens { 838*5367Sahrens static int seq; 839*5367Sahrens zfs_cmd_t zc = { 0 }; 840*5367Sahrens int err; 841*5367Sahrens prop_changelist_t *clp = NULL; 842*5367Sahrens 843*5367Sahrens if (strchr(name, '@') == NULL) { 844*5367Sahrens zfs_handle_t *zhp = zfs_open(hdl, name, 845*5367Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 846*5367Sahrens if (zhp == NULL) 847*5367Sahrens return (-1); 848*5367Sahrens clp = changelist_gather(zhp, ZFS_PROP_NAME, 849*5367Sahrens flags.force ? MS_FORCE : 0); 850*5367Sahrens zfs_close(zhp); 851*5367Sahrens if (clp == NULL) 852*5367Sahrens return (-1); 853*5367Sahrens err = changelist_prefix(clp); 854*5367Sahrens if (err) 855*5367Sahrens return (err); 856*5367Sahrens } 857*5367Sahrens 858*5367Sahrens if (tryname) { 859*5367Sahrens (void) strcpy(newname, tryname); 860*5367Sahrens 861*5367Sahrens zc.zc_objset_type = DMU_OST_ZFS; 862*5367Sahrens (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); 863*5367Sahrens (void) strlcpy(zc.zc_value, tryname, sizeof (zc.zc_value)); 864*5367Sahrens 865*5367Sahrens if (flags.verbose) { 866*5367Sahrens (void) printf("attempting rename %s to %s\n", 867*5367Sahrens zc.zc_name, zc.zc_value); 868*5367Sahrens } 869*5367Sahrens err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc); 870*5367Sahrens if (err == 0 && clp) 871*5367Sahrens changelist_rename(clp, name, tryname); 872*5367Sahrens } else { 873*5367Sahrens err = ENOENT; 874*5367Sahrens } 875*5367Sahrens 876*5367Sahrens if (err != 0 && strncmp(name+baselen, "recv-", 5) != 0) { 877*5367Sahrens seq++; 878*5367Sahrens 879*5367Sahrens (void) strncpy(newname, name, baselen); 880*5367Sahrens (void) snprintf(newname+baselen, ZFS_MAXNAMELEN-baselen, 881*5367Sahrens "recv-%u-%u", getpid(), seq); 882*5367Sahrens (void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value)); 883*5367Sahrens 884*5367Sahrens if (flags.verbose) { 885*5367Sahrens (void) printf("failed - trying rename %s to %s\n", 886*5367Sahrens zc.zc_name, zc.zc_value); 887*5367Sahrens } 888*5367Sahrens err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc); 889*5367Sahrens if (err == 0 && clp) 890*5367Sahrens changelist_rename(clp, name, newname); 891*5367Sahrens if (err && flags.verbose) { 892*5367Sahrens (void) printf("failed (%u) - " 893*5367Sahrens "will try again on next pass\n", errno); 894*5367Sahrens } 895*5367Sahrens err = EAGAIN; 896*5367Sahrens } else if (flags.verbose) { 897*5367Sahrens if (err == 0) 898*5367Sahrens (void) printf("success\n"); 899*5367Sahrens else 900*5367Sahrens (void) printf("failed (%u)\n", errno); 901*5367Sahrens } 902*5367Sahrens 903*5367Sahrens if (clp) { 904*5367Sahrens (void) changelist_postfix(clp); 905*5367Sahrens changelist_free(clp); 906*5367Sahrens } 907*5367Sahrens 908*5367Sahrens 909*5367Sahrens return (err); 910*5367Sahrens } 911*5367Sahrens 912*5367Sahrens static int 913*5367Sahrens recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen, 914*5367Sahrens char *newname, recvflags_t flags) 915*5367Sahrens { 916*5367Sahrens zfs_cmd_t zc = { 0 }; 917*5367Sahrens int err; 918*5367Sahrens zfs_handle_t *zhp = NULL; 919*5367Sahrens 920*5367Sahrens zc.zc_objset_type = DMU_OST_ZFS; 921*5367Sahrens (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); 922*5367Sahrens 923*5367Sahrens /* unmount it */ 924*5367Sahrens if (strchr(name, '@') == NULL) { 925*5367Sahrens zhp = zfs_open(hdl, name, 926*5367Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 927*5367Sahrens if (zhp == NULL) 928*5367Sahrens return (-1); 929*5367Sahrens err = zfs_unmount(zhp, NULL, flags.force ? MS_FORCE : 0); 930*5367Sahrens if (err) { 931*5367Sahrens zfs_close(zhp); 932*5367Sahrens return (err); 933*5367Sahrens } 934*5367Sahrens } 935*5367Sahrens 936*5367Sahrens if (flags.verbose) 937*5367Sahrens (void) printf("attempting destroy %s\n", zc.zc_name); 938*5367Sahrens err = ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); 939*5367Sahrens 940*5367Sahrens if (err != 0) { 941*5367Sahrens (void) zfs_mount(zhp, NULL, 0); 942*5367Sahrens err = recv_rename(hdl, name, NULL, baselen, newname, flags); 943*5367Sahrens } 944*5367Sahrens if (zhp) 945*5367Sahrens zfs_close(zhp); 946*5367Sahrens 947*5367Sahrens if (flags.verbose) { 948*5367Sahrens if (err == 0) 949*5367Sahrens (void) printf("success\n"); 950*5367Sahrens else 951*5367Sahrens (void) printf("failed (%u)\n", errno); 952*5367Sahrens } 953*5367Sahrens 954*5367Sahrens return (err); 955*5367Sahrens } 956*5367Sahrens 957*5367Sahrens typedef struct guid_to_name_data { 958*5367Sahrens uint64_t guid; 959*5367Sahrens char *name; 960*5367Sahrens } guid_to_name_data_t; 961*5367Sahrens 962*5367Sahrens static int 963*5367Sahrens guid_to_name_cb(zfs_handle_t *zhp, void *arg) 964*5367Sahrens { 965*5367Sahrens guid_to_name_data_t *gtnd = arg; 966*5367Sahrens int err; 967*5367Sahrens 968*5367Sahrens if (zhp->zfs_dmustats.dds_guid == gtnd->guid) { 969*5367Sahrens (void) strcpy(gtnd->name, zhp->zfs_name); 970*5367Sahrens return (EEXIST); 971*5367Sahrens } 972*5367Sahrens err = zfs_iter_children(zhp, guid_to_name_cb, gtnd); 973*5367Sahrens zfs_close(zhp); 974*5367Sahrens return (err); 975*5367Sahrens } 976*5367Sahrens 977*5367Sahrens static int 978*5367Sahrens guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid, 979*5367Sahrens char *name) 980*5367Sahrens { 981*5367Sahrens /* exhaustive search all local snapshots */ 982*5367Sahrens guid_to_name_data_t gtnd; 983*5367Sahrens int err = 0; 984*5367Sahrens zfs_handle_t *zhp; 985*5367Sahrens char *cp; 986*5367Sahrens 987*5367Sahrens gtnd.guid = guid; 988*5367Sahrens gtnd.name = name; 989*5367Sahrens 990*5367Sahrens if (strchr(parent, '@') == NULL) { 991*5367Sahrens zhp = make_dataset_handle(hdl, parent); 992*5367Sahrens if (zhp != NULL) { 993*5367Sahrens err = zfs_iter_children(zhp, guid_to_name_cb, >nd); 994*5367Sahrens zfs_close(zhp); 995*5367Sahrens if (err == EEXIST) 996*5367Sahrens return (0); 997*5367Sahrens } 998*5367Sahrens } 999*5367Sahrens 1000*5367Sahrens cp = strchr(parent, '/'); 1001*5367Sahrens if (cp) 1002*5367Sahrens *cp = '\0'; 1003*5367Sahrens zhp = make_dataset_handle(hdl, parent); 1004*5367Sahrens if (cp) 1005*5367Sahrens *cp = '/'; 1006*5367Sahrens 1007*5367Sahrens if (zhp) { 1008*5367Sahrens err = zfs_iter_children(zhp, guid_to_name_cb, >nd); 1009*5367Sahrens zfs_close(zhp); 1010*5367Sahrens } 1011*5367Sahrens 1012*5367Sahrens return (err == EEXIST ? 0 : ENOENT); 1013*5367Sahrens 1014*5367Sahrens } 1015*5367Sahrens 1016*5367Sahrens /* 1017*5367Sahrens * Return true if dataset guid1 is created before guid2. 1018*5367Sahrens */ 1019*5367Sahrens static boolean_t 1020*5367Sahrens created_before(libzfs_handle_t *hdl, avl_tree_t *avl, 1021*5367Sahrens uint64_t guid1, uint64_t guid2) 1022*5367Sahrens { 1023*5367Sahrens nvlist_t *nvfs; 1024*5367Sahrens char *fsname, *snapname; 1025*5367Sahrens char buf[ZFS_MAXNAMELEN]; 1026*5367Sahrens boolean_t rv; 1027*5367Sahrens zfs_node_t zn1, zn2; 1028*5367Sahrens 1029*5367Sahrens if (guid2 == 0) 1030*5367Sahrens return (B_FALSE); 1031*5367Sahrens if (guid1 == 0) 1032*5367Sahrens return (B_TRUE); 1033*5367Sahrens 1034*5367Sahrens nvfs = fsavl_find(avl, guid1, &snapname); 1035*5367Sahrens VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); 1036*5367Sahrens (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname); 1037*5367Sahrens zn1.zn_handle = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); 1038*5367Sahrens 1039*5367Sahrens nvfs = fsavl_find(avl, guid2, &snapname); 1040*5367Sahrens VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); 1041*5367Sahrens (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname); 1042*5367Sahrens zn2.zn_handle = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); 1043*5367Sahrens 1044*5367Sahrens rv = (zfs_snapshot_compare(&zn1, &zn2) == -1); 1045*5367Sahrens 1046*5367Sahrens zfs_close(zn1.zn_handle); 1047*5367Sahrens zfs_close(zn2.zn_handle); 1048*5367Sahrens 1049*5367Sahrens return (rv); 1050*5367Sahrens } 1051*5367Sahrens 1052*5367Sahrens static int 1053*5367Sahrens recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs, 1054*5367Sahrens recvflags_t flags, nvlist_t *stream_nv, avl_tree_t *stream_avl) 1055*5367Sahrens { 1056*5367Sahrens nvlist_t *local_nv; 1057*5367Sahrens avl_tree_t *local_avl; 1058*5367Sahrens nvpair_t *fselem, *nextfselem; 1059*5367Sahrens char *tosnap, *fromsnap; 1060*5367Sahrens char newname[ZFS_MAXNAMELEN]; 1061*5367Sahrens int error; 1062*5367Sahrens boolean_t needagain, progress; 1063*5367Sahrens 1064*5367Sahrens VERIFY(0 == nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap)); 1065*5367Sahrens VERIFY(0 == nvlist_lookup_string(stream_nv, "tosnap", &tosnap)); 1066*5367Sahrens 1067*5367Sahrens if (flags.dryrun) 1068*5367Sahrens return (0); 1069*5367Sahrens 1070*5367Sahrens again: 1071*5367Sahrens needagain = progress = B_FALSE; 1072*5367Sahrens 1073*5367Sahrens if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL, 1074*5367Sahrens &local_nv, &local_avl)) != 0) 1075*5367Sahrens return (error); 1076*5367Sahrens 1077*5367Sahrens /* 1078*5367Sahrens * Process deletes and renames 1079*5367Sahrens */ 1080*5367Sahrens for (fselem = nvlist_next_nvpair(local_nv, NULL); 1081*5367Sahrens fselem; fselem = nextfselem) { 1082*5367Sahrens nvlist_t *nvfs, *snaps; 1083*5367Sahrens nvlist_t *stream_nvfs = NULL; 1084*5367Sahrens nvpair_t *snapelem, *nextsnapelem; 1085*5367Sahrens uint64_t fromguid = 0; 1086*5367Sahrens uint64_t originguid = 0; 1087*5367Sahrens uint64_t stream_originguid = 0; 1088*5367Sahrens uint64_t parent_fromsnap_guid, stream_parent_fromsnap_guid; 1089*5367Sahrens char *fsname, *stream_fsname; 1090*5367Sahrens 1091*5367Sahrens nextfselem = nvlist_next_nvpair(local_nv, fselem); 1092*5367Sahrens 1093*5367Sahrens VERIFY(0 == nvpair_value_nvlist(fselem, &nvfs)); 1094*5367Sahrens VERIFY(0 == nvlist_lookup_nvlist(nvfs, "snaps", &snaps)); 1095*5367Sahrens VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); 1096*5367Sahrens VERIFY(0 == nvlist_lookup_uint64(nvfs, "parentfromsnap", 1097*5367Sahrens &parent_fromsnap_guid)); 1098*5367Sahrens (void) nvlist_lookup_uint64(nvfs, "origin", &originguid); 1099*5367Sahrens 1100*5367Sahrens /* 1101*5367Sahrens * First find the stream's fs, so we can check for 1102*5367Sahrens * a different origin (due to "zfs promote") 1103*5367Sahrens */ 1104*5367Sahrens for (snapelem = nvlist_next_nvpair(snaps, NULL); 1105*5367Sahrens snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) { 1106*5367Sahrens uint64_t thisguid; 1107*5367Sahrens 1108*5367Sahrens VERIFY(0 == nvpair_value_uint64(snapelem, &thisguid)); 1109*5367Sahrens stream_nvfs = fsavl_find(stream_avl, thisguid, NULL); 1110*5367Sahrens 1111*5367Sahrens if (stream_nvfs != NULL) 1112*5367Sahrens break; 1113*5367Sahrens } 1114*5367Sahrens 1115*5367Sahrens /* check for promote */ 1116*5367Sahrens (void) nvlist_lookup_uint64(stream_nvfs, "origin", 1117*5367Sahrens &stream_originguid); 1118*5367Sahrens if (stream_nvfs && originguid != stream_originguid) { 1119*5367Sahrens if (created_before(hdl, local_avl, stream_originguid, 1120*5367Sahrens originguid)) { 1121*5367Sahrens /* promote it! */ 1122*5367Sahrens zfs_cmd_t zc = { 0 }; 1123*5367Sahrens nvlist_t *origin_nvfs; 1124*5367Sahrens char *origin_fsname; 1125*5367Sahrens 1126*5367Sahrens if (flags.verbose) 1127*5367Sahrens (void) printf("promoting %s\n", fsname); 1128*5367Sahrens 1129*5367Sahrens origin_nvfs = fsavl_find(local_avl, originguid, 1130*5367Sahrens NULL); 1131*5367Sahrens VERIFY(0 == nvlist_lookup_string(origin_nvfs, 1132*5367Sahrens "name", &origin_fsname)); 1133*5367Sahrens (void) strlcpy(zc.zc_value, origin_fsname, 1134*5367Sahrens sizeof (zc.zc_value)); 1135*5367Sahrens (void) strlcpy(zc.zc_name, fsname, 1136*5367Sahrens sizeof (zc.zc_name)); 1137*5367Sahrens error = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); 1138*5367Sahrens if (error == 0) 1139*5367Sahrens progress = B_TRUE; 1140*5367Sahrens } 1141*5367Sahrens /* 1142*5367Sahrens * We had/have the wrong origin, therefore our 1143*5367Sahrens * list of snapshots is wrong. Need to handle 1144*5367Sahrens * them on the next pass. 1145*5367Sahrens */ 1146*5367Sahrens needagain = B_TRUE; 1147*5367Sahrens continue; 1148*5367Sahrens } 1149*5367Sahrens 1150*5367Sahrens for (snapelem = nvlist_next_nvpair(snaps, NULL); 1151*5367Sahrens snapelem; snapelem = nextsnapelem) { 1152*5367Sahrens uint64_t thisguid; 1153*5367Sahrens char *stream_snapname; 1154*5367Sahrens nvlist_t *found; 1155*5367Sahrens 1156*5367Sahrens nextsnapelem = nvlist_next_nvpair(snaps, snapelem); 1157*5367Sahrens 1158*5367Sahrens VERIFY(0 == nvpair_value_uint64(snapelem, &thisguid)); 1159*5367Sahrens found = fsavl_find(stream_avl, thisguid, 1160*5367Sahrens &stream_snapname); 1161*5367Sahrens 1162*5367Sahrens /* check for delete */ 1163*5367Sahrens if (found == NULL) { 1164*5367Sahrens char name[ZFS_MAXNAMELEN]; 1165*5367Sahrens 1166*5367Sahrens if (!flags.force) 1167*5367Sahrens continue; 1168*5367Sahrens 1169*5367Sahrens (void) snprintf(name, sizeof (name), "%s@%s", 1170*5367Sahrens fsname, nvpair_name(snapelem)); 1171*5367Sahrens 1172*5367Sahrens error = recv_destroy(hdl, name, 1173*5367Sahrens strlen(fsname)+1, newname, flags); 1174*5367Sahrens if (error) 1175*5367Sahrens needagain = B_TRUE; 1176*5367Sahrens else 1177*5367Sahrens progress = B_TRUE; 1178*5367Sahrens continue; 1179*5367Sahrens } 1180*5367Sahrens 1181*5367Sahrens stream_nvfs = found; 1182*5367Sahrens 1183*5367Sahrens /* check for different snapname */ 1184*5367Sahrens if (strcmp(nvpair_name(snapelem), 1185*5367Sahrens stream_snapname) != 0) { 1186*5367Sahrens char name[ZFS_MAXNAMELEN]; 1187*5367Sahrens char tryname[ZFS_MAXNAMELEN]; 1188*5367Sahrens 1189*5367Sahrens (void) snprintf(name, sizeof (name), "%s@%s", 1190*5367Sahrens fsname, nvpair_name(snapelem)); 1191*5367Sahrens (void) snprintf(tryname, sizeof (name), "%s@%s", 1192*5367Sahrens fsname, stream_snapname); 1193*5367Sahrens 1194*5367Sahrens error = recv_rename(hdl, name, tryname, 1195*5367Sahrens strlen(fsname)+1, newname, flags); 1196*5367Sahrens if (error) 1197*5367Sahrens needagain = B_TRUE; 1198*5367Sahrens else 1199*5367Sahrens progress = B_TRUE; 1200*5367Sahrens } 1201*5367Sahrens 1202*5367Sahrens if (strcmp(stream_snapname, fromsnap) == 0) 1203*5367Sahrens fromguid = thisguid; 1204*5367Sahrens } 1205*5367Sahrens 1206*5367Sahrens /* check for delete */ 1207*5367Sahrens if (stream_nvfs == NULL) { 1208*5367Sahrens if (!flags.force) 1209*5367Sahrens continue; 1210*5367Sahrens 1211*5367Sahrens error = recv_destroy(hdl, fsname, strlen(tofs)+1, 1212*5367Sahrens newname, flags); 1213*5367Sahrens if (error) 1214*5367Sahrens needagain = B_TRUE; 1215*5367Sahrens else 1216*5367Sahrens progress = B_TRUE; 1217*5367Sahrens continue; 1218*5367Sahrens } 1219*5367Sahrens 1220*5367Sahrens if (fromguid == 0 && flags.verbose) { 1221*5367Sahrens (void) printf("local fs %s does not have fromsnap " 1222*5367Sahrens "(%s in stream); must have been deleted locally; " 1223*5367Sahrens "ignoring\n", fsname, fromsnap); 1224*5367Sahrens continue; 1225*5367Sahrens } 1226*5367Sahrens 1227*5367Sahrens VERIFY(0 == nvlist_lookup_string(stream_nvfs, 1228*5367Sahrens "name", &stream_fsname)); 1229*5367Sahrens VERIFY(0 == nvlist_lookup_uint64(stream_nvfs, 1230*5367Sahrens "parentfromsnap", &stream_parent_fromsnap_guid)); 1231*5367Sahrens 1232*5367Sahrens /* check for rename */ 1233*5367Sahrens if ((stream_parent_fromsnap_guid != 0 && 1234*5367Sahrens stream_parent_fromsnap_guid != parent_fromsnap_guid) || 1235*5367Sahrens strcmp(strrchr(fsname, '/'), 1236*5367Sahrens strrchr(stream_fsname, '/')) != 0) { 1237*5367Sahrens nvlist_t *parent; 1238*5367Sahrens char tryname[ZFS_MAXNAMELEN]; 1239*5367Sahrens 1240*5367Sahrens parent = fsavl_find(local_avl, 1241*5367Sahrens stream_parent_fromsnap_guid, NULL); 1242*5367Sahrens /* 1243*5367Sahrens * NB: parent might not be found if we used the 1244*5367Sahrens * tosnap for stream_parent_fromsnap_guid, 1245*5367Sahrens * because the parent is a newly-created fs; 1246*5367Sahrens * we'll be able to rename it after we recv the 1247*5367Sahrens * new fs. 1248*5367Sahrens */ 1249*5367Sahrens if (parent != NULL) { 1250*5367Sahrens char *pname; 1251*5367Sahrens 1252*5367Sahrens VERIFY(0 == nvlist_lookup_string(parent, "name", 1253*5367Sahrens &pname)); 1254*5367Sahrens (void) snprintf(tryname, sizeof (tryname), 1255*5367Sahrens "%s%s", pname, strrchr(stream_fsname, '/')); 1256*5367Sahrens } else { 1257*5367Sahrens tryname[0] = '\0'; 1258*5367Sahrens if (flags.verbose) { 1259*5367Sahrens (void) printf("local fs %s new parent " 1260*5367Sahrens "not found\n", fsname); 1261*5367Sahrens } 1262*5367Sahrens } 1263*5367Sahrens 1264*5367Sahrens error = recv_rename(hdl, fsname, tryname, 1265*5367Sahrens strlen(tofs)+1, newname, flags); 1266*5367Sahrens if (error) 1267*5367Sahrens needagain = B_TRUE; 1268*5367Sahrens else 1269*5367Sahrens progress = B_TRUE; 1270*5367Sahrens } 1271*5367Sahrens } 1272*5367Sahrens 1273*5367Sahrens fsavl_destroy(local_avl); 1274*5367Sahrens nvlist_free(local_nv); 1275*5367Sahrens 1276*5367Sahrens if (needagain && progress) { 1277*5367Sahrens /* do another pass to fix up temporary names */ 1278*5367Sahrens if (flags.verbose) 1279*5367Sahrens (void) printf("another pass:\n"); 1280*5367Sahrens goto again; 1281*5367Sahrens } 1282*5367Sahrens 1283*5367Sahrens return (needagain); 1284*5367Sahrens } 1285*5367Sahrens 1286*5367Sahrens static int 1287*5367Sahrens zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, 1288*5367Sahrens recvflags_t flags, dmu_replay_record_t *drr, zio_cksum_t *zc) 1289*5367Sahrens { 1290*5367Sahrens nvlist_t *stream_nv = NULL; 1291*5367Sahrens avl_tree_t *stream_avl = NULL; 1292*5367Sahrens char *fromsnap = NULL; 1293*5367Sahrens char tofs[ZFS_MAXNAMELEN]; 1294*5367Sahrens char errbuf[1024]; 1295*5367Sahrens dmu_replay_record_t drre; 1296*5367Sahrens int error; 1297*5367Sahrens boolean_t anyerr = B_FALSE; 1298*5367Sahrens 1299*5367Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1300*5367Sahrens "cannot receive")); 1301*5367Sahrens 1302*5367Sahrens if (strchr(destname, '@')) { 1303*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1304*5367Sahrens "can not specify snapshot name for multi-snapshot stream")); 1305*5367Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 1306*5367Sahrens } 1307*5367Sahrens 1308*5367Sahrens assert(drr->drr_type == DRR_BEGIN); 1309*5367Sahrens assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC); 1310*5367Sahrens assert(drr->drr_u.drr_begin.drr_version == DMU_BACKUP_HEADER_VERSION); 1311*5367Sahrens 1312*5367Sahrens /* 1313*5367Sahrens * Read in the nvlist from the stream. 1314*5367Sahrens */ 1315*5367Sahrens if (drr->drr_payloadlen != 0) { 1316*5367Sahrens if (!flags.isprefix) { 1317*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1318*5367Sahrens "must use -d to receive replication " 1319*5367Sahrens "(send -R) stream")); 1320*5367Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 1321*5367Sahrens } 1322*5367Sahrens 1323*5367Sahrens error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen, 1324*5367Sahrens &stream_nv, flags.byteswap, zc); 1325*5367Sahrens if (error) { 1326*5367Sahrens error = zfs_error(hdl, EZFS_BADSTREAM, errbuf); 1327*5367Sahrens goto out; 1328*5367Sahrens } 1329*5367Sahrens } 1330*5367Sahrens 1331*5367Sahrens /* 1332*5367Sahrens * Read in the end record and verify checksum. 1333*5367Sahrens */ 1334*5367Sahrens if (0 != (error = recv_read(hdl, fd, &drre, sizeof (drre), 1335*5367Sahrens flags.byteswap, NULL))) 1336*5367Sahrens goto out; 1337*5367Sahrens if (flags.byteswap) { 1338*5367Sahrens drre.drr_type = BSWAP_32(drre.drr_type); 1339*5367Sahrens drre.drr_u.drr_end.drr_checksum.zc_word[0] = 1340*5367Sahrens BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[0]); 1341*5367Sahrens drre.drr_u.drr_end.drr_checksum.zc_word[1] = 1342*5367Sahrens BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[1]); 1343*5367Sahrens drre.drr_u.drr_end.drr_checksum.zc_word[2] = 1344*5367Sahrens BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[2]); 1345*5367Sahrens drre.drr_u.drr_end.drr_checksum.zc_word[3] = 1346*5367Sahrens BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[3]); 1347*5367Sahrens } 1348*5367Sahrens if (drre.drr_type != DRR_END) { 1349*5367Sahrens error = zfs_error(hdl, EZFS_BADSTREAM, errbuf); 1350*5367Sahrens goto out; 1351*5367Sahrens } 1352*5367Sahrens if (!ZIO_CHECKSUM_EQUAL(drre.drr_u.drr_end.drr_checksum, *zc)) { 1353*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1354*5367Sahrens "incorrect header checksum")); 1355*5367Sahrens error = zfs_error(hdl, EZFS_BADSTREAM, errbuf); 1356*5367Sahrens goto out; 1357*5367Sahrens } 1358*5367Sahrens 1359*5367Sahrens (void) nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap); 1360*5367Sahrens 1361*5367Sahrens if (drr->drr_payloadlen != 0) { 1362*5367Sahrens nvlist_t *stream_fss; 1363*5367Sahrens 1364*5367Sahrens VERIFY(0 == nvlist_lookup_nvlist(stream_nv, "fss", 1365*5367Sahrens &stream_fss)); 1366*5367Sahrens stream_avl = fsavl_create(stream_fss); 1367*5367Sahrens 1368*5367Sahrens if (fromsnap != NULL) { 1369*5367Sahrens (void) strlcpy(tofs, destname, ZFS_MAXNAMELEN); 1370*5367Sahrens if (flags.isprefix) { 1371*5367Sahrens int i = strcspn(drr->drr_u.drr_begin.drr_toname, 1372*5367Sahrens "/@"); 1373*5367Sahrens /* zfs_receive_one() will create_parents() */ 1374*5367Sahrens (void) strlcat(tofs, 1375*5367Sahrens &drr->drr_u.drr_begin.drr_toname[i], 1376*5367Sahrens ZFS_MAXNAMELEN); 1377*5367Sahrens *strchr(tofs, '@') = '\0'; 1378*5367Sahrens } 1379*5367Sahrens anyerr |= recv_incremental_replication(hdl, tofs, 1380*5367Sahrens flags, stream_nv, stream_avl); 1381*5367Sahrens } 1382*5367Sahrens } 1383*5367Sahrens 1384*5367Sahrens 1385*5367Sahrens /* Finally, receive each contained stream */ 1386*5367Sahrens do { 1387*5367Sahrens /* 1388*5367Sahrens * we should figure out if it has a recoverable 1389*5367Sahrens * error, in which case do a recv_skip() and drive on. 1390*5367Sahrens * Note, if we fail due to already having this guid, 1391*5367Sahrens * zfs_receive_one() will take care of it (ie, 1392*5367Sahrens * recv_skip() and return 0). 1393*5367Sahrens */ 1394*5367Sahrens error = zfs_receive(hdl, destname, flags, fd, stream_avl); 1395*5367Sahrens if (error == ENODATA) { 1396*5367Sahrens error = 0; 1397*5367Sahrens break; 1398*5367Sahrens } 1399*5367Sahrens anyerr |= error; 1400*5367Sahrens } while (error == 0); 1401*5367Sahrens 1402*5367Sahrens if (drr->drr_payloadlen != 0 && fromsnap != NULL) { 1403*5367Sahrens /* 1404*5367Sahrens * Now that we have the fs's they sent us, try the 1405*5367Sahrens * renames again. 1406*5367Sahrens */ 1407*5367Sahrens anyerr |= recv_incremental_replication(hdl, tofs, flags, 1408*5367Sahrens stream_nv, stream_avl); 1409*5367Sahrens } 1410*5367Sahrens 1411*5367Sahrens out: 1412*5367Sahrens fsavl_destroy(stream_avl); 1413*5367Sahrens if (stream_nv) 1414*5367Sahrens nvlist_free(stream_nv); 1415*5367Sahrens if (anyerr) 1416*5367Sahrens error = -1; 1417*5367Sahrens return (error); 1418*5367Sahrens } 1419*5367Sahrens 1420*5367Sahrens static int 1421*5367Sahrens recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap) 1422*5367Sahrens { 1423*5367Sahrens dmu_replay_record_t *drr; 1424*5367Sahrens void *buf = malloc(1<<20); 1425*5367Sahrens 1426*5367Sahrens /* XXX would be great to use lseek if possible... */ 1427*5367Sahrens drr = buf; 1428*5367Sahrens 1429*5367Sahrens while (recv_read(hdl, fd, drr, sizeof (dmu_replay_record_t), 1430*5367Sahrens byteswap, NULL) == 0) { 1431*5367Sahrens if (byteswap) 1432*5367Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 1433*5367Sahrens 1434*5367Sahrens switch (drr->drr_type) { 1435*5367Sahrens case DRR_BEGIN: 1436*5367Sahrens /* NB: not to be used on v2 stream packages */ 1437*5367Sahrens assert(drr->drr_payloadlen == 0); 1438*5367Sahrens break; 1439*5367Sahrens 1440*5367Sahrens case DRR_END: 1441*5367Sahrens free(buf); 1442*5367Sahrens return (0); 1443*5367Sahrens 1444*5367Sahrens case DRR_OBJECT: 1445*5367Sahrens if (byteswap) { 1446*5367Sahrens drr->drr_u.drr_object.drr_bonuslen = 1447*5367Sahrens BSWAP_32(drr->drr_u.drr_object. 1448*5367Sahrens drr_bonuslen); 1449*5367Sahrens } 1450*5367Sahrens (void) recv_read(hdl, fd, buf, 1451*5367Sahrens P2ROUNDUP(drr->drr_u.drr_object.drr_bonuslen, 8), 1452*5367Sahrens B_FALSE, NULL); 1453*5367Sahrens break; 1454*5367Sahrens 1455*5367Sahrens case DRR_WRITE: 1456*5367Sahrens if (byteswap) { 1457*5367Sahrens drr->drr_u.drr_write.drr_length = 1458*5367Sahrens BSWAP_32(drr->drr_u.drr_write.drr_length); 1459*5367Sahrens } 1460*5367Sahrens (void) recv_read(hdl, fd, buf, 1461*5367Sahrens drr->drr_u.drr_write.drr_length, B_FALSE, NULL); 1462*5367Sahrens break; 1463*5367Sahrens 1464*5367Sahrens case DRR_FREEOBJECTS: 1465*5367Sahrens case DRR_FREE: 1466*5367Sahrens break; 1467*5367Sahrens 1468*5367Sahrens default: 1469*5367Sahrens assert(!"invalid record type"); 1470*5367Sahrens } 1471*5367Sahrens } 1472*5367Sahrens 1473*5367Sahrens free(buf); 1474*5367Sahrens return (-1); 1475*5367Sahrens } 1476*5367Sahrens 1477*5367Sahrens /* 1478*5367Sahrens * Restores a backup of tosnap from the file descriptor specified by infd. 1479*5367Sahrens */ 1480*5367Sahrens static int 1481*5367Sahrens zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, 1482*5367Sahrens recvflags_t flags, dmu_replay_record_t *drr, 1483*5367Sahrens dmu_replay_record_t *drr_noswap, avl_tree_t *stream_avl) 1484*5367Sahrens { 1485*5367Sahrens zfs_cmd_t zc = { 0 }; 1486*5367Sahrens time_t begin_time; 1487*5367Sahrens int ioctl_err, ioctl_errno, err, choplen; 1488*5367Sahrens char *cp; 1489*5367Sahrens struct drr_begin *drrb = &drr->drr_u.drr_begin; 1490*5367Sahrens char errbuf[1024]; 1491*5367Sahrens char chopprefix[ZFS_MAXNAMELEN]; 1492*5367Sahrens boolean_t newfs = B_FALSE; 1493*5367Sahrens boolean_t stream_wantsnewfs; 1494*5367Sahrens uint64_t parent_snapguid = 0; 1495*5367Sahrens prop_changelist_t *clp = NULL; 1496*5367Sahrens 1497*5367Sahrens begin_time = time(NULL); 1498*5367Sahrens 1499*5367Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1500*5367Sahrens "cannot receive")); 1501*5367Sahrens 1502*5367Sahrens if (stream_avl != NULL) { 1503*5367Sahrens nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid, NULL); 1504*5367Sahrens nvlist_t *props; 1505*5367Sahrens 1506*5367Sahrens (void) nvlist_lookup_uint64(fs, "parentfromsnap", 1507*5367Sahrens &parent_snapguid); 1508*5367Sahrens err = nvlist_lookup_nvlist(fs, "props", &props); 1509*5367Sahrens if (err) 1510*5367Sahrens VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0)); 1511*5367Sahrens if (flags.canmountoff) { 1512*5367Sahrens VERIFY(0 == nvlist_add_uint64(props, 1513*5367Sahrens zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0)); 1514*5367Sahrens } 1515*5367Sahrens if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) 1516*5367Sahrens return (-1); 1517*5367Sahrens if (err) 1518*5367Sahrens nvlist_free(props); 1519*5367Sahrens } 1520*5367Sahrens 1521*5367Sahrens /* 1522*5367Sahrens * Determine how much of the snapshot name stored in the stream 1523*5367Sahrens * we are going to tack on to the name they specified on the 1524*5367Sahrens * command line, and how much we are going to chop off. 1525*5367Sahrens * 1526*5367Sahrens * If they specified a snapshot, chop the entire name stored in 1527*5367Sahrens * the stream. 1528*5367Sahrens */ 1529*5367Sahrens (void) strcpy(chopprefix, drrb->drr_toname); 1530*5367Sahrens if (flags.isprefix) { 1531*5367Sahrens /* 1532*5367Sahrens * They specified a fs with -d, we want to tack on 1533*5367Sahrens * everything but the pool name stored in the stream 1534*5367Sahrens */ 1535*5367Sahrens if (strchr(tosnap, '@')) { 1536*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 1537*5367Sahrens "argument - snapshot not allowed with -d")); 1538*5367Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1539*5367Sahrens } 1540*5367Sahrens cp = strchr(chopprefix, '/'); 1541*5367Sahrens if (cp == NULL) 1542*5367Sahrens cp = strchr(chopprefix, '@'); 1543*5367Sahrens *cp = '\0'; 1544*5367Sahrens } else if (strchr(tosnap, '@') == NULL) { 1545*5367Sahrens /* 1546*5367Sahrens * If they specified a filesystem without -d, we want to 1547*5367Sahrens * tack on everything after the fs specified in the 1548*5367Sahrens * first name from the stream. 1549*5367Sahrens */ 1550*5367Sahrens cp = strchr(chopprefix, '@'); 1551*5367Sahrens *cp = '\0'; 1552*5367Sahrens } 1553*5367Sahrens choplen = strlen(chopprefix); 1554*5367Sahrens 1555*5367Sahrens /* 1556*5367Sahrens * Determine name of destination snapshot, store in zc_value. 1557*5367Sahrens */ 1558*5367Sahrens (void) strcpy(zc.zc_value, tosnap); 1559*5367Sahrens (void) strncat(zc.zc_value, drrb->drr_toname+choplen, 1560*5367Sahrens sizeof (zc.zc_value)); 1561*5367Sahrens if (!zfs_name_valid(zc.zc_value, ZFS_TYPE_SNAPSHOT)) 1562*5367Sahrens return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1563*5367Sahrens 1564*5367Sahrens /* 1565*5367Sahrens * Determine the name of the origin snapshot, store in zc_string. 1566*5367Sahrens */ 1567*5367Sahrens if (drrb->drr_flags & DRR_FLAG_CLONE) { 1568*5367Sahrens if (guid_to_name(hdl, tosnap, 1569*5367Sahrens drrb->drr_fromguid, zc.zc_string) != 0) { 1570*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1571*5367Sahrens "local origin for clone %s does not exist"), 1572*5367Sahrens zc.zc_value); 1573*5367Sahrens return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1574*5367Sahrens } 1575*5367Sahrens if (flags.verbose) 1576*5367Sahrens (void) printf("found clone origin %s\n", zc.zc_string); 1577*5367Sahrens } 1578*5367Sahrens 1579*5367Sahrens stream_wantsnewfs = (drrb->drr_fromguid == NULL || 1580*5367Sahrens (drrb->drr_flags & DRR_FLAG_CLONE)); 1581*5367Sahrens 1582*5367Sahrens if (stream_wantsnewfs) { 1583*5367Sahrens /* 1584*5367Sahrens * if the parent fs does not exist, look for it based on 1585*5367Sahrens * the parent snap GUID 1586*5367Sahrens */ 1587*5367Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1588*5367Sahrens "cannot receive new filesystem stream")); 1589*5367Sahrens 1590*5367Sahrens (void) strcpy(zc.zc_name, zc.zc_value); 1591*5367Sahrens cp = strrchr(zc.zc_name, '/'); 1592*5367Sahrens if (cp) 1593*5367Sahrens *cp = '\0'; 1594*5367Sahrens if (cp && 1595*5367Sahrens !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { 1596*5367Sahrens char suffix[ZFS_MAXNAMELEN]; 1597*5367Sahrens (void) strcpy(suffix, strrchr(zc.zc_value, '/')); 1598*5367Sahrens if (guid_to_name(hdl, tosnap, parent_snapguid, 1599*5367Sahrens zc.zc_value) == 0) { 1600*5367Sahrens *strchr(zc.zc_value, '@') = '\0'; 1601*5367Sahrens (void) strcat(zc.zc_value, suffix); 1602*5367Sahrens } 1603*5367Sahrens } 1604*5367Sahrens } else { 1605*5367Sahrens /* 1606*5367Sahrens * if the fs does not exist, look for it based on the 1607*5367Sahrens * fromsnap GUID 1608*5367Sahrens */ 1609*5367Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1610*5367Sahrens "cannot receive incremental stream")); 1611*5367Sahrens 1612*5367Sahrens (void) strcpy(zc.zc_name, zc.zc_value); 1613*5367Sahrens *strchr(zc.zc_name, '@') = '\0'; 1614*5367Sahrens 1615*5367Sahrens if (!zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { 1616*5367Sahrens char snap[ZFS_MAXNAMELEN]; 1617*5367Sahrens (void) strcpy(snap, strchr(zc.zc_value, '@')); 1618*5367Sahrens if (guid_to_name(hdl, tosnap, drrb->drr_fromguid, 1619*5367Sahrens zc.zc_value) == 0) { 1620*5367Sahrens *strchr(zc.zc_value, '@') = '\0'; 1621*5367Sahrens (void) strcat(zc.zc_value, snap); 1622*5367Sahrens } 1623*5367Sahrens } 1624*5367Sahrens } 1625*5367Sahrens 1626*5367Sahrens (void) strcpy(zc.zc_name, zc.zc_value); 1627*5367Sahrens *strchr(zc.zc_name, '@') = '\0'; 1628*5367Sahrens 1629*5367Sahrens if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { 1630*5367Sahrens zfs_handle_t *zhp; 1631*5367Sahrens /* 1632*5367Sahrens * Destination fs exists. Therefore this should either 1633*5367Sahrens * be an incremental, or the stream specifies a new fs 1634*5367Sahrens * (full stream or clone) and they want us to blow it 1635*5367Sahrens * away (and have therefore specified -F and removed any 1636*5367Sahrens * snapshots). 1637*5367Sahrens */ 1638*5367Sahrens 1639*5367Sahrens if (stream_wantsnewfs) { 1640*5367Sahrens if (!flags.force) { 1641*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1642*5367Sahrens "destination '%s' exists\n" 1643*5367Sahrens "must specify -F to overwrite it"), 1644*5367Sahrens zc.zc_name); 1645*5367Sahrens return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1646*5367Sahrens } 1647*5367Sahrens if (ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 1648*5367Sahrens &zc) == 0) { 1649*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1650*5367Sahrens "destination has snapshots (eg. %s)\n" 1651*5367Sahrens "must destroy them to overwrite it"), 1652*5367Sahrens zc.zc_name); 1653*5367Sahrens return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1654*5367Sahrens } 1655*5367Sahrens } 1656*5367Sahrens 1657*5367Sahrens zhp = zfs_open(hdl, zc.zc_name, 1658*5367Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 1659*5367Sahrens if (zhp == NULL) 1660*5367Sahrens return (-1); 1661*5367Sahrens if (stream_wantsnewfs && 1662*5367Sahrens zhp->zfs_dmustats.dds_origin[0]) { 1663*5367Sahrens zfs_close(zhp); 1664*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1665*5367Sahrens "destination '%s' is a clone\n" 1666*5367Sahrens "must destroy it to overwrite it"), 1667*5367Sahrens zc.zc_name); 1668*5367Sahrens return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1669*5367Sahrens } 1670*5367Sahrens 1671*5367Sahrens if (!flags.dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM && 1672*5367Sahrens stream_wantsnewfs) { 1673*5367Sahrens /* We can't do online recv in this case */ 1674*5367Sahrens clp = changelist_gather(zhp, ZFS_PROP_NAME, 0); 1675*5367Sahrens if (clp == NULL) 1676*5367Sahrens return (-1); 1677*5367Sahrens if (changelist_prefix(clp) != 0) { 1678*5367Sahrens changelist_free(clp); 1679*5367Sahrens return (-1); 1680*5367Sahrens } 1681*5367Sahrens } 1682*5367Sahrens if (!flags.dryrun && zhp->zfs_type == ZFS_TYPE_VOLUME) { 1683*5367Sahrens if (zvol_remove_link(hdl, zhp->zfs_name) != 0) { 1684*5367Sahrens zfs_close(zhp); 1685*5367Sahrens return (-1); 1686*5367Sahrens } 1687*5367Sahrens } 1688*5367Sahrens zfs_close(zhp); 1689*5367Sahrens } else { 1690*5367Sahrens /* 1691*5367Sahrens * Destination FS does not exist. Therefore we better 1692*5367Sahrens * be creating a new filesystem (either from a full 1693*5367Sahrens * backup, or a clone) 1694*5367Sahrens */ 1695*5367Sahrens 1696*5367Sahrens if (!stream_wantsnewfs) { 1697*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1698*5367Sahrens "destination '%s' does not exist"), zc.zc_name); 1699*5367Sahrens return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1700*5367Sahrens } 1701*5367Sahrens 1702*5367Sahrens /* Do the recvbackup ioctl to the fs's parent. */ 1703*5367Sahrens *strrchr(zc.zc_name, '/') = '\0'; 1704*5367Sahrens 1705*5367Sahrens if (flags.isprefix && !flags.dryrun) { 1706*5367Sahrens err = create_parents(hdl, zc.zc_value, strlen(tosnap)); 1707*5367Sahrens if (err != 0) { 1708*5367Sahrens return (zfs_error(hdl, 1709*5367Sahrens EZFS_BADRESTORE, errbuf)); 1710*5367Sahrens } 1711*5367Sahrens } 1712*5367Sahrens 1713*5367Sahrens newfs = B_TRUE; 1714*5367Sahrens } 1715*5367Sahrens 1716*5367Sahrens zc.zc_begin_record = drr_noswap->drr_u.drr_begin; 1717*5367Sahrens zc.zc_cookie = infd; 1718*5367Sahrens zc.zc_guid = flags.force; 1719*5367Sahrens if (flags.verbose) { 1720*5367Sahrens (void) printf("%s %s stream of %s into %s\n", 1721*5367Sahrens flags.dryrun ? "would receive" : "receiving", 1722*5367Sahrens drrb->drr_fromguid ? "incremental" : "full", 1723*5367Sahrens drrb->drr_toname, zc.zc_value); 1724*5367Sahrens (void) fflush(stdout); 1725*5367Sahrens } 1726*5367Sahrens 1727*5367Sahrens if (flags.dryrun) 1728*5367Sahrens return (recv_skip(hdl, infd, flags.byteswap)); 1729*5367Sahrens 1730*5367Sahrens err = ioctl_err = zfs_ioctl(hdl, ZFS_IOC_RECV, &zc); 1731*5367Sahrens ioctl_errno = errno; 1732*5367Sahrens if (err && (ioctl_errno == ENOENT || ioctl_errno == ENODEV)) { 1733*5367Sahrens /* 1734*5367Sahrens * It may be that this snapshot already exists, 1735*5367Sahrens * in which case we want to consume & ignore it 1736*5367Sahrens * rather than failing. 1737*5367Sahrens */ 1738*5367Sahrens avl_tree_t *local_avl; 1739*5367Sahrens nvlist_t *local_nv, *fs; 1740*5367Sahrens char *cp = strchr(zc.zc_value, '@'); 1741*5367Sahrens 1742*5367Sahrens /* 1743*5367Sahrens * XXX Do this faster by just iterating over snaps in 1744*5367Sahrens * this fs. Also if zc_value does not exist, we will 1745*5367Sahrens * get a strange "does not exist" error message. 1746*5367Sahrens */ 1747*5367Sahrens *cp = '\0'; 1748*5367Sahrens if (gather_nvlist(hdl, zc.zc_value, NULL, NULL, 1749*5367Sahrens &local_nv, &local_avl) == 0) { 1750*5367Sahrens *cp = '@'; 1751*5367Sahrens fs = fsavl_find(local_avl, drrb->drr_toguid, NULL); 1752*5367Sahrens fsavl_destroy(local_avl); 1753*5367Sahrens nvlist_free(local_nv); 1754*5367Sahrens 1755*5367Sahrens if (fs != NULL) { 1756*5367Sahrens if (flags.verbose) { 1757*5367Sahrens (void) printf("snap %s already exists; " 1758*5367Sahrens "ignoring\n", zc.zc_value); 1759*5367Sahrens } 1760*5367Sahrens ioctl_err = recv_skip(hdl, infd, 1761*5367Sahrens flags.byteswap); 1762*5367Sahrens } 1763*5367Sahrens } 1764*5367Sahrens *cp = '@'; 1765*5367Sahrens } 1766*5367Sahrens 1767*5367Sahrens if (ioctl_err != 0) { 1768*5367Sahrens switch (ioctl_errno) { 1769*5367Sahrens case ENODEV: 1770*5367Sahrens cp = strchr(zc.zc_value, '@'); 1771*5367Sahrens *cp = '\0'; 1772*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1773*5367Sahrens "most recent snapshot of %s does not\n" 1774*5367Sahrens "match incremental source"), zc.zc_value); 1775*5367Sahrens (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 1776*5367Sahrens *cp = '@'; 1777*5367Sahrens break; 1778*5367Sahrens case ETXTBSY: 1779*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1780*5367Sahrens "destination %s has been modified\n" 1781*5367Sahrens "since most recent snapshot"), zc.zc_name); 1782*5367Sahrens (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 1783*5367Sahrens break; 1784*5367Sahrens case EEXIST: 1785*5367Sahrens cp = strchr(zc.zc_value, '@'); 1786*5367Sahrens if (newfs) { 1787*5367Sahrens /* it's the containing fs that exists */ 1788*5367Sahrens *cp = '\0'; 1789*5367Sahrens } 1790*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1791*5367Sahrens "destination already exists")); 1792*5367Sahrens (void) zfs_error_fmt(hdl, EZFS_EXISTS, 1793*5367Sahrens dgettext(TEXT_DOMAIN, "cannot restore to %s"), 1794*5367Sahrens zc.zc_value); 1795*5367Sahrens *cp = '@'; 1796*5367Sahrens break; 1797*5367Sahrens case EINVAL: 1798*5367Sahrens (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 1799*5367Sahrens break; 1800*5367Sahrens case ECKSUM: 1801*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1802*5367Sahrens "invalid stream (checksum mismatch)")); 1803*5367Sahrens (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 1804*5367Sahrens break; 1805*5367Sahrens default: 1806*5367Sahrens (void) zfs_standard_error(hdl, ioctl_errno, errbuf); 1807*5367Sahrens } 1808*5367Sahrens } 1809*5367Sahrens 1810*5367Sahrens /* 1811*5367Sahrens * Mount or recreate the /dev links for the target filesystem 1812*5367Sahrens * (if created, or if we tore them down to do an incremental 1813*5367Sahrens * restore), and the /dev links for the new snapshot (if 1814*5367Sahrens * created). Also mount any children of the target filesystem 1815*5367Sahrens * if we did an incremental receive. 1816*5367Sahrens */ 1817*5367Sahrens cp = strchr(zc.zc_value, '@'); 1818*5367Sahrens if (cp && (ioctl_err == 0 || !newfs)) { 1819*5367Sahrens zfs_handle_t *h; 1820*5367Sahrens 1821*5367Sahrens *cp = '\0'; 1822*5367Sahrens h = zfs_open(hdl, zc.zc_value, 1823*5367Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 1824*5367Sahrens *cp = '@'; 1825*5367Sahrens if (h) { 1826*5367Sahrens if (h->zfs_type == ZFS_TYPE_VOLUME) { 1827*5367Sahrens err = zvol_create_link(hdl, h->zfs_name); 1828*5367Sahrens if (err == 0 && ioctl_err == 0) 1829*5367Sahrens err = zvol_create_link(hdl, 1830*5367Sahrens zc.zc_value); 1831*5367Sahrens } else if (newfs) { 1832*5367Sahrens err = zfs_mount(h, NULL, 0); 1833*5367Sahrens } 1834*5367Sahrens zfs_close(h); 1835*5367Sahrens } 1836*5367Sahrens } 1837*5367Sahrens 1838*5367Sahrens if (clp) { 1839*5367Sahrens err |= changelist_postfix(clp); 1840*5367Sahrens changelist_free(clp); 1841*5367Sahrens } 1842*5367Sahrens 1843*5367Sahrens if (err || ioctl_err) 1844*5367Sahrens return (-1); 1845*5367Sahrens 1846*5367Sahrens if (flags.verbose) { 1847*5367Sahrens char buf1[64]; 1848*5367Sahrens char buf2[64]; 1849*5367Sahrens uint64_t bytes = zc.zc_cookie; 1850*5367Sahrens time_t delta = time(NULL) - begin_time; 1851*5367Sahrens if (delta == 0) 1852*5367Sahrens delta = 1; 1853*5367Sahrens zfs_nicenum(bytes, buf1, sizeof (buf1)); 1854*5367Sahrens zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 1855*5367Sahrens 1856*5367Sahrens (void) printf("received %sB stream in %lu seconds (%sB/sec)\n", 1857*5367Sahrens buf1, delta, buf2); 1858*5367Sahrens } 1859*5367Sahrens 1860*5367Sahrens return (0); 1861*5367Sahrens } 1862*5367Sahrens 1863*5367Sahrens /* 1864*5367Sahrens * Restores a backup of tosnap from the file descriptor specified by infd. 1865*5367Sahrens */ 1866*5367Sahrens int 1867*5367Sahrens zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags, 1868*5367Sahrens int infd, avl_tree_t *stream_avl) 1869*5367Sahrens { 1870*5367Sahrens int err; 1871*5367Sahrens dmu_replay_record_t drr, drr_noswap; 1872*5367Sahrens struct drr_begin *drrb = &drr.drr_u.drr_begin; 1873*5367Sahrens char errbuf[1024]; 1874*5367Sahrens zio_cksum_t zcksum = { 0 }; 1875*5367Sahrens 1876*5367Sahrens (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1877*5367Sahrens "cannot receive")); 1878*5367Sahrens 1879*5367Sahrens if (flags.isprefix && 1880*5367Sahrens !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) { 1881*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs " 1882*5367Sahrens "(%s) does not exist"), tosnap); 1883*5367Sahrens return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1884*5367Sahrens } 1885*5367Sahrens 1886*5367Sahrens /* read in the BEGIN record */ 1887*5367Sahrens if (0 != (err = recv_read(hdl, infd, &drr, sizeof (drr), B_FALSE, 1888*5367Sahrens &zcksum))) 1889*5367Sahrens return (err); 1890*5367Sahrens 1891*5367Sahrens if (drr.drr_type == DRR_END || drr.drr_type == BSWAP_32(DRR_END)) { 1892*5367Sahrens /* It's the double end record at the end of a package */ 1893*5367Sahrens return (ENODATA); 1894*5367Sahrens } 1895*5367Sahrens 1896*5367Sahrens /* the kernel needs the non-byteswapped begin record */ 1897*5367Sahrens drr_noswap = drr; 1898*5367Sahrens 1899*5367Sahrens if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { 1900*5367Sahrens /* 1901*5367Sahrens * We computed the checksum in the wrong byteorder in 1902*5367Sahrens * recv_read() above; do it again correctly. 1903*5367Sahrens */ 1904*5367Sahrens bzero(&zcksum, sizeof (zio_cksum_t)); 1905*5367Sahrens fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum); 1906*5367Sahrens flags.byteswap = B_TRUE; 1907*5367Sahrens 1908*5367Sahrens drr.drr_type = BSWAP_32(drr.drr_type); 1909*5367Sahrens drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen); 1910*5367Sahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 1911*5367Sahrens drrb->drr_version = BSWAP_64(drrb->drr_version); 1912*5367Sahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 1913*5367Sahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 1914*5367Sahrens drrb->drr_flags = BSWAP_32(drrb->drr_flags); 1915*5367Sahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 1916*5367Sahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 1917*5367Sahrens } 1918*5367Sahrens 1919*5367Sahrens if (drrb->drr_magic != DMU_BACKUP_MAGIC || drr.drr_type != DRR_BEGIN) { 1920*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 1921*5367Sahrens "stream (bad magic number)")); 1922*5367Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 1923*5367Sahrens } 1924*5367Sahrens 1925*5367Sahrens if (strchr(drrb->drr_toname, '@') == NULL) { 1926*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 1927*5367Sahrens "stream (bad snapshot name)")); 1928*5367Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 1929*5367Sahrens } 1930*5367Sahrens 1931*5367Sahrens if (drrb->drr_version == DMU_BACKUP_STREAM_VERSION) { 1932*5367Sahrens return (zfs_receive_one(hdl, infd, tosnap, flags, 1933*5367Sahrens &drr, &drr_noswap, stream_avl)); 1934*5367Sahrens } else if (drrb->drr_version == DMU_BACKUP_HEADER_VERSION) { 1935*5367Sahrens return (zfs_receive_package(hdl, infd, tosnap, flags, 1936*5367Sahrens &drr, &zcksum)); 1937*5367Sahrens } else { 1938*5367Sahrens zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1939*5367Sahrens "stream is unsupported version %llu"), 1940*5367Sahrens drrb->drr_version); 1941*5367Sahrens return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 1942*5367Sahrens } 1943*5367Sahrens } 1944