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