libzfs_sendrecv.c revision 209962
1185029Spjd/* 2185029Spjd * CDDL HEADER START 3185029Spjd * 4185029Spjd * The contents of this file are subject to the terms of the 5185029Spjd * Common Development and Distribution License (the "License"). 6185029Spjd * You may not use this file except in compliance with the License. 7185029Spjd * 8185029Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9185029Spjd * or http://www.opensolaris.org/os/licensing. 10185029Spjd * See the License for the specific language governing permissions 11185029Spjd * and limitations under the License. 12185029Spjd * 13185029Spjd * When distributing Covered Code, include this CDDL HEADER in each 14185029Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15185029Spjd * If applicable, add the following below this CDDL HEADER, with the 16185029Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17185029Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18185029Spjd * 19185029Spjd * CDDL HEADER END 20185029Spjd */ 21185029Spjd 22185029Spjd/* 23200516Sdelphij * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24185029Spjd * Use is subject to license terms. 25185029Spjd */ 26185029Spjd 27185029Spjd#include <assert.h> 28185029Spjd#include <ctype.h> 29185029Spjd#include <errno.h> 30185029Spjd#include <libintl.h> 31185029Spjd#include <stdio.h> 32185029Spjd#include <stdlib.h> 33185029Spjd#include <strings.h> 34185029Spjd#include <unistd.h> 35185029Spjd#include <stddef.h> 36185029Spjd#include <fcntl.h> 37186515Srwatson#include <sys/param.h> 38185029Spjd#include <sys/mount.h> 39185029Spjd#include <sys/mntent.h> 40185029Spjd#include <sys/mnttab.h> 41185029Spjd#include <sys/avl.h> 42185029Spjd#include <stddef.h> 43185029Spjd 44185029Spjd#include <libzfs.h> 45185029Spjd 46185029Spjd#include "zfs_namecheck.h" 47185029Spjd#include "zfs_prop.h" 48185029Spjd#include "libzfs_impl.h" 49185029Spjd 50185029Spjd#include <fletcher.c> /* XXX */ 51185029Spjd 52185029Spjd/* We need to use something for ENODATA. */ 53185029Spjd#define ENODATA EIDRM 54185029Spjd 55185029Spjdstatic int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t, 56185029Spjd int, avl_tree_t *, char **); 57185029Spjd 58185029Spjd/* 59185029Spjd * Routines for dealing with the AVL tree of fs-nvlists 60185029Spjd */ 61185029Spjdtypedef struct fsavl_node { 62185029Spjd avl_node_t fn_node; 63185029Spjd nvlist_t *fn_nvfs; 64185029Spjd char *fn_snapname; 65185029Spjd uint64_t fn_guid; 66185029Spjd} fsavl_node_t; 67185029Spjd 68185029Spjdstatic int 69185029Spjdfsavl_compare(const void *arg1, const void *arg2) 70185029Spjd{ 71185029Spjd const fsavl_node_t *fn1 = arg1; 72185029Spjd const fsavl_node_t *fn2 = arg2; 73185029Spjd 74185029Spjd if (fn1->fn_guid > fn2->fn_guid) 75185029Spjd return (+1); 76185029Spjd else if (fn1->fn_guid < fn2->fn_guid) 77185029Spjd return (-1); 78185029Spjd else 79185029Spjd return (0); 80185029Spjd} 81185029Spjd 82185029Spjd/* 83185029Spjd * Given the GUID of a snapshot, find its containing filesystem and 84185029Spjd * (optionally) name. 85185029Spjd */ 86185029Spjdstatic nvlist_t * 87185029Spjdfsavl_find(avl_tree_t *avl, uint64_t snapguid, char **snapname) 88185029Spjd{ 89185029Spjd fsavl_node_t fn_find; 90185029Spjd fsavl_node_t *fn; 91185029Spjd 92185029Spjd fn_find.fn_guid = snapguid; 93185029Spjd 94185029Spjd fn = avl_find(avl, &fn_find, NULL); 95185029Spjd if (fn) { 96185029Spjd if (snapname) 97185029Spjd *snapname = fn->fn_snapname; 98185029Spjd return (fn->fn_nvfs); 99185029Spjd } 100185029Spjd return (NULL); 101185029Spjd} 102185029Spjd 103185029Spjdstatic void 104185029Spjdfsavl_destroy(avl_tree_t *avl) 105185029Spjd{ 106185029Spjd fsavl_node_t *fn; 107185029Spjd void *cookie; 108185029Spjd 109185029Spjd if (avl == NULL) 110185029Spjd return; 111185029Spjd 112185029Spjd cookie = NULL; 113185029Spjd while ((fn = avl_destroy_nodes(avl, &cookie)) != NULL) 114185029Spjd free(fn); 115185029Spjd avl_destroy(avl); 116185029Spjd free(avl); 117185029Spjd} 118185029Spjd 119185029Spjdstatic avl_tree_t * 120185029Spjdfsavl_create(nvlist_t *fss) 121185029Spjd{ 122185029Spjd avl_tree_t *fsavl; 123185029Spjd nvpair_t *fselem = NULL; 124185029Spjd 125185029Spjd if ((fsavl = malloc(sizeof (avl_tree_t))) == NULL) 126185029Spjd return (NULL); 127185029Spjd 128185029Spjd avl_create(fsavl, fsavl_compare, sizeof (fsavl_node_t), 129185029Spjd offsetof(fsavl_node_t, fn_node)); 130185029Spjd 131185029Spjd while ((fselem = nvlist_next_nvpair(fss, fselem)) != NULL) { 132185029Spjd nvlist_t *nvfs, *snaps; 133185029Spjd nvpair_t *snapelem = NULL; 134185029Spjd 135185029Spjd VERIFY(0 == nvpair_value_nvlist(fselem, &nvfs)); 136185029Spjd VERIFY(0 == nvlist_lookup_nvlist(nvfs, "snaps", &snaps)); 137185029Spjd 138185029Spjd while ((snapelem = 139185029Spjd nvlist_next_nvpair(snaps, snapelem)) != NULL) { 140185029Spjd fsavl_node_t *fn; 141185029Spjd uint64_t guid; 142185029Spjd 143185029Spjd VERIFY(0 == nvpair_value_uint64(snapelem, &guid)); 144185029Spjd if ((fn = malloc(sizeof (fsavl_node_t))) == NULL) { 145185029Spjd fsavl_destroy(fsavl); 146185029Spjd return (NULL); 147185029Spjd } 148185029Spjd fn->fn_nvfs = nvfs; 149185029Spjd fn->fn_snapname = nvpair_name(snapelem); 150185029Spjd fn->fn_guid = guid; 151185029Spjd 152185029Spjd /* 153185029Spjd * Note: if there are multiple snaps with the 154185029Spjd * same GUID, we ignore all but one. 155185029Spjd */ 156185029Spjd if (avl_find(fsavl, fn, NULL) == NULL) 157185029Spjd avl_add(fsavl, fn); 158185029Spjd else 159185029Spjd free(fn); 160185029Spjd } 161185029Spjd } 162185029Spjd 163185029Spjd return (fsavl); 164185029Spjd} 165185029Spjd 166185029Spjd/* 167185029Spjd * Routines for dealing with the giant nvlist of fs-nvlists, etc. 168185029Spjd */ 169185029Spjdtypedef struct send_data { 170185029Spjd uint64_t parent_fromsnap_guid; 171185029Spjd nvlist_t *parent_snaps; 172185029Spjd nvlist_t *fss; 173185029Spjd nvlist_t *snapprops; 174185029Spjd const char *fromsnap; 175185029Spjd const char *tosnap; 176185029Spjd 177185029Spjd /* 178185029Spjd * The header nvlist is of the following format: 179185029Spjd * { 180185029Spjd * "tosnap" -> string 181185029Spjd * "fromsnap" -> string (if incremental) 182185029Spjd * "fss" -> { 183185029Spjd * id -> { 184185029Spjd * 185185029Spjd * "name" -> string (full name; for debugging) 186185029Spjd * "parentfromsnap" -> number (guid of fromsnap in parent) 187185029Spjd * 188185029Spjd * "props" -> { name -> value (only if set here) } 189185029Spjd * "snaps" -> { name (lastname) -> number (guid) } 190185029Spjd * "snapprops" -> { name (lastname) -> { name -> value } } 191185029Spjd * 192185029Spjd * "origin" -> number (guid) (if clone) 193185029Spjd * "sent" -> boolean (not on-disk) 194185029Spjd * } 195185029Spjd * } 196185029Spjd * } 197185029Spjd * 198185029Spjd */ 199185029Spjd} send_data_t; 200185029Spjd 201185029Spjdstatic void send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv); 202185029Spjd 203185029Spjdstatic int 204185029Spjdsend_iterate_snap(zfs_handle_t *zhp, void *arg) 205185029Spjd{ 206185029Spjd send_data_t *sd = arg; 207185029Spjd uint64_t guid = zhp->zfs_dmustats.dds_guid; 208185029Spjd char *snapname; 209185029Spjd nvlist_t *nv; 210185029Spjd 211185029Spjd snapname = strrchr(zhp->zfs_name, '@')+1; 212185029Spjd 213185029Spjd VERIFY(0 == nvlist_add_uint64(sd->parent_snaps, snapname, guid)); 214185029Spjd /* 215185029Spjd * NB: if there is no fromsnap here (it's a newly created fs in 216185029Spjd * an incremental replication), we will substitute the tosnap. 217185029Spjd */ 218185029Spjd if ((sd->fromsnap && strcmp(snapname, sd->fromsnap) == 0) || 219185029Spjd (sd->parent_fromsnap_guid == 0 && sd->tosnap && 220185029Spjd strcmp(snapname, sd->tosnap) == 0)) { 221185029Spjd sd->parent_fromsnap_guid = guid; 222185029Spjd } 223185029Spjd 224185029Spjd VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0)); 225185029Spjd send_iterate_prop(zhp, nv); 226185029Spjd VERIFY(0 == nvlist_add_nvlist(sd->snapprops, snapname, nv)); 227185029Spjd nvlist_free(nv); 228185029Spjd 229185029Spjd zfs_close(zhp); 230185029Spjd return (0); 231185029Spjd} 232185029Spjd 233185029Spjdstatic void 234185029Spjdsend_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv) 235185029Spjd{ 236185029Spjd nvpair_t *elem = NULL; 237185029Spjd 238185029Spjd while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) { 239185029Spjd char *propname = nvpair_name(elem); 240185029Spjd zfs_prop_t prop = zfs_name_to_prop(propname); 241185029Spjd nvlist_t *propnv; 242185029Spjd 243209962Smm assert(zfs_prop_user(propname) || prop != ZPROP_INVAL); 244209962Smm 245185029Spjd if (!zfs_prop_user(propname) && zfs_prop_readonly(prop)) 246185029Spjd continue; 247185029Spjd 248185029Spjd verify(nvpair_value_nvlist(elem, &propnv) == 0); 249185029Spjd if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION) { 250185029Spjd /* these guys are modifyable, but have no source */ 251185029Spjd uint64_t value; 252185029Spjd verify(nvlist_lookup_uint64(propnv, 253185029Spjd ZPROP_VALUE, &value) == 0); 254185029Spjd if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) 255185029Spjd continue; 256185029Spjd } else { 257185029Spjd char *source; 258185029Spjd if (nvlist_lookup_string(propnv, 259185029Spjd ZPROP_SOURCE, &source) != 0) 260185029Spjd continue; 261185029Spjd if (strcmp(source, zhp->zfs_name) != 0) 262185029Spjd continue; 263185029Spjd } 264185029Spjd 265185029Spjd if (zfs_prop_user(propname) || 266185029Spjd zfs_prop_get_type(prop) == PROP_TYPE_STRING) { 267185029Spjd char *value; 268185029Spjd verify(nvlist_lookup_string(propnv, 269185029Spjd ZPROP_VALUE, &value) == 0); 270185029Spjd VERIFY(0 == nvlist_add_string(nv, propname, value)); 271185029Spjd } else { 272185029Spjd uint64_t value; 273185029Spjd verify(nvlist_lookup_uint64(propnv, 274185029Spjd ZPROP_VALUE, &value) == 0); 275185029Spjd VERIFY(0 == nvlist_add_uint64(nv, propname, value)); 276185029Spjd } 277185029Spjd } 278185029Spjd} 279185029Spjd 280185029Spjdstatic int 281185029Spjdsend_iterate_fs(zfs_handle_t *zhp, void *arg) 282185029Spjd{ 283185029Spjd send_data_t *sd = arg; 284185029Spjd nvlist_t *nvfs, *nv; 285185029Spjd int rv; 286185029Spjd uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid; 287185029Spjd uint64_t guid = zhp->zfs_dmustats.dds_guid; 288185029Spjd char guidstring[64]; 289185029Spjd 290185029Spjd VERIFY(0 == nvlist_alloc(&nvfs, NV_UNIQUE_NAME, 0)); 291185029Spjd VERIFY(0 == nvlist_add_string(nvfs, "name", zhp->zfs_name)); 292185029Spjd VERIFY(0 == nvlist_add_uint64(nvfs, "parentfromsnap", 293185029Spjd sd->parent_fromsnap_guid)); 294185029Spjd 295185029Spjd if (zhp->zfs_dmustats.dds_origin[0]) { 296185029Spjd zfs_handle_t *origin = zfs_open(zhp->zfs_hdl, 297185029Spjd zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT); 298185029Spjd if (origin == NULL) 299185029Spjd return (-1); 300185029Spjd VERIFY(0 == nvlist_add_uint64(nvfs, "origin", 301185029Spjd origin->zfs_dmustats.dds_guid)); 302185029Spjd } 303185029Spjd 304185029Spjd /* iterate over props */ 305185029Spjd VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0)); 306185029Spjd send_iterate_prop(zhp, nv); 307185029Spjd VERIFY(0 == nvlist_add_nvlist(nvfs, "props", nv)); 308185029Spjd nvlist_free(nv); 309185029Spjd 310185029Spjd /* iterate over snaps, and set sd->parent_fromsnap_guid */ 311185029Spjd sd->parent_fromsnap_guid = 0; 312185029Spjd VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0)); 313185029Spjd VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0)); 314185029Spjd (void) zfs_iter_snapshots(zhp, send_iterate_snap, sd); 315185029Spjd VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps)); 316185029Spjd VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops)); 317185029Spjd nvlist_free(sd->parent_snaps); 318185029Spjd nvlist_free(sd->snapprops); 319185029Spjd 320185029Spjd /* add this fs to nvlist */ 321185029Spjd (void) snprintf(guidstring, sizeof (guidstring), 322185029Spjd "0x%llx", (longlong_t)guid); 323185029Spjd VERIFY(0 == nvlist_add_nvlist(sd->fss, guidstring, nvfs)); 324185029Spjd nvlist_free(nvfs); 325185029Spjd 326185029Spjd /* iterate over children */ 327185029Spjd rv = zfs_iter_filesystems(zhp, send_iterate_fs, sd); 328185029Spjd 329185029Spjd sd->parent_fromsnap_guid = parent_fromsnap_guid_save; 330185029Spjd 331185029Spjd zfs_close(zhp); 332185029Spjd return (rv); 333185029Spjd} 334185029Spjd 335185029Spjdstatic int 336185029Spjdgather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, 337185029Spjd const char *tosnap, nvlist_t **nvlp, avl_tree_t **avlp) 338185029Spjd{ 339185029Spjd zfs_handle_t *zhp; 340185029Spjd send_data_t sd = { 0 }; 341185029Spjd int error; 342185029Spjd 343185029Spjd zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 344185029Spjd if (zhp == NULL) 345185029Spjd return (EZFS_BADTYPE); 346185029Spjd 347185029Spjd VERIFY(0 == nvlist_alloc(&sd.fss, NV_UNIQUE_NAME, 0)); 348185029Spjd sd.fromsnap = fromsnap; 349185029Spjd sd.tosnap = tosnap; 350185029Spjd 351185029Spjd if ((error = send_iterate_fs(zhp, &sd)) != 0) { 352185029Spjd nvlist_free(sd.fss); 353185029Spjd if (avlp != NULL) 354185029Spjd *avlp = NULL; 355185029Spjd *nvlp = NULL; 356185029Spjd return (error); 357185029Spjd } 358185029Spjd 359185029Spjd if (avlp != NULL && (*avlp = fsavl_create(sd.fss)) == NULL) { 360185029Spjd nvlist_free(sd.fss); 361185029Spjd *nvlp = NULL; 362185029Spjd return (EZFS_NOMEM); 363185029Spjd } 364185029Spjd 365185029Spjd *nvlp = sd.fss; 366185029Spjd return (0); 367185029Spjd} 368185029Spjd 369185029Spjd/* 370185029Spjd * Routines for dealing with the sorted snapshot functionality 371185029Spjd */ 372185029Spjdtypedef struct zfs_node { 373185029Spjd zfs_handle_t *zn_handle; 374185029Spjd avl_node_t zn_avlnode; 375185029Spjd} zfs_node_t; 376185029Spjd 377185029Spjdstatic int 378185029Spjdzfs_sort_snaps(zfs_handle_t *zhp, void *data) 379185029Spjd{ 380185029Spjd avl_tree_t *avl = data; 381185029Spjd zfs_node_t *node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t)); 382185029Spjd 383185029Spjd node->zn_handle = zhp; 384185029Spjd avl_add(avl, node); 385185029Spjd return (0); 386185029Spjd} 387185029Spjd 388185029Spjd/* ARGSUSED */ 389185029Spjdstatic int 390185029Spjdzfs_snapshot_compare(const void *larg, const void *rarg) 391185029Spjd{ 392185029Spjd zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle; 393185029Spjd zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle; 394185029Spjd uint64_t lcreate, rcreate; 395185029Spjd 396185029Spjd /* 397185029Spjd * Sort them according to creation time. We use the hidden 398185029Spjd * CREATETXG property to get an absolute ordering of snapshots. 399185029Spjd */ 400185029Spjd lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG); 401185029Spjd rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG); 402185029Spjd 403185029Spjd if (lcreate < rcreate) 404185029Spjd return (-1); 405185029Spjd else if (lcreate > rcreate) 406185029Spjd return (+1); 407185029Spjd else 408185029Spjd return (0); 409185029Spjd} 410185029Spjd 411185029Spjdstatic int 412185029Spjdzfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data) 413185029Spjd{ 414185029Spjd int ret = 0; 415185029Spjd zfs_node_t *node; 416185029Spjd avl_tree_t avl; 417185029Spjd void *cookie = NULL; 418185029Spjd 419185029Spjd avl_create(&avl, zfs_snapshot_compare, 420185029Spjd sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode)); 421185029Spjd 422185029Spjd ret = zfs_iter_snapshots(zhp, zfs_sort_snaps, &avl); 423185029Spjd 424185029Spjd for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node)) 425185029Spjd ret |= callback(node->zn_handle, data); 426185029Spjd 427185029Spjd while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL) 428185029Spjd free(node); 429185029Spjd 430185029Spjd avl_destroy(&avl); 431185029Spjd 432185029Spjd return (ret); 433185029Spjd} 434185029Spjd 435185029Spjd/* 436185029Spjd * Routines specific to "zfs send" 437185029Spjd */ 438185029Spjdtypedef struct send_dump_data { 439185029Spjd /* these are all just the short snapname (the part after the @) */ 440185029Spjd const char *fromsnap; 441185029Spjd const char *tosnap; 442185029Spjd char lastsnap[ZFS_MAXNAMELEN]; 443185029Spjd boolean_t seenfrom, seento, replicate, doall, fromorigin; 444185029Spjd boolean_t verbose; 445185029Spjd int outfd; 446185029Spjd boolean_t err; 447185029Spjd nvlist_t *fss; 448185029Spjd avl_tree_t *fsavl; 449185029Spjd} send_dump_data_t; 450185029Spjd 451185029Spjd/* 452185029Spjd * Dumps a backup of the given snapshot (incremental from fromsnap if it's not 453185029Spjd * NULL) to the file descriptor specified by outfd. 454185029Spjd */ 455185029Spjdstatic int 456185029Spjddump_ioctl(zfs_handle_t *zhp, const char *fromsnap, boolean_t fromorigin, 457185029Spjd int outfd) 458185029Spjd{ 459185029Spjd zfs_cmd_t zc = { 0 }; 460185029Spjd libzfs_handle_t *hdl = zhp->zfs_hdl; 461185029Spjd 462185029Spjd assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 463185029Spjd assert(fromsnap == NULL || fromsnap[0] == '\0' || !fromorigin); 464185029Spjd 465185029Spjd (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 466185029Spjd if (fromsnap) 467185029Spjd (void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_value)); 468185029Spjd zc.zc_cookie = outfd; 469185029Spjd zc.zc_obj = fromorigin; 470185029Spjd 471185029Spjd if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SEND, &zc) != 0) { 472185029Spjd char errbuf[1024]; 473185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 474185029Spjd "warning: cannot send '%s'"), zhp->zfs_name); 475185029Spjd 476185029Spjd switch (errno) { 477185029Spjd 478185029Spjd case EXDEV: 479185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 480185029Spjd "not an earlier snapshot from the same fs")); 481185029Spjd return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 482185029Spjd 483185029Spjd case ENOENT: 484185029Spjd if (zfs_dataset_exists(hdl, zc.zc_name, 485185029Spjd ZFS_TYPE_SNAPSHOT)) { 486185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 487185029Spjd "incremental source (@%s) does not exist"), 488185029Spjd zc.zc_value); 489185029Spjd } 490185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 491185029Spjd 492185029Spjd case EDQUOT: 493185029Spjd case EFBIG: 494185029Spjd case EIO: 495185029Spjd case ENOLINK: 496185029Spjd case ENOSPC: 497185029Spjd case ENXIO: 498185029Spjd case EPIPE: 499185029Spjd case ERANGE: 500185029Spjd case EFAULT: 501185029Spjd case EROFS: 502185029Spjd zfs_error_aux(hdl, strerror(errno)); 503185029Spjd return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 504185029Spjd 505185029Spjd default: 506185029Spjd return (zfs_standard_error(hdl, errno, errbuf)); 507185029Spjd } 508185029Spjd } 509185029Spjd 510185029Spjd return (0); 511185029Spjd} 512185029Spjd 513185029Spjdstatic int 514185029Spjddump_snapshot(zfs_handle_t *zhp, void *arg) 515185029Spjd{ 516185029Spjd send_dump_data_t *sdd = arg; 517185029Spjd const char *thissnap; 518185029Spjd int err; 519185029Spjd 520185029Spjd thissnap = strchr(zhp->zfs_name, '@') + 1; 521185029Spjd 522185029Spjd if (sdd->fromsnap && !sdd->seenfrom && 523185029Spjd strcmp(sdd->fromsnap, thissnap) == 0) { 524185029Spjd sdd->seenfrom = B_TRUE; 525185029Spjd (void) strcpy(sdd->lastsnap, thissnap); 526185029Spjd zfs_close(zhp); 527185029Spjd return (0); 528185029Spjd } 529185029Spjd 530185029Spjd if (sdd->seento || !sdd->seenfrom) { 531185029Spjd zfs_close(zhp); 532185029Spjd return (0); 533185029Spjd } 534185029Spjd 535185029Spjd /* send it */ 536185029Spjd if (sdd->verbose) { 537185029Spjd (void) fprintf(stderr, "sending from @%s to %s\n", 538185029Spjd sdd->lastsnap, zhp->zfs_name); 539185029Spjd } 540185029Spjd 541185029Spjd err = dump_ioctl(zhp, sdd->lastsnap, 542185029Spjd sdd->lastsnap[0] == '\0' && (sdd->fromorigin || sdd->replicate), 543185029Spjd sdd->outfd); 544185029Spjd 545185029Spjd if (!sdd->seento && strcmp(sdd->tosnap, thissnap) == 0) 546185029Spjd sdd->seento = B_TRUE; 547185029Spjd 548185029Spjd (void) strcpy(sdd->lastsnap, thissnap); 549185029Spjd zfs_close(zhp); 550185029Spjd return (err); 551185029Spjd} 552185029Spjd 553185029Spjdstatic int 554185029Spjddump_filesystem(zfs_handle_t *zhp, void *arg) 555185029Spjd{ 556185029Spjd int rv = 0; 557185029Spjd send_dump_data_t *sdd = arg; 558185029Spjd boolean_t missingfrom = B_FALSE; 559185029Spjd zfs_cmd_t zc = { 0 }; 560185029Spjd 561185029Spjd (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s", 562185029Spjd zhp->zfs_name, sdd->tosnap); 563185029Spjd if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 564185029Spjd (void) fprintf(stderr, "WARNING: " 565185029Spjd "could not send %s@%s: does not exist\n", 566185029Spjd zhp->zfs_name, sdd->tosnap); 567185029Spjd sdd->err = B_TRUE; 568185029Spjd return (0); 569185029Spjd } 570185029Spjd 571185029Spjd if (sdd->replicate && sdd->fromsnap) { 572185029Spjd /* 573185029Spjd * If this fs does not have fromsnap, and we're doing 574185029Spjd * recursive, we need to send a full stream from the 575185029Spjd * beginning (or an incremental from the origin if this 576185029Spjd * is a clone). If we're doing non-recursive, then let 577185029Spjd * them get the error. 578185029Spjd */ 579185029Spjd (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s", 580185029Spjd zhp->zfs_name, sdd->fromsnap); 581185029Spjd if (ioctl(zhp->zfs_hdl->libzfs_fd, 582185029Spjd ZFS_IOC_OBJSET_STATS, &zc) != 0) { 583185029Spjd missingfrom = B_TRUE; 584185029Spjd } 585185029Spjd } 586185029Spjd 587185029Spjd if (sdd->doall) { 588185029Spjd sdd->seenfrom = sdd->seento = sdd->lastsnap[0] = 0; 589185029Spjd if (sdd->fromsnap == NULL || missingfrom) 590185029Spjd sdd->seenfrom = B_TRUE; 591185029Spjd 592185029Spjd rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg); 593185029Spjd if (!sdd->seenfrom) { 594185029Spjd (void) fprintf(stderr, 595185029Spjd "WARNING: could not send %s@%s:\n" 596185029Spjd "incremental source (%s@%s) does not exist\n", 597185029Spjd zhp->zfs_name, sdd->tosnap, 598185029Spjd zhp->zfs_name, sdd->fromsnap); 599185029Spjd sdd->err = B_TRUE; 600185029Spjd } else if (!sdd->seento) { 601209962Smm if (sdd->fromsnap) { 602209962Smm (void) fprintf(stderr, 603209962Smm "WARNING: could not send %s@%s:\n" 604209962Smm "incremental source (%s@%s) " 605209962Smm "is not earlier than it\n", 606209962Smm zhp->zfs_name, sdd->tosnap, 607209962Smm zhp->zfs_name, sdd->fromsnap); 608209962Smm } else { 609209962Smm (void) fprintf(stderr, "WARNING: " 610209962Smm "could not send %s@%s: does not exist\n", 611209962Smm zhp->zfs_name, sdd->tosnap); 612209962Smm } 613185029Spjd sdd->err = B_TRUE; 614185029Spjd } 615185029Spjd } else { 616185029Spjd zfs_handle_t *snapzhp; 617185029Spjd char snapname[ZFS_MAXNAMELEN]; 618185029Spjd 619185029Spjd (void) snprintf(snapname, sizeof (snapname), "%s@%s", 620185029Spjd zfs_get_name(zhp), sdd->tosnap); 621185029Spjd snapzhp = zfs_open(zhp->zfs_hdl, snapname, ZFS_TYPE_SNAPSHOT); 622185029Spjd if (snapzhp == NULL) { 623185029Spjd rv = -1; 624185029Spjd } else { 625185029Spjd rv = dump_ioctl(snapzhp, 626185029Spjd missingfrom ? NULL : sdd->fromsnap, 627185029Spjd sdd->fromorigin || missingfrom, 628185029Spjd sdd->outfd); 629185029Spjd sdd->seento = B_TRUE; 630185029Spjd zfs_close(snapzhp); 631185029Spjd } 632185029Spjd } 633185029Spjd 634185029Spjd return (rv); 635185029Spjd} 636185029Spjd 637185029Spjdstatic int 638185029Spjddump_filesystems(zfs_handle_t *rzhp, void *arg) 639185029Spjd{ 640185029Spjd send_dump_data_t *sdd = arg; 641185029Spjd nvpair_t *fspair; 642185029Spjd boolean_t needagain, progress; 643185029Spjd 644185029Spjd if (!sdd->replicate) 645185029Spjd return (dump_filesystem(rzhp, sdd)); 646185029Spjd 647185029Spjdagain: 648185029Spjd needagain = progress = B_FALSE; 649185029Spjd for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair; 650185029Spjd fspair = nvlist_next_nvpair(sdd->fss, fspair)) { 651185029Spjd nvlist_t *fslist; 652185029Spjd char *fsname; 653185029Spjd zfs_handle_t *zhp; 654185029Spjd int err; 655185029Spjd uint64_t origin_guid = 0; 656185029Spjd nvlist_t *origin_nv; 657185029Spjd 658185029Spjd VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0); 659185029Spjd if (nvlist_lookup_boolean(fslist, "sent") == 0) 660185029Spjd continue; 661185029Spjd 662185029Spjd VERIFY(nvlist_lookup_string(fslist, "name", &fsname) == 0); 663185029Spjd (void) nvlist_lookup_uint64(fslist, "origin", &origin_guid); 664185029Spjd 665185029Spjd origin_nv = fsavl_find(sdd->fsavl, origin_guid, NULL); 666185029Spjd if (origin_nv && 667185029Spjd nvlist_lookup_boolean(origin_nv, "sent") == ENOENT) { 668185029Spjd /* 669185029Spjd * origin has not been sent yet; 670185029Spjd * skip this clone. 671185029Spjd */ 672185029Spjd needagain = B_TRUE; 673185029Spjd continue; 674185029Spjd } 675185029Spjd 676185029Spjd zhp = zfs_open(rzhp->zfs_hdl, fsname, ZFS_TYPE_DATASET); 677185029Spjd if (zhp == NULL) 678185029Spjd return (-1); 679185029Spjd err = dump_filesystem(zhp, sdd); 680185029Spjd VERIFY(nvlist_add_boolean(fslist, "sent") == 0); 681185029Spjd progress = B_TRUE; 682185029Spjd zfs_close(zhp); 683185029Spjd if (err) 684185029Spjd return (err); 685185029Spjd } 686185029Spjd if (needagain) { 687185029Spjd assert(progress); 688185029Spjd goto again; 689185029Spjd } 690185029Spjd return (0); 691185029Spjd} 692185029Spjd 693185029Spjd/* 694185029Spjd * Dumps a backup of tosnap, incremental from fromsnap if it isn't NULL. 695185029Spjd * If 'doall', dump all intermediate snaps. 696185029Spjd * If 'replicate', dump special header and do recursively. 697185029Spjd */ 698185029Spjdint 699185029Spjdzfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, 700185029Spjd boolean_t replicate, boolean_t doall, boolean_t fromorigin, 701185029Spjd boolean_t verbose, int outfd) 702185029Spjd{ 703185029Spjd char errbuf[1024]; 704185029Spjd send_dump_data_t sdd = { 0 }; 705185029Spjd int err; 706185029Spjd nvlist_t *fss = NULL; 707185029Spjd avl_tree_t *fsavl = NULL; 708185029Spjd 709185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 710185029Spjd "cannot send '%s'"), zhp->zfs_name); 711185029Spjd 712185029Spjd if (fromsnap && fromsnap[0] == '\0') { 713185029Spjd zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 714185029Spjd "zero-length incremental source")); 715185029Spjd return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); 716185029Spjd } 717185029Spjd 718185029Spjd if (replicate || doall) { 719185029Spjd dmu_replay_record_t drr = { 0 }; 720185029Spjd char *packbuf = NULL; 721185029Spjd size_t buflen = 0; 722185029Spjd zio_cksum_t zc = { 0 }; 723185029Spjd 724185029Spjd assert(fromsnap || doall); 725185029Spjd 726185029Spjd if (replicate) { 727185029Spjd nvlist_t *hdrnv; 728185029Spjd 729185029Spjd VERIFY(0 == nvlist_alloc(&hdrnv, NV_UNIQUE_NAME, 0)); 730185029Spjd if (fromsnap) { 731185029Spjd VERIFY(0 == nvlist_add_string(hdrnv, 732185029Spjd "fromsnap", fromsnap)); 733185029Spjd } 734185029Spjd VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap)); 735185029Spjd 736185029Spjd err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name, 737185029Spjd fromsnap, tosnap, &fss, &fsavl); 738185029Spjd if (err) 739185029Spjd return (err); 740185029Spjd VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss)); 741185029Spjd err = nvlist_pack(hdrnv, &packbuf, &buflen, 742185029Spjd NV_ENCODE_XDR, 0); 743185029Spjd nvlist_free(hdrnv); 744185029Spjd if (err) { 745185029Spjd fsavl_destroy(fsavl); 746185029Spjd nvlist_free(fss); 747185029Spjd return (zfs_standard_error(zhp->zfs_hdl, 748185029Spjd err, errbuf)); 749185029Spjd } 750185029Spjd } 751185029Spjd 752185029Spjd /* write first begin record */ 753185029Spjd drr.drr_type = DRR_BEGIN; 754185029Spjd drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 755185029Spjd drr.drr_u.drr_begin.drr_version = DMU_BACKUP_HEADER_VERSION; 756185029Spjd (void) snprintf(drr.drr_u.drr_begin.drr_toname, 757185029Spjd sizeof (drr.drr_u.drr_begin.drr_toname), 758185029Spjd "%s@%s", zhp->zfs_name, tosnap); 759185029Spjd drr.drr_payloadlen = buflen; 760185029Spjd fletcher_4_incremental_native(&drr, sizeof (drr), &zc); 761185029Spjd err = write(outfd, &drr, sizeof (drr)); 762185029Spjd 763185029Spjd /* write header nvlist */ 764185029Spjd if (err != -1) { 765185029Spjd fletcher_4_incremental_native(packbuf, buflen, &zc); 766185029Spjd err = write(outfd, packbuf, buflen); 767185029Spjd } 768185029Spjd free(packbuf); 769185029Spjd if (err == -1) { 770185029Spjd fsavl_destroy(fsavl); 771185029Spjd nvlist_free(fss); 772185029Spjd return (zfs_standard_error(zhp->zfs_hdl, 773185029Spjd errno, errbuf)); 774185029Spjd } 775185029Spjd 776185029Spjd /* write end record */ 777185029Spjd if (err != -1) { 778185029Spjd bzero(&drr, sizeof (drr)); 779185029Spjd drr.drr_type = DRR_END; 780185029Spjd drr.drr_u.drr_end.drr_checksum = zc; 781185029Spjd err = write(outfd, &drr, sizeof (drr)); 782185029Spjd if (err == -1) { 783185029Spjd fsavl_destroy(fsavl); 784185029Spjd nvlist_free(fss); 785185029Spjd return (zfs_standard_error(zhp->zfs_hdl, 786185029Spjd errno, errbuf)); 787185029Spjd } 788185029Spjd } 789185029Spjd } 790185029Spjd 791185029Spjd /* dump each stream */ 792185029Spjd sdd.fromsnap = fromsnap; 793185029Spjd sdd.tosnap = tosnap; 794185029Spjd sdd.outfd = outfd; 795185029Spjd sdd.replicate = replicate; 796185029Spjd sdd.doall = doall; 797185029Spjd sdd.fromorigin = fromorigin; 798185029Spjd sdd.fss = fss; 799185029Spjd sdd.fsavl = fsavl; 800185029Spjd sdd.verbose = verbose; 801185029Spjd err = dump_filesystems(zhp, &sdd); 802185029Spjd fsavl_destroy(fsavl); 803185029Spjd nvlist_free(fss); 804185029Spjd 805185029Spjd if (replicate || doall) { 806185029Spjd /* 807185029Spjd * write final end record. NB: want to do this even if 808185029Spjd * there was some error, because it might not be totally 809185029Spjd * failed. 810185029Spjd */ 811185029Spjd dmu_replay_record_t drr = { 0 }; 812185029Spjd drr.drr_type = DRR_END; 813185029Spjd if (write(outfd, &drr, sizeof (drr)) == -1) { 814185029Spjd return (zfs_standard_error(zhp->zfs_hdl, 815185029Spjd errno, errbuf)); 816185029Spjd } 817185029Spjd } 818185029Spjd 819185029Spjd return (err || sdd.err); 820185029Spjd} 821185029Spjd 822185029Spjd/* 823185029Spjd * Routines specific to "zfs recv" 824185029Spjd */ 825185029Spjd 826185029Spjdstatic int 827185029Spjdrecv_read(libzfs_handle_t *hdl, int fd, void *buf, int ilen, 828185029Spjd boolean_t byteswap, zio_cksum_t *zc) 829185029Spjd{ 830185029Spjd char *cp = buf; 831185029Spjd int rv; 832185029Spjd int len = ilen; 833185029Spjd 834185029Spjd do { 835185029Spjd rv = read(fd, cp, len); 836185029Spjd cp += rv; 837185029Spjd len -= rv; 838185029Spjd } while (rv > 0); 839185029Spjd 840185029Spjd if (rv < 0 || len != 0) { 841185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 842185029Spjd "failed to read from stream")); 843185029Spjd return (zfs_error(hdl, EZFS_BADSTREAM, dgettext(TEXT_DOMAIN, 844185029Spjd "cannot receive"))); 845185029Spjd } 846185029Spjd 847185029Spjd if (zc) { 848185029Spjd if (byteswap) 849185029Spjd fletcher_4_incremental_byteswap(buf, ilen, zc); 850185029Spjd else 851185029Spjd fletcher_4_incremental_native(buf, ilen, zc); 852185029Spjd } 853185029Spjd return (0); 854185029Spjd} 855185029Spjd 856185029Spjdstatic int 857185029Spjdrecv_read_nvlist(libzfs_handle_t *hdl, int fd, int len, nvlist_t **nvp, 858185029Spjd boolean_t byteswap, zio_cksum_t *zc) 859185029Spjd{ 860185029Spjd char *buf; 861185029Spjd int err; 862185029Spjd 863185029Spjd buf = zfs_alloc(hdl, len); 864185029Spjd if (buf == NULL) 865185029Spjd return (ENOMEM); 866185029Spjd 867185029Spjd err = recv_read(hdl, fd, buf, len, byteswap, zc); 868185029Spjd if (err != 0) { 869185029Spjd free(buf); 870185029Spjd return (err); 871185029Spjd } 872185029Spjd 873185029Spjd err = nvlist_unpack(buf, len, nvp, 0); 874185029Spjd free(buf); 875185029Spjd if (err != 0) { 876185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 877185029Spjd "stream (malformed nvlist)")); 878185029Spjd return (EINVAL); 879185029Spjd } 880185029Spjd return (0); 881185029Spjd} 882185029Spjd 883185029Spjdstatic int 884185029Spjdrecv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname, 885185029Spjd int baselen, char *newname, recvflags_t flags) 886185029Spjd{ 887185029Spjd static int seq; 888185029Spjd zfs_cmd_t zc = { 0 }; 889185029Spjd int err; 890185029Spjd prop_changelist_t *clp; 891185029Spjd zfs_handle_t *zhp; 892185029Spjd 893185029Spjd zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET); 894185029Spjd if (zhp == NULL) 895185029Spjd return (-1); 896185029Spjd clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 897185029Spjd flags.force ? MS_FORCE : 0); 898185029Spjd zfs_close(zhp); 899185029Spjd if (clp == NULL) 900185029Spjd return (-1); 901185029Spjd err = changelist_prefix(clp); 902185029Spjd if (err) 903185029Spjd return (err); 904185029Spjd 905185029Spjd if (tryname) { 906185029Spjd (void) strcpy(newname, tryname); 907185029Spjd 908185029Spjd zc.zc_objset_type = DMU_OST_ZFS; 909185029Spjd (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); 910185029Spjd (void) strlcpy(zc.zc_value, tryname, sizeof (zc.zc_value)); 911185029Spjd 912185029Spjd if (flags.verbose) { 913185029Spjd (void) printf("attempting rename %s to %s\n", 914185029Spjd zc.zc_name, zc.zc_value); 915185029Spjd } 916185029Spjd err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc); 917185029Spjd if (err == 0) 918185029Spjd changelist_rename(clp, name, tryname); 919185029Spjd } else { 920185029Spjd err = ENOENT; 921185029Spjd } 922185029Spjd 923185029Spjd if (err != 0 && strncmp(name+baselen, "recv-", 5) != 0) { 924185029Spjd seq++; 925185029Spjd 926185029Spjd (void) strncpy(newname, name, baselen); 927185029Spjd (void) snprintf(newname+baselen, ZFS_MAXNAMELEN-baselen, 928185029Spjd "recv-%u-%u", getpid(), seq); 929185029Spjd (void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value)); 930185029Spjd 931185029Spjd if (flags.verbose) { 932185029Spjd (void) printf("failed - trying rename %s to %s\n", 933185029Spjd zc.zc_name, zc.zc_value); 934185029Spjd } 935185029Spjd err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc); 936185029Spjd if (err == 0) 937185029Spjd changelist_rename(clp, name, newname); 938185029Spjd if (err && flags.verbose) { 939185029Spjd (void) printf("failed (%u) - " 940185029Spjd "will try again on next pass\n", errno); 941185029Spjd } 942185029Spjd err = EAGAIN; 943185029Spjd } else if (flags.verbose) { 944185029Spjd if (err == 0) 945185029Spjd (void) printf("success\n"); 946185029Spjd else 947185029Spjd (void) printf("failed (%u)\n", errno); 948185029Spjd } 949185029Spjd 950185029Spjd (void) changelist_postfix(clp); 951185029Spjd changelist_free(clp); 952185029Spjd 953185029Spjd return (err); 954185029Spjd} 955185029Spjd 956185029Spjdstatic int 957185029Spjdrecv_destroy(libzfs_handle_t *hdl, const char *name, int baselen, 958185029Spjd char *newname, recvflags_t flags) 959185029Spjd{ 960185029Spjd zfs_cmd_t zc = { 0 }; 961185029Spjd int err = 0; 962185029Spjd prop_changelist_t *clp; 963185029Spjd zfs_handle_t *zhp; 964185029Spjd 965185029Spjd zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET); 966185029Spjd if (zhp == NULL) 967185029Spjd return (-1); 968185029Spjd clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 969185029Spjd flags.force ? MS_FORCE : 0); 970185029Spjd zfs_close(zhp); 971185029Spjd if (clp == NULL) 972185029Spjd return (-1); 973185029Spjd err = changelist_prefix(clp); 974185029Spjd if (err) 975185029Spjd return (err); 976185029Spjd 977185029Spjd zc.zc_objset_type = DMU_OST_ZFS; 978185029Spjd (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); 979185029Spjd 980185029Spjd if (flags.verbose) 981185029Spjd (void) printf("attempting destroy %s\n", zc.zc_name); 982185029Spjd err = ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); 983185029Spjd 984185029Spjd if (err == 0) { 985185029Spjd if (flags.verbose) 986185029Spjd (void) printf("success\n"); 987185029Spjd changelist_remove(clp, zc.zc_name); 988185029Spjd } 989185029Spjd 990185029Spjd (void) changelist_postfix(clp); 991185029Spjd changelist_free(clp); 992185029Spjd 993185029Spjd if (err != 0) 994185029Spjd err = recv_rename(hdl, name, NULL, baselen, newname, flags); 995185029Spjd 996185029Spjd return (err); 997185029Spjd} 998185029Spjd 999185029Spjdtypedef struct guid_to_name_data { 1000185029Spjd uint64_t guid; 1001185029Spjd char *name; 1002185029Spjd} guid_to_name_data_t; 1003185029Spjd 1004185029Spjdstatic int 1005185029Spjdguid_to_name_cb(zfs_handle_t *zhp, void *arg) 1006185029Spjd{ 1007185029Spjd guid_to_name_data_t *gtnd = arg; 1008185029Spjd int err; 1009185029Spjd 1010185029Spjd if (zhp->zfs_dmustats.dds_guid == gtnd->guid) { 1011185029Spjd (void) strcpy(gtnd->name, zhp->zfs_name); 1012185029Spjd return (EEXIST); 1013185029Spjd } 1014185029Spjd err = zfs_iter_children(zhp, guid_to_name_cb, gtnd); 1015185029Spjd zfs_close(zhp); 1016185029Spjd return (err); 1017185029Spjd} 1018185029Spjd 1019185029Spjdstatic int 1020185029Spjdguid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid, 1021185029Spjd char *name) 1022185029Spjd{ 1023185029Spjd /* exhaustive search all local snapshots */ 1024185029Spjd guid_to_name_data_t gtnd; 1025185029Spjd int err = 0; 1026185029Spjd zfs_handle_t *zhp; 1027185029Spjd char *cp; 1028185029Spjd 1029185029Spjd gtnd.guid = guid; 1030185029Spjd gtnd.name = name; 1031185029Spjd 1032185029Spjd if (strchr(parent, '@') == NULL) { 1033185029Spjd zhp = make_dataset_handle(hdl, parent); 1034185029Spjd if (zhp != NULL) { 1035185029Spjd err = zfs_iter_children(zhp, guid_to_name_cb, >nd); 1036185029Spjd zfs_close(zhp); 1037185029Spjd if (err == EEXIST) 1038185029Spjd return (0); 1039185029Spjd } 1040185029Spjd } 1041185029Spjd 1042185029Spjd cp = strchr(parent, '/'); 1043185029Spjd if (cp) 1044185029Spjd *cp = '\0'; 1045185029Spjd zhp = make_dataset_handle(hdl, parent); 1046185029Spjd if (cp) 1047185029Spjd *cp = '/'; 1048185029Spjd 1049185029Spjd if (zhp) { 1050185029Spjd err = zfs_iter_children(zhp, guid_to_name_cb, >nd); 1051185029Spjd zfs_close(zhp); 1052185029Spjd } 1053185029Spjd 1054185029Spjd return (err == EEXIST ? 0 : ENOENT); 1055185029Spjd 1056185029Spjd} 1057185029Spjd 1058185029Spjd/* 1059185029Spjd * Return true if dataset guid1 is created before guid2. 1060185029Spjd */ 1061185029Spjdstatic int 1062185029Spjdcreated_before(libzfs_handle_t *hdl, avl_tree_t *avl, 1063185029Spjd uint64_t guid1, uint64_t guid2) 1064185029Spjd{ 1065185029Spjd nvlist_t *nvfs; 1066185029Spjd char *fsname, *snapname; 1067185029Spjd char buf[ZFS_MAXNAMELEN]; 1068185029Spjd int rv; 1069185029Spjd zfs_node_t zn1, zn2; 1070185029Spjd 1071185029Spjd if (guid2 == 0) 1072185029Spjd return (0); 1073185029Spjd if (guid1 == 0) 1074185029Spjd return (1); 1075185029Spjd 1076185029Spjd nvfs = fsavl_find(avl, guid1, &snapname); 1077185029Spjd VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); 1078185029Spjd (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname); 1079185029Spjd zn1.zn_handle = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); 1080185029Spjd if (zn1.zn_handle == NULL) 1081185029Spjd return (-1); 1082185029Spjd 1083185029Spjd nvfs = fsavl_find(avl, guid2, &snapname); 1084185029Spjd VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); 1085185029Spjd (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname); 1086185029Spjd zn2.zn_handle = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); 1087185029Spjd if (zn2.zn_handle == NULL) { 1088185029Spjd zfs_close(zn2.zn_handle); 1089185029Spjd return (-1); 1090185029Spjd } 1091185029Spjd 1092185029Spjd rv = (zfs_snapshot_compare(&zn1, &zn2) == -1); 1093185029Spjd 1094185029Spjd zfs_close(zn1.zn_handle); 1095185029Spjd zfs_close(zn2.zn_handle); 1096185029Spjd 1097185029Spjd return (rv); 1098185029Spjd} 1099185029Spjd 1100185029Spjdstatic int 1101185029Spjdrecv_incremental_replication(libzfs_handle_t *hdl, const char *tofs, 1102185029Spjd recvflags_t flags, nvlist_t *stream_nv, avl_tree_t *stream_avl) 1103185029Spjd{ 1104185029Spjd nvlist_t *local_nv; 1105185029Spjd avl_tree_t *local_avl; 1106185029Spjd nvpair_t *fselem, *nextfselem; 1107185029Spjd char *tosnap, *fromsnap; 1108185029Spjd char newname[ZFS_MAXNAMELEN]; 1109185029Spjd int error; 1110185029Spjd boolean_t needagain, progress; 1111209962Smm char *s1, *s2; 1112185029Spjd 1113185029Spjd VERIFY(0 == nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap)); 1114185029Spjd VERIFY(0 == nvlist_lookup_string(stream_nv, "tosnap", &tosnap)); 1115185029Spjd 1116185029Spjd if (flags.dryrun) 1117185029Spjd return (0); 1118185029Spjd 1119185029Spjdagain: 1120185029Spjd needagain = progress = B_FALSE; 1121185029Spjd 1122185029Spjd if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL, 1123185029Spjd &local_nv, &local_avl)) != 0) 1124185029Spjd return (error); 1125185029Spjd 1126185029Spjd /* 1127185029Spjd * Process deletes and renames 1128185029Spjd */ 1129185029Spjd for (fselem = nvlist_next_nvpair(local_nv, NULL); 1130185029Spjd fselem; fselem = nextfselem) { 1131185029Spjd nvlist_t *nvfs, *snaps; 1132185029Spjd nvlist_t *stream_nvfs = NULL; 1133185029Spjd nvpair_t *snapelem, *nextsnapelem; 1134185029Spjd uint64_t fromguid = 0; 1135185029Spjd uint64_t originguid = 0; 1136185029Spjd uint64_t stream_originguid = 0; 1137185029Spjd uint64_t parent_fromsnap_guid, stream_parent_fromsnap_guid; 1138196305Spjd char *fsname, *stream_fsname, *p1, *p2; 1139185029Spjd 1140185029Spjd nextfselem = nvlist_next_nvpair(local_nv, fselem); 1141185029Spjd 1142185029Spjd VERIFY(0 == nvpair_value_nvlist(fselem, &nvfs)); 1143185029Spjd VERIFY(0 == nvlist_lookup_nvlist(nvfs, "snaps", &snaps)); 1144185029Spjd VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); 1145185029Spjd VERIFY(0 == nvlist_lookup_uint64(nvfs, "parentfromsnap", 1146185029Spjd &parent_fromsnap_guid)); 1147185029Spjd (void) nvlist_lookup_uint64(nvfs, "origin", &originguid); 1148185029Spjd 1149185029Spjd /* 1150185029Spjd * First find the stream's fs, so we can check for 1151185029Spjd * a different origin (due to "zfs promote") 1152185029Spjd */ 1153185029Spjd for (snapelem = nvlist_next_nvpair(snaps, NULL); 1154185029Spjd snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) { 1155185029Spjd uint64_t thisguid; 1156185029Spjd 1157185029Spjd VERIFY(0 == nvpair_value_uint64(snapelem, &thisguid)); 1158185029Spjd stream_nvfs = fsavl_find(stream_avl, thisguid, NULL); 1159185029Spjd 1160185029Spjd if (stream_nvfs != NULL) 1161185029Spjd break; 1162185029Spjd } 1163185029Spjd 1164185029Spjd /* check for promote */ 1165185029Spjd (void) nvlist_lookup_uint64(stream_nvfs, "origin", 1166185029Spjd &stream_originguid); 1167185029Spjd if (stream_nvfs && originguid != stream_originguid) { 1168185029Spjd switch (created_before(hdl, local_avl, 1169185029Spjd stream_originguid, originguid)) { 1170185029Spjd case 1: { 1171185029Spjd /* promote it! */ 1172185029Spjd zfs_cmd_t zc = { 0 }; 1173185029Spjd nvlist_t *origin_nvfs; 1174185029Spjd char *origin_fsname; 1175185029Spjd 1176185029Spjd if (flags.verbose) 1177185029Spjd (void) printf("promoting %s\n", fsname); 1178185029Spjd 1179185029Spjd origin_nvfs = fsavl_find(local_avl, originguid, 1180185029Spjd NULL); 1181185029Spjd VERIFY(0 == nvlist_lookup_string(origin_nvfs, 1182185029Spjd "name", &origin_fsname)); 1183185029Spjd (void) strlcpy(zc.zc_value, origin_fsname, 1184185029Spjd sizeof (zc.zc_value)); 1185185029Spjd (void) strlcpy(zc.zc_name, fsname, 1186185029Spjd sizeof (zc.zc_name)); 1187185029Spjd error = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); 1188185029Spjd if (error == 0) 1189185029Spjd progress = B_TRUE; 1190185029Spjd break; 1191185029Spjd } 1192185029Spjd default: 1193185029Spjd break; 1194185029Spjd case -1: 1195185029Spjd fsavl_destroy(local_avl); 1196185029Spjd nvlist_free(local_nv); 1197185029Spjd return (-1); 1198185029Spjd } 1199185029Spjd /* 1200185029Spjd * We had/have the wrong origin, therefore our 1201185029Spjd * list of snapshots is wrong. Need to handle 1202185029Spjd * them on the next pass. 1203185029Spjd */ 1204185029Spjd needagain = B_TRUE; 1205185029Spjd continue; 1206185029Spjd } 1207185029Spjd 1208185029Spjd for (snapelem = nvlist_next_nvpair(snaps, NULL); 1209185029Spjd snapelem; snapelem = nextsnapelem) { 1210185029Spjd uint64_t thisguid; 1211185029Spjd char *stream_snapname; 1212185029Spjd nvlist_t *found, *props; 1213185029Spjd 1214185029Spjd nextsnapelem = nvlist_next_nvpair(snaps, snapelem); 1215185029Spjd 1216185029Spjd VERIFY(0 == nvpair_value_uint64(snapelem, &thisguid)); 1217185029Spjd found = fsavl_find(stream_avl, thisguid, 1218185029Spjd &stream_snapname); 1219185029Spjd 1220185029Spjd /* check for delete */ 1221185029Spjd if (found == NULL) { 1222185029Spjd char name[ZFS_MAXNAMELEN]; 1223185029Spjd 1224185029Spjd if (!flags.force) 1225185029Spjd continue; 1226185029Spjd 1227185029Spjd (void) snprintf(name, sizeof (name), "%s@%s", 1228185029Spjd fsname, nvpair_name(snapelem)); 1229185029Spjd 1230185029Spjd error = recv_destroy(hdl, name, 1231185029Spjd strlen(fsname)+1, newname, flags); 1232185029Spjd if (error) 1233185029Spjd needagain = B_TRUE; 1234185029Spjd else 1235185029Spjd progress = B_TRUE; 1236185029Spjd continue; 1237185029Spjd } 1238185029Spjd 1239185029Spjd stream_nvfs = found; 1240185029Spjd 1241185029Spjd if (0 == nvlist_lookup_nvlist(stream_nvfs, "snapprops", 1242185029Spjd &props) && 0 == nvlist_lookup_nvlist(props, 1243185029Spjd stream_snapname, &props)) { 1244185029Spjd zfs_cmd_t zc = { 0 }; 1245185029Spjd 1246185029Spjd zc.zc_cookie = B_TRUE; /* clear current props */ 1247185029Spjd (void) snprintf(zc.zc_name, sizeof (zc.zc_name), 1248185029Spjd "%s@%s", fsname, nvpair_name(snapelem)); 1249185029Spjd if (zcmd_write_src_nvlist(hdl, &zc, 1250185029Spjd props) == 0) { 1251185029Spjd (void) zfs_ioctl(hdl, 1252185029Spjd ZFS_IOC_SET_PROP, &zc); 1253185029Spjd zcmd_free_nvlists(&zc); 1254185029Spjd } 1255185029Spjd } 1256185029Spjd 1257185029Spjd /* check for different snapname */ 1258185029Spjd if (strcmp(nvpair_name(snapelem), 1259185029Spjd stream_snapname) != 0) { 1260185029Spjd char name[ZFS_MAXNAMELEN]; 1261185029Spjd char tryname[ZFS_MAXNAMELEN]; 1262185029Spjd 1263185029Spjd (void) snprintf(name, sizeof (name), "%s@%s", 1264185029Spjd fsname, nvpair_name(snapelem)); 1265185029Spjd (void) snprintf(tryname, sizeof (name), "%s@%s", 1266185029Spjd fsname, stream_snapname); 1267185029Spjd 1268185029Spjd error = recv_rename(hdl, name, tryname, 1269185029Spjd strlen(fsname)+1, newname, flags); 1270185029Spjd if (error) 1271185029Spjd needagain = B_TRUE; 1272185029Spjd else 1273185029Spjd progress = B_TRUE; 1274185029Spjd } 1275185029Spjd 1276185029Spjd if (strcmp(stream_snapname, fromsnap) == 0) 1277185029Spjd fromguid = thisguid; 1278185029Spjd } 1279185029Spjd 1280185029Spjd /* check for delete */ 1281185029Spjd if (stream_nvfs == NULL) { 1282185029Spjd if (!flags.force) 1283185029Spjd continue; 1284185029Spjd 1285185029Spjd error = recv_destroy(hdl, fsname, strlen(tofs)+1, 1286185029Spjd newname, flags); 1287185029Spjd if (error) 1288185029Spjd needagain = B_TRUE; 1289185029Spjd else 1290185029Spjd progress = B_TRUE; 1291185029Spjd continue; 1292185029Spjd } 1293185029Spjd 1294185029Spjd if (fromguid == 0 && flags.verbose) { 1295185029Spjd (void) printf("local fs %s does not have fromsnap " 1296185029Spjd "(%s in stream); must have been deleted locally; " 1297185029Spjd "ignoring\n", fsname, fromsnap); 1298185029Spjd continue; 1299185029Spjd } 1300185029Spjd 1301185029Spjd VERIFY(0 == nvlist_lookup_string(stream_nvfs, 1302185029Spjd "name", &stream_fsname)); 1303185029Spjd VERIFY(0 == nvlist_lookup_uint64(stream_nvfs, 1304185029Spjd "parentfromsnap", &stream_parent_fromsnap_guid)); 1305185029Spjd 1306209962Smm s1 = strrchr(fsname, '/'); 1307209962Smm s2 = strrchr(stream_fsname, '/'); 1308209962Smm 1309185029Spjd /* check for rename */ 1310185029Spjd if ((stream_parent_fromsnap_guid != 0 && 1311185029Spjd stream_parent_fromsnap_guid != parent_fromsnap_guid) || 1312209962Smm ((s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) { 1313185029Spjd nvlist_t *parent; 1314185029Spjd char tryname[ZFS_MAXNAMELEN]; 1315185029Spjd 1316185029Spjd parent = fsavl_find(local_avl, 1317185029Spjd stream_parent_fromsnap_guid, NULL); 1318185029Spjd /* 1319185029Spjd * NB: parent might not be found if we used the 1320185029Spjd * tosnap for stream_parent_fromsnap_guid, 1321185029Spjd * because the parent is a newly-created fs; 1322185029Spjd * we'll be able to rename it after we recv the 1323185029Spjd * new fs. 1324185029Spjd */ 1325185029Spjd if (parent != NULL) { 1326185029Spjd char *pname; 1327185029Spjd 1328185029Spjd VERIFY(0 == nvlist_lookup_string(parent, "name", 1329185029Spjd &pname)); 1330185029Spjd (void) snprintf(tryname, sizeof (tryname), 1331196305Spjd "%s%s", pname, p2 != NULL ? p2 : ""); 1332185029Spjd } else { 1333185029Spjd tryname[0] = '\0'; 1334185029Spjd if (flags.verbose) { 1335185029Spjd (void) printf("local fs %s new parent " 1336185029Spjd "not found\n", fsname); 1337185029Spjd } 1338185029Spjd } 1339185029Spjd 1340185029Spjd error = recv_rename(hdl, fsname, tryname, 1341185029Spjd strlen(tofs)+1, newname, flags); 1342185029Spjd if (error) 1343185029Spjd needagain = B_TRUE; 1344185029Spjd else 1345185029Spjd progress = B_TRUE; 1346185029Spjd } 1347185029Spjd } 1348185029Spjd 1349185029Spjd fsavl_destroy(local_avl); 1350185029Spjd nvlist_free(local_nv); 1351185029Spjd 1352185029Spjd if (needagain && progress) { 1353185029Spjd /* do another pass to fix up temporary names */ 1354185029Spjd if (flags.verbose) 1355185029Spjd (void) printf("another pass:\n"); 1356185029Spjd goto again; 1357185029Spjd } 1358185029Spjd 1359185029Spjd return (needagain); 1360185029Spjd} 1361185029Spjd 1362185029Spjdstatic int 1363185029Spjdzfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, 1364185029Spjd recvflags_t flags, dmu_replay_record_t *drr, zio_cksum_t *zc, 1365185029Spjd char **top_zfs) 1366185029Spjd{ 1367185029Spjd nvlist_t *stream_nv = NULL; 1368185029Spjd avl_tree_t *stream_avl = NULL; 1369185029Spjd char *fromsnap = NULL; 1370185029Spjd char tofs[ZFS_MAXNAMELEN]; 1371185029Spjd char errbuf[1024]; 1372185029Spjd dmu_replay_record_t drre; 1373185029Spjd int error; 1374185029Spjd boolean_t anyerr = B_FALSE; 1375185029Spjd boolean_t softerr = B_FALSE; 1376185029Spjd 1377185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1378185029Spjd "cannot receive")); 1379185029Spjd 1380185029Spjd if (strchr(destname, '@')) { 1381185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1382185029Spjd "can not specify snapshot name for multi-snapshot stream")); 1383185029Spjd return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 1384185029Spjd } 1385185029Spjd 1386185029Spjd assert(drr->drr_type == DRR_BEGIN); 1387185029Spjd assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC); 1388185029Spjd assert(drr->drr_u.drr_begin.drr_version == DMU_BACKUP_HEADER_VERSION); 1389185029Spjd 1390185029Spjd /* 1391185029Spjd * Read in the nvlist from the stream. 1392185029Spjd */ 1393185029Spjd if (drr->drr_payloadlen != 0) { 1394185029Spjd if (!flags.isprefix) { 1395185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1396185029Spjd "must use -d to receive replication " 1397185029Spjd "(send -R) stream")); 1398185029Spjd return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 1399185029Spjd } 1400185029Spjd 1401185029Spjd error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen, 1402185029Spjd &stream_nv, flags.byteswap, zc); 1403185029Spjd if (error) { 1404185029Spjd error = zfs_error(hdl, EZFS_BADSTREAM, errbuf); 1405185029Spjd goto out; 1406185029Spjd } 1407185029Spjd } 1408185029Spjd 1409185029Spjd /* 1410185029Spjd * Read in the end record and verify checksum. 1411185029Spjd */ 1412185029Spjd if (0 != (error = recv_read(hdl, fd, &drre, sizeof (drre), 1413185029Spjd flags.byteswap, NULL))) 1414185029Spjd goto out; 1415185029Spjd if (flags.byteswap) { 1416185029Spjd drre.drr_type = BSWAP_32(drre.drr_type); 1417185029Spjd drre.drr_u.drr_end.drr_checksum.zc_word[0] = 1418185029Spjd BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[0]); 1419185029Spjd drre.drr_u.drr_end.drr_checksum.zc_word[1] = 1420185029Spjd BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[1]); 1421185029Spjd drre.drr_u.drr_end.drr_checksum.zc_word[2] = 1422185029Spjd BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[2]); 1423185029Spjd drre.drr_u.drr_end.drr_checksum.zc_word[3] = 1424185029Spjd BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[3]); 1425185029Spjd } 1426185029Spjd if (drre.drr_type != DRR_END) { 1427185029Spjd error = zfs_error(hdl, EZFS_BADSTREAM, errbuf); 1428185029Spjd goto out; 1429185029Spjd } 1430185029Spjd if (!ZIO_CHECKSUM_EQUAL(drre.drr_u.drr_end.drr_checksum, *zc)) { 1431185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1432185029Spjd "incorrect header checksum")); 1433185029Spjd error = zfs_error(hdl, EZFS_BADSTREAM, errbuf); 1434185029Spjd goto out; 1435185029Spjd } 1436185029Spjd 1437185029Spjd (void) nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap); 1438185029Spjd 1439185029Spjd if (drr->drr_payloadlen != 0) { 1440185029Spjd nvlist_t *stream_fss; 1441185029Spjd 1442185029Spjd VERIFY(0 == nvlist_lookup_nvlist(stream_nv, "fss", 1443185029Spjd &stream_fss)); 1444185029Spjd if ((stream_avl = fsavl_create(stream_fss)) == NULL) { 1445185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1446185029Spjd "couldn't allocate avl tree")); 1447185029Spjd error = zfs_error(hdl, EZFS_NOMEM, errbuf); 1448185029Spjd goto out; 1449185029Spjd } 1450185029Spjd 1451185029Spjd if (fromsnap != NULL) { 1452185029Spjd (void) strlcpy(tofs, destname, ZFS_MAXNAMELEN); 1453185029Spjd if (flags.isprefix) { 1454185029Spjd int i = strcspn(drr->drr_u.drr_begin.drr_toname, 1455185029Spjd "/@"); 1456185029Spjd /* zfs_receive_one() will create_parents() */ 1457185029Spjd (void) strlcat(tofs, 1458185029Spjd &drr->drr_u.drr_begin.drr_toname[i], 1459185029Spjd ZFS_MAXNAMELEN); 1460185029Spjd *strchr(tofs, '@') = '\0'; 1461185029Spjd } 1462185029Spjd softerr = recv_incremental_replication(hdl, tofs, 1463185029Spjd flags, stream_nv, stream_avl); 1464185029Spjd } 1465185029Spjd } 1466185029Spjd 1467185029Spjd 1468185029Spjd /* Finally, receive each contained stream */ 1469185029Spjd do { 1470185029Spjd /* 1471185029Spjd * we should figure out if it has a recoverable 1472185029Spjd * error, in which case do a recv_skip() and drive on. 1473185029Spjd * Note, if we fail due to already having this guid, 1474185029Spjd * zfs_receive_one() will take care of it (ie, 1475185029Spjd * recv_skip() and return 0). 1476185029Spjd */ 1477185029Spjd error = zfs_receive_impl(hdl, destname, flags, fd, 1478185029Spjd stream_avl, top_zfs); 1479185029Spjd if (error == ENODATA) { 1480185029Spjd error = 0; 1481185029Spjd break; 1482185029Spjd } 1483185029Spjd anyerr |= error; 1484185029Spjd } while (error == 0); 1485185029Spjd 1486185029Spjd if (drr->drr_payloadlen != 0 && fromsnap != NULL) { 1487185029Spjd /* 1488185029Spjd * Now that we have the fs's they sent us, try the 1489185029Spjd * renames again. 1490185029Spjd */ 1491185029Spjd softerr = recv_incremental_replication(hdl, tofs, flags, 1492185029Spjd stream_nv, stream_avl); 1493185029Spjd } 1494185029Spjd 1495185029Spjdout: 1496185029Spjd fsavl_destroy(stream_avl); 1497185029Spjd if (stream_nv) 1498185029Spjd nvlist_free(stream_nv); 1499185029Spjd if (softerr) 1500185029Spjd error = -2; 1501185029Spjd if (anyerr) 1502185029Spjd error = -1; 1503185029Spjd return (error); 1504185029Spjd} 1505185029Spjd 1506185029Spjdstatic int 1507185029Spjdrecv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap) 1508185029Spjd{ 1509185029Spjd dmu_replay_record_t *drr; 1510185029Spjd void *buf = malloc(1<<20); 1511185029Spjd 1512185029Spjd /* XXX would be great to use lseek if possible... */ 1513185029Spjd drr = buf; 1514185029Spjd 1515185029Spjd while (recv_read(hdl, fd, drr, sizeof (dmu_replay_record_t), 1516185029Spjd byteswap, NULL) == 0) { 1517185029Spjd if (byteswap) 1518185029Spjd drr->drr_type = BSWAP_32(drr->drr_type); 1519185029Spjd 1520185029Spjd switch (drr->drr_type) { 1521185029Spjd case DRR_BEGIN: 1522185029Spjd /* NB: not to be used on v2 stream packages */ 1523185029Spjd assert(drr->drr_payloadlen == 0); 1524185029Spjd break; 1525185029Spjd 1526185029Spjd case DRR_END: 1527185029Spjd free(buf); 1528185029Spjd return (0); 1529185029Spjd 1530185029Spjd case DRR_OBJECT: 1531185029Spjd if (byteswap) { 1532185029Spjd drr->drr_u.drr_object.drr_bonuslen = 1533185029Spjd BSWAP_32(drr->drr_u.drr_object. 1534185029Spjd drr_bonuslen); 1535185029Spjd } 1536185029Spjd (void) recv_read(hdl, fd, buf, 1537185029Spjd P2ROUNDUP(drr->drr_u.drr_object.drr_bonuslen, 8), 1538185029Spjd B_FALSE, NULL); 1539185029Spjd break; 1540185029Spjd 1541185029Spjd case DRR_WRITE: 1542185029Spjd if (byteswap) { 1543185029Spjd drr->drr_u.drr_write.drr_length = 1544185029Spjd BSWAP_64(drr->drr_u.drr_write.drr_length); 1545185029Spjd } 1546185029Spjd (void) recv_read(hdl, fd, buf, 1547185029Spjd drr->drr_u.drr_write.drr_length, B_FALSE, NULL); 1548185029Spjd break; 1549185029Spjd 1550185029Spjd case DRR_FREEOBJECTS: 1551185029Spjd case DRR_FREE: 1552185029Spjd break; 1553185029Spjd 1554185029Spjd default: 1555185029Spjd assert(!"invalid record type"); 1556185029Spjd } 1557185029Spjd } 1558185029Spjd 1559185029Spjd free(buf); 1560185029Spjd return (-1); 1561185029Spjd} 1562185029Spjd 1563185029Spjd/* 1564185029Spjd * Restores a backup of tosnap from the file descriptor specified by infd. 1565185029Spjd */ 1566185029Spjdstatic int 1567185029Spjdzfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, 1568185029Spjd recvflags_t flags, dmu_replay_record_t *drr, 1569185029Spjd dmu_replay_record_t *drr_noswap, avl_tree_t *stream_avl, 1570185029Spjd char **top_zfs) 1571185029Spjd{ 1572185029Spjd zfs_cmd_t zc = { 0 }; 1573185029Spjd time_t begin_time; 1574185029Spjd int ioctl_err, ioctl_errno, err, choplen; 1575185029Spjd char *cp; 1576185029Spjd struct drr_begin *drrb = &drr->drr_u.drr_begin; 1577185029Spjd char errbuf[1024]; 1578185029Spjd char chopprefix[ZFS_MAXNAMELEN]; 1579185029Spjd boolean_t newfs = B_FALSE; 1580185029Spjd boolean_t stream_wantsnewfs; 1581185029Spjd uint64_t parent_snapguid = 0; 1582185029Spjd prop_changelist_t *clp = NULL; 1583185029Spjd nvlist_t *snapprops_nvlist = NULL; 1584185029Spjd 1585185029Spjd begin_time = time(NULL); 1586185029Spjd 1587185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1588185029Spjd "cannot receive")); 1589185029Spjd 1590185029Spjd if (stream_avl != NULL) { 1591185029Spjd char *snapname; 1592185029Spjd nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid, 1593185029Spjd &snapname); 1594185029Spjd nvlist_t *props; 1595185029Spjd int ret; 1596185029Spjd 1597185029Spjd (void) nvlist_lookup_uint64(fs, "parentfromsnap", 1598185029Spjd &parent_snapguid); 1599185029Spjd err = nvlist_lookup_nvlist(fs, "props", &props); 1600185029Spjd if (err) 1601185029Spjd VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0)); 1602185029Spjd 1603185029Spjd if (flags.canmountoff) { 1604185029Spjd VERIFY(0 == nvlist_add_uint64(props, 1605185029Spjd zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0)); 1606185029Spjd } 1607185029Spjd ret = zcmd_write_src_nvlist(hdl, &zc, props); 1608185029Spjd if (err) 1609185029Spjd nvlist_free(props); 1610185029Spjd 1611185029Spjd if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) { 1612185029Spjd VERIFY(0 == nvlist_lookup_nvlist(props, 1613185029Spjd snapname, &snapprops_nvlist)); 1614185029Spjd } 1615185029Spjd 1616185029Spjd if (ret != 0) 1617185029Spjd return (-1); 1618185029Spjd } 1619185029Spjd 1620185029Spjd /* 1621185029Spjd * Determine how much of the snapshot name stored in the stream 1622185029Spjd * we are going to tack on to the name they specified on the 1623185029Spjd * command line, and how much we are going to chop off. 1624185029Spjd * 1625185029Spjd * If they specified a snapshot, chop the entire name stored in 1626185029Spjd * the stream. 1627185029Spjd */ 1628185029Spjd (void) strcpy(chopprefix, drrb->drr_toname); 1629185029Spjd if (flags.isprefix) { 1630185029Spjd /* 1631185029Spjd * They specified a fs with -d, we want to tack on 1632185029Spjd * everything but the pool name stored in the stream 1633185029Spjd */ 1634185029Spjd if (strchr(tosnap, '@')) { 1635185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 1636185029Spjd "argument - snapshot not allowed with -d")); 1637185029Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1638185029Spjd } 1639185029Spjd cp = strchr(chopprefix, '/'); 1640185029Spjd if (cp == NULL) 1641185029Spjd cp = strchr(chopprefix, '@'); 1642185029Spjd *cp = '\0'; 1643185029Spjd } else if (strchr(tosnap, '@') == NULL) { 1644185029Spjd /* 1645185029Spjd * If they specified a filesystem without -d, we want to 1646185029Spjd * tack on everything after the fs specified in the 1647185029Spjd * first name from the stream. 1648185029Spjd */ 1649185029Spjd cp = strchr(chopprefix, '@'); 1650185029Spjd *cp = '\0'; 1651185029Spjd } 1652185029Spjd choplen = strlen(chopprefix); 1653185029Spjd 1654185029Spjd /* 1655185029Spjd * Determine name of destination snapshot, store in zc_value. 1656185029Spjd */ 1657185029Spjd (void) strcpy(zc.zc_value, tosnap); 1658185029Spjd (void) strncat(zc.zc_value, drrb->drr_toname+choplen, 1659185029Spjd sizeof (zc.zc_value)); 1660185029Spjd if (!zfs_name_valid(zc.zc_value, ZFS_TYPE_SNAPSHOT)) { 1661185029Spjd zcmd_free_nvlists(&zc); 1662185029Spjd return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 1663185029Spjd } 1664185029Spjd 1665185029Spjd /* 1666185029Spjd * Determine the name of the origin snapshot, store in zc_string. 1667185029Spjd */ 1668185029Spjd if (drrb->drr_flags & DRR_FLAG_CLONE) { 1669185029Spjd if (guid_to_name(hdl, tosnap, 1670185029Spjd drrb->drr_fromguid, zc.zc_string) != 0) { 1671185029Spjd zcmd_free_nvlists(&zc); 1672185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1673185029Spjd "local origin for clone %s does not exist"), 1674185029Spjd zc.zc_value); 1675185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1676185029Spjd } 1677185029Spjd if (flags.verbose) 1678185029Spjd (void) printf("found clone origin %s\n", zc.zc_string); 1679185029Spjd } 1680185029Spjd 1681185029Spjd stream_wantsnewfs = (drrb->drr_fromguid == 0 || 1682185029Spjd (drrb->drr_flags & DRR_FLAG_CLONE)); 1683185029Spjd 1684185029Spjd if (stream_wantsnewfs) { 1685185029Spjd /* 1686185029Spjd * if the parent fs does not exist, look for it based on 1687185029Spjd * the parent snap GUID 1688185029Spjd */ 1689185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1690185029Spjd "cannot receive new filesystem stream")); 1691185029Spjd 1692185029Spjd (void) strcpy(zc.zc_name, zc.zc_value); 1693185029Spjd cp = strrchr(zc.zc_name, '/'); 1694185029Spjd if (cp) 1695185029Spjd *cp = '\0'; 1696185029Spjd if (cp && 1697185029Spjd !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { 1698185029Spjd char suffix[ZFS_MAXNAMELEN]; 1699185029Spjd (void) strcpy(suffix, strrchr(zc.zc_value, '/')); 1700185029Spjd if (guid_to_name(hdl, tosnap, parent_snapguid, 1701185029Spjd zc.zc_value) == 0) { 1702185029Spjd *strchr(zc.zc_value, '@') = '\0'; 1703185029Spjd (void) strcat(zc.zc_value, suffix); 1704185029Spjd } 1705185029Spjd } 1706185029Spjd } else { 1707185029Spjd /* 1708185029Spjd * if the fs does not exist, look for it based on the 1709185029Spjd * fromsnap GUID 1710185029Spjd */ 1711185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1712185029Spjd "cannot receive incremental stream")); 1713185029Spjd 1714185029Spjd (void) strcpy(zc.zc_name, zc.zc_value); 1715185029Spjd *strchr(zc.zc_name, '@') = '\0'; 1716185029Spjd 1717185029Spjd if (!zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { 1718185029Spjd char snap[ZFS_MAXNAMELEN]; 1719185029Spjd (void) strcpy(snap, strchr(zc.zc_value, '@')); 1720185029Spjd if (guid_to_name(hdl, tosnap, drrb->drr_fromguid, 1721185029Spjd zc.zc_value) == 0) { 1722185029Spjd *strchr(zc.zc_value, '@') = '\0'; 1723185029Spjd (void) strcat(zc.zc_value, snap); 1724185029Spjd } 1725185029Spjd } 1726185029Spjd } 1727185029Spjd 1728185029Spjd (void) strcpy(zc.zc_name, zc.zc_value); 1729185029Spjd *strchr(zc.zc_name, '@') = '\0'; 1730185029Spjd 1731185029Spjd if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { 1732185029Spjd zfs_handle_t *zhp; 1733185029Spjd /* 1734185029Spjd * Destination fs exists. Therefore this should either 1735185029Spjd * be an incremental, or the stream specifies a new fs 1736185029Spjd * (full stream or clone) and they want us to blow it 1737185029Spjd * away (and have therefore specified -F and removed any 1738185029Spjd * snapshots). 1739185029Spjd */ 1740185029Spjd 1741185029Spjd if (stream_wantsnewfs) { 1742185029Spjd if (!flags.force) { 1743185029Spjd zcmd_free_nvlists(&zc); 1744185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1745185029Spjd "destination '%s' exists\n" 1746185029Spjd "must specify -F to overwrite it"), 1747185029Spjd zc.zc_name); 1748185029Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1749185029Spjd } 1750185029Spjd if (ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 1751185029Spjd &zc) == 0) { 1752185029Spjd zcmd_free_nvlists(&zc); 1753185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1754185029Spjd "destination has snapshots (eg. %s)\n" 1755185029Spjd "must destroy them to overwrite it"), 1756185029Spjd zc.zc_name); 1757185029Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1758185029Spjd } 1759185029Spjd } 1760185029Spjd 1761185029Spjd if ((zhp = zfs_open(hdl, zc.zc_name, 1762185029Spjd ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) { 1763185029Spjd zcmd_free_nvlists(&zc); 1764185029Spjd return (-1); 1765185029Spjd } 1766185029Spjd 1767185029Spjd if (stream_wantsnewfs && 1768185029Spjd zhp->zfs_dmustats.dds_origin[0]) { 1769185029Spjd zcmd_free_nvlists(&zc); 1770185029Spjd zfs_close(zhp); 1771185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1772185029Spjd "destination '%s' is a clone\n" 1773185029Spjd "must destroy it to overwrite it"), 1774185029Spjd zc.zc_name); 1775185029Spjd return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 1776185029Spjd } 1777185029Spjd 1778185029Spjd if (!flags.dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM && 1779185029Spjd stream_wantsnewfs) { 1780185029Spjd /* We can't do online recv in this case */ 1781185029Spjd clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0); 1782185029Spjd if (clp == NULL) { 1783185029Spjd zcmd_free_nvlists(&zc); 1784185029Spjd return (-1); 1785185029Spjd } 1786185029Spjd if (changelist_prefix(clp) != 0) { 1787185029Spjd changelist_free(clp); 1788185029Spjd zcmd_free_nvlists(&zc); 1789185029Spjd return (-1); 1790185029Spjd } 1791185029Spjd } 1792185029Spjd if (!flags.dryrun && zhp->zfs_type == ZFS_TYPE_VOLUME && 1793185029Spjd zvol_remove_link(hdl, zhp->zfs_name) != 0) { 1794185029Spjd zfs_close(zhp); 1795185029Spjd zcmd_free_nvlists(&zc); 1796185029Spjd return (-1); 1797185029Spjd } 1798185029Spjd zfs_close(zhp); 1799185029Spjd } else { 1800185029Spjd /* 1801185029Spjd * Destination filesystem does not exist. Therefore we better 1802185029Spjd * be creating a new filesystem (either from a full backup, or 1803185029Spjd * a clone). It would therefore be invalid if the user 1804185029Spjd * specified only the pool name (i.e. if the destination name 1805185029Spjd * contained no slash character). 1806185029Spjd */ 1807185029Spjd if (!stream_wantsnewfs || 1808185029Spjd (cp = strrchr(zc.zc_name, '/')) == NULL) { 1809185029Spjd zcmd_free_nvlists(&zc); 1810185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1811185029Spjd "destination '%s' does not exist"), zc.zc_name); 1812185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1813185029Spjd } 1814185029Spjd 1815185029Spjd /* 1816185029Spjd * Trim off the final dataset component so we perform the 1817185029Spjd * recvbackup ioctl to the filesystems's parent. 1818185029Spjd */ 1819185029Spjd *cp = '\0'; 1820185029Spjd 1821185029Spjd if (flags.isprefix && !flags.dryrun && 1822185029Spjd create_parents(hdl, zc.zc_value, strlen(tosnap)) != 0) { 1823185029Spjd zcmd_free_nvlists(&zc); 1824185029Spjd return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); 1825185029Spjd } 1826185029Spjd 1827185029Spjd newfs = B_TRUE; 1828185029Spjd } 1829185029Spjd 1830185029Spjd zc.zc_begin_record = drr_noswap->drr_u.drr_begin; 1831185029Spjd zc.zc_cookie = infd; 1832185029Spjd zc.zc_guid = flags.force; 1833185029Spjd if (flags.verbose) { 1834185029Spjd (void) printf("%s %s stream of %s into %s\n", 1835185029Spjd flags.dryrun ? "would receive" : "receiving", 1836185029Spjd drrb->drr_fromguid ? "incremental" : "full", 1837185029Spjd drrb->drr_toname, zc.zc_value); 1838185029Spjd (void) fflush(stdout); 1839185029Spjd } 1840185029Spjd 1841185029Spjd if (flags.dryrun) { 1842185029Spjd zcmd_free_nvlists(&zc); 1843185029Spjd return (recv_skip(hdl, infd, flags.byteswap)); 1844185029Spjd } 1845185029Spjd 1846185029Spjd err = ioctl_err = zfs_ioctl(hdl, ZFS_IOC_RECV, &zc); 1847185029Spjd ioctl_errno = errno; 1848185029Spjd zcmd_free_nvlists(&zc); 1849185029Spjd 1850185029Spjd if (err == 0 && snapprops_nvlist) { 1851185029Spjd zfs_cmd_t zc2 = { 0 }; 1852185029Spjd 1853185029Spjd (void) strcpy(zc2.zc_name, zc.zc_value); 1854185029Spjd if (zcmd_write_src_nvlist(hdl, &zc2, snapprops_nvlist) == 0) { 1855185029Spjd (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc2); 1856185029Spjd zcmd_free_nvlists(&zc2); 1857185029Spjd } 1858185029Spjd } 1859185029Spjd 1860185029Spjd if (err && (ioctl_errno == ENOENT || ioctl_errno == ENODEV)) { 1861185029Spjd /* 1862185029Spjd * It may be that this snapshot already exists, 1863185029Spjd * in which case we want to consume & ignore it 1864185029Spjd * rather than failing. 1865185029Spjd */ 1866185029Spjd avl_tree_t *local_avl; 1867185029Spjd nvlist_t *local_nv, *fs; 1868185029Spjd char *cp = strchr(zc.zc_value, '@'); 1869185029Spjd 1870185029Spjd /* 1871185029Spjd * XXX Do this faster by just iterating over snaps in 1872185029Spjd * this fs. Also if zc_value does not exist, we will 1873185029Spjd * get a strange "does not exist" error message. 1874185029Spjd */ 1875185029Spjd *cp = '\0'; 1876185029Spjd if (gather_nvlist(hdl, zc.zc_value, NULL, NULL, 1877185029Spjd &local_nv, &local_avl) == 0) { 1878185029Spjd *cp = '@'; 1879185029Spjd fs = fsavl_find(local_avl, drrb->drr_toguid, NULL); 1880185029Spjd fsavl_destroy(local_avl); 1881185029Spjd nvlist_free(local_nv); 1882185029Spjd 1883185029Spjd if (fs != NULL) { 1884185029Spjd if (flags.verbose) { 1885185029Spjd (void) printf("snap %s already exists; " 1886185029Spjd "ignoring\n", zc.zc_value); 1887185029Spjd } 1888185029Spjd ioctl_err = recv_skip(hdl, infd, 1889185029Spjd flags.byteswap); 1890185029Spjd } 1891185029Spjd } 1892185029Spjd *cp = '@'; 1893185029Spjd } 1894185029Spjd 1895185029Spjd 1896185029Spjd if (ioctl_err != 0) { 1897185029Spjd switch (ioctl_errno) { 1898185029Spjd case ENODEV: 1899185029Spjd cp = strchr(zc.zc_value, '@'); 1900185029Spjd *cp = '\0'; 1901185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1902185029Spjd "most recent snapshot of %s does not\n" 1903185029Spjd "match incremental source"), zc.zc_value); 1904185029Spjd (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 1905185029Spjd *cp = '@'; 1906185029Spjd break; 1907185029Spjd case ETXTBSY: 1908185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1909185029Spjd "destination %s has been modified\n" 1910185029Spjd "since most recent snapshot"), zc.zc_name); 1911185029Spjd (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 1912185029Spjd break; 1913185029Spjd case EEXIST: 1914185029Spjd cp = strchr(zc.zc_value, '@'); 1915185029Spjd if (newfs) { 1916185029Spjd /* it's the containing fs that exists */ 1917185029Spjd *cp = '\0'; 1918185029Spjd } 1919185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1920185029Spjd "destination already exists")); 1921185029Spjd (void) zfs_error_fmt(hdl, EZFS_EXISTS, 1922185029Spjd dgettext(TEXT_DOMAIN, "cannot restore to %s"), 1923185029Spjd zc.zc_value); 1924185029Spjd *cp = '@'; 1925185029Spjd break; 1926185029Spjd case EINVAL: 1927185029Spjd (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 1928185029Spjd break; 1929185029Spjd case ECKSUM: 1930185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1931185029Spjd "invalid stream (checksum mismatch)")); 1932185029Spjd (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 1933185029Spjd break; 1934185029Spjd default: 1935185029Spjd (void) zfs_standard_error(hdl, ioctl_errno, errbuf); 1936185029Spjd } 1937185029Spjd } 1938185029Spjd 1939185029Spjd /* 1940185029Spjd * Mount or recreate the /dev links for the target filesystem 1941185029Spjd * (if created, or if we tore them down to do an incremental 1942185029Spjd * restore), and the /dev links for the new snapshot (if 1943185029Spjd * created). Also mount any children of the target filesystem 1944185029Spjd * if we did an incremental receive. 1945185029Spjd */ 1946185029Spjd cp = strchr(zc.zc_value, '@'); 1947185029Spjd if (cp && (ioctl_err == 0 || !newfs)) { 1948185029Spjd zfs_handle_t *h; 1949185029Spjd 1950185029Spjd *cp = '\0'; 1951185029Spjd h = zfs_open(hdl, zc.zc_value, 1952185029Spjd ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 1953185029Spjd if (h != NULL) { 1954185029Spjd if (h->zfs_type == ZFS_TYPE_VOLUME) { 1955185029Spjd *cp = '@'; 1956185029Spjd err = zvol_create_link(hdl, h->zfs_name); 1957185029Spjd if (err == 0 && ioctl_err == 0) 1958185029Spjd err = zvol_create_link(hdl, 1959185029Spjd zc.zc_value); 1960185029Spjd } else if (newfs) { 1961185029Spjd /* 1962185029Spjd * Track the first/top of hierarchy fs, 1963185029Spjd * for mounting and sharing later. 1964185029Spjd */ 1965185029Spjd if (top_zfs && *top_zfs == NULL) 1966185029Spjd *top_zfs = zfs_strdup(hdl, zc.zc_value); 1967185029Spjd } 1968185029Spjd zfs_close(h); 1969185029Spjd } 1970185029Spjd *cp = '@'; 1971185029Spjd } 1972185029Spjd 1973185029Spjd if (clp) { 1974185029Spjd err |= changelist_postfix(clp); 1975185029Spjd changelist_free(clp); 1976185029Spjd } 1977185029Spjd 1978185029Spjd if (err || ioctl_err) 1979185029Spjd return (-1); 1980185029Spjd 1981185029Spjd if (flags.verbose) { 1982185029Spjd char buf1[64]; 1983185029Spjd char buf2[64]; 1984185029Spjd uint64_t bytes = zc.zc_cookie; 1985185029Spjd time_t delta = time(NULL) - begin_time; 1986185029Spjd if (delta == 0) 1987185029Spjd delta = 1; 1988185029Spjd zfs_nicenum(bytes, buf1, sizeof (buf1)); 1989185029Spjd zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 1990185029Spjd 1991185029Spjd (void) printf("received %sB stream in %lu seconds (%sB/sec)\n", 1992185029Spjd buf1, delta, buf2); 1993185029Spjd } 1994185029Spjd 1995185029Spjd return (0); 1996185029Spjd} 1997185029Spjd 1998185029Spjdstatic int 1999185029Spjdzfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags, 2000185029Spjd int infd, avl_tree_t *stream_avl, char **top_zfs) 2001185029Spjd{ 2002185029Spjd int err; 2003185029Spjd dmu_replay_record_t drr, drr_noswap; 2004185029Spjd struct drr_begin *drrb = &drr.drr_u.drr_begin; 2005185029Spjd char errbuf[1024]; 2006185029Spjd zio_cksum_t zcksum = { 0 }; 2007185029Spjd 2008185029Spjd (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2009185029Spjd "cannot receive")); 2010185029Spjd 2011185029Spjd if (flags.isprefix && 2012185029Spjd !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) { 2013185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs " 2014185029Spjd "(%s) does not exist"), tosnap); 2015185029Spjd return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2016185029Spjd } 2017185029Spjd 2018185029Spjd /* read in the BEGIN record */ 2019185029Spjd if (0 != (err = recv_read(hdl, infd, &drr, sizeof (drr), B_FALSE, 2020185029Spjd &zcksum))) 2021185029Spjd return (err); 2022185029Spjd 2023185029Spjd if (drr.drr_type == DRR_END || drr.drr_type == BSWAP_32(DRR_END)) { 2024185029Spjd /* It's the double end record at the end of a package */ 2025185029Spjd return (ENODATA); 2026185029Spjd } 2027185029Spjd 2028185029Spjd /* the kernel needs the non-byteswapped begin record */ 2029185029Spjd drr_noswap = drr; 2030185029Spjd 2031185029Spjd flags.byteswap = B_FALSE; 2032185029Spjd if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { 2033185029Spjd /* 2034185029Spjd * We computed the checksum in the wrong byteorder in 2035185029Spjd * recv_read() above; do it again correctly. 2036185029Spjd */ 2037185029Spjd bzero(&zcksum, sizeof (zio_cksum_t)); 2038185029Spjd fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum); 2039185029Spjd flags.byteswap = B_TRUE; 2040185029Spjd 2041185029Spjd drr.drr_type = BSWAP_32(drr.drr_type); 2042185029Spjd drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen); 2043185029Spjd drrb->drr_magic = BSWAP_64(drrb->drr_magic); 2044185029Spjd drrb->drr_version = BSWAP_64(drrb->drr_version); 2045185029Spjd drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 2046185029Spjd drrb->drr_type = BSWAP_32(drrb->drr_type); 2047185029Spjd drrb->drr_flags = BSWAP_32(drrb->drr_flags); 2048185029Spjd drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 2049185029Spjd drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 2050185029Spjd } 2051185029Spjd 2052185029Spjd if (drrb->drr_magic != DMU_BACKUP_MAGIC || drr.drr_type != DRR_BEGIN) { 2053185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2054185029Spjd "stream (bad magic number)")); 2055185029Spjd return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2056185029Spjd } 2057185029Spjd 2058185029Spjd if (strchr(drrb->drr_toname, '@') == NULL) { 2059185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2060185029Spjd "stream (bad snapshot name)")); 2061185029Spjd return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2062185029Spjd } 2063185029Spjd 2064185029Spjd if (drrb->drr_version == DMU_BACKUP_STREAM_VERSION) { 2065185029Spjd return (zfs_receive_one(hdl, infd, tosnap, flags, 2066185029Spjd &drr, &drr_noswap, stream_avl, top_zfs)); 2067185029Spjd } else if (drrb->drr_version == DMU_BACKUP_HEADER_VERSION) { 2068185029Spjd return (zfs_receive_package(hdl, infd, tosnap, flags, 2069185029Spjd &drr, &zcksum, top_zfs)); 2070185029Spjd } else { 2071185029Spjd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2072185029Spjd "stream is unsupported version %llu"), 2073185029Spjd drrb->drr_version); 2074185029Spjd return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2075185029Spjd } 2076185029Spjd} 2077185029Spjd 2078185029Spjd/* 2079185029Spjd * Restores a backup of tosnap from the file descriptor specified by infd. 2080185029Spjd * Return 0 on total success, -2 if some things couldn't be 2081185029Spjd * destroyed/renamed/promoted, -1 if some things couldn't be received. 2082185029Spjd * (-1 will override -2). 2083185029Spjd */ 2084185029Spjdint 2085185029Spjdzfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags, 2086185029Spjd int infd, avl_tree_t *stream_avl) 2087185029Spjd{ 2088185029Spjd char *top_zfs = NULL; 2089185029Spjd int err; 2090185029Spjd 2091185029Spjd err = zfs_receive_impl(hdl, tosnap, flags, infd, stream_avl, &top_zfs); 2092185029Spjd 2093200516Sdelphij if (err == 0 && !flags.nomount && top_zfs) { 2094185029Spjd zfs_handle_t *zhp; 2095185029Spjd prop_changelist_t *clp; 2096185029Spjd 2097185029Spjd zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM); 2098185029Spjd if (zhp != NULL) { 2099185029Spjd clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 2100185029Spjd CL_GATHER_MOUNT_ALWAYS, 0); 2101185029Spjd zfs_close(zhp); 2102185029Spjd if (clp != NULL) { 2103185029Spjd /* mount and share received datasets */ 2104185029Spjd err = changelist_postfix(clp); 2105185029Spjd changelist_free(clp); 2106185029Spjd } 2107185029Spjd } 2108185029Spjd if (zhp == NULL || clp == NULL || err) 2109185029Spjd err = -1; 2110185029Spjd } 2111185029Spjd if (top_zfs) 2112185029Spjd free(top_zfs); 2113185029Spjd 2114185029Spjd return (err); 2115185029Spjd} 2116