Path: blob/main/sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c
108769 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.24* Copyright (c) 2011, 2020 by Delphix. All rights reserved.25* Copyright (c) 2012, Joyent, Inc. All rights reserved.26* Copyright (c) 2012 Pawel Jakub Dawidek <[email protected]>.27* All rights reserved28* Copyright (c) 2013 Steven Hartland. All rights reserved.29* Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.30* Copyright 2016 Igor Kozhukhov <[email protected]>31* Copyright (c) 2018, loli10K <[email protected]>. All rights reserved.32* Copyright (c) 2019 Datto Inc.33* Copyright (c) 2024, Klara, Inc.34*/3536#include <assert.h>37#include <ctype.h>38#include <errno.h>39#include <libintl.h>40#include <stdio.h>41#include <stdlib.h>42#include <string.h>43#include <unistd.h>44#include <stddef.h>45#include <fcntl.h>46#include <sys/mount.h>47#include <sys/mntent.h>48#include <sys/mnttab.h>49#include <sys/avl.h>50#include <sys/debug.h>51#include <sys/stat.h>52#include <pthread.h>53#include <umem.h>54#include <time.h>5556#include <libzfs.h>57#include <libzfs_core.h>58#include <libzutil.h>5960#include "zfs_namecheck.h"61#include "zfs_prop.h"62#include "zfs_fletcher.h"63#include "libzfs_impl.h"64#include <cityhash.h>65#include <zlib.h>66#include <sys/zio_checksum.h>67#include <sys/dsl_crypt.h>68#include <sys/ddt.h>69#include <sys/socket.h>70#include <sys/sha2.h>7172static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,73recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **,74const char *, nvlist_t *);75static int guid_to_name_redact_snaps(libzfs_handle_t *hdl, const char *parent,76uint64_t guid, boolean_t bookmark_ok, uint64_t *redact_snap_guids,77uint64_t num_redact_snaps, char *name);78static int guid_to_name(libzfs_handle_t *, const char *,79uint64_t, boolean_t, char *);8081typedef struct progress_arg {82zfs_handle_t *pa_zhp;83int pa_fd;84boolean_t pa_parsable;85boolean_t pa_estimate;86int pa_verbosity;87boolean_t pa_astitle;88boolean_t pa_progress;89uint64_t pa_size;90} progress_arg_t;9192static int93dump_record(dmu_replay_record_t *drr, void *payload, size_t payload_len,94zio_cksum_t *zc, int outfd)95{96ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),97==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));98fletcher_4_incremental_native(drr,99offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), zc);100if (drr->drr_type != DRR_BEGIN) {101ASSERT(ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.102drr_checksum.drr_checksum));103drr->drr_u.drr_checksum.drr_checksum = *zc;104}105fletcher_4_incremental_native(&drr->drr_u.drr_checksum.drr_checksum,106sizeof (zio_cksum_t), zc);107if (write(outfd, drr, sizeof (*drr)) == -1)108return (errno);109if (payload_len != 0) {110fletcher_4_incremental_native(payload, payload_len, zc);111if (write(outfd, payload, payload_len) == -1)112return (errno);113}114return (0);115}116117/*118* Routines for dealing with the AVL tree of fs-nvlists119*/120typedef struct fsavl_node {121avl_node_t fn_node;122nvlist_t *fn_nvfs;123const char *fn_snapname;124uint64_t fn_guid;125} fsavl_node_t;126127static int128fsavl_compare(const void *arg1, const void *arg2)129{130const fsavl_node_t *fn1 = (const fsavl_node_t *)arg1;131const fsavl_node_t *fn2 = (const fsavl_node_t *)arg2;132133return (TREE_CMP(fn1->fn_guid, fn2->fn_guid));134}135136/*137* Given the GUID of a snapshot, find its containing filesystem and138* (optionally) name.139*/140static nvlist_t *141fsavl_find(avl_tree_t *avl, uint64_t snapguid, const char **snapname)142{143fsavl_node_t fn_find;144fsavl_node_t *fn;145146fn_find.fn_guid = snapguid;147148fn = avl_find(avl, &fn_find, NULL);149if (fn) {150if (snapname)151*snapname = fn->fn_snapname;152return (fn->fn_nvfs);153}154return (NULL);155}156157static void158fsavl_destroy(avl_tree_t *avl)159{160fsavl_node_t *fn;161void *cookie;162163if (avl == NULL)164return;165166cookie = NULL;167while ((fn = avl_destroy_nodes(avl, &cookie)) != NULL)168free(fn);169avl_destroy(avl);170free(avl);171}172173/*174* Given an nvlist, produce an avl tree of snapshots, ordered by guid175*/176static avl_tree_t *177fsavl_create(nvlist_t *fss)178{179avl_tree_t *fsavl;180nvpair_t *fselem = NULL;181182if ((fsavl = malloc(sizeof (avl_tree_t))) == NULL)183return (NULL);184185avl_create(fsavl, fsavl_compare, sizeof (fsavl_node_t),186offsetof(fsavl_node_t, fn_node));187188while ((fselem = nvlist_next_nvpair(fss, fselem)) != NULL) {189nvlist_t *nvfs, *snaps;190nvpair_t *snapelem = NULL;191192nvfs = fnvpair_value_nvlist(fselem);193snaps = fnvlist_lookup_nvlist(nvfs, "snaps");194195while ((snapelem =196nvlist_next_nvpair(snaps, snapelem)) != NULL) {197fsavl_node_t *fn;198199if ((fn = malloc(sizeof (fsavl_node_t))) == NULL) {200fsavl_destroy(fsavl);201return (NULL);202}203fn->fn_nvfs = nvfs;204fn->fn_snapname = nvpair_name(snapelem);205fn->fn_guid = fnvpair_value_uint64(snapelem);206207/*208* Note: if there are multiple snaps with the209* same GUID, we ignore all but one.210*/211avl_index_t where = 0;212if (avl_find(fsavl, fn, &where) == NULL)213avl_insert(fsavl, fn, where);214else215free(fn);216}217}218219return (fsavl);220}221222/*223* Routines for dealing with the giant nvlist of fs-nvlists, etc.224*/225typedef struct send_data {226/*227* assigned inside every recursive call,228* restored from *_save on return:229*230* guid of fromsnap snapshot in parent dataset231* txg of fromsnap snapshot in current dataset232* txg of tosnap snapshot in current dataset233*/234235uint64_t parent_fromsnap_guid;236uint64_t fromsnap_txg;237uint64_t tosnap_txg;238239/* the nvlists get accumulated during depth-first traversal */240nvlist_t *parent_snaps;241nvlist_t *fss;242nvlist_t *snapprops;243nvlist_t *snapholds; /* user holds */244245/* send-receive configuration, does not change during traversal */246const char *fsname;247const char *fromsnap;248const char *tosnap;249boolean_t recursive;250boolean_t raw;251boolean_t doall;252boolean_t replicate;253boolean_t skipmissing;254boolean_t verbose;255boolean_t backup;256boolean_t seenfrom;257boolean_t seento;258boolean_t holds; /* were holds requested with send -h */259boolean_t props;260261/*262* The header nvlist is of the following format:263* {264* "tosnap" -> string265* "fromsnap" -> string (if incremental)266* "fss" -> {267* id -> {268*269* "name" -> string (full name; for debugging)270* "parentfromsnap" -> number (guid of fromsnap in parent)271*272* "props" -> { name -> value (only if set here) }273* "snaps" -> { name (lastname) -> number (guid) }274* "snapprops" -> { name (lastname) -> { name -> value } }275* "snapholds" -> { name (lastname) -> { holdname -> crtime } }276*277* "origin" -> number (guid) (if clone)278* "is_encroot" -> boolean279* "sent" -> boolean (not on-disk)280* }281* }282* }283*284*/285} send_data_t;286287static void288send_iterate_prop(zfs_handle_t *zhp, boolean_t received_only, nvlist_t *nv);289290/*291* Collect guid, valid props, optionally holds, etc. of a snapshot.292* This interface is intended for use as a zfs_iter_snapshots_v2_sorted visitor.293*/294static int295send_iterate_snap(zfs_handle_t *zhp, void *arg)296{297send_data_t *sd = arg;298uint64_t guid = zhp->zfs_dmustats.dds_guid;299uint64_t txg = zhp->zfs_dmustats.dds_creation_txg;300boolean_t isfromsnap, istosnap, istosnapwithnofrom;301char *snapname;302const char *from = sd->fromsnap;303const char *to = sd->tosnap;304305snapname = strrchr(zhp->zfs_name, '@');306assert(snapname != NULL);307++snapname;308309isfromsnap = (from != NULL && strcmp(from, snapname) == 0);310istosnap = (to != NULL && strcmp(to, snapname) == 0);311istosnapwithnofrom = (istosnap && from == NULL);312313if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {314if (sd->verbose) {315(void) fprintf(stderr, dgettext(TEXT_DOMAIN,316"skipping snapshot %s because it was created "317"after the destination snapshot (%s)\n"),318zhp->zfs_name, to);319}320zfs_close(zhp);321return (0);322}323324fnvlist_add_uint64(sd->parent_snaps, snapname, guid);325326/*327* NB: if there is no fromsnap here (it's a newly created fs in328* an incremental replication), we will substitute the tosnap.329*/330if (isfromsnap || (sd->parent_fromsnap_guid == 0 && istosnap))331sd->parent_fromsnap_guid = guid;332333if (!sd->recursive) {334/*335* To allow a doall stream to work properly336* with a NULL fromsnap337*/338if (sd->doall && from == NULL && !sd->seenfrom)339sd->seenfrom = B_TRUE;340341if (!sd->seenfrom && isfromsnap) {342sd->seenfrom = B_TRUE;343zfs_close(zhp);344return (0);345}346347if ((sd->seento || !sd->seenfrom) && !istosnapwithnofrom) {348zfs_close(zhp);349return (0);350}351352if (istosnap)353sd->seento = B_TRUE;354}355356nvlist_t *nv = fnvlist_alloc();357send_iterate_prop(zhp, sd->backup, nv);358fnvlist_add_nvlist(sd->snapprops, snapname, nv);359fnvlist_free(nv);360361if (sd->holds) {362nvlist_t *holds;363if (lzc_get_holds(zhp->zfs_name, &holds) == 0) {364fnvlist_add_nvlist(sd->snapholds, snapname, holds);365fnvlist_free(holds);366}367}368369zfs_close(zhp);370return (0);371}372373/*374* Collect all valid props from the handle snap into an nvlist.375*/376static void377send_iterate_prop(zfs_handle_t *zhp, boolean_t received_only, nvlist_t *nv)378{379nvlist_t *props;380381if (received_only)382props = zfs_get_recvd_props(zhp);383else384props = zhp->zfs_props;385386nvpair_t *elem = NULL;387while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {388const char *propname = nvpair_name(elem);389zfs_prop_t prop = zfs_name_to_prop(propname);390391if (!zfs_prop_user(propname)) {392/*393* Realistically, this should never happen. However,394* we want the ability to add DSL properties without395* needing to make incompatible version changes. We396* need to ignore unknown properties to allow older397* software to still send datasets containing these398* properties, with the unknown properties elided.399*/400if (prop == ZPROP_INVAL)401continue;402403if (zfs_prop_readonly(prop))404continue;405}406407nvlist_t *propnv = fnvpair_value_nvlist(elem);408409boolean_t isspacelimit = (prop == ZFS_PROP_QUOTA ||410prop == ZFS_PROP_RESERVATION ||411prop == ZFS_PROP_REFQUOTA ||412prop == ZFS_PROP_REFRESERVATION);413if (isspacelimit && zhp->zfs_type == ZFS_TYPE_SNAPSHOT)414continue;415416const char *source;417if (nvlist_lookup_string(propnv, ZPROP_SOURCE, &source) == 0) {418if (strcmp(source, zhp->zfs_name) != 0 &&419strcmp(source, ZPROP_SOURCE_VAL_RECVD) != 0)420continue;421} else {422/*423* May have no source before SPA_VERSION_RECVD_PROPS,424* but is still modifiable.425*/426if (!isspacelimit)427continue;428}429430if (zfs_prop_user(propname) ||431zfs_prop_get_type(prop) == PROP_TYPE_STRING) {432const char *value;433value = fnvlist_lookup_string(propnv, ZPROP_VALUE);434fnvlist_add_string(nv, propname, value);435} else {436uint64_t value;437value = fnvlist_lookup_uint64(propnv, ZPROP_VALUE);438fnvlist_add_uint64(nv, propname, value);439}440}441}442443/*444* returns snapshot guid445* and returns 0 if the snapshot does not exist446*/447static uint64_t448get_snap_guid(libzfs_handle_t *hdl, const char *fs, const char *snap)449{450char name[MAXPATHLEN + 1];451uint64_t guid = 0;452453if (fs == NULL || fs[0] == '\0' || snap == NULL || snap[0] == '\0')454return (guid);455456(void) snprintf(name, sizeof (name), "%s@%s", fs, snap);457zfs_handle_t *zhp = zfs_open(hdl, name, ZFS_TYPE_SNAPSHOT);458if (zhp != NULL) {459guid = zfs_prop_get_int(zhp, ZFS_PROP_GUID);460zfs_close(zhp);461}462463return (guid);464}465466/*467* returns snapshot creation txg468* and returns 0 if the snapshot does not exist469*/470static uint64_t471get_snap_txg(libzfs_handle_t *hdl, const char *fs, const char *snap)472{473char name[ZFS_MAX_DATASET_NAME_LEN];474uint64_t txg = 0;475476if (fs == NULL || fs[0] == '\0' || snap == NULL || snap[0] == '\0')477return (txg);478479(void) snprintf(name, sizeof (name), "%s@%s", fs, snap);480if (zfs_dataset_exists(hdl, name, ZFS_TYPE_SNAPSHOT)) {481zfs_handle_t *zhp = zfs_open(hdl, name, ZFS_TYPE_SNAPSHOT);482if (zhp != NULL) {483txg = zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG);484zfs_close(zhp);485}486}487488return (txg);489}490491/*492* Recursively generate nvlists describing datasets. See comment493* for the data structure send_data_t above for description of contents494* of the nvlist.495*/496static int497send_iterate_fs(zfs_handle_t *zhp, void *arg)498{499send_data_t *sd = arg;500nvlist_t *nvfs = NULL, *nv = NULL;501int rv = 0;502uint64_t min_txg = 0, max_txg = 0;503uint64_t txg = zhp->zfs_dmustats.dds_creation_txg;504uint64_t guid = zhp->zfs_dmustats.dds_guid;505uint64_t fromsnap_txg, tosnap_txg;506char guidstring[64];507508/* These fields are restored on return from a recursive call. */509uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid;510uint64_t fromsnap_txg_save = sd->fromsnap_txg;511uint64_t tosnap_txg_save = sd->tosnap_txg;512513fromsnap_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sd->fromsnap);514if (fromsnap_txg != 0)515sd->fromsnap_txg = fromsnap_txg;516517tosnap_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sd->tosnap);518if (tosnap_txg != 0)519sd->tosnap_txg = tosnap_txg;520521/*522* On the send side, if the current dataset does not have tosnap,523* perform two additional checks:524*525* - Skip sending the current dataset if it was created later than526* the parent tosnap.527* - Return error if the current dataset was created earlier than528* the parent tosnap, unless --skip-missing specified. Then529* just print a warning.530*/531if (sd->tosnap != NULL && tosnap_txg == 0) {532if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {533if (sd->verbose) {534(void) fprintf(stderr, dgettext(TEXT_DOMAIN,535"skipping dataset %s: snapshot %s does "536"not exist\n"), zhp->zfs_name, sd->tosnap);537}538} else if (sd->skipmissing) {539(void) fprintf(stderr, dgettext(TEXT_DOMAIN,540"WARNING: skipping dataset %s and its children:"541" snapshot %s does not exist\n"),542zhp->zfs_name, sd->tosnap);543} else {544(void) fprintf(stderr, dgettext(TEXT_DOMAIN,545"cannot send %s@%s%s: snapshot %s@%s does not "546"exist\n"), sd->fsname, sd->tosnap, sd->recursive ?547dgettext(TEXT_DOMAIN, " recursively") : "",548zhp->zfs_name, sd->tosnap);549rv = EZFS_NOENT;550}551goto out;552}553554nvfs = fnvlist_alloc();555fnvlist_add_string(nvfs, "name", zhp->zfs_name);556fnvlist_add_uint64(nvfs, "parentfromsnap", sd->parent_fromsnap_guid);557558if (zhp->zfs_dmustats.dds_origin[0] != '\0') {559zfs_handle_t *origin = zfs_open(zhp->zfs_hdl,560zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT);561if (origin == NULL) {562rv = -1;563goto out;564}565fnvlist_add_uint64(nvfs, "origin",566origin->zfs_dmustats.dds_guid);567zfs_close(origin);568}569570/* Iterate over props. */571if (sd->props || sd->backup || sd->recursive) {572nv = fnvlist_alloc();573send_iterate_prop(zhp, sd->backup, nv);574fnvlist_add_nvlist(nvfs, "props", nv);575}576if (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) != ZIO_CRYPT_OFF) {577boolean_t encroot;578579/* Determine if this dataset is an encryption root. */580if (zfs_crypto_get_encryption_root(zhp, &encroot, NULL) != 0) {581rv = -1;582goto out;583}584585if (encroot)586fnvlist_add_boolean(nvfs, "is_encroot");587588/*589* Encrypted datasets can only be sent with properties if590* the raw flag is specified because the receive side doesn't591* currently have a mechanism for recursively asking the user592* for new encryption parameters.593*/594if (!sd->raw) {595(void) fprintf(stderr, dgettext(TEXT_DOMAIN,596"cannot send %s@%s: encrypted dataset %s may not "597"be sent with properties without the raw flag\n"),598sd->fsname, sd->tosnap, zhp->zfs_name);599rv = -1;600goto out;601}602603}604605/*606* Iterate over snaps, and set sd->parent_fromsnap_guid.607*608* If this is a "doall" send, a replicate send or we're just trying609* to gather a list of previous snapshots, iterate through all the610* snaps in the txg range. Otherwise just look at the one we're611* interested in.612*/613sd->parent_fromsnap_guid = 0;614sd->parent_snaps = fnvlist_alloc();615sd->snapprops = fnvlist_alloc();616if (sd->holds)617sd->snapholds = fnvlist_alloc();618if (sd->doall || sd->replicate || sd->tosnap == NULL) {619if (!sd->replicate && fromsnap_txg != 0)620min_txg = fromsnap_txg;621if (!sd->replicate && tosnap_txg != 0)622max_txg = tosnap_txg;623(void) zfs_iter_snapshots_sorted_v2(zhp, 0, send_iterate_snap,624sd, min_txg, max_txg);625} else {626char snapname[MAXPATHLEN] = { 0 };627zfs_handle_t *snap;628629(void) snprintf(snapname, sizeof (snapname), "%s@%s",630zhp->zfs_name, sd->tosnap);631if (sd->fromsnap != NULL)632sd->seenfrom = B_TRUE;633snap = zfs_open(zhp->zfs_hdl, snapname, ZFS_TYPE_SNAPSHOT);634if (snap != NULL)635(void) send_iterate_snap(snap, sd);636}637638fnvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps);639fnvlist_free(sd->parent_snaps);640fnvlist_add_nvlist(nvfs, "snapprops", sd->snapprops);641fnvlist_free(sd->snapprops);642if (sd->holds) {643fnvlist_add_nvlist(nvfs, "snapholds", sd->snapholds);644fnvlist_free(sd->snapholds);645}646647/* Do not allow the size of the properties list to exceed the limit */648if ((fnvlist_size(nvfs) + fnvlist_size(sd->fss)) >649zhp->zfs_hdl->libzfs_max_nvlist) {650(void) fprintf(stderr, dgettext(TEXT_DOMAIN,651"warning: cannot send %s@%s: the size of the list of "652"snapshots and properties is too large to be received "653"successfully.\n"654"Select a smaller number of snapshots to send.\n"),655zhp->zfs_name, sd->tosnap);656rv = EZFS_NOSPC;657goto out;658}659/* Add this fs to nvlist. */660(void) snprintf(guidstring, sizeof (guidstring),661"0x%llx", (longlong_t)guid);662fnvlist_add_nvlist(sd->fss, guidstring, nvfs);663664/* Iterate over children. */665if (sd->recursive)666rv = zfs_iter_filesystems_v2(zhp, 0, send_iterate_fs, sd);667668out:669/* Restore saved fields. */670sd->parent_fromsnap_guid = parent_fromsnap_guid_save;671sd->fromsnap_txg = fromsnap_txg_save;672sd->tosnap_txg = tosnap_txg_save;673674fnvlist_free(nv);675fnvlist_free(nvfs);676677zfs_close(zhp);678return (rv);679}680681static int682gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,683const char *tosnap, boolean_t recursive, boolean_t raw, boolean_t doall,684boolean_t replicate, boolean_t skipmissing, boolean_t verbose,685boolean_t backup, boolean_t holds, boolean_t props, nvlist_t **nvlp,686avl_tree_t **avlp)687{688zfs_handle_t *zhp;689send_data_t sd = { 0 };690int error;691692zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);693if (zhp == NULL)694return (EZFS_BADTYPE);695696sd.fss = fnvlist_alloc();697sd.fsname = fsname;698sd.fromsnap = fromsnap;699sd.tosnap = tosnap;700sd.recursive = recursive;701sd.raw = raw;702sd.doall = doall;703sd.replicate = replicate;704sd.skipmissing = skipmissing;705sd.verbose = verbose;706sd.backup = backup;707sd.holds = holds;708sd.props = props;709710if ((error = send_iterate_fs(zhp, &sd)) != 0) {711fnvlist_free(sd.fss);712if (avlp != NULL)713*avlp = NULL;714*nvlp = NULL;715return (error);716}717718if (avlp != NULL && (*avlp = fsavl_create(sd.fss)) == NULL) {719fnvlist_free(sd.fss);720*nvlp = NULL;721return (EZFS_NOMEM);722}723724*nvlp = sd.fss;725return (0);726}727728/*729* Routines specific to "zfs send"730*/731typedef struct send_dump_data {732/* these are all just the short snapname (the part after the @) */733const char *fromsnap;734const char *tosnap;735char prevsnap[ZFS_MAX_DATASET_NAME_LEN];736uint64_t prevsnap_obj;737boolean_t seenfrom, seento, replicate, doall, fromorigin;738boolean_t dryrun, parsable, progress, embed_data, std_out;739boolean_t large_block, compress, raw, holds;740boolean_t progressastitle;741int outfd;742boolean_t err;743nvlist_t *fss;744nvlist_t *snapholds;745avl_tree_t *fsavl;746snapfilter_cb_t *filter_cb;747void *filter_cb_arg;748nvlist_t *debugnv;749char holdtag[ZFS_MAX_DATASET_NAME_LEN];750int cleanup_fd;751int verbosity;752uint64_t size;753} send_dump_data_t;754755static int756zfs_send_space(zfs_handle_t *zhp, const char *snapname, const char *from,757enum lzc_send_flags flags, uint64_t *spacep)758{759assert(snapname != NULL);760761int error = lzc_send_space(snapname, from, flags, spacep);762if (error == 0)763return (0);764765char errbuf[ERRBUFLEN];766(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,767"warning: cannot estimate space for '%s'"), snapname);768769libzfs_handle_t *hdl = zhp->zfs_hdl;770switch (error) {771case EXDEV:772zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,773"not an earlier snapshot from the same fs"));774return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));775776case ENOENT:777if (zfs_dataset_exists(hdl, snapname,778ZFS_TYPE_SNAPSHOT)) {779zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,780"incremental source (%s) does not exist"),781snapname);782}783return (zfs_error(hdl, EZFS_NOENT, errbuf));784785case EDQUOT:786case EFBIG:787case EIO:788case ENOLINK:789case ENOSPC:790case ENOSTR:791case ENXIO:792case EPIPE:793case ERANGE:794case EFAULT:795case EROFS:796case EINVAL:797zfs_error_aux(hdl, "%s", zfs_strerror(error));798return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));799800default:801return (zfs_standard_error(hdl, error, errbuf));802}803}804805/*806* Dumps a backup of the given snapshot (incremental from fromsnap if it's not807* NULL) to the file descriptor specified by outfd.808*/809static int810dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,811boolean_t fromorigin, int outfd, enum lzc_send_flags flags,812nvlist_t *debugnv)813{814zfs_cmd_t zc = {"\0"};815libzfs_handle_t *hdl = zhp->zfs_hdl;816nvlist_t *thisdbg;817818assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);819assert(fromsnap_obj == 0 || !fromorigin);820821(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));822zc.zc_cookie = outfd;823zc.zc_obj = fromorigin;824zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);825zc.zc_fromobj = fromsnap_obj;826zc.zc_flags = flags;827828if (debugnv != NULL) {829thisdbg = fnvlist_alloc();830if (fromsnap != NULL && fromsnap[0] != '\0')831fnvlist_add_string(thisdbg, "fromsnap", fromsnap);832}833834if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {835char errbuf[ERRBUFLEN];836int error = errno;837838(void) snprintf(errbuf, sizeof (errbuf), "%s '%s'",839dgettext(TEXT_DOMAIN, "warning: cannot send"),840zhp->zfs_name);841842if (debugnv != NULL) {843fnvlist_add_uint64(thisdbg, "error", error);844fnvlist_add_nvlist(debugnv, zhp->zfs_name, thisdbg);845fnvlist_free(thisdbg);846}847848switch (error) {849case EXDEV:850zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,851"not an earlier snapshot from the same fs"));852return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));853854case EACCES:855zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,856"source key must be loaded"));857return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));858859case ENOENT:860if (zfs_dataset_exists(hdl, zc.zc_name,861ZFS_TYPE_SNAPSHOT)) {862zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,863"incremental source (@%s) does not exist"),864zc.zc_value);865}866return (zfs_error(hdl, EZFS_NOENT, errbuf));867868case EDQUOT:869case EFBIG:870case EIO:871case ENOLINK:872case ENOSPC:873case ENOSTR:874case ENXIO:875case EPIPE:876case ERANGE:877case EFAULT:878case EROFS:879case EINVAL:880zfs_error_aux(hdl, "%s", zfs_strerror(errno));881return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));882883default:884return (zfs_standard_error(hdl, errno, errbuf));885}886}887888if (debugnv != NULL) {889fnvlist_add_nvlist(debugnv, zhp->zfs_name, thisdbg);890fnvlist_free(thisdbg);891}892893return (0);894}895896static void897gather_holds(zfs_handle_t *zhp, send_dump_data_t *sdd)898{899assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);900901/*902* zfs_send() only sets snapholds for sends that need them,903* e.g. replication and doall.904*/905if (sdd->snapholds == NULL)906return;907908fnvlist_add_string(sdd->snapholds, zhp->zfs_name, sdd->holdtag);909}910911int912zfs_send_progress(zfs_handle_t *zhp, int fd, uint64_t *bytes_written,913uint64_t *blocks_visited)914{915zfs_cmd_t zc = {"\0"};916917if (bytes_written != NULL)918*bytes_written = 0;919if (blocks_visited != NULL)920*blocks_visited = 0;921(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));922zc.zc_cookie = fd;923if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND_PROGRESS, &zc) != 0)924return (errno);925if (bytes_written != NULL)926*bytes_written = zc.zc_cookie;927if (blocks_visited != NULL)928*blocks_visited = zc.zc_objset_type;929return (0);930}931932static volatile boolean_t send_progress_thread_signal_duetotimer;933static void934send_progress_thread_act(int sig, siginfo_t *info, void *ucontext)935{936(void) sig, (void) ucontext;937send_progress_thread_signal_duetotimer = info->si_code == SI_TIMER;938}939940struct timer_desirability {941timer_t timer;942boolean_t desired;943};944static void945timer_delete_cleanup(void *timer)946{947struct timer_desirability *td = timer;948if (td->desired)949timer_delete(td->timer);950}951952#ifdef SIGINFO953#define SEND_PROGRESS_THREAD_PARENT_BLOCK_SIGINFO sigaddset(&new, SIGINFO)954#else955#define SEND_PROGRESS_THREAD_PARENT_BLOCK_SIGINFO956#endif957#define SEND_PROGRESS_THREAD_PARENT_BLOCK(old) { \958sigset_t new; \959sigemptyset(&new); \960sigaddset(&new, SIGUSR1); \961SEND_PROGRESS_THREAD_PARENT_BLOCK_SIGINFO; \962pthread_sigmask(SIG_BLOCK, &new, old); \963}964965static void *966send_progress_thread(void *arg)967{968progress_arg_t *pa = arg;969zfs_handle_t *zhp = pa->pa_zhp;970uint64_t bytes;971uint64_t blocks;972uint64_t total = pa->pa_size / 100;973char buf[16];974time_t t;975struct tm tm;976int err;977978const struct sigaction signal_action =979{.sa_sigaction = send_progress_thread_act, .sa_flags = SA_SIGINFO};980struct sigevent timer_cfg =981{.sigev_notify = SIGEV_SIGNAL, .sigev_signo = SIGUSR1};982const struct itimerspec timer_time =983{.it_value = {.tv_sec = 1}, .it_interval = {.tv_sec = 1}};984struct timer_desirability timer = {};985986sigaction(SIGUSR1, &signal_action, NULL);987#ifdef SIGINFO988sigaction(SIGINFO, &signal_action, NULL);989#endif990991if ((timer.desired = pa->pa_progress || pa->pa_astitle)) {992if (timer_create(CLOCK_MONOTONIC, &timer_cfg, &timer.timer))993return ((void *)(uintptr_t)errno);994(void) timer_settime(timer.timer, 0, &timer_time, NULL);995}996pthread_cleanup_push(timer_delete_cleanup, &timer);997998if (!pa->pa_parsable && pa->pa_progress) {999(void) fprintf(stderr,1000"TIME %s %sSNAPSHOT %s\n",1001pa->pa_estimate ? "BYTES" : " SENT",1002pa->pa_verbosity >= 2 ? " BLOCKS " : "",1003zhp->zfs_name);1004}10051006/*1007* Print the progress from ZFS_IOC_SEND_PROGRESS every second.1008*/1009for (;;) {1010pause();1011if ((err = zfs_send_progress(zhp, pa->pa_fd, &bytes,1012&blocks)) != 0) {1013if (err == EINTR || err == ENOENT)1014err = 0;1015/* Use break to reach pthread_cleanup_pop() below. */1016break;1017}10181019(void) time(&t);1020localtime_r(&t, &tm);10211022if (pa->pa_astitle) {1023char buf_bytes[16];1024char buf_size[16];1025int pct;1026zfs_nicenum(bytes, buf_bytes, sizeof (buf_bytes));1027zfs_nicenum(pa->pa_size, buf_size, sizeof (buf_size));1028pct = (total > 0) ? bytes / total : 100;1029zfs_setproctitle("sending %s (%d%%: %s/%s)",1030zhp->zfs_name, MIN(pct, 100), buf_bytes, buf_size);1031}10321033if (pa->pa_verbosity >= 2 && pa->pa_parsable) {1034(void) fprintf(stderr,1035"%02d:%02d:%02d\t%llu\t%llu\t%s\n",1036tm.tm_hour, tm.tm_min, tm.tm_sec,1037(u_longlong_t)bytes, (u_longlong_t)blocks,1038zhp->zfs_name);1039} else if (pa->pa_verbosity >= 2) {1040zfs_nicenum(bytes, buf, sizeof (buf));1041(void) fprintf(stderr,1042"%02d:%02d:%02d %5s %8llu %s\n",1043tm.tm_hour, tm.tm_min, tm.tm_sec,1044buf, (u_longlong_t)blocks, zhp->zfs_name);1045} else if (pa->pa_parsable) {1046(void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n",1047tm.tm_hour, tm.tm_min, tm.tm_sec,1048(u_longlong_t)bytes, zhp->zfs_name);1049} else if (pa->pa_progress ||1050!send_progress_thread_signal_duetotimer) {1051zfs_nicebytes(bytes, buf, sizeof (buf));1052(void) fprintf(stderr, "%02d:%02d:%02d %5s %s\n",1053tm.tm_hour, tm.tm_min, tm.tm_sec,1054buf, zhp->zfs_name);1055}1056}1057pthread_cleanup_pop(B_TRUE);1058pthread_exit(((void *)(uintptr_t)err));1059}10601061static boolean_t1062send_progress_thread_exit(1063libzfs_handle_t *hdl, pthread_t ptid, sigset_t *oldmask)1064{1065void *status = NULL;1066(void) pthread_cancel(ptid);1067(void) pthread_join(ptid, &status);1068pthread_sigmask(SIG_SETMASK, oldmask, NULL);1069int error = (int)(uintptr_t)status;1070if (error != 0 && status != PTHREAD_CANCELED)1071return (zfs_standard_error(hdl, error,1072dgettext(TEXT_DOMAIN, "progress thread exited nonzero")));1073else1074return (B_FALSE);1075}10761077static void1078send_print_verbose(FILE *fout, const char *tosnap, const char *fromsnap,1079uint64_t size, boolean_t parsable)1080{1081if (parsable) {1082if (fromsnap != NULL) {1083(void) fprintf(fout, dgettext(TEXT_DOMAIN,1084"incremental\t%s\t%s"), fromsnap, tosnap);1085} else {1086/*1087* Workaround for GCC 12+ with UBSan enabled deficencies.1088*1089* GCC 12+ invoked with -fsanitize=undefined incorrectly reports the code1090* below as violating -Wformat-overflow.1091*/1092#if defined(__GNUC__) && !defined(__clang__) && \1093defined(ZFS_UBSAN_ENABLED) && defined(HAVE_FORMAT_OVERFLOW)1094#pragma GCC diagnostic push1095#pragma GCC diagnostic ignored "-Wformat-overflow"1096#endif1097(void) fprintf(fout, dgettext(TEXT_DOMAIN,1098"full\t%s"), tosnap);1099#if defined(__GNUC__) && !defined(__clang__) && \1100defined(ZFS_UBSAN_ENABLED) && defined(HAVE_FORMAT_OVERFLOW)1101#pragma GCC diagnostic pop1102#endif1103}1104(void) fprintf(fout, "\t%llu", (longlong_t)size);1105} else {1106if (fromsnap != NULL) {1107if (strchr(fromsnap, '@') == NULL &&1108strchr(fromsnap, '#') == NULL) {1109(void) fprintf(fout, dgettext(TEXT_DOMAIN,1110"send from @%s to %s"), fromsnap, tosnap);1111} else {1112(void) fprintf(fout, dgettext(TEXT_DOMAIN,1113"send from %s to %s"), fromsnap, tosnap);1114}1115} else {1116(void) fprintf(fout, dgettext(TEXT_DOMAIN,1117"full send of %s"), tosnap);1118}1119if (size != 0) {1120char buf[16];1121zfs_nicebytes(size, buf, sizeof (buf));1122/*1123* Workaround for GCC 12+ with UBSan enabled deficencies.1124*1125* GCC 12+ invoked with -fsanitize=undefined incorrectly reports the code1126* below as violating -Wformat-overflow.1127*/1128#if defined(__GNUC__) && !defined(__clang__) && \1129defined(ZFS_UBSAN_ENABLED) && defined(HAVE_FORMAT_OVERFLOW)1130#pragma GCC diagnostic push1131#pragma GCC diagnostic ignored "-Wformat-overflow"1132#endif1133(void) fprintf(fout, dgettext(TEXT_DOMAIN,1134" estimated size is %s"), buf);1135#if defined(__GNUC__) && !defined(__clang__) && \1136defined(ZFS_UBSAN_ENABLED) && defined(HAVE_FORMAT_OVERFLOW)1137#pragma GCC diagnostic pop1138#endif1139}1140}1141(void) fprintf(fout, "\n");1142}11431144/*1145* Send a single filesystem snapshot, updating the send dump data.1146* This interface is intended for use as a zfs_iter_snapshots_v2_sorted visitor.1147*/1148static int1149dump_snapshot(zfs_handle_t *zhp, void *arg)1150{1151send_dump_data_t *sdd = arg;1152progress_arg_t pa = { 0 };1153pthread_t tid;1154char *thissnap;1155enum lzc_send_flags flags = 0;1156int err;1157boolean_t isfromsnap, istosnap, fromorigin;1158boolean_t exclude = B_FALSE;1159FILE *fout = sdd->std_out ? stdout : stderr;11601161err = 0;1162thissnap = strchr(zhp->zfs_name, '@') + 1;1163isfromsnap = (sdd->fromsnap != NULL &&1164strcmp(sdd->fromsnap, thissnap) == 0);11651166if (!sdd->seenfrom && isfromsnap) {1167gather_holds(zhp, sdd);1168sdd->seenfrom = B_TRUE;1169(void) strlcpy(sdd->prevsnap, thissnap, sizeof (sdd->prevsnap));1170sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);1171zfs_close(zhp);1172return (0);1173}11741175if (sdd->seento || !sdd->seenfrom) {1176zfs_close(zhp);1177return (0);1178}11791180istosnap = (strcmp(sdd->tosnap, thissnap) == 0);1181if (istosnap)1182sdd->seento = B_TRUE;11831184if (sdd->large_block)1185flags |= LZC_SEND_FLAG_LARGE_BLOCK;1186if (sdd->embed_data)1187flags |= LZC_SEND_FLAG_EMBED_DATA;1188if (sdd->compress)1189flags |= LZC_SEND_FLAG_COMPRESS;1190if (sdd->raw)1191flags |= LZC_SEND_FLAG_RAW;11921193if (!sdd->doall && !isfromsnap && !istosnap) {1194if (sdd->replicate) {1195const char *snapname;1196nvlist_t *snapprops;1197/*1198* Filter out all intermediate snapshots except origin1199* snapshots needed to replicate clones.1200*/1201nvlist_t *nvfs = fsavl_find(sdd->fsavl,1202zhp->zfs_dmustats.dds_guid, &snapname);12031204if (nvfs != NULL) {1205snapprops = fnvlist_lookup_nvlist(nvfs,1206"snapprops");1207snapprops = fnvlist_lookup_nvlist(snapprops,1208thissnap);1209exclude = !nvlist_exists(snapprops,1210"is_clone_origin");1211}1212} else {1213exclude = B_TRUE;1214}1215}12161217/*1218* If a filter function exists, call it to determine whether1219* this snapshot will be sent.1220*/1221if (exclude || (sdd->filter_cb != NULL &&1222sdd->filter_cb(zhp, sdd->filter_cb_arg) == B_FALSE)) {1223/*1224* This snapshot is filtered out. Don't send it, and don't1225* set prevsnap_obj, so it will be as if this snapshot didn't1226* exist, and the next accepted snapshot will be sent as1227* an incremental from the last accepted one, or as the1228* first (and full) snapshot in the case of a replication,1229* non-incremental send.1230*/1231zfs_close(zhp);1232return (0);1233}12341235gather_holds(zhp, sdd);1236fromorigin = sdd->prevsnap[0] == '\0' &&1237(sdd->fromorigin || sdd->replicate);12381239if (sdd->verbosity != 0) {1240uint64_t size = 0;1241char fromds[ZFS_MAX_DATASET_NAME_LEN];12421243if (sdd->prevsnap[0] != '\0') {1244(void) strlcpy(fromds, zhp->zfs_name, sizeof (fromds));1245*(strchr(fromds, '@') + 1) = '\0';1246(void) strlcat(fromds, sdd->prevsnap, sizeof (fromds));1247}1248if (zfs_send_space(zhp, zhp->zfs_name,1249sdd->prevsnap[0] ? fromds : NULL, flags, &size) == 0) {1250send_print_verbose(fout, zhp->zfs_name,1251sdd->prevsnap[0] ? sdd->prevsnap : NULL,1252size, sdd->parsable);1253sdd->size += size;1254}1255}12561257if (!sdd->dryrun) {1258/*1259* If progress reporting is requested, spawn a new thread to1260* poll ZFS_IOC_SEND_PROGRESS at a regular interval.1261*/1262sigset_t oldmask;1263{1264pa.pa_zhp = zhp;1265pa.pa_fd = sdd->outfd;1266pa.pa_parsable = sdd->parsable;1267pa.pa_estimate = B_FALSE;1268pa.pa_verbosity = sdd->verbosity;1269pa.pa_size = sdd->size;1270pa.pa_astitle = sdd->progressastitle;1271pa.pa_progress = sdd->progress;12721273if ((err = pthread_create(&tid, NULL,1274send_progress_thread, &pa)) != 0) {1275zfs_close(zhp);1276return (err);1277}1278SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);1279}12801281err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,1282fromorigin, sdd->outfd, flags, sdd->debugnv);12831284if (send_progress_thread_exit(zhp->zfs_hdl, tid, &oldmask))1285return (-1);1286}12871288(void) strlcpy(sdd->prevsnap, thissnap, sizeof (sdd->prevsnap));1289sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);1290zfs_close(zhp);1291return (err);1292}12931294/*1295* Send all snapshots for a filesystem, updating the send dump data.1296*/1297static int1298dump_filesystem(zfs_handle_t *zhp, send_dump_data_t *sdd)1299{1300int rv = 0;1301boolean_t missingfrom = B_FALSE;1302zfs_cmd_t zc = {"\0"};1303uint64_t min_txg = 0, max_txg = 0;13041305/*1306* Make sure the tosnap exists.1307*/1308(void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",1309zhp->zfs_name, sdd->tosnap);1310if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_STATS, &zc) != 0) {1311(void) fprintf(stderr, dgettext(TEXT_DOMAIN,1312"WARNING: could not send %s@%s: does not exist\n"),1313zhp->zfs_name, sdd->tosnap);1314sdd->err = B_TRUE;1315return (0);1316}13171318/*1319* If this fs does not have fromsnap, and we're doing1320* recursive, we need to send a full stream from the1321* beginning (or an incremental from the origin if this1322* is a clone). If we're doing non-recursive, then let1323* them get the error.1324*/1325if (sdd->replicate && sdd->fromsnap) {1326/*1327* Make sure the fromsnap exists.1328*/1329(void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",1330zhp->zfs_name, sdd->fromsnap);1331if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_STATS, &zc) != 0)1332missingfrom = B_TRUE;1333}13341335sdd->seenfrom = sdd->seento = B_FALSE;1336sdd->prevsnap[0] = '\0';1337sdd->prevsnap_obj = 0;1338if (sdd->fromsnap == NULL || missingfrom)1339sdd->seenfrom = B_TRUE;13401341/*1342* Iterate through all snapshots and process the ones we will be1343* sending. If we only have a "from" and "to" snapshot to deal1344* with, we can avoid iterating through all the other snapshots.1345*/1346if (sdd->doall || sdd->replicate || sdd->tosnap == NULL) {1347if (!sdd->replicate) {1348if (sdd->fromsnap != NULL) {1349min_txg = get_snap_txg(zhp->zfs_hdl,1350zhp->zfs_name, sdd->fromsnap);1351}1352if (sdd->tosnap != NULL) {1353max_txg = get_snap_txg(zhp->zfs_hdl,1354zhp->zfs_name, sdd->tosnap);1355}1356}1357rv = zfs_iter_snapshots_sorted_v2(zhp, 0, dump_snapshot, sdd,1358min_txg, max_txg);1359} else {1360char snapname[MAXPATHLEN] = { 0 };1361zfs_handle_t *snap;13621363/* Dump fromsnap. */1364if (!sdd->seenfrom) {1365(void) snprintf(snapname, sizeof (snapname),1366"%s@%s", zhp->zfs_name, sdd->fromsnap);1367snap = zfs_open(zhp->zfs_hdl, snapname,1368ZFS_TYPE_SNAPSHOT);1369if (snap != NULL)1370rv = dump_snapshot(snap, sdd);1371else1372rv = errno;1373}13741375/* Dump tosnap. */1376if (rv == 0) {1377(void) snprintf(snapname, sizeof (snapname),1378"%s@%s", zhp->zfs_name, sdd->tosnap);1379snap = zfs_open(zhp->zfs_hdl, snapname,1380ZFS_TYPE_SNAPSHOT);1381if (snap != NULL)1382rv = dump_snapshot(snap, sdd);1383else1384rv = errno;1385}1386}13871388if (!sdd->seenfrom) {1389(void) fprintf(stderr, dgettext(TEXT_DOMAIN,1390"WARNING: could not send %s@%s:\n"1391"incremental source (%s@%s) does not exist\n"),1392zhp->zfs_name, sdd->tosnap,1393zhp->zfs_name, sdd->fromsnap);1394sdd->err = B_TRUE;1395} else if (!sdd->seento) {1396if (sdd->fromsnap) {1397(void) fprintf(stderr, dgettext(TEXT_DOMAIN,1398"WARNING: could not send %s@%s:\n"1399"incremental source (%s@%s) "1400"is not earlier than it\n"),1401zhp->zfs_name, sdd->tosnap,1402zhp->zfs_name, sdd->fromsnap);1403} else {1404(void) fprintf(stderr, dgettext(TEXT_DOMAIN,1405"WARNING: "1406"could not send %s@%s: does not exist\n"),1407zhp->zfs_name, sdd->tosnap);1408}1409sdd->err = B_TRUE;1410}14111412return (rv);1413}14141415/*1416* Send all snapshots for all filesystems in sdd.1417*/1418static int1419dump_filesystems(zfs_handle_t *rzhp, send_dump_data_t *sdd)1420{1421nvpair_t *fspair;1422boolean_t needagain, progress;14231424if (!sdd->replicate)1425return (dump_filesystem(rzhp, sdd));14261427/* Mark the clone origin snapshots. */1428for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;1429fspair = nvlist_next_nvpair(sdd->fss, fspair)) {1430nvlist_t *nvfs;1431uint64_t origin_guid = 0;14321433nvfs = fnvpair_value_nvlist(fspair);1434(void) nvlist_lookup_uint64(nvfs, "origin", &origin_guid);1435if (origin_guid != 0) {1436const char *snapname;1437nvlist_t *origin_nv = fsavl_find(sdd->fsavl,1438origin_guid, &snapname);1439if (origin_nv != NULL) {1440nvlist_t *snapprops;1441snapprops = fnvlist_lookup_nvlist(origin_nv,1442"snapprops");1443snapprops = fnvlist_lookup_nvlist(snapprops,1444snapname);1445fnvlist_add_boolean(snapprops,1446"is_clone_origin");1447}1448}1449}1450again:1451needagain = progress = B_FALSE;1452for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;1453fspair = nvlist_next_nvpair(sdd->fss, fspair)) {1454nvlist_t *fslist, *parent_nv;1455const char *fsname;1456zfs_handle_t *zhp;1457int err;1458uint64_t origin_guid = 0;1459uint64_t parent_guid = 0;14601461fslist = fnvpair_value_nvlist(fspair);1462if (nvlist_lookup_boolean(fslist, "sent") == 0)1463continue;14641465fsname = fnvlist_lookup_string(fslist, "name");1466(void) nvlist_lookup_uint64(fslist, "origin", &origin_guid);1467(void) nvlist_lookup_uint64(fslist, "parentfromsnap",1468&parent_guid);14691470if (parent_guid != 0) {1471parent_nv = fsavl_find(sdd->fsavl, parent_guid, NULL);1472if (!nvlist_exists(parent_nv, "sent")) {1473/* Parent has not been sent; skip this one. */1474needagain = B_TRUE;1475continue;1476}1477}14781479if (origin_guid != 0) {1480nvlist_t *origin_nv = fsavl_find(sdd->fsavl,1481origin_guid, NULL);1482if (origin_nv != NULL &&1483!nvlist_exists(origin_nv, "sent")) {1484/*1485* Origin has not been sent yet;1486* skip this clone.1487*/1488needagain = B_TRUE;1489continue;1490}1491}14921493zhp = zfs_open(rzhp->zfs_hdl, fsname, ZFS_TYPE_DATASET);1494if (zhp == NULL)1495return (-1);1496err = dump_filesystem(zhp, sdd);1497fnvlist_add_boolean(fslist, "sent");1498progress = B_TRUE;1499zfs_close(zhp);1500if (err)1501return (err);1502}1503if (needagain) {1504assert(progress);1505goto again;1506}15071508/* Clean out the sent flags in case we reuse this fss. */1509for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;1510fspair = nvlist_next_nvpair(sdd->fss, fspair)) {1511nvlist_t *fslist;15121513fslist = fnvpair_value_nvlist(fspair);1514(void) nvlist_remove_all(fslist, "sent");1515}15161517return (0);1518}15191520nvlist_t *1521zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)1522{1523unsigned int version;1524int nread, i;1525unsigned long long checksum, packed_len;15261527/*1528* Decode token header, which is:1529* <token version>-<checksum of payload>-<uncompressed payload length>1530* Note that the only supported token version is 1.1531*/1532nread = sscanf(token, "%u-%llx-%llx-",1533&version, &checksum, &packed_len);1534if (nread != 3) {1535zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1536"resume token is corrupt (invalid format)"));1537return (NULL);1538}15391540if (version != ZFS_SEND_RESUME_TOKEN_VERSION) {1541zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1542"resume token is corrupt (invalid version %u)"),1543version);1544return (NULL);1545}15461547/* Convert hexadecimal representation to binary. */1548token = strrchr(token, '-') + 1;1549int len = strlen(token) / 2;1550unsigned char *compressed = zfs_alloc(hdl, len);1551for (i = 0; i < len; i++) {1552nread = sscanf(token + i * 2, "%2hhx", compressed + i);1553if (nread != 1) {1554free(compressed);1555zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1556"resume token is corrupt "1557"(payload is not hex-encoded)"));1558return (NULL);1559}1560}15611562/* Verify checksum. */1563zio_cksum_t cksum;1564fletcher_4_native_varsize(compressed, len, &cksum);1565if (cksum.zc_word[0] != checksum) {1566free(compressed);1567zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1568"resume token is corrupt (incorrect checksum)"));1569return (NULL);1570}15711572/* Uncompress. */1573void *packed = zfs_alloc(hdl, packed_len);1574uLongf packed_len_long = packed_len;1575if (uncompress(packed, &packed_len_long, compressed, len) != Z_OK ||1576packed_len_long != packed_len) {1577free(packed);1578free(compressed);1579zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1580"resume token is corrupt (decompression failed)"));1581return (NULL);1582}15831584/* Unpack nvlist. */1585nvlist_t *nv;1586int error = nvlist_unpack(packed, packed_len, &nv, KM_SLEEP);1587free(packed);1588free(compressed);1589if (error != 0) {1590zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1591"resume token is corrupt (nvlist_unpack failed)"));1592return (NULL);1593}1594return (nv);1595}15961597static enum lzc_send_flags1598lzc_flags_from_sendflags(const sendflags_t *flags)1599{1600enum lzc_send_flags lzc_flags = 0;16011602if (flags->largeblock)1603lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;1604if (flags->embed_data)1605lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;1606if (flags->compress)1607lzc_flags |= LZC_SEND_FLAG_COMPRESS;1608if (flags->raw)1609lzc_flags |= LZC_SEND_FLAG_RAW;1610if (flags->saved)1611lzc_flags |= LZC_SEND_FLAG_SAVED;16121613return (lzc_flags);1614}16151616static int1617estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,1618uint64_t resumeobj, uint64_t resumeoff, uint64_t bytes,1619const char *redactbook, char *errbuf, uint64_t *sizep)1620{1621uint64_t size;1622FILE *fout = flags->dryrun ? stdout : stderr;1623progress_arg_t pa = { 0 };1624int err = 0;1625pthread_t ptid;1626sigset_t oldmask;16271628{1629pa.pa_zhp = zhp;1630pa.pa_fd = fd;1631pa.pa_parsable = flags->parsable;1632pa.pa_estimate = B_TRUE;1633pa.pa_verbosity = flags->verbosity;16341635err = pthread_create(&ptid, NULL,1636send_progress_thread, &pa);1637if (err != 0) {1638zfs_error_aux(zhp->zfs_hdl, "%s", zfs_strerror(errno));1639return (zfs_error(zhp->zfs_hdl,1640EZFS_THREADCREATEFAILED, errbuf));1641}1642SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);1643}16441645err = lzc_send_space_resume_redacted(zhp->zfs_name, from,1646lzc_flags_from_sendflags(flags), resumeobj, resumeoff, bytes,1647redactbook, fd, &size);1648*sizep = size;16491650if (send_progress_thread_exit(zhp->zfs_hdl, ptid, &oldmask))1651return (-1);16521653if (!flags->progress && !flags->parsable)1654return (err);16551656if (err != 0) {1657zfs_error_aux(zhp->zfs_hdl, "%s", zfs_strerror(err));1658return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,1659errbuf));1660}1661send_print_verbose(fout, zhp->zfs_name, from, size,1662flags->parsable);16631664if (flags->parsable) {1665(void) fprintf(fout, "size\t%llu\n", (longlong_t)size);1666} else {1667char buf[16];1668zfs_nicenum(size, buf, sizeof (buf));1669(void) fprintf(fout, dgettext(TEXT_DOMAIN,1670"total estimated size is %s\n"), buf);1671}1672return (0);1673}16741675static boolean_t1676redact_snaps_contains(const uint64_t *snaps, uint64_t num_snaps, uint64_t guid)1677{1678for (int i = 0; i < num_snaps; i++) {1679if (snaps[i] == guid)1680return (B_TRUE);1681}1682return (B_FALSE);1683}16841685static boolean_t1686redact_snaps_equal(const uint64_t *snaps1, uint64_t num_snaps1,1687const uint64_t *snaps2, uint64_t num_snaps2)1688{1689if (num_snaps1 != num_snaps2)1690return (B_FALSE);1691for (int i = 0; i < num_snaps1; i++) {1692if (!redact_snaps_contains(snaps2, num_snaps2, snaps1[i]))1693return (B_FALSE);1694}1695return (B_TRUE);1696}16971698static int1699get_bookmarks(const char *path, nvlist_t **bmarksp)1700{1701nvlist_t *props = fnvlist_alloc();1702int error;17031704fnvlist_add_boolean(props, "redact_complete");1705fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS));1706error = lzc_get_bookmarks(path, props, bmarksp);1707fnvlist_free(props);1708return (error);1709}17101711static nvpair_t *1712find_redact_pair(nvlist_t *bmarks, const uint64_t *redact_snap_guids,1713int num_redact_snaps)1714{1715nvpair_t *pair;17161717for (pair = nvlist_next_nvpair(bmarks, NULL); pair;1718pair = nvlist_next_nvpair(bmarks, pair)) {17191720nvlist_t *bmark = fnvpair_value_nvlist(pair);1721nvlist_t *vallist = fnvlist_lookup_nvlist(bmark,1722zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS));1723uint_t len = 0;1724uint64_t *bmarksnaps = fnvlist_lookup_uint64_array(vallist,1725ZPROP_VALUE, &len);1726if (redact_snaps_equal(redact_snap_guids,1727num_redact_snaps, bmarksnaps, len)) {1728break;1729}1730}1731return (pair);1732}17331734static boolean_t1735get_redact_complete(nvpair_t *pair)1736{1737nvlist_t *bmark = fnvpair_value_nvlist(pair);1738nvlist_t *vallist = fnvlist_lookup_nvlist(bmark, "redact_complete");1739boolean_t complete = fnvlist_lookup_boolean_value(vallist,1740ZPROP_VALUE);17411742return (complete);1743}17441745/*1746* Check that the list of redaction snapshots in the bookmark matches the send1747* we're resuming, and return whether or not it's complete.1748*1749* Note that the caller needs to free the contents of *bookname with free() if1750* this function returns successfully.1751*/1752static int1753find_redact_book(libzfs_handle_t *hdl, const char *path,1754const uint64_t *redact_snap_guids, int num_redact_snaps,1755char **bookname)1756{1757char errbuf[ERRBUFLEN];1758nvlist_t *bmarks;17591760(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,1761"cannot resume send"));17621763int error = get_bookmarks(path, &bmarks);1764if (error != 0) {1765if (error == ESRCH) {1766zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1767"nonexistent redaction bookmark provided"));1768} else if (error == ENOENT) {1769zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1770"dataset to be sent no longer exists"));1771} else {1772zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1773"unknown error: %s"), zfs_strerror(error));1774}1775return (zfs_error(hdl, EZFS_BADPROP, errbuf));1776}1777nvpair_t *pair = find_redact_pair(bmarks, redact_snap_guids,1778num_redact_snaps);1779if (pair == NULL) {1780fnvlist_free(bmarks);1781zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1782"no appropriate redaction bookmark exists"));1783return (zfs_error(hdl, EZFS_BADPROP, errbuf));1784}1785boolean_t complete = get_redact_complete(pair);1786if (!complete) {1787fnvlist_free(bmarks);1788zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1789"incomplete redaction bookmark provided"));1790return (zfs_error(hdl, EZFS_BADPROP, errbuf));1791}1792*bookname = strndup(nvpair_name(pair), ZFS_MAX_DATASET_NAME_LEN);1793ASSERT3P(*bookname, !=, NULL);1794fnvlist_free(bmarks);1795return (0);1796}17971798static enum lzc_send_flags1799lzc_flags_from_resume_nvl(nvlist_t *resume_nvl)1800{1801enum lzc_send_flags lzc_flags = 0;18021803if (nvlist_exists(resume_nvl, "largeblockok"))1804lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;1805if (nvlist_exists(resume_nvl, "embedok"))1806lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;1807if (nvlist_exists(resume_nvl, "compressok"))1808lzc_flags |= LZC_SEND_FLAG_COMPRESS;1809if (nvlist_exists(resume_nvl, "rawok"))1810lzc_flags |= LZC_SEND_FLAG_RAW;1811if (nvlist_exists(resume_nvl, "savedok"))1812lzc_flags |= LZC_SEND_FLAG_SAVED;18131814return (lzc_flags);1815}18161817static int1818zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,1819int outfd, nvlist_t *resume_nvl)1820{1821char errbuf[ERRBUFLEN];1822const char *toname;1823const char *fromname = NULL;1824uint64_t resumeobj, resumeoff, toguid, fromguid, bytes;1825zfs_handle_t *zhp;1826int error = 0;1827char name[ZFS_MAX_DATASET_NAME_LEN];1828FILE *fout = (flags->verbosity > 0 && flags->dryrun) ? stdout : stderr;1829uint64_t *redact_snap_guids = NULL;1830int num_redact_snaps = 0;1831char *redact_book = NULL;1832uint64_t size = 0;18331834(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,1835"cannot resume send"));18361837if (flags->verbosity != 0) {1838(void) fprintf(fout, dgettext(TEXT_DOMAIN,1839"resume token contents:\n"));1840nvlist_print(fout, resume_nvl);1841}18421843if (nvlist_lookup_string(resume_nvl, "toname", &toname) != 0 ||1844nvlist_lookup_uint64(resume_nvl, "object", &resumeobj) != 0 ||1845nvlist_lookup_uint64(resume_nvl, "offset", &resumeoff) != 0 ||1846nvlist_lookup_uint64(resume_nvl, "bytes", &bytes) != 0 ||1847nvlist_lookup_uint64(resume_nvl, "toguid", &toguid) != 0) {1848zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1849"resume token is corrupt"));1850return (zfs_error(hdl, EZFS_FAULT, errbuf));1851}1852fromguid = 0;1853(void) nvlist_lookup_uint64(resume_nvl, "fromguid", &fromguid);18541855if (flags->saved) {1856(void) strlcpy(name, toname, sizeof (name));1857} else {1858error = guid_to_name(hdl, toname, toguid, B_FALSE, name);1859if (error != 0) {1860if (zfs_dataset_exists(hdl, toname, ZFS_TYPE_DATASET)) {1861zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1862"'%s' is no longer the same snapshot "1863"used in the initial send"), toname);1864} else {1865zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1866"'%s' used in the initial send no "1867"longer exists"), toname);1868}1869return (zfs_error(hdl, EZFS_BADPATH, errbuf));1870}1871}18721873zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);1874if (zhp == NULL) {1875zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1876"unable to access '%s'"), name);1877return (zfs_error(hdl, EZFS_BADPATH, errbuf));1878}18791880if (nvlist_lookup_uint64_array(resume_nvl, "book_redact_snaps",1881&redact_snap_guids, (uint_t *)&num_redact_snaps) != 0) {1882num_redact_snaps = -1;1883}18841885if (fromguid != 0) {1886if (guid_to_name_redact_snaps(hdl, toname, fromguid, B_TRUE,1887redact_snap_guids, num_redact_snaps, name) != 0) {1888zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1889"incremental source %#llx no longer exists"),1890(longlong_t)fromguid);1891return (zfs_error(hdl, EZFS_BADPATH, errbuf));1892}1893fromname = name;1894}18951896redact_snap_guids = NULL;18971898if (nvlist_lookup_uint64_array(resume_nvl,1899zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS), &redact_snap_guids,1900(uint_t *)&num_redact_snaps) == 0) {1901char path[ZFS_MAX_DATASET_NAME_LEN];19021903(void) strlcpy(path, toname, sizeof (path));1904char *at = strchr(path, '@');1905ASSERT3P(at, !=, NULL);19061907*at = '\0';19081909if ((error = find_redact_book(hdl, path, redact_snap_guids,1910num_redact_snaps, &redact_book)) != 0) {1911return (error);1912}1913}19141915enum lzc_send_flags lzc_flags = lzc_flags_from_sendflags(flags) |1916lzc_flags_from_resume_nvl(resume_nvl);19171918if (flags->verbosity != 0 || flags->progressastitle) {1919/*1920* Some of these may have come from the resume token, set them1921* here for size estimate purposes.1922*/1923sendflags_t tmpflags = *flags;1924if (lzc_flags & LZC_SEND_FLAG_LARGE_BLOCK)1925tmpflags.largeblock = B_TRUE;1926if (lzc_flags & LZC_SEND_FLAG_COMPRESS)1927tmpflags.compress = B_TRUE;1928if (lzc_flags & LZC_SEND_FLAG_EMBED_DATA)1929tmpflags.embed_data = B_TRUE;1930if (lzc_flags & LZC_SEND_FLAG_RAW)1931tmpflags.raw = B_TRUE;1932if (lzc_flags & LZC_SEND_FLAG_SAVED)1933tmpflags.saved = B_TRUE;1934error = estimate_size(zhp, fromname, outfd, &tmpflags,1935resumeobj, resumeoff, bytes, redact_book, errbuf, &size);1936}19371938if (!flags->dryrun) {1939progress_arg_t pa = { 0 };1940pthread_t tid;1941sigset_t oldmask;1942/*1943* If progress reporting is requested, spawn a new thread to1944* poll ZFS_IOC_SEND_PROGRESS at a regular interval.1945*/1946{1947pa.pa_zhp = zhp;1948pa.pa_fd = outfd;1949pa.pa_parsable = flags->parsable;1950pa.pa_estimate = B_FALSE;1951pa.pa_verbosity = flags->verbosity;1952pa.pa_size = size;1953pa.pa_astitle = flags->progressastitle;1954pa.pa_progress = flags->progress;19551956error = pthread_create(&tid, NULL,1957send_progress_thread, &pa);1958if (error != 0) {1959if (redact_book != NULL)1960free(redact_book);1961zfs_close(zhp);1962return (error);1963}1964SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);1965}19661967error = lzc_send_resume_redacted(zhp->zfs_name, fromname, outfd,1968lzc_flags, resumeobj, resumeoff, redact_book);1969if (redact_book != NULL)1970free(redact_book);19711972if (send_progress_thread_exit(hdl, tid, &oldmask)) {1973zfs_close(zhp);1974return (-1);1975}19761977char errbuf[ERRBUFLEN];1978(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,1979"warning: cannot send '%s'"), zhp->zfs_name);19801981zfs_close(zhp);19821983switch (error) {1984case 0:1985return (0);1986case EACCES:1987zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1988"source key must be loaded"));1989return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));1990case ESRCH:1991if (lzc_exists(zhp->zfs_name)) {1992zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1993"incremental source could not be found"));1994}1995return (zfs_error(hdl, EZFS_NOENT, errbuf));19961997case EXDEV:1998case ENOENT:1999case EDQUOT:2000case EFBIG:2001case EIO:2002case ENOLINK:2003case ENOSPC:2004case ENOSTR:2005case ENXIO:2006case EPIPE:2007case ERANGE:2008case EFAULT:2009case EROFS:2010zfs_error_aux(hdl, "%s", zfs_strerror(errno));2011return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));20122013default:2014return (zfs_standard_error(hdl, errno, errbuf));2015}2016} else {2017if (redact_book != NULL)2018free(redact_book);2019}20202021zfs_close(zhp);20222023return (error);2024}20252026struct zfs_send_resume_impl {2027libzfs_handle_t *hdl;2028sendflags_t *flags;2029nvlist_t *resume_nvl;2030};20312032static int2033zfs_send_resume_impl_cb(int outfd, void *arg)2034{2035struct zfs_send_resume_impl *zsri = arg;2036return (zfs_send_resume_impl_cb_impl(zsri->hdl, zsri->flags, outfd,2037zsri->resume_nvl));2038}20392040static int2041zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,2042nvlist_t *resume_nvl)2043{2044struct zfs_send_resume_impl zsri = {2045.hdl = hdl,2046.flags = flags,2047.resume_nvl = resume_nvl,2048};2049return (lzc_send_wrapper(zfs_send_resume_impl_cb, outfd, &zsri));2050}20512052int2053zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,2054const char *resume_token)2055{2056int ret;2057char errbuf[ERRBUFLEN];2058nvlist_t *resume_nvl;20592060(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,2061"cannot resume send"));20622063resume_nvl = zfs_send_resume_token_to_nvlist(hdl, resume_token);2064if (resume_nvl == NULL) {2065/*2066* zfs_error_aux has already been set by2067* zfs_send_resume_token_to_nvlist()2068*/2069return (zfs_error(hdl, EZFS_FAULT, errbuf));2070}20712072ret = zfs_send_resume_impl(hdl, flags, outfd, resume_nvl);2073fnvlist_free(resume_nvl);20742075return (ret);2076}20772078int2079zfs_send_saved(zfs_handle_t *zhp, sendflags_t *flags, int outfd,2080const char *resume_token)2081{2082int ret;2083libzfs_handle_t *hdl = zhp->zfs_hdl;2084nvlist_t *saved_nvl = NULL, *resume_nvl = NULL;2085uint64_t saved_guid = 0, resume_guid = 0;2086uint64_t obj = 0, off = 0, bytes = 0;2087char token_buf[ZFS_MAXPROPLEN];2088char errbuf[ERRBUFLEN];20892090(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,2091"saved send failed"));20922093ret = zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,2094token_buf, sizeof (token_buf), NULL, NULL, 0, B_TRUE);2095if (ret != 0)2096goto out;20972098saved_nvl = zfs_send_resume_token_to_nvlist(hdl, token_buf);2099if (saved_nvl == NULL) {2100/*2101* zfs_error_aux has already been set by2102* zfs_send_resume_token_to_nvlist()2103*/2104ret = zfs_error(hdl, EZFS_FAULT, errbuf);2105goto out;2106}21072108/*2109* If a resume token is provided we use the object and offset2110* from that instead of the default, which starts from the2111* beginning.2112*/2113if (resume_token != NULL) {2114resume_nvl = zfs_send_resume_token_to_nvlist(hdl,2115resume_token);2116if (resume_nvl == NULL) {2117ret = zfs_error(hdl, EZFS_FAULT, errbuf);2118goto out;2119}21202121if (nvlist_lookup_uint64(resume_nvl, "object", &obj) != 0 ||2122nvlist_lookup_uint64(resume_nvl, "offset", &off) != 0 ||2123nvlist_lookup_uint64(resume_nvl, "bytes", &bytes) != 0 ||2124nvlist_lookup_uint64(resume_nvl, "toguid",2125&resume_guid) != 0) {2126zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2127"provided resume token is corrupt"));2128ret = zfs_error(hdl, EZFS_FAULT, errbuf);2129goto out;2130}21312132if (nvlist_lookup_uint64(saved_nvl, "toguid",2133&saved_guid)) {2134zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2135"dataset's resume token is corrupt"));2136ret = zfs_error(hdl, EZFS_FAULT, errbuf);2137goto out;2138}21392140if (resume_guid != saved_guid) {2141zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2142"provided resume token does not match dataset"));2143ret = zfs_error(hdl, EZFS_BADBACKUP, errbuf);2144goto out;2145}2146}21472148(void) nvlist_remove_all(saved_nvl, "object");2149fnvlist_add_uint64(saved_nvl, "object", obj);21502151(void) nvlist_remove_all(saved_nvl, "offset");2152fnvlist_add_uint64(saved_nvl, "offset", off);21532154(void) nvlist_remove_all(saved_nvl, "bytes");2155fnvlist_add_uint64(saved_nvl, "bytes", bytes);21562157(void) nvlist_remove_all(saved_nvl, "toname");2158fnvlist_add_string(saved_nvl, "toname", zhp->zfs_name);21592160ret = zfs_send_resume_impl(hdl, flags, outfd, saved_nvl);21612162out:2163fnvlist_free(saved_nvl);2164fnvlist_free(resume_nvl);2165return (ret);2166}21672168/*2169* This function informs the target system that the recursive send is complete.2170* The record is also expected in the case of a send -p.2171*/2172static int2173send_conclusion_record(int fd, zio_cksum_t *zc)2174{2175dmu_replay_record_t drr;2176memset(&drr, 0, sizeof (dmu_replay_record_t));2177drr.drr_type = DRR_END;2178if (zc != NULL)2179drr.drr_u.drr_end.drr_checksum = *zc;2180if (write(fd, &drr, sizeof (drr)) == -1) {2181return (errno);2182}2183return (0);2184}21852186/*2187* This function is responsible for sending the records that contain the2188* necessary information for the target system's libzfs to be able to set the2189* properties of the filesystem being received, or to be able to prepare for2190* a recursive receive.2191*2192* The "zhp" argument is the handle of the snapshot we are sending2193* (the "tosnap"). The "from" argument is the short snapshot name (the part2194* after the @) of the incremental source.2195*/2196static int2197send_prelim_records(zfs_handle_t *zhp, const char *from, int fd,2198boolean_t gather_props, boolean_t recursive, boolean_t verbose,2199boolean_t dryrun, boolean_t raw, boolean_t replicate, boolean_t skipmissing,2200boolean_t backup, boolean_t holds, boolean_t props, boolean_t doall,2201nvlist_t **fssp, avl_tree_t **fsavlp)2202{2203int err = 0;2204char *packbuf = NULL;2205size_t buflen = 0;2206zio_cksum_t zc = { {0} };2207int featureflags = 0;2208/* name of filesystem/volume that contains snapshot we are sending */2209char tofs[ZFS_MAX_DATASET_NAME_LEN];2210/* short name of snap we are sending */2211const char *tosnap = "";22122213char errbuf[ERRBUFLEN];2214(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,2215"warning: cannot send '%s'"), zhp->zfs_name);2216if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM && zfs_prop_get_int(zhp,2217ZFS_PROP_VERSION) >= ZPL_VERSION_SA) {2218featureflags |= DMU_BACKUP_FEATURE_SA_SPILL;2219}22202221if (holds)2222featureflags |= DMU_BACKUP_FEATURE_HOLDS;22232224(void) strlcpy(tofs, zhp->zfs_name, ZFS_MAX_DATASET_NAME_LEN);2225char *at = strchr(tofs, '@');2226if (at != NULL) {2227*at = '\0';2228tosnap = at + 1;2229}22302231if (gather_props) {2232nvlist_t *hdrnv = fnvlist_alloc();2233nvlist_t *fss = NULL;22342235if (from != NULL)2236fnvlist_add_string(hdrnv, "fromsnap", from);2237fnvlist_add_string(hdrnv, "tosnap", tosnap);2238if (!recursive)2239fnvlist_add_boolean(hdrnv, "not_recursive");22402241if (raw) {2242fnvlist_add_boolean(hdrnv, "raw");2243}22442245if (gather_nvlist(zhp->zfs_hdl, tofs,2246from, tosnap, recursive, raw, doall, replicate, skipmissing,2247verbose, backup, holds, props, &fss, fsavlp) != 0) {2248return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,2249errbuf));2250}2251/*2252* Do not allow the size of the properties list to exceed2253* the limit2254*/2255if ((fnvlist_size(fss) + fnvlist_size(hdrnv)) >2256zhp->zfs_hdl->libzfs_max_nvlist) {2257(void) snprintf(errbuf, sizeof (errbuf),2258dgettext(TEXT_DOMAIN, "warning: cannot send '%s': "2259"the size of the list of snapshots and properties "2260"is too large to be received successfully.\n"2261"Select a smaller number of snapshots to send.\n"),2262zhp->zfs_name);2263return (zfs_error(zhp->zfs_hdl, EZFS_NOSPC,2264errbuf));2265}2266fnvlist_add_nvlist(hdrnv, "fss", fss);2267VERIFY0(nvlist_pack(hdrnv, &packbuf, &buflen, NV_ENCODE_XDR,22680));2269if (fssp != NULL) {2270*fssp = fss;2271} else {2272fnvlist_free(fss);2273}2274fnvlist_free(hdrnv);2275}22762277if (!dryrun) {2278dmu_replay_record_t drr;2279memset(&drr, 0, sizeof (dmu_replay_record_t));2280/* write first begin record */2281drr.drr_type = DRR_BEGIN;2282drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;2283DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.2284drr_versioninfo, DMU_COMPOUNDSTREAM);2285DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.2286drr_versioninfo, featureflags);2287if (snprintf(drr.drr_u.drr_begin.drr_toname,2288sizeof (drr.drr_u.drr_begin.drr_toname), "%s@%s", tofs,2289tosnap) >= sizeof (drr.drr_u.drr_begin.drr_toname)) {2290return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,2291errbuf));2292}2293drr.drr_payloadlen = buflen;22942295err = dump_record(&drr, packbuf, buflen, &zc, fd);2296free(packbuf);2297if (err != 0) {2298zfs_error_aux(zhp->zfs_hdl, "%s", zfs_strerror(err));2299return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,2300errbuf));2301}2302err = send_conclusion_record(fd, &zc);2303if (err != 0) {2304zfs_error_aux(zhp->zfs_hdl, "%s", zfs_strerror(err));2305return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,2306errbuf));2307}2308}2309return (0);2310}23112312/*2313* Generate a send stream. The "zhp" argument is the filesystem/volume2314* that contains the snapshot to send. The "fromsnap" argument is the2315* short name (the part after the '@') of the snapshot that is the2316* incremental source to send from (if non-NULL). The "tosnap" argument2317* is the short name of the snapshot to send.2318*2319* The content of the send stream is the snapshot identified by2320* 'tosnap'. Incremental streams are requested in two ways:2321* - from the snapshot identified by "fromsnap" (if non-null) or2322* - from the origin of the dataset identified by zhp, which must2323* be a clone. In this case, "fromsnap" is null and "fromorigin"2324* is TRUE.2325*2326* The send stream is recursive (i.e. dumps a hierarchy of snapshots) and2327* uses a special header (with a hdrtype field of DMU_COMPOUNDSTREAM)2328* if "replicate" is set. If "doall" is set, dump all the intermediate2329* snapshots. The DMU_COMPOUNDSTREAM header is used in the "doall"2330* case too. If "props" is set, send properties.2331*2332* Pre-wrapped (cf. lzc_send_wrapper()).2333*/2334static int2335zfs_send_cb_impl(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,2336sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,2337void *cb_arg, nvlist_t **debugnvp)2338{2339char errbuf[ERRBUFLEN];2340send_dump_data_t sdd = { 0 };2341int err = 0;2342nvlist_t *fss = NULL;2343avl_tree_t *fsavl = NULL;2344static uint64_t holdseq;2345int spa_version;2346FILE *fout;23472348(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,2349"cannot send '%s'"), zhp->zfs_name);23502351if (fromsnap && fromsnap[0] == '\0') {2352zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,2353"zero-length incremental source"));2354return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));2355}23562357if (fromsnap) {2358char full_fromsnap_name[ZFS_MAX_DATASET_NAME_LEN];2359if (snprintf(full_fromsnap_name, sizeof (full_fromsnap_name),2360"%s@%s", zhp->zfs_name, fromsnap) >=2361sizeof (full_fromsnap_name)) {2362err = EINVAL;2363goto stderr_out;2364}2365zfs_handle_t *fromsnapn = zfs_open(zhp->zfs_hdl,2366full_fromsnap_name, ZFS_TYPE_SNAPSHOT);2367if (fromsnapn == NULL) {2368err = -1;2369goto err_out;2370}2371zfs_close(fromsnapn);2372}23732374if (flags->replicate || flags->doall || flags->props ||2375flags->holds || flags->backup) {2376char full_tosnap_name[ZFS_MAX_DATASET_NAME_LEN];2377if (snprintf(full_tosnap_name, sizeof (full_tosnap_name),2378"%s@%s", zhp->zfs_name, tosnap) >=2379sizeof (full_tosnap_name)) {2380err = EINVAL;2381goto stderr_out;2382}2383zfs_handle_t *tosnap = zfs_open(zhp->zfs_hdl,2384full_tosnap_name, ZFS_TYPE_SNAPSHOT);2385if (tosnap == NULL) {2386err = -1;2387goto err_out;2388}2389err = send_prelim_records(tosnap, fromsnap, outfd,2390flags->replicate || flags->props || flags->holds,2391flags->replicate, flags->verbosity > 0, flags->dryrun,2392flags->raw, flags->replicate, flags->skipmissing,2393flags->backup, flags->holds, flags->props, flags->doall,2394&fss, &fsavl);2395zfs_close(tosnap);2396if (err != 0)2397goto err_out;2398}23992400/* dump each stream */2401sdd.fromsnap = fromsnap;2402sdd.tosnap = tosnap;2403sdd.outfd = outfd;2404sdd.replicate = flags->replicate;2405sdd.doall = flags->doall;2406sdd.fromorigin = flags->fromorigin;2407sdd.fss = fss;2408sdd.fsavl = fsavl;2409sdd.verbosity = flags->verbosity;2410sdd.parsable = flags->parsable;2411sdd.progress = flags->progress;2412sdd.progressastitle = flags->progressastitle;2413sdd.dryrun = flags->dryrun;2414sdd.large_block = flags->largeblock;2415sdd.embed_data = flags->embed_data;2416sdd.compress = flags->compress;2417sdd.raw = flags->raw;2418sdd.holds = flags->holds;2419sdd.filter_cb = filter_func;2420sdd.filter_cb_arg = cb_arg;2421if (debugnvp)2422sdd.debugnv = *debugnvp;2423if (sdd.verbosity != 0 && sdd.dryrun)2424sdd.std_out = B_TRUE;2425fout = sdd.std_out ? stdout : stderr;24262427/*2428* Some flags require that we place user holds on the datasets that are2429* being sent so they don't get destroyed during the send. We can skip2430* this step if the pool is imported read-only since the datasets cannot2431* be destroyed.2432*/2433if (!flags->dryrun && !zpool_get_prop_int(zfs_get_pool_handle(zhp),2434ZPOOL_PROP_READONLY, NULL) &&2435zfs_spa_version(zhp, &spa_version) == 0 &&2436spa_version >= SPA_VERSION_USERREFS &&2437(flags->doall || flags->replicate)) {2438++holdseq;2439(void) snprintf(sdd.holdtag, sizeof (sdd.holdtag),2440".send-%d-%llu", getpid(), (u_longlong_t)holdseq);2441sdd.cleanup_fd = open(ZFS_DEV, O_RDWR | O_CLOEXEC);2442if (sdd.cleanup_fd < 0) {2443err = errno;2444goto stderr_out;2445}2446sdd.snapholds = fnvlist_alloc();2447} else {2448sdd.cleanup_fd = -1;2449sdd.snapholds = NULL;2450}24512452if (flags->verbosity != 0 || sdd.snapholds != NULL) {2453/*2454* Do a verbose no-op dry run to get all the verbose output2455* or to gather snapshot hold's before generating any data,2456* then do a non-verbose real run to generate the streams.2457*/2458sdd.dryrun = B_TRUE;2459err = dump_filesystems(zhp, &sdd);24602461if (err != 0)2462goto stderr_out;24632464if (flags->verbosity != 0) {2465if (flags->parsable) {2466(void) fprintf(fout, "size\t%llu\n",2467(longlong_t)sdd.size);2468} else {2469char buf[16];2470zfs_nicebytes(sdd.size, buf, sizeof (buf));2471(void) fprintf(fout, dgettext(TEXT_DOMAIN,2472"total estimated size is %s\n"), buf);2473}2474}24752476/* Ensure no snaps found is treated as an error. */2477if (!sdd.seento) {2478err = ENOENT;2479goto err_out;2480}24812482/* Skip the second run if dryrun was requested. */2483if (flags->dryrun)2484goto err_out;24852486if (sdd.snapholds != NULL) {2487err = zfs_hold_nvl(zhp, sdd.cleanup_fd, sdd.snapholds);2488if (err != 0)2489goto stderr_out;24902491fnvlist_free(sdd.snapholds);2492sdd.snapholds = NULL;2493}24942495sdd.dryrun = B_FALSE;2496sdd.verbosity = 0;2497}24982499err = dump_filesystems(zhp, &sdd);2500fsavl_destroy(fsavl);2501fnvlist_free(fss);25022503/* Ensure no snaps found is treated as an error. */2504if (err == 0 && !sdd.seento)2505err = ENOENT;25062507if (sdd.cleanup_fd != -1) {2508VERIFY0(close(sdd.cleanup_fd));2509sdd.cleanup_fd = -1;2510}25112512if (!flags->dryrun && (flags->replicate || flags->doall ||2513flags->props || flags->backup || flags->holds)) {2514/*2515* write final end record. NB: want to do this even if2516* there was some error, because it might not be totally2517* failed.2518*/2519int err2 = send_conclusion_record(outfd, NULL);2520if (err2 != 0)2521return (zfs_standard_error(zhp->zfs_hdl, err2, errbuf));2522}25232524return (err || sdd.err);25252526stderr_out:2527err = zfs_standard_error(zhp->zfs_hdl, err, errbuf);2528err_out:2529fsavl_destroy(fsavl);2530fnvlist_free(fss);2531fnvlist_free(sdd.snapholds);25322533if (sdd.cleanup_fd != -1)2534VERIFY0(close(sdd.cleanup_fd));2535return (err);2536}25372538struct zfs_send {2539zfs_handle_t *zhp;2540const char *fromsnap;2541const char *tosnap;2542sendflags_t *flags;2543snapfilter_cb_t *filter_func;2544void *cb_arg;2545nvlist_t **debugnvp;2546};25472548static int2549zfs_send_cb(int outfd, void *arg)2550{2551struct zfs_send *zs = arg;2552return (zfs_send_cb_impl(zs->zhp, zs->fromsnap, zs->tosnap, zs->flags,2553outfd, zs->filter_func, zs->cb_arg, zs->debugnvp));2554}25552556int2557zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,2558sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,2559void *cb_arg, nvlist_t **debugnvp)2560{2561struct zfs_send arg = {2562.zhp = zhp,2563.fromsnap = fromsnap,2564.tosnap = tosnap,2565.flags = flags,2566.filter_func = filter_func,2567.cb_arg = cb_arg,2568.debugnvp = debugnvp,2569};2570return (lzc_send_wrapper(zfs_send_cb, outfd, &arg));2571}257225732574static zfs_handle_t *2575name_to_dir_handle(libzfs_handle_t *hdl, const char *snapname)2576{2577char dirname[ZFS_MAX_DATASET_NAME_LEN];2578(void) strlcpy(dirname, snapname, ZFS_MAX_DATASET_NAME_LEN);2579char *c = strchr(dirname, '@');2580if (c != NULL)2581*c = '\0';2582return (zfs_open(hdl, dirname, ZFS_TYPE_DATASET));2583}25842585/*2586* Returns B_TRUE if earlier is an earlier snapshot in later's timeline; either2587* an earlier snapshot in the same filesystem, or a snapshot before later's2588* origin, or it's origin's origin, etc.2589*/2590static boolean_t2591snapshot_is_before(zfs_handle_t *earlier, zfs_handle_t *later)2592{2593boolean_t ret;2594uint64_t later_txg =2595(later->zfs_type == ZFS_TYPE_FILESYSTEM ||2596later->zfs_type == ZFS_TYPE_VOLUME ?2597UINT64_MAX : zfs_prop_get_int(later, ZFS_PROP_CREATETXG));2598uint64_t earlier_txg = zfs_prop_get_int(earlier, ZFS_PROP_CREATETXG);25992600if (earlier_txg >= later_txg)2601return (B_FALSE);26022603zfs_handle_t *earlier_dir = name_to_dir_handle(earlier->zfs_hdl,2604earlier->zfs_name);2605zfs_handle_t *later_dir = name_to_dir_handle(later->zfs_hdl,2606later->zfs_name);26072608if (strcmp(earlier_dir->zfs_name, later_dir->zfs_name) == 0) {2609zfs_close(earlier_dir);2610zfs_close(later_dir);2611return (B_TRUE);2612}26132614char clonename[ZFS_MAX_DATASET_NAME_LEN];2615if (zfs_prop_get(later_dir, ZFS_PROP_ORIGIN, clonename,2616ZFS_MAX_DATASET_NAME_LEN, NULL, NULL, 0, B_TRUE) != 0) {2617zfs_close(earlier_dir);2618zfs_close(later_dir);2619return (B_FALSE);2620}26212622zfs_handle_t *origin = zfs_open(earlier->zfs_hdl, clonename,2623ZFS_TYPE_DATASET);2624uint64_t origin_txg = zfs_prop_get_int(origin, ZFS_PROP_CREATETXG);26252626/*2627* If "earlier" is exactly the origin, then2628* snapshot_is_before(earlier, origin) will return false (because2629* they're the same).2630*/2631if (origin_txg == earlier_txg &&2632strcmp(origin->zfs_name, earlier->zfs_name) == 0) {2633zfs_close(earlier_dir);2634zfs_close(later_dir);2635zfs_close(origin);2636return (B_TRUE);2637}2638zfs_close(earlier_dir);2639zfs_close(later_dir);26402641ret = snapshot_is_before(earlier, origin);2642zfs_close(origin);2643return (ret);2644}26452646/*2647* The "zhp" argument is the handle of the dataset to send (typically a2648* snapshot). The "from" argument is the full name of the snapshot or2649* bookmark that is the incremental source.2650*2651* Pre-wrapped (cf. lzc_send_wrapper()).2652*/2653static int2654zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,2655sendflags_t *flags, const char *redactbook)2656{2657int err;2658libzfs_handle_t *hdl = zhp->zfs_hdl;2659char *name = zhp->zfs_name;2660pthread_t ptid;2661progress_arg_t pa = { 0 };2662uint64_t size = 0;26632664char errbuf[ERRBUFLEN];2665(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,2666"warning: cannot send '%s'"), name);26672668if (from != NULL && strchr(from, '@')) {2669zfs_handle_t *from_zhp = zfs_open(hdl, from,2670ZFS_TYPE_DATASET);2671if (from_zhp == NULL)2672return (-1);2673if (!snapshot_is_before(from_zhp, zhp)) {2674zfs_close(from_zhp);2675zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2676"not an earlier snapshot from the same fs"));2677return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));2678}2679zfs_close(from_zhp);2680}26812682if (redactbook != NULL) {2683char bookname[ZFS_MAX_DATASET_NAME_LEN];2684nvlist_t *redact_snaps;2685zfs_handle_t *book_zhp;2686char *at, *pound;2687int dsnamelen;26882689pound = strchr(redactbook, '#');2690if (pound != NULL)2691redactbook = pound + 1;2692at = strchr(name, '@');2693if (at == NULL) {2694zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2695"cannot do a redacted send to a filesystem"));2696return (zfs_error(hdl, EZFS_BADTYPE, errbuf));2697}2698dsnamelen = at - name;2699if (snprintf(bookname, sizeof (bookname), "%.*s#%s",2700dsnamelen, name, redactbook)2701>= sizeof (bookname)) {2702zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2703"invalid bookmark name"));2704return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));2705}2706book_zhp = zfs_open(hdl, bookname, ZFS_TYPE_BOOKMARK);2707if (book_zhp == NULL)2708return (-1);2709if (nvlist_lookup_nvlist(book_zhp->zfs_props,2710zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS),2711&redact_snaps) != 0 || redact_snaps == NULL) {2712zfs_close(book_zhp);2713zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2714"not a redaction bookmark"));2715return (zfs_error(hdl, EZFS_BADTYPE, errbuf));2716}2717zfs_close(book_zhp);2718}27192720/*2721* Send fs properties2722*/2723if (flags->props || flags->holds || flags->backup) {2724/*2725* Note: the header generated by send_prelim_records()2726* assumes that the incremental source is in the same2727* filesystem/volume as the target (which is a requirement2728* when doing "zfs send -R"). But that isn't always the2729* case here (e.g. send from snap in origin, or send from2730* bookmark). We pass from=NULL, which will omit this2731* information from the prelim records; it isn't used2732* when receiving this type of stream.2733*/2734err = send_prelim_records(zhp, NULL, fd, B_TRUE, B_FALSE,2735flags->verbosity > 0, flags->dryrun, flags->raw,2736flags->replicate, B_FALSE, flags->backup, flags->holds,2737flags->props, flags->doall, NULL, NULL);2738if (err != 0)2739return (err);2740}27412742/*2743* Perform size estimate if verbose was specified.2744*/2745if (flags->verbosity != 0 || flags->progressastitle) {2746err = estimate_size(zhp, from, fd, flags, 0, 0, 0, redactbook,2747errbuf, &size);2748if (err != 0)2749return (err);2750}27512752if (flags->dryrun)2753return (0);27542755/*2756* If progress reporting is requested, spawn a new thread to poll2757* ZFS_IOC_SEND_PROGRESS at a regular interval.2758*/2759sigset_t oldmask;2760{2761pa.pa_zhp = zhp;2762pa.pa_fd = fd;2763pa.pa_parsable = flags->parsable;2764pa.pa_estimate = B_FALSE;2765pa.pa_verbosity = flags->verbosity;2766pa.pa_size = size;2767pa.pa_astitle = flags->progressastitle;2768pa.pa_progress = flags->progress;27692770err = pthread_create(&ptid, NULL,2771send_progress_thread, &pa);2772if (err != 0) {2773zfs_error_aux(zhp->zfs_hdl, "%s", zfs_strerror(errno));2774return (zfs_error(zhp->zfs_hdl,2775EZFS_THREADCREATEFAILED, errbuf));2776}2777SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);2778}27792780err = lzc_send_redacted(name, from, fd,2781lzc_flags_from_sendflags(flags), redactbook);27822783if (send_progress_thread_exit(hdl, ptid, &oldmask))2784return (-1);27852786if (err == 0 && (flags->props || flags->holds || flags->backup)) {2787/* Write the final end record. */2788err = send_conclusion_record(fd, NULL);2789if (err != 0)2790return (zfs_standard_error(hdl, err, errbuf));2791}2792if (err != 0) {2793switch (errno) {2794case EXDEV:2795zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2796"not an earlier snapshot from the same fs"));2797return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));27982799case ENOENT:2800case ESRCH:2801if (lzc_exists(name)) {2802zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2803"incremental source (%s) does not exist"),2804from);2805}2806return (zfs_error(hdl, EZFS_NOENT, errbuf));28072808case EACCES:2809zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2810"dataset key must be loaded"));2811return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));28122813case EBUSY:2814zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2815"target is busy; if a filesystem, "2816"it must not be mounted"));2817return (zfs_error(hdl, EZFS_BUSY, errbuf));28182819case EDQUOT:2820case EFAULT:2821case EFBIG:2822case EINVAL:2823case EIO:2824case ENOLINK:2825case ENOSPC:2826case ENOSTR:2827case ENXIO:2828case EPIPE:2829case ERANGE:2830case EROFS:2831zfs_error_aux(hdl, "%s", zfs_strerror(errno));2832return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));2833case ZFS_ERR_STREAM_LARGE_MICROZAP:2834zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2835"source snapshot contains large microzaps, "2836"need -L (--large-block) or -w (--raw) to "2837"generate stream"));2838return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));2839default:2840return (zfs_standard_error(hdl, errno, errbuf));2841}2842}2843return (err != 0);2844}28452846struct zfs_send_one {2847zfs_handle_t *zhp;2848const char *from;2849sendflags_t *flags;2850const char *redactbook;2851};28522853static int2854zfs_send_one_cb(int fd, void *arg)2855{2856struct zfs_send_one *zso = arg;2857return (zfs_send_one_cb_impl(zso->zhp, zso->from, fd, zso->flags,2858zso->redactbook));2859}28602861int2862zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,2863const char *redactbook)2864{2865struct zfs_send_one zso = {2866.zhp = zhp,2867.from = from,2868.flags = flags,2869.redactbook = redactbook,2870};2871return (lzc_send_wrapper(zfs_send_one_cb, fd, &zso));2872}28732874/*2875* Routines specific to "zfs recv"2876*/28772878static int2879recv_read(libzfs_handle_t *hdl, int fd, void *buf, int ilen,2880boolean_t byteswap, zio_cksum_t *zc)2881{2882char *cp = buf;2883int rv;2884int len = ilen;28852886do {2887rv = read(fd, cp, len);2888cp += rv;2889len -= rv;2890} while (rv > 0);28912892if (rv < 0 || len != 0) {2893zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2894"failed to read from stream"));2895return (zfs_error(hdl, EZFS_BADSTREAM, dgettext(TEXT_DOMAIN,2896"cannot receive")));2897}28982899if (zc) {2900if (byteswap)2901fletcher_4_incremental_byteswap(buf, ilen, zc);2902else2903fletcher_4_incremental_native(buf, ilen, zc);2904}2905return (0);2906}29072908static int2909recv_read_nvlist(libzfs_handle_t *hdl, int fd, int len, nvlist_t **nvp,2910boolean_t byteswap, zio_cksum_t *zc)2911{2912char *buf;2913int err;29142915buf = zfs_alloc(hdl, len);29162917if (len > hdl->libzfs_max_nvlist) {2918zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "nvlist too large"));2919free(buf);2920return (ENOMEM);2921}29222923err = recv_read(hdl, fd, buf, len, byteswap, zc);2924if (err != 0) {2925free(buf);2926return (err);2927}29282929err = nvlist_unpack(buf, len, nvp, 0);2930free(buf);2931if (err != 0) {2932zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "2933"stream (malformed nvlist)"));2934return (EINVAL);2935}2936return (0);2937}29382939/*2940* Returns the grand origin (origin of origin of origin...) of a given handle.2941* If this dataset is not a clone, it simply returns a copy of the original2942* handle.2943*/2944static zfs_handle_t *2945recv_open_grand_origin(zfs_handle_t *zhp)2946{2947char origin[ZFS_MAX_DATASET_NAME_LEN];2948zprop_source_t src;2949zfs_handle_t *ozhp = zfs_handle_dup(zhp);29502951while (ozhp != NULL) {2952if (zfs_prop_get(ozhp, ZFS_PROP_ORIGIN, origin,2953sizeof (origin), &src, NULL, 0, B_FALSE) != 0)2954break;29552956(void) zfs_close(ozhp);2957ozhp = zfs_open(zhp->zfs_hdl, origin, ZFS_TYPE_FILESYSTEM);2958}29592960return (ozhp);2961}29622963static int2964recv_rename_impl(zfs_handle_t *zhp, const char *name, const char *newname)2965{2966int err;2967zfs_handle_t *ozhp = NULL;29682969/*2970* Attempt to rename the dataset. If it fails with EACCES we have2971* attempted to rename the dataset outside of its encryption root.2972* Force the dataset to become an encryption root and try again.2973*/2974err = lzc_rename(name, newname);2975if (err == EACCES) {2976ozhp = recv_open_grand_origin(zhp);2977if (ozhp == NULL) {2978err = ENOENT;2979goto out;2980}29812982err = lzc_change_key(ozhp->zfs_name, DCP_CMD_FORCE_NEW_KEY,2983NULL, NULL, 0);2984if (err != 0)2985goto out;29862987err = lzc_rename(name, newname);2988}29892990out:2991if (ozhp != NULL)2992zfs_close(ozhp);2993return (err);2994}29952996static int2997recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,2998int baselen, char *newname, recvflags_t *flags)2999{3000static int seq;3001int err;3002prop_changelist_t *clp = NULL;3003zfs_handle_t *zhp = NULL;30043005zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);3006if (zhp == NULL) {3007err = -1;3008goto out;3009}3010clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,3011flags->force ? MS_FORCE : 0);3012if (clp == NULL) {3013err = -1;3014goto out;3015}3016err = changelist_prefix(clp);3017if (err)3018goto out;30193020if (tryname) {3021(void) strlcpy(newname, tryname, ZFS_MAX_DATASET_NAME_LEN);3022if (flags->verbose) {3023(void) printf("attempting rename %s to %s\n",3024name, newname);3025}3026err = recv_rename_impl(zhp, name, newname);3027if (err == 0)3028changelist_rename(clp, name, tryname);3029} else {3030err = ENOENT;3031}30323033if (err != 0 && strncmp(name + baselen, "recv-", 5) != 0) {3034seq++;30353036(void) snprintf(newname, ZFS_MAX_DATASET_NAME_LEN,3037"%.*srecv-%u-%u", baselen, name, getpid(), seq);30383039if (flags->verbose) {3040(void) printf("failed - trying rename %s to %s\n",3041name, newname);3042}3043err = recv_rename_impl(zhp, name, newname);3044if (err == 0)3045changelist_rename(clp, name, newname);3046if (err && flags->verbose) {3047(void) printf("failed (%u) - "3048"will try again on next pass\n", errno);3049}3050err = EAGAIN;3051} else if (flags->verbose) {3052if (err == 0)3053(void) printf("success\n");3054else3055(void) printf("failed (%u)\n", errno);3056}30573058(void) changelist_postfix(clp);30593060out:3061if (clp != NULL)3062changelist_free(clp);3063if (zhp != NULL)3064zfs_close(zhp);30653066return (err);3067}30683069static int3070recv_promote(libzfs_handle_t *hdl, const char *fsname,3071const char *origin_fsname, recvflags_t *flags)3072{3073int err;3074zfs_cmd_t zc = {"\0"};3075zfs_handle_t *zhp = NULL, *ozhp = NULL;30763077if (flags->verbose)3078(void) printf("promoting %s\n", fsname);30793080(void) strlcpy(zc.zc_value, origin_fsname, sizeof (zc.zc_value));3081(void) strlcpy(zc.zc_name, fsname, sizeof (zc.zc_name));30823083/*3084* Attempt to promote the dataset. If it fails with EACCES the3085* promotion would cause this dataset to leave its encryption root.3086* Force the origin to become an encryption root and try again.3087*/3088err = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);3089if (err == EACCES) {3090zhp = zfs_open(hdl, fsname, ZFS_TYPE_DATASET);3091if (zhp == NULL) {3092err = -1;3093goto out;3094}30953096ozhp = recv_open_grand_origin(zhp);3097if (ozhp == NULL) {3098err = -1;3099goto out;3100}31013102err = lzc_change_key(ozhp->zfs_name, DCP_CMD_FORCE_NEW_KEY,3103NULL, NULL, 0);3104if (err != 0)3105goto out;31063107err = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);3108}31093110out:3111if (zhp != NULL)3112zfs_close(zhp);3113if (ozhp != NULL)3114zfs_close(ozhp);31153116return (err);3117}31183119static int3120recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,3121char *newname, recvflags_t *flags)3122{3123int err = 0;3124prop_changelist_t *clp;3125zfs_handle_t *zhp;3126boolean_t defer = B_FALSE;3127int spa_version;31283129zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);3130if (zhp == NULL)3131return (-1);3132zfs_type_t type = zfs_get_type(zhp);3133if (type == ZFS_TYPE_SNAPSHOT &&3134zfs_spa_version(zhp, &spa_version) == 0 &&3135spa_version >= SPA_VERSION_USERREFS)3136defer = B_TRUE;3137clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,3138flags->force ? MS_FORCE : 0);3139zfs_close(zhp);3140if (clp == NULL)3141return (-1);31423143err = changelist_prefix(clp);3144if (err)3145return (err);31463147if (flags->verbose)3148(void) printf("attempting destroy %s\n", name);3149if (type == ZFS_TYPE_SNAPSHOT) {3150nvlist_t *nv = fnvlist_alloc();3151fnvlist_add_boolean(nv, name);3152err = lzc_destroy_snaps(nv, defer, NULL);3153fnvlist_free(nv);3154} else {3155err = lzc_destroy(name);3156}3157if (err == 0) {3158if (flags->verbose)3159(void) printf("success\n");3160changelist_remove(clp, name);3161}31623163(void) changelist_postfix(clp);3164changelist_free(clp);31653166/*3167* Deferred destroy might destroy the snapshot or only mark it to be3168* destroyed later, and it returns success in either case.3169*/3170if (err != 0 || (defer && zfs_dataset_exists(hdl, name,3171ZFS_TYPE_SNAPSHOT))) {3172err = recv_rename(hdl, name, NULL, baselen, newname, flags);3173}31743175return (err);3176}31773178typedef struct guid_to_name_data {3179uint64_t guid;3180boolean_t bookmark_ok;3181char *name;3182char *skip;3183uint64_t *redact_snap_guids;3184uint64_t num_redact_snaps;3185} guid_to_name_data_t;31863187static boolean_t3188redact_snaps_match(zfs_handle_t *zhp, guid_to_name_data_t *gtnd)3189{3190uint64_t *bmark_snaps;3191uint_t bmark_num_snaps;3192nvlist_t *nvl;3193if (zhp->zfs_type != ZFS_TYPE_BOOKMARK)3194return (B_FALSE);31953196nvl = fnvlist_lookup_nvlist(zhp->zfs_props,3197zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS));3198bmark_snaps = fnvlist_lookup_uint64_array(nvl, ZPROP_VALUE,3199&bmark_num_snaps);3200if (bmark_num_snaps != gtnd->num_redact_snaps)3201return (B_FALSE);3202int i = 0;3203for (; i < bmark_num_snaps; i++) {3204int j = 0;3205for (; j < bmark_num_snaps; j++) {3206if (bmark_snaps[i] == gtnd->redact_snap_guids[j])3207break;3208}3209if (j == bmark_num_snaps)3210break;3211}3212return (i == bmark_num_snaps);3213}32143215static int3216guid_to_name_cb(zfs_handle_t *zhp, void *arg)3217{3218guid_to_name_data_t *gtnd = arg;3219const char *slash;3220int err;32213222if (gtnd->skip != NULL &&3223(slash = strrchr(zhp->zfs_name, '/')) != NULL &&3224strcmp(slash + 1, gtnd->skip) == 0) {3225zfs_close(zhp);3226return (0);3227}32283229if (zfs_prop_get_int(zhp, ZFS_PROP_GUID) == gtnd->guid &&3230(gtnd->num_redact_snaps == -1 || redact_snaps_match(zhp, gtnd))) {3231(void) strcpy(gtnd->name, zhp->zfs_name);3232zfs_close(zhp);3233return (EEXIST);3234}32353236err = zfs_iter_children_v2(zhp, 0, guid_to_name_cb, gtnd);3237if (err != EEXIST && gtnd->bookmark_ok)3238err = zfs_iter_bookmarks_v2(zhp, 0, guid_to_name_cb, gtnd);3239zfs_close(zhp);3240return (err);3241}32423243/*3244* Attempt to find the local dataset associated with this guid. In the case of3245* multiple matches, we attempt to find the "best" match by searching3246* progressively larger portions of the hierarchy. This allows one to send a3247* tree of datasets individually and guarantee that we will find the source3248* guid within that hierarchy, even if there are multiple matches elsewhere.3249*3250* If num_redact_snaps is not -1, we attempt to find a redaction bookmark with3251* the specified number of redaction snapshots. If num_redact_snaps isn't 0 or3252* -1, then redact_snap_guids will be an array of the guids of the snapshots the3253* redaction bookmark was created with. If num_redact_snaps is -1, then we will3254* attempt to find a snapshot or bookmark (if bookmark_ok is passed) with the3255* given guid. Note that a redaction bookmark can be returned if3256* num_redact_snaps == -1.3257*/3258static int3259guid_to_name_redact_snaps(libzfs_handle_t *hdl, const char *parent,3260uint64_t guid, boolean_t bookmark_ok, uint64_t *redact_snap_guids,3261uint64_t num_redact_snaps, char *name)3262{3263char pname[ZFS_MAX_DATASET_NAME_LEN];3264guid_to_name_data_t gtnd;32653266gtnd.guid = guid;3267gtnd.bookmark_ok = bookmark_ok;3268gtnd.name = name;3269gtnd.skip = NULL;3270gtnd.redact_snap_guids = redact_snap_guids;3271gtnd.num_redact_snaps = num_redact_snaps;32723273/*3274* Search progressively larger portions of the hierarchy, starting3275* with the filesystem specified by 'parent'. This will3276* select the "most local" version of the origin snapshot in the case3277* that there are multiple matching snapshots in the system.3278*/3279(void) strlcpy(pname, parent, sizeof (pname));3280char *cp = strrchr(pname, '@');3281if (cp == NULL)3282cp = strchr(pname, '\0');3283for (; cp != NULL; cp = strrchr(pname, '/')) {3284/* Chop off the last component and open the parent */3285*cp = '\0';3286zfs_handle_t *zhp = make_dataset_handle(hdl, pname);32873288if (zhp == NULL)3289continue;3290int err = guid_to_name_cb(zfs_handle_dup(zhp), >nd);3291if (err != EEXIST)3292err = zfs_iter_children_v2(zhp, 0, guid_to_name_cb,3293>nd);3294if (err != EEXIST && bookmark_ok)3295err = zfs_iter_bookmarks_v2(zhp, 0, guid_to_name_cb,3296>nd);3297zfs_close(zhp);3298if (err == EEXIST)3299return (0);33003301/*3302* Remember the last portion of the dataset so we skip it next3303* time through (as we've already searched that portion of the3304* hierarchy).3305*/3306gtnd.skip = strrchr(pname, '/') + 1;3307}33083309return (ENOENT);3310}33113312static int3313guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid,3314boolean_t bookmark_ok, char *name)3315{3316return (guid_to_name_redact_snaps(hdl, parent, guid, bookmark_ok, NULL,3317-1, name));3318}33193320/*3321* Return +1 if guid1 is before guid2, 0 if they are the same, and -1 if3322* guid1 is after guid2.3323*/3324static int3325created_before(libzfs_handle_t *hdl, avl_tree_t *avl,3326uint64_t guid1, uint64_t guid2)3327{3328nvlist_t *nvfs;3329const char *fsname = NULL, *snapname = NULL;3330char buf[ZFS_MAX_DATASET_NAME_LEN];3331int rv;3332zfs_handle_t *guid1hdl, *guid2hdl;3333uint64_t create1, create2;33343335if (guid2 == 0)3336return (0);3337if (guid1 == 0)3338return (1);33393340nvfs = fsavl_find(avl, guid1, &snapname);3341fsname = fnvlist_lookup_string(nvfs, "name");3342(void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);3343guid1hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);3344if (guid1hdl == NULL)3345return (-1);33463347nvfs = fsavl_find(avl, guid2, &snapname);3348fsname = fnvlist_lookup_string(nvfs, "name");3349(void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);3350guid2hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);3351if (guid2hdl == NULL) {3352zfs_close(guid1hdl);3353return (-1);3354}33553356create1 = zfs_prop_get_int(guid1hdl, ZFS_PROP_CREATETXG);3357create2 = zfs_prop_get_int(guid2hdl, ZFS_PROP_CREATETXG);33583359if (create1 < create2)3360rv = -1;3361else if (create1 > create2)3362rv = +1;3363else3364rv = 0;33653366zfs_close(guid1hdl);3367zfs_close(guid2hdl);33683369return (rv);3370}33713372/*3373* This function reestablishes the hierarchy of encryption roots after a3374* recursive incremental receive has completed. This must be done after the3375* second call to recv_incremental_replication() has renamed and promoted all3376* sent datasets to their final locations in the dataset hierarchy.3377*/3378static int3379recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs,3380nvlist_t *stream_nv, avl_tree_t *stream_avl)3381{3382int err;3383nvpair_t *fselem = NULL;3384nvlist_t *local_nv;3385avl_tree_t *local_avl;3386boolean_t recursive;33873388recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==3389ENOENT);33903391/* Using top_zfs, gather the nvlists for all local filesystems. */3392if ((err = gather_nvlist(hdl, top_zfs, NULL, NULL,3393recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE,3394B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0)3395return (err);33963397/*3398* Go through the nvlists of the local filesystems and check for3399* encryption roots.3400*/3401while ((fselem = nvlist_next_nvpair(local_nv, fselem)) != NULL) {3402zfs_handle_t *zhp = NULL;3403uint64_t crypt;3404nvlist_t *stream_props, *snaps, *stream_nvfs = NULL,3405*nvfs = NULL;3406boolean_t is_encroot, is_clone, stream_encroot;3407const char *stream_keylocation = NULL, *fsname;3408char keylocation[MAXNAMELEN];3409nvpair_t *snapelem;34103411nvfs = fnvpair_value_nvlist(fselem);3412snaps = fnvlist_lookup_nvlist(nvfs, "snaps");3413fsname = fnvlist_lookup_string(nvfs, "name");3414zhp = zfs_open(hdl, fsname, ZFS_TYPE_DATASET);3415if (zhp == NULL) {3416err = ENOENT;3417goto error;3418}34193420/* we don't need to do anything for unencrypted datasets */3421crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);3422if (crypt == ZIO_CRYPT_OFF) {3423zfs_close(zhp);3424continue;3425}34263427is_clone = zhp->zfs_dmustats.dds_origin[0] != '\0';3428(void) zfs_crypto_get_encryption_root(zhp, &is_encroot, NULL);3429keylocation[0] = '\0';34303431/*3432* Go through the snapshots of the local filesystem and find3433* the stream's filesystem.3434*/3435for (snapelem = nvlist_next_nvpair(snaps, NULL);3436snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) {3437uint64_t thisguid;34383439thisguid = fnvpair_value_uint64(snapelem);3440stream_nvfs = fsavl_find(stream_avl, thisguid, NULL);34413442if (stream_nvfs != NULL)3443break;3444}34453446if (stream_nvfs == NULL)3447continue;34483449stream_props = fnvlist_lookup_nvlist(stream_nvfs, "props");3450stream_encroot = nvlist_exists(stream_nvfs, "is_encroot");34513452/*3453* If the dataset is flagged as an encryption root, was not3454* received as a clone and is not currently an encryption root,3455* force it to become one. Fixup the keylocation if necessary.3456*/3457if (stream_encroot) {3458if (!is_clone && !is_encroot) {3459err = lzc_change_key(fsname,3460DCP_CMD_FORCE_NEW_KEY, NULL, NULL, 0);3461if (err != 0) {3462zfs_close(zhp);3463goto error;3464}3465}34663467stream_keylocation = fnvlist_lookup_string(stream_props,3468zfs_prop_to_name(ZFS_PROP_KEYLOCATION));34693470/*3471* Refresh the properties in case the call to3472* lzc_change_key() changed the value.3473*/3474zfs_refresh_properties(zhp);3475err = zfs_prop_get(zhp, ZFS_PROP_KEYLOCATION,3476keylocation, sizeof (keylocation), NULL, NULL,34770, B_TRUE);3478if (err != 0) {3479zfs_close(zhp);3480goto error;3481}34823483if (strcmp(keylocation, stream_keylocation) != 0) {3484err = zfs_prop_set(zhp,3485zfs_prop_to_name(ZFS_PROP_KEYLOCATION),3486stream_keylocation);3487if (err != 0) {3488zfs_close(zhp);3489goto error;3490}3491}3492}34933494/*3495* If the dataset is not flagged as an encryption root and is3496* currently an encryption root, force it to inherit from its3497* parent. The root of a raw send should never be3498* force-inherited.3499*/3500if (!stream_encroot && is_encroot &&3501strcmp(top_zfs, fsname) != 0) {3502err = lzc_change_key(fsname, DCP_CMD_FORCE_INHERIT,3503NULL, NULL, 0);3504if (err != 0) {3505zfs_close(zhp);3506goto error;3507}3508}35093510zfs_close(zhp);3511}35123513return (0);35143515error:3516return (err);3517}35183519static int3520recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,3521recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,3522nvlist_t *renamed)3523{3524nvlist_t *local_nv, *deleted = NULL;3525avl_tree_t *local_avl;3526nvpair_t *fselem, *nextfselem;3527const char *fromsnap;3528char newname[ZFS_MAX_DATASET_NAME_LEN];3529char guidname[32];3530int error;3531boolean_t needagain, progress, recursive;3532const char *s1, *s2;35333534if (flags->dryrun)3535return (0);35363537fromsnap = fnvlist_lookup_string(stream_nv, "fromsnap");35383539recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==3540ENOENT);35413542again:3543needagain = progress = B_FALSE;35443545deleted = fnvlist_alloc();35463547if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,3548recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE,3549B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0)3550return (error);35513552/*3553* Process deletes and renames3554*/3555for (fselem = nvlist_next_nvpair(local_nv, NULL);3556fselem; fselem = nextfselem) {3557nvlist_t *nvfs, *snaps;3558nvlist_t *stream_nvfs = NULL;3559nvpair_t *snapelem, *nextsnapelem;3560uint64_t fromguid = 0;3561uint64_t originguid = 0;3562uint64_t stream_originguid = 0;3563uint64_t parent_fromsnap_guid, stream_parent_fromsnap_guid;3564const char *fsname, *stream_fsname;35653566nextfselem = nvlist_next_nvpair(local_nv, fselem);35673568nvfs = fnvpair_value_nvlist(fselem);3569snaps = fnvlist_lookup_nvlist(nvfs, "snaps");3570fsname = fnvlist_lookup_string(nvfs, "name");3571parent_fromsnap_guid = fnvlist_lookup_uint64(nvfs,3572"parentfromsnap");3573(void) nvlist_lookup_uint64(nvfs, "origin", &originguid);35743575/*3576* First find the stream's fs, so we can check for3577* a different origin (due to "zfs promote")3578*/3579for (snapelem = nvlist_next_nvpair(snaps, NULL);3580snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) {3581uint64_t thisguid;35823583thisguid = fnvpair_value_uint64(snapelem);3584stream_nvfs = fsavl_find(stream_avl, thisguid, NULL);35853586if (stream_nvfs != NULL)3587break;3588}35893590/* check for promote */3591(void) nvlist_lookup_uint64(stream_nvfs, "origin",3592&stream_originguid);3593if (stream_nvfs && originguid != stream_originguid) {3594switch (created_before(hdl, local_avl,3595stream_originguid, originguid)) {3596case 1: {3597/* promote it! */3598nvlist_t *origin_nvfs;3599const char *origin_fsname;36003601origin_nvfs = fsavl_find(local_avl, originguid,3602NULL);3603origin_fsname = fnvlist_lookup_string(3604origin_nvfs, "name");3605error = recv_promote(hdl, fsname, origin_fsname,3606flags);3607if (error == 0)3608progress = B_TRUE;3609break;3610}3611default:3612break;3613case -1:3614fsavl_destroy(local_avl);3615fnvlist_free(local_nv);3616return (-1);3617}3618/*3619* We had/have the wrong origin, therefore our3620* list of snapshots is wrong. Need to handle3621* them on the next pass.3622*/3623needagain = B_TRUE;3624continue;3625}36263627for (snapelem = nvlist_next_nvpair(snaps, NULL);3628snapelem; snapelem = nextsnapelem) {3629uint64_t thisguid;3630const char *stream_snapname;3631nvlist_t *found, *props;36323633nextsnapelem = nvlist_next_nvpair(snaps, snapelem);36343635thisguid = fnvpair_value_uint64(snapelem);3636found = fsavl_find(stream_avl, thisguid,3637&stream_snapname);36383639/* check for delete */3640if (found == NULL) {3641char name[ZFS_MAX_DATASET_NAME_LEN];36423643if (!flags->force)3644continue;36453646(void) snprintf(name, sizeof (name), "%s@%s",3647fsname, nvpair_name(snapelem));36483649error = recv_destroy(hdl, name,3650strlen(fsname)+1, newname, flags);3651if (error)3652needagain = B_TRUE;3653else3654progress = B_TRUE;3655sprintf(guidname, "%llu",3656(u_longlong_t)thisguid);3657nvlist_add_boolean(deleted, guidname);3658continue;3659}36603661stream_nvfs = found;36623663if (0 == nvlist_lookup_nvlist(stream_nvfs, "snapprops",3664&props) && 0 == nvlist_lookup_nvlist(props,3665stream_snapname, &props)) {3666zfs_cmd_t zc = {"\0"};36673668zc.zc_cookie = B_TRUE; /* received */3669(void) snprintf(zc.zc_name, sizeof (zc.zc_name),3670"%s@%s", fsname, nvpair_name(snapelem));3671zcmd_write_src_nvlist(hdl, &zc, props);3672(void) zfs_ioctl(hdl,3673ZFS_IOC_SET_PROP, &zc);3674zcmd_free_nvlists(&zc);3675}36763677/* check for different snapname */3678if (strcmp(nvpair_name(snapelem),3679stream_snapname) != 0) {3680char name[ZFS_MAX_DATASET_NAME_LEN];3681char tryname[ZFS_MAX_DATASET_NAME_LEN];36823683(void) snprintf(name, sizeof (name), "%s@%s",3684fsname, nvpair_name(snapelem));3685(void) snprintf(tryname, sizeof (name), "%s@%s",3686fsname, stream_snapname);36873688error = recv_rename(hdl, name, tryname,3689strlen(fsname)+1, newname, flags);3690if (error)3691needagain = B_TRUE;3692else3693progress = B_TRUE;3694}36953696if (strcmp(stream_snapname, fromsnap) == 0)3697fromguid = thisguid;3698}36993700/* check for delete */3701if (stream_nvfs == NULL) {3702if (!flags->force)3703continue;37043705error = recv_destroy(hdl, fsname, strlen(tofs)+1,3706newname, flags);3707if (error)3708needagain = B_TRUE;3709else3710progress = B_TRUE;3711sprintf(guidname, "%llu",3712(u_longlong_t)parent_fromsnap_guid);3713nvlist_add_boolean(deleted, guidname);3714continue;3715}37163717if (fromguid == 0) {3718if (flags->verbose) {3719(void) printf("local fs %s does not have "3720"fromsnap (%s in stream); must have "3721"been deleted locally; ignoring\n",3722fsname, fromsnap);3723}3724continue;3725}37263727stream_fsname = fnvlist_lookup_string(stream_nvfs, "name");3728stream_parent_fromsnap_guid = fnvlist_lookup_uint64(3729stream_nvfs, "parentfromsnap");37303731s1 = strrchr(fsname, '/');3732s2 = strrchr(stream_fsname, '/');37333734/*3735* Check if we're going to rename based on parent guid change3736* and the current parent guid was also deleted. If it was then3737* rename will fail and is likely unneeded, so avoid this and3738* force an early retry to determine the new3739* parent_fromsnap_guid.3740*/3741if (stream_parent_fromsnap_guid != 0 &&3742parent_fromsnap_guid != 0 &&3743stream_parent_fromsnap_guid != parent_fromsnap_guid) {3744sprintf(guidname, "%llu",3745(u_longlong_t)parent_fromsnap_guid);3746if (nvlist_exists(deleted, guidname)) {3747progress = B_TRUE;3748needagain = B_TRUE;3749goto doagain;3750}3751}37523753/*3754* Check for rename. If the exact receive path is specified, it3755* does not count as a rename, but we still need to check the3756* datasets beneath it.3757*/3758if ((stream_parent_fromsnap_guid != 0 &&3759parent_fromsnap_guid != 0 &&3760stream_parent_fromsnap_guid != parent_fromsnap_guid) ||3761((flags->isprefix || strcmp(tofs, fsname) != 0) &&3762(s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) {3763nvlist_t *parent;3764char tryname[ZFS_MAX_DATASET_NAME_LEN];37653766parent = fsavl_find(local_avl,3767stream_parent_fromsnap_guid, NULL);3768/*3769* NB: parent might not be found if we used the3770* tosnap for stream_parent_fromsnap_guid,3771* because the parent is a newly-created fs;3772* we'll be able to rename it after we recv the3773* new fs.3774*/3775if (parent != NULL) {3776const char *pname;37773778pname = fnvlist_lookup_string(parent, "name");3779(void) snprintf(tryname, sizeof (tryname),3780"%s%s", pname, strrchr(stream_fsname, '/'));3781} else {3782tryname[0] = '\0';3783if (flags->verbose) {3784(void) printf("local fs %s new parent "3785"not found\n", fsname);3786}3787}37883789newname[0] = '\0';37903791error = recv_rename(hdl, fsname, tryname,3792strlen(tofs)+1, newname, flags);37933794if (renamed != NULL && newname[0] != '\0') {3795fnvlist_add_boolean(renamed, newname);3796}37973798if (error)3799needagain = B_TRUE;3800else3801progress = B_TRUE;3802}3803}38043805doagain:3806fsavl_destroy(local_avl);3807fnvlist_free(local_nv);3808fnvlist_free(deleted);38093810if (needagain && progress) {3811/* do another pass to fix up temporary names */3812if (flags->verbose)3813(void) printf("another pass:\n");3814goto again;3815}38163817return (needagain || error != 0);3818}38193820static int3821zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,3822recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,3823char **top_zfs, nvlist_t *cmdprops)3824{3825nvlist_t *stream_nv = NULL;3826avl_tree_t *stream_avl = NULL;3827const char *fromsnap = NULL;3828const char *sendsnap = NULL;3829char *cp;3830char tofs[ZFS_MAX_DATASET_NAME_LEN];3831char sendfs[ZFS_MAX_DATASET_NAME_LEN];3832char errbuf[ERRBUFLEN];3833dmu_replay_record_t drre;3834int error;3835boolean_t anyerr = B_FALSE;3836boolean_t softerr = B_FALSE;3837boolean_t recursive, raw;38383839(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,3840"cannot receive"));38413842assert(drr->drr_type == DRR_BEGIN);3843assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);3844assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==3845DMU_COMPOUNDSTREAM);38463847/*3848* Read in the nvlist from the stream.3849*/3850if (drr->drr_payloadlen != 0) {3851error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen,3852&stream_nv, flags->byteswap, zc);3853if (error) {3854error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);3855goto out;3856}3857}38583859recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==3860ENOENT);3861raw = (nvlist_lookup_boolean(stream_nv, "raw") == 0);38623863if (recursive && strchr(destname, '@')) {3864zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,3865"cannot specify snapshot name for multi-snapshot stream"));3866error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);3867goto out;3868}38693870/*3871* Read in the end record and verify checksum.3872*/3873if (0 != (error = recv_read(hdl, fd, &drre, sizeof (drre),3874flags->byteswap, NULL)))3875goto out;3876if (flags->byteswap) {3877drre.drr_type = BSWAP_32(drre.drr_type);3878drre.drr_u.drr_end.drr_checksum.zc_word[0] =3879BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[0]);3880drre.drr_u.drr_end.drr_checksum.zc_word[1] =3881BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[1]);3882drre.drr_u.drr_end.drr_checksum.zc_word[2] =3883BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[2]);3884drre.drr_u.drr_end.drr_checksum.zc_word[3] =3885BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[3]);3886}3887if (drre.drr_type != DRR_END) {3888error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);3889goto out;3890}3891if (!ZIO_CHECKSUM_EQUAL(drre.drr_u.drr_end.drr_checksum, *zc)) {3892zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,3893"incorrect header checksum"));3894error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);3895goto out;3896}38973898(void) nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap);38993900if (drr->drr_payloadlen != 0) {3901nvlist_t *stream_fss;39023903stream_fss = fnvlist_lookup_nvlist(stream_nv, "fss");3904if ((stream_avl = fsavl_create(stream_fss)) == NULL) {3905zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,3906"couldn't allocate avl tree"));3907error = zfs_error(hdl, EZFS_NOMEM, errbuf);3908goto out;3909}39103911if (fromsnap != NULL && recursive) {3912nvlist_t *renamed = NULL;3913nvpair_t *pair = NULL;39143915(void) strlcpy(tofs, destname, sizeof (tofs));3916if (flags->isprefix) {3917struct drr_begin *drrb = &drr->drr_u.drr_begin;3918int i;39193920if (flags->istail) {3921cp = strrchr(drrb->drr_toname, '/');3922if (cp == NULL) {3923(void) strlcat(tofs, "/",3924sizeof (tofs));3925i = 0;3926} else {3927i = (cp - drrb->drr_toname);3928}3929} else {3930i = strcspn(drrb->drr_toname, "/@");3931}3932/* zfs_receive_one() will create_parents() */3933(void) strlcat(tofs, &drrb->drr_toname[i],3934sizeof (tofs));3935*strchr(tofs, '@') = '\0';3936}39373938if (!flags->dryrun && !flags->nomount) {3939renamed = fnvlist_alloc();3940}39413942softerr = recv_incremental_replication(hdl, tofs, flags,3943stream_nv, stream_avl, renamed);39443945/* Unmount renamed filesystems before receiving. */3946while ((pair = nvlist_next_nvpair(renamed,3947pair)) != NULL) {3948zfs_handle_t *zhp;3949prop_changelist_t *clp = NULL;39503951zhp = zfs_open(hdl, nvpair_name(pair),3952ZFS_TYPE_FILESYSTEM);3953if (zhp != NULL) {3954clp = changelist_gather(zhp,3955ZFS_PROP_MOUNTPOINT, 0,3956flags->forceunmount ? MS_FORCE : 0);3957zfs_close(zhp);3958if (clp != NULL) {3959softerr |=3960changelist_prefix(clp);3961changelist_free(clp);3962}3963}3964}39653966fnvlist_free(renamed);3967}3968}39693970/*3971* Get the fs specified by the first path in the stream (the top level3972* specified by 'zfs send') and pass it to each invocation of3973* zfs_receive_one().3974*/3975(void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,3976sizeof (sendfs));3977if ((cp = strchr(sendfs, '@')) != NULL) {3978*cp = '\0';3979/*3980* Find the "sendsnap", the final snapshot in a replication3981* stream. zfs_receive_one() handles certain errors3982* differently, depending on if the contained stream is the3983* last one or not.3984*/3985sendsnap = (cp + 1);3986}39873988/* Finally, receive each contained stream */3989do {3990/*3991* we should figure out if it has a recoverable3992* error, in which case do a recv_skip() and drive on.3993* Note, if we fail due to already having this guid,3994* zfs_receive_one() will take care of it (ie,3995* recv_skip() and return 0).3996*/3997error = zfs_receive_impl(hdl, destname, NULL, flags, fd,3998sendfs, stream_nv, stream_avl, top_zfs, sendsnap, cmdprops);3999if (error == ENODATA) {4000error = 0;4001break;4002}4003anyerr |= error;4004} while (error == 0);40054006if (drr->drr_payloadlen != 0 && recursive && fromsnap != NULL) {4007/*4008* Now that we have the fs's they sent us, try the4009* renames again.4010*/4011softerr = recv_incremental_replication(hdl, tofs, flags,4012stream_nv, stream_avl, NULL);4013}40144015if (raw && *top_zfs != NULL && !flags->dryrun) {4016softerr = recv_fix_encryption_hierarchy(hdl, *top_zfs,4017stream_nv, stream_avl);4018}40194020out:4021fsavl_destroy(stream_avl);4022fnvlist_free(stream_nv);4023if (softerr)4024error = -2;4025if (anyerr)4026error = -1;4027return (error);4028}40294030static void4031trunc_prop_errs(int truncated)4032{4033ASSERT(truncated != 0);40344035if (truncated == 1)4036(void) fprintf(stderr, dgettext(TEXT_DOMAIN,4037"1 more property could not be set\n"));4038else4039(void) fprintf(stderr, dgettext(TEXT_DOMAIN,4040"%d more properties could not be set\n"), truncated);4041}40424043static int4044recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)4045{4046dmu_replay_record_t *drr;4047void *buf = zfs_alloc(hdl, SPA_MAXBLOCKSIZE);4048uint64_t payload_size;4049char errbuf[ERRBUFLEN];40504051(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,4052"cannot receive"));40534054/* XXX would be great to use lseek if possible... */4055drr = buf;40564057while (recv_read(hdl, fd, drr, sizeof (dmu_replay_record_t),4058byteswap, NULL) == 0) {4059if (byteswap)4060drr->drr_type = BSWAP_32(drr->drr_type);40614062switch (drr->drr_type) {4063case DRR_BEGIN:4064if (drr->drr_payloadlen != 0) {4065(void) recv_read(hdl, fd, buf,4066drr->drr_payloadlen, B_FALSE, NULL);4067}4068break;40694070case DRR_END:4071free(buf);4072return (0);40734074case DRR_OBJECT:4075if (byteswap) {4076drr->drr_u.drr_object.drr_bonuslen =4077BSWAP_32(drr->drr_u.drr_object.4078drr_bonuslen);4079drr->drr_u.drr_object.drr_raw_bonuslen =4080BSWAP_32(drr->drr_u.drr_object.4081drr_raw_bonuslen);4082}40834084payload_size =4085DRR_OBJECT_PAYLOAD_SIZE(&drr->drr_u.drr_object);4086(void) recv_read(hdl, fd, buf, payload_size,4087B_FALSE, NULL);4088break;40894090case DRR_WRITE:4091if (byteswap) {4092drr->drr_u.drr_write.drr_logical_size =4093BSWAP_64(4094drr->drr_u.drr_write.drr_logical_size);4095drr->drr_u.drr_write.drr_compressed_size =4096BSWAP_64(4097drr->drr_u.drr_write.drr_compressed_size);4098}4099payload_size =4100DRR_WRITE_PAYLOAD_SIZE(&drr->drr_u.drr_write);4101assert(payload_size <= SPA_MAXBLOCKSIZE);4102(void) recv_read(hdl, fd, buf,4103payload_size, B_FALSE, NULL);4104break;4105case DRR_SPILL:4106if (byteswap) {4107drr->drr_u.drr_spill.drr_length =4108BSWAP_64(drr->drr_u.drr_spill.drr_length);4109drr->drr_u.drr_spill.drr_compressed_size =4110BSWAP_64(drr->drr_u.drr_spill.4111drr_compressed_size);4112}41134114payload_size =4115DRR_SPILL_PAYLOAD_SIZE(&drr->drr_u.drr_spill);4116(void) recv_read(hdl, fd, buf, payload_size,4117B_FALSE, NULL);4118break;4119case DRR_WRITE_EMBEDDED:4120if (byteswap) {4121drr->drr_u.drr_write_embedded.drr_psize =4122BSWAP_32(drr->drr_u.drr_write_embedded.4123drr_psize);4124}4125(void) recv_read(hdl, fd, buf,4126P2ROUNDUP(drr->drr_u.drr_write_embedded.drr_psize,41278), B_FALSE, NULL);4128break;4129case DRR_OBJECT_RANGE:4130case DRR_WRITE_BYREF:4131case DRR_FREEOBJECTS:4132case DRR_FREE:4133break;41344135default:4136zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4137"invalid record type"));4138free(buf);4139return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));4140}4141}41424143free(buf);4144return (-1);4145}41464147static void4148recv_ecksum_set_aux(libzfs_handle_t *hdl, const char *target_snap,4149boolean_t resumable, boolean_t checksum)4150{4151char target_fs[ZFS_MAX_DATASET_NAME_LEN];41524153zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, (checksum ?4154"checksum mismatch" : "incomplete stream")));41554156if (!resumable)4157return;4158(void) strlcpy(target_fs, target_snap, sizeof (target_fs));4159*strchr(target_fs, '@') = '\0';4160zfs_handle_t *zhp = zfs_open(hdl, target_fs,4161ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);4162if (zhp == NULL)4163return;41644165char token_buf[ZFS_MAXPROPLEN];4166int error = zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,4167token_buf, sizeof (token_buf),4168NULL, NULL, 0, B_TRUE);4169if (error == 0) {4170zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4171"checksum mismatch or incomplete stream.\n"4172"Partially received snapshot is saved.\n"4173"A resuming stream can be generated on the sending "4174"system by running:\n"4175" zfs send -t %s"),4176token_buf);4177}4178zfs_close(zhp);4179}41804181/*4182* Prepare a new nvlist of properties that are to override (-o) or be excluded4183* (-x) from the received dataset4184* recvprops: received properties from the send stream4185* cmdprops: raw input properties from command line4186* origprops: properties, both locally-set and received, currently set on the4187* target dataset if it exists, NULL otherwise.4188* oxprops: valid output override (-o) and excluded (-x) properties4189*/4190static int4191zfs_setup_cmdline_props(libzfs_handle_t *hdl, zfs_type_t type,4192char *fsname, boolean_t zoned, boolean_t recursive, boolean_t newfs,4193boolean_t raw, boolean_t toplevel, nvlist_t *recvprops, nvlist_t *cmdprops,4194nvlist_t *origprops, nvlist_t **oxprops, uint8_t **wkeydata_out,4195uint_t *wkeylen_out, const char *errbuf)4196{4197nvpair_t *nvp;4198nvlist_t *oprops, *voprops;4199zfs_handle_t *zhp = NULL;4200zpool_handle_t *zpool_hdl = NULL;4201char *cp;4202int ret = 0;4203char namebuf[ZFS_MAX_DATASET_NAME_LEN];42044205if (nvlist_empty(cmdprops))4206return (0); /* No properties to override or exclude */42074208*oxprops = fnvlist_alloc();4209oprops = fnvlist_alloc();42104211strlcpy(namebuf, fsname, ZFS_MAX_DATASET_NAME_LEN);42124213/*4214* Get our dataset handle. The target dataset may not exist yet.4215*/4216if (zfs_dataset_exists(hdl, namebuf, ZFS_TYPE_DATASET)) {4217zhp = zfs_open(hdl, namebuf, ZFS_TYPE_DATASET);4218if (zhp == NULL) {4219ret = -1;4220goto error;4221}4222}42234224/* open the zpool handle */4225cp = strchr(namebuf, '/');4226if (cp != NULL)4227*cp = '\0';4228zpool_hdl = zpool_open(hdl, namebuf);4229if (zpool_hdl == NULL) {4230ret = -1;4231goto error;4232}42334234/* restore namebuf to match fsname for later use */4235if (cp != NULL)4236*cp = '/';42374238/*4239* first iteration: process excluded (-x) properties now and gather4240* added (-o) properties to be later processed by zfs_valid_proplist()4241*/4242nvp = NULL;4243while ((nvp = nvlist_next_nvpair(cmdprops, nvp)) != NULL) {4244const char *name = nvpair_name(nvp);4245zfs_prop_t prop = zfs_name_to_prop(name);42464247/*4248* It turns out, if we don't normalize "aliased" names4249* e.g. compress= against the "real" names (e.g. compression)4250* here, then setting/excluding them does not work as4251* intended.4252*4253* But since user-defined properties wouldn't have a valid4254* mapping here, we do this conditional dance.4255*/4256const char *newname = name;4257if (prop >= ZFS_PROP_TYPE)4258newname = zfs_prop_to_name(prop);42594260/* "origin" is processed separately, don't handle it here */4261if (prop == ZFS_PROP_ORIGIN)4262continue;42634264/* raw streams can't override encryption properties */4265if ((zfs_prop_encryption_key_param(prop) ||4266prop == ZFS_PROP_ENCRYPTION) && raw) {4267zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4268"encryption property '%s' cannot "4269"be set or excluded for raw streams."), name);4270ret = zfs_error(hdl, EZFS_BADPROP, errbuf);4271goto error;4272}42734274/*4275* For plain replicated send, we can ignore encryption4276* properties other than first stream4277*/4278if ((zfs_prop_encryption_key_param(prop) || prop ==4279ZFS_PROP_ENCRYPTION) && !newfs && recursive && !raw) {4280continue;4281}42824283/* incremental streams can only exclude encryption properties */4284if ((zfs_prop_encryption_key_param(prop) ||4285prop == ZFS_PROP_ENCRYPTION) && !newfs &&4286nvpair_type(nvp) != DATA_TYPE_BOOLEAN) {4287zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4288"encryption property '%s' cannot "4289"be set for incremental streams."), name);4290ret = zfs_error(hdl, EZFS_BADPROP, errbuf);4291goto error;4292}42934294switch (nvpair_type(nvp)) {4295case DATA_TYPE_BOOLEAN: /* -x property */4296/*4297* DATA_TYPE_BOOLEAN is the way we're asked to "exclude"4298* a property: this is done by forcing an explicit4299* inherit on the destination so the effective value is4300* not the one we received from the send stream.4301*/4302if (!zfs_prop_valid_for_type(prop, type, B_FALSE) &&4303!zfs_prop_user(name)) {4304(void) fprintf(stderr, dgettext(TEXT_DOMAIN,4305"Warning: %s: property '%s' does not "4306"apply to datasets of this type\n"),4307fsname, name);4308continue;4309}4310/*4311* We do this only if the property is not already4312* locally-set, in which case its value will take4313* priority over the received anyway.4314*/4315if (nvlist_exists(origprops, newname)) {4316nvlist_t *attrs;4317const char *source = NULL;43184319attrs = fnvlist_lookup_nvlist(origprops,4320newname);4321if (nvlist_lookup_string(attrs,4322ZPROP_SOURCE, &source) == 0 &&4323strcmp(source, ZPROP_SOURCE_VAL_RECVD) != 0)4324continue;4325}4326/*4327* We can't force an explicit inherit on non-inheritable4328* properties: if we're asked to exclude this kind of4329* values we remove them from "recvprops" input nvlist.4330*/4331if (!zfs_prop_user(name) && /* can be inherited too */4332!zfs_prop_inheritable(prop) &&4333nvlist_exists(recvprops, newname))4334fnvlist_remove(recvprops, newname);4335else4336fnvlist_add_boolean(*oxprops, newname);4337break;4338case DATA_TYPE_STRING: /* -o property=value */4339/*4340* we're trying to override a property that does not4341* make sense for this type of dataset, but we don't4342* want to fail if the receive is recursive: this comes4343* in handy when the send stream contains, for4344* instance, a child ZVOL and we're trying to receive4345* it with "-o atime=on"4346*/4347if (!zfs_prop_valid_for_type(prop, type, B_FALSE) &&4348!zfs_prop_user(name)) {4349if (recursive)4350continue;4351zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4352"property '%s' does not apply to datasets "4353"of this type"), name);4354ret = zfs_error(hdl, EZFS_BADPROP, errbuf);4355goto error;4356}4357fnvlist_add_string(oprops, newname,4358fnvpair_value_string(nvp));4359break;4360default:4361zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4362"property '%s' must be a string or boolean"), name);4363ret = zfs_error(hdl, EZFS_BADPROP, errbuf);4364goto error;4365}4366}43674368if (toplevel) {4369/* convert override strings properties to native */4370if ((voprops = zfs_valid_proplist(hdl, ZFS_TYPE_DATASET,4371oprops, zoned, zhp, zpool_hdl, B_FALSE, errbuf)) == NULL) {4372ret = zfs_error(hdl, EZFS_BADPROP, errbuf);4373goto error;4374}43754376/*4377* zfs_crypto_create() requires the parent name. Get it4378* by truncating the fsname copy stored in namebuf.4379*/4380cp = strrchr(namebuf, '/');4381if (cp != NULL)4382*cp = '\0';43834384if (!raw && !(!newfs && recursive) &&4385zfs_crypto_create(hdl, namebuf, voprops, NULL,4386B_FALSE, wkeydata_out, wkeylen_out) != 0) {4387fnvlist_free(voprops);4388ret = zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf);4389goto error;4390}43914392/* second pass: process "-o" properties */4393fnvlist_merge(*oxprops, voprops);4394fnvlist_free(voprops);4395} else {4396/* override props on child dataset are inherited */4397nvp = NULL;4398while ((nvp = nvlist_next_nvpair(oprops, nvp)) != NULL) {4399const char *name = nvpair_name(nvp);4400fnvlist_add_boolean(*oxprops, name);4401}4402}44034404error:4405if (zhp != NULL)4406zfs_close(zhp);4407if (zpool_hdl != NULL)4408zpool_close(zpool_hdl);4409fnvlist_free(oprops);4410return (ret);4411}44124413/*4414* Restores a backup of tosnap from the file descriptor specified by infd.4415*/4416static int4417zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,4418const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,4419dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,4420avl_tree_t *stream_avl, char **top_zfs,4421const char *finalsnap, nvlist_t *cmdprops)4422{4423struct timespec begin_time;4424int ioctl_err, ioctl_errno, err;4425char *cp;4426struct drr_begin *drrb = &drr->drr_u.drr_begin;4427char errbuf[ERRBUFLEN];4428const char *chopprefix;4429boolean_t newfs = B_FALSE;4430boolean_t stream_wantsnewfs, stream_resumingnewfs;4431boolean_t newprops = B_FALSE;4432uint64_t read_bytes = 0;4433uint64_t errflags = 0;4434uint64_t parent_snapguid = 0;4435prop_changelist_t *clp = NULL;4436nvlist_t *snapprops_nvlist = NULL;4437nvlist_t *snapholds_nvlist = NULL;4438zprop_errflags_t prop_errflags;4439nvlist_t *prop_errors = NULL;4440boolean_t recursive;4441const char *snapname = NULL;4442char destsnap[MAXPATHLEN * 2];4443char origin[MAXNAMELEN] = {0};4444char name[MAXPATHLEN];4445char tmp_keylocation[MAXNAMELEN] = {0};4446nvlist_t *rcvprops = NULL; /* props received from the send stream */4447nvlist_t *oxprops = NULL; /* override (-o) and exclude (-x) props */4448nvlist_t *origprops = NULL; /* original props (if destination exists) */4449zfs_type_t type = ZFS_TYPE_INVALID;4450boolean_t toplevel = B_FALSE;4451boolean_t zoned = B_FALSE;4452boolean_t hastoken = B_FALSE;4453boolean_t redacted;4454uint8_t *wkeydata = NULL;4455uint_t wkeylen = 0;44564457#ifndef CLOCK_MONOTONIC_RAW4458#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC4459#endif4460clock_gettime(CLOCK_MONOTONIC_RAW, &begin_time);44614462(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,4463"cannot receive"));44644465recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==4466ENOENT);44674468/* Did the user request holds be skipped via zfs recv -k? */4469boolean_t holds = flags->holds && !flags->skipholds;44704471if (stream_avl != NULL) {4472const char *keylocation = NULL;4473nvlist_t *lookup = NULL;4474nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,4475&snapname);44764477(void) nvlist_lookup_uint64(fs, "parentfromsnap",4478&parent_snapguid);4479err = nvlist_lookup_nvlist(fs, "props", &rcvprops);4480if (err) {4481rcvprops = fnvlist_alloc();4482newprops = B_TRUE;4483}44844485/*4486* The keylocation property may only be set on encryption roots,4487* but this dataset might not become an encryption root until4488* recv_fix_encryption_hierarchy() is called. That function4489* will fixup the keylocation anyway, so we temporarily unset4490* the keylocation for now to avoid any errors from the receive4491* ioctl.4492*/4493err = nvlist_lookup_string(rcvprops,4494zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation);4495if (err == 0) {4496strlcpy(tmp_keylocation, keylocation, MAXNAMELEN);4497(void) nvlist_remove_all(rcvprops,4498zfs_prop_to_name(ZFS_PROP_KEYLOCATION));4499}45004501if (flags->canmountoff) {4502fnvlist_add_uint64(rcvprops,4503zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0);4504} else if (newprops) { /* nothing in rcvprops, eliminate it */4505fnvlist_free(rcvprops);4506rcvprops = NULL;4507newprops = B_FALSE;4508}4509if (0 == nvlist_lookup_nvlist(fs, "snapprops", &lookup)) {4510snapprops_nvlist = fnvlist_lookup_nvlist(lookup,4511snapname);4512}4513if (holds) {4514if (0 == nvlist_lookup_nvlist(fs, "snapholds",4515&lookup)) {4516snapholds_nvlist = fnvlist_lookup_nvlist(4517lookup, snapname);4518}4519}4520}45214522cp = NULL;45234524/*4525* Determine how much of the snapshot name stored in the stream4526* we are going to tack on to the name they specified on the4527* command line, and how much we are going to chop off.4528*4529* If they specified a snapshot, chop the entire name stored in4530* the stream.4531*/4532if (flags->istail) {4533/*4534* A filesystem was specified with -e. We want to tack on only4535* the tail of the sent snapshot path.4536*/4537if (strchr(tosnap, '@')) {4538zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "4539"argument - snapshot not allowed with -e"));4540err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);4541goto out;4542}45434544chopprefix = strrchr(sendfs, '/');45454546if (chopprefix == NULL) {4547/*4548* The tail is the poolname, so we need to4549* prepend a path separator.4550*/4551int len = strlen(drrb->drr_toname);4552cp = umem_alloc(len + 2, UMEM_NOFAIL);4553cp[0] = '/';4554(void) strcpy(&cp[1], drrb->drr_toname);4555chopprefix = cp;4556} else {4557chopprefix = drrb->drr_toname + (chopprefix - sendfs);4558}4559} else if (flags->isprefix) {4560/*4561* A filesystem was specified with -d. We want to tack on4562* everything but the first element of the sent snapshot path4563* (all but the pool name).4564*/4565if (strchr(tosnap, '@')) {4566zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "4567"argument - snapshot not allowed with -d"));4568err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);4569goto out;4570}45714572chopprefix = strchr(drrb->drr_toname, '/');4573if (chopprefix == NULL)4574chopprefix = strchr(drrb->drr_toname, '@');4575} else if (strchr(tosnap, '@') == NULL) {4576/*4577* If a filesystem was specified without -d or -e, we want to4578* tack on everything after the fs specified by 'zfs send'.4579*/4580chopprefix = drrb->drr_toname + strlen(sendfs);4581} else {4582/* A snapshot was specified as an exact path (no -d or -e). */4583if (recursive) {4584zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4585"cannot specify snapshot name for multi-snapshot "4586"stream"));4587err = zfs_error(hdl, EZFS_BADSTREAM, errbuf);4588goto out;4589}4590chopprefix = drrb->drr_toname + strlen(drrb->drr_toname);4591}45924593ASSERT(strstr(drrb->drr_toname, sendfs) == drrb->drr_toname);4594ASSERT(chopprefix > drrb->drr_toname || strchr(sendfs, '/') == NULL);4595ASSERT(chopprefix <= drrb->drr_toname + strlen(drrb->drr_toname) ||4596strchr(sendfs, '/') == NULL);4597ASSERT(chopprefix[0] == '/' || chopprefix[0] == '@' ||4598chopprefix[0] == '\0');45994600/*4601* Determine name of destination snapshot.4602*/4603(void) strlcpy(destsnap, tosnap, sizeof (destsnap));4604(void) strlcat(destsnap, chopprefix, sizeof (destsnap));4605if (cp != NULL)4606umem_free(cp, strlen(cp) + 1);4607if (!zfs_name_valid(destsnap, ZFS_TYPE_SNAPSHOT)) {4608err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);4609goto out;4610}46114612/*4613* Determine the name of the origin snapshot.4614*/4615if (originsnap) {4616(void) strlcpy(origin, originsnap, sizeof (origin));4617if (flags->verbose)4618(void) printf("using provided clone origin %s\n",4619origin);4620} else if (drrb->drr_flags & DRR_FLAG_CLONE) {4621if (guid_to_name(hdl, destsnap,4622drrb->drr_fromguid, B_FALSE, origin) != 0) {4623zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4624"local origin for clone %s does not exist"),4625destsnap);4626err = zfs_error(hdl, EZFS_NOENT, errbuf);4627goto out;4628}4629if (flags->verbose)4630(void) printf("found clone origin %s\n", origin);4631}46324633if ((DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &4634DMU_BACKUP_FEATURE_DEDUP)) {4635(void) fprintf(stderr,4636gettext("ERROR: \"zfs receive\" no longer supports "4637"deduplicated send streams. Use\n"4638"the \"zstream redup\" command to convert this stream "4639"to a regular,\n"4640"non-deduplicated stream.\n"));4641err = zfs_error(hdl, EZFS_NOTSUP, errbuf);4642goto out;4643}46444645boolean_t resuming = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &4646DMU_BACKUP_FEATURE_RESUMING;4647boolean_t raw = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &4648DMU_BACKUP_FEATURE_RAW;4649boolean_t embedded = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &4650DMU_BACKUP_FEATURE_EMBED_DATA;4651stream_wantsnewfs = (drrb->drr_fromguid == 0 ||4652(drrb->drr_flags & DRR_FLAG_CLONE) || originsnap) && !resuming;4653stream_resumingnewfs = (drrb->drr_fromguid == 0 ||4654(drrb->drr_flags & DRR_FLAG_CLONE) || originsnap) && resuming;46554656if (stream_wantsnewfs) {4657/*4658* if the parent fs does not exist, look for it based on4659* the parent snap GUID4660*/4661(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,4662"cannot receive new filesystem stream"));46634664(void) strlcpy(name, destsnap, sizeof (name));4665cp = strrchr(name, '/');4666if (cp)4667*cp = '\0';4668if (cp &&4669!zfs_dataset_exists(hdl, name, ZFS_TYPE_DATASET)) {4670char suffix[ZFS_MAX_DATASET_NAME_LEN];4671(void) strlcpy(suffix, strrchr(destsnap, '/'),4672sizeof (suffix));4673if (guid_to_name(hdl, name, parent_snapguid,4674B_FALSE, destsnap) == 0) {4675*strchr(destsnap, '@') = '\0';4676(void) strlcat(destsnap, suffix,4677sizeof (destsnap));4678}4679}4680} else {4681/*4682* If the fs does not exist, look for it based on the4683* fromsnap GUID.4684*/4685if (resuming) {4686(void) snprintf(errbuf, sizeof (errbuf),4687dgettext(TEXT_DOMAIN,4688"cannot receive resume stream"));4689} else {4690(void) snprintf(errbuf, sizeof (errbuf),4691dgettext(TEXT_DOMAIN,4692"cannot receive incremental stream"));4693}46944695(void) strlcpy(name, destsnap, sizeof (name));4696*strchr(name, '@') = '\0';46974698/*4699* If the exact receive path was specified and this is the4700* topmost path in the stream, then if the fs does not exist we4701* should look no further.4702*/4703if ((flags->isprefix || (*(chopprefix = drrb->drr_toname +4704strlen(sendfs)) != '\0' && *chopprefix != '@')) &&4705!zfs_dataset_exists(hdl, name, ZFS_TYPE_DATASET)) {4706char snap[ZFS_MAX_DATASET_NAME_LEN];4707(void) strlcpy(snap, strchr(destsnap, '@'),4708sizeof (snap));4709if (guid_to_name(hdl, name, drrb->drr_fromguid,4710B_FALSE, destsnap) == 0) {4711*strchr(destsnap, '@') = '\0';4712(void) strlcat(destsnap, snap,4713sizeof (destsnap));4714}4715}4716}47174718(void) strlcpy(name, destsnap, sizeof (name));4719*strchr(name, '@') = '\0';47204721redacted = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &4722DMU_BACKUP_FEATURE_REDACTED;47234724if (flags->heal) {4725if (flags->isprefix || flags->istail || flags->force ||4726flags->canmountoff || flags->resumable || flags->nomount ||4727flags->skipholds) {4728zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4729"corrective recv can not be used when combined with"4730" this flag"));4731err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);4732goto out;4733}4734uint64_t guid =4735get_snap_guid(hdl, name, strchr(destsnap, '@') + 1);4736if (guid == 0) {4737zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4738"corrective recv must specify an existing snapshot"4739" to heal"));4740err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);4741goto out;4742} else if (guid != drrb->drr_toguid) {4743zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4744"local snapshot doesn't match the snapshot"4745" in the provided stream"));4746err = zfs_error(hdl, EZFS_WRONG_PARENT, errbuf);4747goto out;4748}4749} else if (zfs_dataset_exists(hdl, name, ZFS_TYPE_DATASET)) {4750zfs_cmd_t zc = {"\0"};4751zfs_handle_t *zhp = NULL;4752boolean_t encrypted;47534754(void) strcpy(zc.zc_name, name);47554756/*4757* Destination fs exists. It must be one of these cases:4758* - an incremental send stream4759* - the stream specifies a new fs (full stream or clone)4760* and they want us to blow away the existing fs (and4761* have therefore specified -F and removed any snapshots)4762* - we are resuming a failed receive.4763*/4764if (stream_wantsnewfs) {4765boolean_t is_volume = drrb->drr_type == DMU_OST_ZVOL;4766if (!flags->force) {4767zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4768"destination '%s' exists\n"4769"must specify -F to overwrite it"), name);4770err = zfs_error(hdl, EZFS_EXISTS, errbuf);4771goto out;4772}4773if (zfs_ioctl(hdl, ZFS_IOC_SNAPSHOT_LIST_NEXT,4774&zc) == 0) {4775zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4776"destination has snapshots (eg. %s)\n"4777"must destroy them to overwrite it"),4778zc.zc_name);4779err = zfs_error(hdl, EZFS_EXISTS, errbuf);4780goto out;4781}4782if (is_volume && strrchr(name, '/') == NULL) {4783zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4784"destination %s is the root dataset\n"4785"cannot overwrite with a ZVOL"),4786name);4787err = zfs_error(hdl, EZFS_EXISTS, errbuf);4788goto out;4789}4790if (is_volume &&4791zfs_ioctl(hdl, ZFS_IOC_DATASET_LIST_NEXT,4792&zc) == 0) {4793zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4794"destination has children (eg. %s)\n"4795"cannot overwrite with a ZVOL"),4796zc.zc_name);4797err = zfs_error(hdl, EZFS_WRONG_PARENT, errbuf);4798goto out;4799}4800}48014802if ((zhp = zfs_open(hdl, name,4803ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {4804err = -1;4805goto out;4806}48074808/*4809* When receiving full/newfs on existing dataset, then it4810* should be done with "-F" flag. Its enforced for initial4811* receive in previous checks in this function.4812* Similarly, on resuming full/newfs recv on existing dataset,4813* it should be done with "-F" flag.4814*4815* When dataset doesn't exist, then full/newfs recv is done on4816* newly created dataset and it's marked INCONSISTENT. But4817* When receiving on existing dataset, recv is first done on4818* %recv and its marked INCONSISTENT. Existing dataset is not4819* marked INCONSISTENT.4820* Resume of full/newfs receive with dataset not INCONSISTENT4821* indicates that its resuming newfs on existing dataset. So,4822* enforce "-F" flag in this case.4823*/4824if (stream_resumingnewfs &&4825!zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&4826!flags->force) {4827zfs_close(zhp);4828zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4829"Resuming recv on existing destination '%s'\n"4830"must specify -F to overwrite it"), name);4831err = zfs_error(hdl, EZFS_RESUME_EXISTS, errbuf);4832goto out;4833}48344835if (stream_wantsnewfs &&4836zhp->zfs_dmustats.dds_origin[0]) {4837zfs_close(zhp);4838zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4839"destination '%s' is a clone\n"4840"must destroy it to overwrite it"), name);4841err = zfs_error(hdl, EZFS_EXISTS, errbuf);4842goto out;4843}48444845/*4846* Raw sends can not be performed as an incremental on top4847* of existing unencrypted datasets. zfs recv -F can't be4848* used to blow away an existing encrypted filesystem. This4849* is because it would require the dsl dir to point to the4850* new key (or lack of a key) and the old key at the same4851* time. The -F flag may still be used for deleting4852* intermediate snapshots that would otherwise prevent the4853* receive from working.4854*/4855encrypted = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) !=4856ZIO_CRYPT_OFF;4857if (!stream_wantsnewfs && !encrypted && raw) {4858zfs_close(zhp);4859zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4860"cannot perform raw receive on top of "4861"existing unencrypted dataset"));4862err = zfs_error(hdl, EZFS_BADRESTORE, errbuf);4863goto out;4864}48654866if (stream_wantsnewfs && flags->force &&4867((raw && !encrypted) || encrypted)) {4868zfs_close(zhp);4869zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4870"zfs receive -F cannot be used to destroy an "4871"encrypted filesystem or overwrite an "4872"unencrypted one with an encrypted one"));4873err = zfs_error(hdl, EZFS_BADRESTORE, errbuf);4874goto out;4875}48764877if (!flags->dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&4878(stream_wantsnewfs || stream_resumingnewfs)) {4879/* We can't do online recv in this case */4880clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,4881flags->forceunmount ? MS_FORCE : 0);4882if (clp == NULL) {4883zfs_close(zhp);4884err = -1;4885goto out;4886}4887if (changelist_prefix(clp) != 0) {4888changelist_free(clp);4889zfs_close(zhp);4890err = -1;4891goto out;4892}4893}48944895/*4896* If we are resuming a newfs, set newfs here so that we will4897* mount it if the recv succeeds this time. We can tell4898* that it was a newfs on the first recv because the fs4899* itself will be inconsistent (if the fs existed when we4900* did the first recv, we would have received it into4901* .../%recv).4902*/4903if (resuming && zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT))4904newfs = B_TRUE;49054906/* we want to know if we're zoned when validating -o|-x props */4907zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);49084909/* may need this info later, get it now we have zhp around */4910if (zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN, NULL, 0,4911NULL, NULL, 0, B_TRUE) == 0)4912hastoken = B_TRUE;49134914/* gather existing properties on destination */4915origprops = fnvlist_alloc();4916fnvlist_merge(origprops, zhp->zfs_props);4917fnvlist_merge(origprops, zhp->zfs_user_props);49184919zfs_close(zhp);4920} else {4921zfs_handle_t *zhp;49224923/*4924* Destination filesystem does not exist. Therefore we better4925* be creating a new filesystem (either from a full backup, or4926* a clone). It would therefore be invalid if the user4927* specified only the pool name (i.e. if the destination name4928* contained no slash character).4929*/4930cp = strrchr(name, '/');49314932if (!stream_wantsnewfs || cp == NULL) {4933zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4934"destination '%s' does not exist"), name);4935err = zfs_error(hdl, EZFS_NOENT, errbuf);4936goto out;4937}49384939/*4940* Trim off the final dataset component so we perform the4941* recvbackup ioctl to the filesystems's parent.4942*/4943*cp = '\0';49444945if (flags->isprefix && !flags->istail && !flags->dryrun &&4946create_parents(hdl, destsnap, strlen(tosnap)) != 0) {4947err = zfs_error(hdl, EZFS_BADRESTORE, errbuf);4948goto out;4949}49504951/* validate parent */4952zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);4953if (zhp == NULL) {4954err = zfs_error(hdl, EZFS_BADRESTORE, errbuf);4955goto out;4956}4957if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {4958zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4959"parent '%s' is not a filesystem"), name);4960err = zfs_error(hdl, EZFS_WRONG_PARENT, errbuf);4961zfs_close(zhp);4962goto out;4963}49644965zfs_close(zhp);49664967newfs = B_TRUE;4968*cp = '/';4969}49704971if (flags->verbose) {4972(void) printf("%s %s%s stream of %s into %s\n",4973flags->dryrun ? "would receive" : "receiving",4974flags->heal ? "corrective " : "",4975drrb->drr_fromguid ? "incremental" : "full",4976drrb->drr_toname, destsnap);4977(void) fflush(stdout);4978}49794980/*4981* If this is the top-level dataset, record it so we can use it4982* for recursive operations later.4983*/4984if (top_zfs != NULL &&4985(*top_zfs == NULL || strcmp(*top_zfs, name) == 0)) {4986toplevel = B_TRUE;4987if (*top_zfs == NULL)4988*top_zfs = zfs_strdup(hdl, name);4989}49904991if (drrb->drr_type == DMU_OST_ZVOL) {4992type = ZFS_TYPE_VOLUME;4993} else if (drrb->drr_type == DMU_OST_ZFS) {4994type = ZFS_TYPE_FILESYSTEM;4995} else {4996zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4997"invalid record type: 0x%d"), drrb->drr_type);4998err = zfs_error(hdl, EZFS_BADSTREAM, errbuf);4999goto out;5000}5001if ((err = zfs_setup_cmdline_props(hdl, type, name, zoned, recursive,5002stream_wantsnewfs, raw, toplevel, rcvprops, cmdprops, origprops,5003&oxprops, &wkeydata, &wkeylen, errbuf)) != 0)5004goto out;50055006/*5007* When sending with properties (zfs send -p), the encryption property5008* is not included because it is a SETONCE property and therefore5009* treated as read only. However, we are always able to determine its5010* value because raw sends will include it in the DRR_BDEGIN payload5011* and non-raw sends with properties are not allowed for encrypted5012* datasets. Therefore, if this is a non-raw properties stream, we can5013* infer that the value should be ZIO_CRYPT_OFF and manually add that5014* to the received properties.5015*/5016if (stream_wantsnewfs && !raw && rcvprops != NULL &&5017!nvlist_exists(cmdprops, zfs_prop_to_name(ZFS_PROP_ENCRYPTION))) {5018if (oxprops == NULL)5019oxprops = fnvlist_alloc();5020fnvlist_add_uint64(oxprops,5021zfs_prop_to_name(ZFS_PROP_ENCRYPTION), ZIO_CRYPT_OFF);5022}50235024if (flags->dryrun) {5025void *buf = zfs_alloc(hdl, SPA_MAXBLOCKSIZE);50265027/*5028* We have read the DRR_BEGIN record, but we have5029* not yet read the payload. For non-dryrun sends5030* this will be done by the kernel, so we must5031* emulate that here, before attempting to read5032* more records.5033*/5034err = recv_read(hdl, infd, buf, drr->drr_payloadlen,5035flags->byteswap, NULL);5036free(buf);5037if (err != 0)5038goto out;50395040err = recv_skip(hdl, infd, flags->byteswap);5041goto out;5042}50435044if (flags->heal) {5045err = ioctl_err = lzc_receive_with_heal(destsnap, rcvprops,5046oxprops, wkeydata, wkeylen, origin, flags->force,5047flags->heal, flags->resumable, raw, infd, drr_noswap, -1,5048&read_bytes, &errflags, NULL, &prop_errors);5049} else {5050err = ioctl_err = lzc_receive_with_cmdprops(destsnap, rcvprops,5051oxprops, wkeydata, wkeylen, origin, flags->force,5052flags->resumable, raw, infd, drr_noswap, -1, &read_bytes,5053&errflags, NULL, &prop_errors);5054}5055ioctl_errno = ioctl_err;5056prop_errflags = errflags;50575058if (err == 0) {5059nvpair_t *prop_err = NULL;50605061while ((prop_err = nvlist_next_nvpair(prop_errors,5062prop_err)) != NULL) {5063char tbuf[1024];5064zfs_prop_t prop;5065int intval;50665067prop = zfs_name_to_prop(nvpair_name(prop_err));5068(void) nvpair_value_int32(prop_err, &intval);5069if (strcmp(nvpair_name(prop_err),5070ZPROP_N_MORE_ERRORS) == 0) {5071trunc_prop_errs(intval);5072break;5073} else if (snapname == NULL || finalsnap == NULL ||5074strcmp(finalsnap, snapname) == 0 ||5075strcmp(nvpair_name(prop_err),5076zfs_prop_to_name(ZFS_PROP_REFQUOTA)) != 0) {5077/*5078* Skip the special case of, for example,5079* "refquota", errors on intermediate5080* snapshots leading up to a final one.5081* That's why we have all of the checks above.5082*5083* See zfs_ioctl.c's extract_delay_props() for5084* a list of props which can fail on5085* intermediate snapshots, but shouldn't5086* affect the overall receive.5087*/5088(void) snprintf(tbuf, sizeof (tbuf),5089dgettext(TEXT_DOMAIN,5090"cannot receive %s property on %s"),5091nvpair_name(prop_err), name);5092zfs_setprop_error(hdl, prop, intval, tbuf);5093}5094}5095}50965097if (err == 0 && snapprops_nvlist) {5098zfs_cmd_t zc = {"\0"};50995100(void) strlcpy(zc.zc_name, destsnap, sizeof (zc.zc_name));5101zc.zc_cookie = B_TRUE; /* received */5102zcmd_write_src_nvlist(hdl, &zc, snapprops_nvlist);5103(void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);5104zcmd_free_nvlists(&zc);5105}5106if (err == 0 && snapholds_nvlist) {5107nvpair_t *pair;5108nvlist_t *holds, *errors = NULL;5109int cleanup_fd = -1;51105111VERIFY0(nvlist_alloc(&holds, 0, KM_SLEEP));5112for (pair = nvlist_next_nvpair(snapholds_nvlist, NULL);5113pair != NULL;5114pair = nvlist_next_nvpair(snapholds_nvlist, pair)) {5115fnvlist_add_string(holds, destsnap, nvpair_name(pair));5116}5117(void) lzc_hold(holds, cleanup_fd, &errors);5118fnvlist_free(snapholds_nvlist);5119fnvlist_free(holds);5120}51215122if (err && (ioctl_errno == ENOENT || ioctl_errno == EEXIST)) {5123/*5124* It may be that this snapshot already exists,5125* in which case we want to consume & ignore it5126* rather than failing.5127*/5128avl_tree_t *local_avl;5129nvlist_t *local_nv, *fs;5130cp = strchr(destsnap, '@');51315132/*5133* XXX Do this faster by just iterating over snaps in5134* this fs. Also if zc_value does not exist, we will5135* get a strange "does not exist" error message.5136*/5137*cp = '\0';5138if (gather_nvlist(hdl, destsnap, NULL, NULL, B_FALSE, B_TRUE,5139B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE,5140B_TRUE, &local_nv, &local_avl) == 0) {5141*cp = '@';5142fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);5143fsavl_destroy(local_avl);5144fnvlist_free(local_nv);51455146if (fs != NULL) {5147if (flags->verbose) {5148(void) printf("snap %s already exists; "5149"ignoring\n", destsnap);5150}5151err = ioctl_err = recv_skip(hdl, infd,5152flags->byteswap);5153}5154}5155*cp = '@';5156}51575158if (ioctl_err != 0) {5159switch (ioctl_errno) {5160case ENODEV:5161cp = strchr(destsnap, '@');5162*cp = '\0';5163zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5164"most recent snapshot of %s does not\n"5165"match incremental source"), destsnap);5166(void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);5167*cp = '@';5168break;5169case ETXTBSY:5170zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5171"destination %s has been modified\n"5172"since most recent snapshot"), name);5173(void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);5174break;5175case EACCES:5176if (flags->heal) {5177zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5178"key must be loaded to do a non-raw "5179"corrective recv on an encrypted "5180"dataset."));5181} else if (raw && stream_wantsnewfs) {5182zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5183"failed to create encryption key"));5184} else if (raw && !stream_wantsnewfs) {5185zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5186"encryption key does not match "5187"existing key"));5188} else {5189zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5190"inherited key must be loaded"));5191}5192(void) zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf);5193break;5194case EEXIST:5195cp = strchr(destsnap, '@');5196if (newfs) {5197/* it's the containing fs that exists */5198*cp = '\0';5199}5200zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5201"destination already exists"));5202(void) zfs_error_fmt(hdl, EZFS_EXISTS,5203dgettext(TEXT_DOMAIN, "cannot restore to %s"),5204destsnap);5205*cp = '@';5206break;5207case EINVAL:5208if (embedded && !raw) {5209zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5210"incompatible embedded data stream "5211"feature with encrypted receive."));5212} else if (flags->resumable) {5213zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5214"kernel modules must be upgraded to "5215"receive this stream."));5216}5217(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5218break;5219case ECKSUM:5220case ZFS_ERR_STREAM_TRUNCATED:5221if (flags->heal)5222zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5223"corrective receive was not able to "5224"reconstruct the data needed for "5225"healing."));5226else5227recv_ecksum_set_aux(hdl, destsnap,5228flags->resumable, ioctl_err == ECKSUM);5229(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5230break;5231case ZFS_ERR_STREAM_LARGE_BLOCK_MISMATCH:5232zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5233"incremental send stream requires -L "5234"(--large-block), to match previous receive."));5235(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5236break;5237case ENOTSUP:5238if (flags->heal)5239zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5240"stream is not compatible with the "5241"data in the pool."));5242else5243zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5244"pool must be upgraded to receive this "5245"stream."));5246(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);5247break;5248case ZFS_ERR_CRYPTO_NOTSUP:5249zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5250"stream uses crypto parameters not compatible with "5251"this pool"));5252(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5253break;5254case EDQUOT:5255zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5256"destination %s space quota exceeded."), name);5257(void) zfs_error(hdl, EZFS_NOSPC, errbuf);5258break;5259case ZFS_ERR_FROM_IVSET_GUID_MISSING:5260zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5261"IV set guid missing. See errata %u at "5262"https://openzfs.github.io/openzfs-docs/msg/"5263"ZFS-8000-ER."),5264ZPOOL_ERRATA_ZOL_8308_ENCRYPTION);5265(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5266break;5267case ZFS_ERR_FROM_IVSET_GUID_MISMATCH:5268zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5269"IV set guid mismatch. See the 'zfs receive' "5270"man page section\n discussing the limitations "5271"of raw encrypted send streams."));5272(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5273break;5274case ZFS_ERR_SPILL_BLOCK_FLAG_MISSING:5275zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5276"Spill block flag missing for raw send.\n"5277"The zfs software on the sending system must "5278"be updated."));5279(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5280break;5281case ZFS_ERR_RESUME_EXISTS:5282cp = strchr(destsnap, '@');5283if (newfs) {5284/* it's the containing fs that exists */5285*cp = '\0';5286}5287zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5288"Resuming recv on existing dataset without force"));5289(void) zfs_error_fmt(hdl, EZFS_RESUME_EXISTS,5290dgettext(TEXT_DOMAIN, "cannot resume recv %s"),5291destsnap);5292*cp = '@';5293break;5294case E2BIG:5295zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5296"zfs receive required kernel memory allocation "5297"larger than the system can support. Please file "5298"an issue at the OpenZFS issue tracker:\n"5299"https://github.com/openzfs/zfs/issues/new"));5300(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5301break;5302case EBUSY:5303if (hastoken) {5304zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5305"destination %s contains "5306"partially-complete state from "5307"\"zfs receive -s\"."), name);5308(void) zfs_error(hdl, EZFS_BUSY, errbuf);5309break;5310}5311zfs_fallthrough;5312default:5313(void) zfs_standard_error(hdl, ioctl_errno, errbuf);5314}5315}53165317/*5318* Mount the target filesystem (if created). Also mount any5319* children of the target filesystem if we did a replication5320* receive (indicated by stream_avl being non-NULL).5321*/5322if (clp) {5323if (!flags->nomount)5324err |= changelist_postfix(clp);5325changelist_free(clp);5326}53275328if ((newfs || stream_avl) && type == ZFS_TYPE_FILESYSTEM && !redacted)5329flags->domount = B_TRUE;53305331if (prop_errflags & ZPROP_ERR_NOCLEAR) {5332(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "5333"failed to clear unreceived properties on %s"), name);5334(void) fprintf(stderr, "\n");5335}5336if (prop_errflags & ZPROP_ERR_NORESTORE) {5337(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "5338"failed to restore original properties on %s"), name);5339(void) fprintf(stderr, "\n");5340}53415342if (err || ioctl_err) {5343err = -1;5344goto out;5345}53465347if (flags->verbose) {5348char buf1[64];5349char buf2[64];5350uint64_t bytes = read_bytes;5351struct timespec delta;5352clock_gettime(CLOCK_MONOTONIC_RAW, &delta);5353if (begin_time.tv_nsec > delta.tv_nsec) {5354delta.tv_nsec =53551000000000 + delta.tv_nsec - begin_time.tv_nsec;5356delta.tv_sec -= 1;5357} else5358delta.tv_nsec -= begin_time.tv_nsec;5359delta.tv_sec -= begin_time.tv_sec;5360if (delta.tv_sec == 0 && delta.tv_nsec == 0)5361delta.tv_nsec = 1;5362double delta_f = delta.tv_sec + (delta.tv_nsec / 1e9);5363zfs_nicebytes(bytes, buf1, sizeof (buf1));5364zfs_nicebytes(bytes / delta_f, buf2, sizeof (buf2));53655366(void) printf("received %s stream in %.2f seconds (%s/sec)\n",5367buf1, delta_f, buf2);5368}53695370err = 0;5371out:5372if (prop_errors != NULL)5373fnvlist_free(prop_errors);53745375if (tmp_keylocation[0] != '\0') {5376fnvlist_add_string(rcvprops,5377zfs_prop_to_name(ZFS_PROP_KEYLOCATION), tmp_keylocation);5378}53795380if (newprops)5381fnvlist_free(rcvprops);53825383fnvlist_free(oxprops);5384fnvlist_free(origprops);53855386return (err);5387}53885389/*5390* Check properties we were asked to override (both -o|-x)5391*/5392static boolean_t5393zfs_receive_checkprops(libzfs_handle_t *hdl, nvlist_t *props,5394const char *errbuf)5395{5396nvpair_t *nvp = NULL;5397zfs_prop_t prop;5398const char *name;53995400while ((nvp = nvlist_next_nvpair(props, nvp)) != NULL) {5401name = nvpair_name(nvp);5402prop = zfs_name_to_prop(name);54035404if (prop == ZPROP_USERPROP) {5405if (!zfs_prop_user(name)) {5406zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5407"%s: invalid property '%s'"), errbuf, name);5408return (B_FALSE);5409}5410continue;5411}5412/*5413* "origin" is readonly but is used to receive datasets as5414* clones so we don't raise an error here5415*/5416if (prop == ZFS_PROP_ORIGIN)5417continue;54185419/* encryption params have their own verification later */5420if (prop == ZFS_PROP_ENCRYPTION ||5421zfs_prop_encryption_key_param(prop))5422continue;54235424/*5425* cannot override readonly, set-once and other specific5426* settable properties5427*/5428if (zfs_prop_readonly(prop) || prop == ZFS_PROP_VERSION ||5429prop == ZFS_PROP_VOLSIZE) {5430zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5431"%s: invalid property '%s'"), errbuf, name);5432return (B_FALSE);5433}5434}54355436return (B_TRUE);5437}54385439static int5440zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,5441const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,5442nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs,5443const char *finalsnap, nvlist_t *cmdprops)5444{5445int err;5446dmu_replay_record_t drr, drr_noswap;5447struct drr_begin *drrb = &drr.drr_u.drr_begin;5448char errbuf[ERRBUFLEN];5449zio_cksum_t zcksum = { { 0 } };5450uint64_t featureflags;5451int hdrtype;54525453(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,5454"cannot receive"));54555456/* check cmdline props, raise an error if they cannot be received */5457if (!zfs_receive_checkprops(hdl, cmdprops, errbuf))5458return (zfs_error(hdl, EZFS_BADPROP, errbuf));54595460if (flags->isprefix &&5461!zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {5462zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "5463"(%s) does not exist"), tosnap);5464return (zfs_error(hdl, EZFS_NOENT, errbuf));5465}5466if (originsnap &&5467!zfs_dataset_exists(hdl, originsnap, ZFS_TYPE_DATASET)) {5468zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified origin fs "5469"(%s) does not exist"), originsnap);5470return (zfs_error(hdl, EZFS_NOENT, errbuf));5471}54725473/* read in the BEGIN record */5474if (0 != (err = recv_read(hdl, infd, &drr, sizeof (drr), B_FALSE,5475&zcksum)))5476return (err);54775478if (drr.drr_type == DRR_END || drr.drr_type == BSWAP_32(DRR_END)) {5479/* It's the double end record at the end of a package */5480return (ENODATA);5481}54825483/* the kernel needs the non-byteswapped begin record */5484drr_noswap = drr;54855486flags->byteswap = B_FALSE;5487if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {5488/*5489* We computed the checksum in the wrong byteorder in5490* recv_read() above; do it again correctly.5491*/5492memset(&zcksum, 0, sizeof (zio_cksum_t));5493fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum);5494flags->byteswap = B_TRUE;54955496drr.drr_type = BSWAP_32(drr.drr_type);5497drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen);5498drrb->drr_magic = BSWAP_64(drrb->drr_magic);5499drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo);5500drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);5501drrb->drr_type = BSWAP_32(drrb->drr_type);5502drrb->drr_flags = BSWAP_32(drrb->drr_flags);5503drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);5504drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);5505}55065507if (drrb->drr_magic != DMU_BACKUP_MAGIC || drr.drr_type != DRR_BEGIN) {5508zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "5509"stream (bad magic number)"));5510return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));5511}55125513featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);5514hdrtype = DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo);55155516if (!DMU_STREAM_SUPPORTED(featureflags) ||5517(hdrtype != DMU_SUBSTREAM && hdrtype != DMU_COMPOUNDSTREAM)) {5518/*5519* Let's be explicit about this one, since rather than5520* being a new feature we can't know, it's an old5521* feature we dropped.5522*/5523if (featureflags & DMU_BACKUP_FEATURE_DEDUP) {5524zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5525"stream has deprecated feature: dedup, try "5526"'zstream redup [send in a file] | zfs recv "5527"[...]'"));5528} else {5529zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5530"stream has unsupported feature, feature flags = "5531"%llx (unknown flags = %llx)"),5532(u_longlong_t)featureflags,5533(u_longlong_t)((featureflags) &5534~DMU_BACKUP_FEATURE_MASK));5535}5536return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));5537}55385539/* Holds feature is set once in the compound stream header. */5540if (featureflags & DMU_BACKUP_FEATURE_HOLDS)5541flags->holds = B_TRUE;55425543if (strchr(drrb->drr_toname, '@') == NULL) {5544zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "5545"stream (bad snapshot name)"));5546return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));5547}55485549if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {5550char nonpackage_sendfs[ZFS_MAX_DATASET_NAME_LEN];5551if (sendfs == NULL) {5552/*5553* We were not called from zfs_receive_package(). Get5554* the fs specified by 'zfs send'.5555*/5556char *cp;5557(void) strlcpy(nonpackage_sendfs,5558drr.drr_u.drr_begin.drr_toname,5559sizeof (nonpackage_sendfs));5560if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)5561*cp = '\0';5562sendfs = nonpackage_sendfs;5563VERIFY0P(finalsnap);5564}5565return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,5566&drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,5567finalsnap, cmdprops));5568} else {5569assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==5570DMU_COMPOUNDSTREAM);5571return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,5572&zcksum, top_zfs, cmdprops));5573}5574}55755576/*5577* Restores a backup of tosnap from the file descriptor specified by infd.5578* Return 0 on total success, -2 if some things couldn't be5579* destroyed/renamed/promoted, -1 if some things couldn't be received.5580* (-1 will override -2, if -1 and the resumable flag was specified the5581* transfer can be resumed if the sending side supports it).5582*/5583int5584zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,5585recvflags_t *flags, int infd, avl_tree_t *stream_avl)5586{5587char *top_zfs = NULL;5588int err;5589struct stat sb;5590const char *originsnap = NULL;55915592/*5593* The only way fstat can fail is if we do not have a valid file5594* descriptor.5595*/5596if (fstat(infd, &sb) == -1) {5597perror("fstat");5598return (-2);5599}56005601if (props) {5602err = nvlist_lookup_string(props, "origin", &originsnap);5603if (err && err != ENOENT)5604return (err);5605}56065607err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,5608stream_avl, &top_zfs, NULL, props);56095610if (err == 0 && !flags->nomount && flags->domount && top_zfs) {5611zfs_handle_t *zhp = NULL;5612prop_changelist_t *clp = NULL;56135614zhp = zfs_open(hdl, top_zfs,5615ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);5616if (zhp == NULL) {5617err = -1;5618goto out;5619} else {5620if (zhp->zfs_type == ZFS_TYPE_VOLUME) {5621zfs_close(zhp);5622goto out;5623}56245625clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,5626CL_GATHER_MOUNT_ALWAYS,5627flags->forceunmount ? MS_FORCE : 0);5628zfs_close(zhp);5629if (clp == NULL) {5630err = -1;5631goto out;5632}56335634/* mount and share received datasets */5635err = changelist_postfix(clp);5636changelist_free(clp);5637if (err != 0)5638err = -1;5639}5640}56415642out:5643if (top_zfs)5644free(top_zfs);56455646return (err);5647}564856495650