Path: blob/main/sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c
48378 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;1015pthread_exit(((void *)(uintptr_t)err));1016}10171018(void) time(&t);1019localtime_r(&t, &tm);10201021if (pa->pa_astitle) {1022char buf_bytes[16];1023char buf_size[16];1024int pct;1025zfs_nicenum(bytes, buf_bytes, sizeof (buf_bytes));1026zfs_nicenum(pa->pa_size, buf_size, sizeof (buf_size));1027pct = (total > 0) ? bytes / total : 100;1028zfs_setproctitle("sending %s (%d%%: %s/%s)",1029zhp->zfs_name, MIN(pct, 100), buf_bytes, buf_size);1030}10311032if (pa->pa_verbosity >= 2 && pa->pa_parsable) {1033(void) fprintf(stderr,1034"%02d:%02d:%02d\t%llu\t%llu\t%s\n",1035tm.tm_hour, tm.tm_min, tm.tm_sec,1036(u_longlong_t)bytes, (u_longlong_t)blocks,1037zhp->zfs_name);1038} else if (pa->pa_verbosity >= 2) {1039zfs_nicenum(bytes, buf, sizeof (buf));1040(void) fprintf(stderr,1041"%02d:%02d:%02d %5s %8llu %s\n",1042tm.tm_hour, tm.tm_min, tm.tm_sec,1043buf, (u_longlong_t)blocks, zhp->zfs_name);1044} else if (pa->pa_parsable) {1045(void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n",1046tm.tm_hour, tm.tm_min, tm.tm_sec,1047(u_longlong_t)bytes, zhp->zfs_name);1048} else if (pa->pa_progress ||1049!send_progress_thread_signal_duetotimer) {1050zfs_nicebytes(bytes, buf, sizeof (buf));1051(void) fprintf(stderr, "%02d:%02d:%02d %5s %s\n",1052tm.tm_hour, tm.tm_min, tm.tm_sec,1053buf, zhp->zfs_name);1054}1055}1056pthread_cleanup_pop(B_TRUE);1057return (NULL);1058}10591060static boolean_t1061send_progress_thread_exit(1062libzfs_handle_t *hdl, pthread_t ptid, sigset_t *oldmask)1063{1064void *status = NULL;1065(void) pthread_cancel(ptid);1066(void) pthread_join(ptid, &status);1067pthread_sigmask(SIG_SETMASK, oldmask, NULL);1068int error = (int)(uintptr_t)status;1069if (error != 0 && status != PTHREAD_CANCELED)1070return (zfs_standard_error(hdl, error,1071dgettext(TEXT_DOMAIN, "progress thread exited nonzero")));1072else1073return (B_FALSE);1074}10751076static void1077send_print_verbose(FILE *fout, const char *tosnap, const char *fromsnap,1078uint64_t size, boolean_t parsable)1079{1080if (parsable) {1081if (fromsnap != NULL) {1082(void) fprintf(fout, dgettext(TEXT_DOMAIN,1083"incremental\t%s\t%s"), fromsnap, tosnap);1084} else {1085/*1086* Workaround for GCC 12+ with UBSan enabled deficencies.1087*1088* GCC 12+ invoked with -fsanitize=undefined incorrectly reports the code1089* below as violating -Wformat-overflow.1090*/1091#if defined(__GNUC__) && !defined(__clang__) && \1092defined(ZFS_UBSAN_ENABLED) && defined(HAVE_FORMAT_OVERFLOW)1093#pragma GCC diagnostic push1094#pragma GCC diagnostic ignored "-Wformat-overflow"1095#endif1096(void) fprintf(fout, dgettext(TEXT_DOMAIN,1097"full\t%s"), tosnap);1098#if defined(__GNUC__) && !defined(__clang__) && \1099defined(ZFS_UBSAN_ENABLED) && defined(HAVE_FORMAT_OVERFLOW)1100#pragma GCC diagnostic pop1101#endif1102}1103(void) fprintf(fout, "\t%llu", (longlong_t)size);1104} else {1105if (fromsnap != NULL) {1106if (strchr(fromsnap, '@') == NULL &&1107strchr(fromsnap, '#') == NULL) {1108(void) fprintf(fout, dgettext(TEXT_DOMAIN,1109"send from @%s to %s"), fromsnap, tosnap);1110} else {1111(void) fprintf(fout, dgettext(TEXT_DOMAIN,1112"send from %s to %s"), fromsnap, tosnap);1113}1114} else {1115(void) fprintf(fout, dgettext(TEXT_DOMAIN,1116"full send of %s"), tosnap);1117}1118if (size != 0) {1119char buf[16];1120zfs_nicebytes(size, buf, sizeof (buf));1121/*1122* Workaround for GCC 12+ with UBSan enabled deficencies.1123*1124* GCC 12+ invoked with -fsanitize=undefined incorrectly reports the code1125* below as violating -Wformat-overflow.1126*/1127#if defined(__GNUC__) && !defined(__clang__) && \1128defined(ZFS_UBSAN_ENABLED) && defined(HAVE_FORMAT_OVERFLOW)1129#pragma GCC diagnostic push1130#pragma GCC diagnostic ignored "-Wformat-overflow"1131#endif1132(void) fprintf(fout, dgettext(TEXT_DOMAIN,1133" estimated size is %s"), buf);1134#if defined(__GNUC__) && !defined(__clang__) && \1135defined(ZFS_UBSAN_ENABLED) && defined(HAVE_FORMAT_OVERFLOW)1136#pragma GCC diagnostic pop1137#endif1138}1139}1140(void) fprintf(fout, "\n");1141}11421143/*1144* Send a single filesystem snapshot, updating the send dump data.1145* This interface is intended for use as a zfs_iter_snapshots_v2_sorted visitor.1146*/1147static int1148dump_snapshot(zfs_handle_t *zhp, void *arg)1149{1150send_dump_data_t *sdd = arg;1151progress_arg_t pa = { 0 };1152pthread_t tid;1153char *thissnap;1154enum lzc_send_flags flags = 0;1155int err;1156boolean_t isfromsnap, istosnap, fromorigin;1157boolean_t exclude = B_FALSE;1158FILE *fout = sdd->std_out ? stdout : stderr;11591160err = 0;1161thissnap = strchr(zhp->zfs_name, '@') + 1;1162isfromsnap = (sdd->fromsnap != NULL &&1163strcmp(sdd->fromsnap, thissnap) == 0);11641165if (!sdd->seenfrom && isfromsnap) {1166gather_holds(zhp, sdd);1167sdd->seenfrom = B_TRUE;1168(void) strlcpy(sdd->prevsnap, thissnap, sizeof (sdd->prevsnap));1169sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);1170zfs_close(zhp);1171return (0);1172}11731174if (sdd->seento || !sdd->seenfrom) {1175zfs_close(zhp);1176return (0);1177}11781179istosnap = (strcmp(sdd->tosnap, thissnap) == 0);1180if (istosnap)1181sdd->seento = B_TRUE;11821183if (sdd->large_block)1184flags |= LZC_SEND_FLAG_LARGE_BLOCK;1185if (sdd->embed_data)1186flags |= LZC_SEND_FLAG_EMBED_DATA;1187if (sdd->compress)1188flags |= LZC_SEND_FLAG_COMPRESS;1189if (sdd->raw)1190flags |= LZC_SEND_FLAG_RAW;11911192if (!sdd->doall && !isfromsnap && !istosnap) {1193if (sdd->replicate) {1194const char *snapname;1195nvlist_t *snapprops;1196/*1197* Filter out all intermediate snapshots except origin1198* snapshots needed to replicate clones.1199*/1200nvlist_t *nvfs = fsavl_find(sdd->fsavl,1201zhp->zfs_dmustats.dds_guid, &snapname);12021203if (nvfs != NULL) {1204snapprops = fnvlist_lookup_nvlist(nvfs,1205"snapprops");1206snapprops = fnvlist_lookup_nvlist(snapprops,1207thissnap);1208exclude = !nvlist_exists(snapprops,1209"is_clone_origin");1210}1211} else {1212exclude = B_TRUE;1213}1214}12151216/*1217* If a filter function exists, call it to determine whether1218* this snapshot will be sent.1219*/1220if (exclude || (sdd->filter_cb != NULL &&1221sdd->filter_cb(zhp, sdd->filter_cb_arg) == B_FALSE)) {1222/*1223* This snapshot is filtered out. Don't send it, and don't1224* set prevsnap_obj, so it will be as if this snapshot didn't1225* exist, and the next accepted snapshot will be sent as1226* an incremental from the last accepted one, or as the1227* first (and full) snapshot in the case of a replication,1228* non-incremental send.1229*/1230zfs_close(zhp);1231return (0);1232}12331234gather_holds(zhp, sdd);1235fromorigin = sdd->prevsnap[0] == '\0' &&1236(sdd->fromorigin || sdd->replicate);12371238if (sdd->verbosity != 0) {1239uint64_t size = 0;1240char fromds[ZFS_MAX_DATASET_NAME_LEN];12411242if (sdd->prevsnap[0] != '\0') {1243(void) strlcpy(fromds, zhp->zfs_name, sizeof (fromds));1244*(strchr(fromds, '@') + 1) = '\0';1245(void) strlcat(fromds, sdd->prevsnap, sizeof (fromds));1246}1247if (zfs_send_space(zhp, zhp->zfs_name,1248sdd->prevsnap[0] ? fromds : NULL, flags, &size) == 0) {1249send_print_verbose(fout, zhp->zfs_name,1250sdd->prevsnap[0] ? sdd->prevsnap : NULL,1251size, sdd->parsable);1252sdd->size += size;1253}1254}12551256if (!sdd->dryrun) {1257/*1258* If progress reporting is requested, spawn a new thread to1259* poll ZFS_IOC_SEND_PROGRESS at a regular interval.1260*/1261sigset_t oldmask;1262{1263pa.pa_zhp = zhp;1264pa.pa_fd = sdd->outfd;1265pa.pa_parsable = sdd->parsable;1266pa.pa_estimate = B_FALSE;1267pa.pa_verbosity = sdd->verbosity;1268pa.pa_size = sdd->size;1269pa.pa_astitle = sdd->progressastitle;1270pa.pa_progress = sdd->progress;12711272if ((err = pthread_create(&tid, NULL,1273send_progress_thread, &pa)) != 0) {1274zfs_close(zhp);1275return (err);1276}1277SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);1278}12791280err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,1281fromorigin, sdd->outfd, flags, sdd->debugnv);12821283if (send_progress_thread_exit(zhp->zfs_hdl, tid, &oldmask))1284return (-1);1285}12861287(void) strlcpy(sdd->prevsnap, thissnap, sizeof (sdd->prevsnap));1288sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);1289zfs_close(zhp);1290return (err);1291}12921293/*1294* Send all snapshots for a filesystem, updating the send dump data.1295*/1296static int1297dump_filesystem(zfs_handle_t *zhp, send_dump_data_t *sdd)1298{1299int rv = 0;1300boolean_t missingfrom = B_FALSE;1301zfs_cmd_t zc = {"\0"};1302uint64_t min_txg = 0, max_txg = 0;13031304/*1305* Make sure the tosnap exists.1306*/1307(void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",1308zhp->zfs_name, sdd->tosnap);1309if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_STATS, &zc) != 0) {1310(void) fprintf(stderr, dgettext(TEXT_DOMAIN,1311"WARNING: could not send %s@%s: does not exist\n"),1312zhp->zfs_name, sdd->tosnap);1313sdd->err = B_TRUE;1314return (0);1315}13161317/*1318* If this fs does not have fromsnap, and we're doing1319* recursive, we need to send a full stream from the1320* beginning (or an incremental from the origin if this1321* is a clone). If we're doing non-recursive, then let1322* them get the error.1323*/1324if (sdd->replicate && sdd->fromsnap) {1325/*1326* Make sure the fromsnap exists.1327*/1328(void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",1329zhp->zfs_name, sdd->fromsnap);1330if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_STATS, &zc) != 0)1331missingfrom = B_TRUE;1332}13331334sdd->seenfrom = sdd->seento = B_FALSE;1335sdd->prevsnap[0] = '\0';1336sdd->prevsnap_obj = 0;1337if (sdd->fromsnap == NULL || missingfrom)1338sdd->seenfrom = B_TRUE;13391340/*1341* Iterate through all snapshots and process the ones we will be1342* sending. If we only have a "from" and "to" snapshot to deal1343* with, we can avoid iterating through all the other snapshots.1344*/1345if (sdd->doall || sdd->replicate || sdd->tosnap == NULL) {1346if (!sdd->replicate) {1347if (sdd->fromsnap != NULL) {1348min_txg = get_snap_txg(zhp->zfs_hdl,1349zhp->zfs_name, sdd->fromsnap);1350}1351if (sdd->tosnap != NULL) {1352max_txg = get_snap_txg(zhp->zfs_hdl,1353zhp->zfs_name, sdd->tosnap);1354}1355}1356rv = zfs_iter_snapshots_sorted_v2(zhp, 0, dump_snapshot, sdd,1357min_txg, max_txg);1358} else {1359char snapname[MAXPATHLEN] = { 0 };1360zfs_handle_t *snap;13611362/* Dump fromsnap. */1363if (!sdd->seenfrom) {1364(void) snprintf(snapname, sizeof (snapname),1365"%s@%s", zhp->zfs_name, sdd->fromsnap);1366snap = zfs_open(zhp->zfs_hdl, snapname,1367ZFS_TYPE_SNAPSHOT);1368if (snap != NULL)1369rv = dump_snapshot(snap, sdd);1370else1371rv = errno;1372}13731374/* Dump tosnap. */1375if (rv == 0) {1376(void) snprintf(snapname, sizeof (snapname),1377"%s@%s", zhp->zfs_name, sdd->tosnap);1378snap = zfs_open(zhp->zfs_hdl, snapname,1379ZFS_TYPE_SNAPSHOT);1380if (snap != NULL)1381rv = dump_snapshot(snap, sdd);1382else1383rv = errno;1384}1385}13861387if (!sdd->seenfrom) {1388(void) fprintf(stderr, dgettext(TEXT_DOMAIN,1389"WARNING: could not send %s@%s:\n"1390"incremental source (%s@%s) does not exist\n"),1391zhp->zfs_name, sdd->tosnap,1392zhp->zfs_name, sdd->fromsnap);1393sdd->err = B_TRUE;1394} else if (!sdd->seento) {1395if (sdd->fromsnap) {1396(void) fprintf(stderr, dgettext(TEXT_DOMAIN,1397"WARNING: could not send %s@%s:\n"1398"incremental source (%s@%s) "1399"is not earlier than it\n"),1400zhp->zfs_name, sdd->tosnap,1401zhp->zfs_name, sdd->fromsnap);1402} else {1403(void) fprintf(stderr, dgettext(TEXT_DOMAIN,1404"WARNING: "1405"could not send %s@%s: does not exist\n"),1406zhp->zfs_name, sdd->tosnap);1407}1408sdd->err = B_TRUE;1409}14101411return (rv);1412}14131414/*1415* Send all snapshots for all filesystems in sdd.1416*/1417static int1418dump_filesystems(zfs_handle_t *rzhp, send_dump_data_t *sdd)1419{1420nvpair_t *fspair;1421boolean_t needagain, progress;14221423if (!sdd->replicate)1424return (dump_filesystem(rzhp, sdd));14251426/* Mark the clone origin snapshots. */1427for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;1428fspair = nvlist_next_nvpair(sdd->fss, fspair)) {1429nvlist_t *nvfs;1430uint64_t origin_guid = 0;14311432nvfs = fnvpair_value_nvlist(fspair);1433(void) nvlist_lookup_uint64(nvfs, "origin", &origin_guid);1434if (origin_guid != 0) {1435const char *snapname;1436nvlist_t *origin_nv = fsavl_find(sdd->fsavl,1437origin_guid, &snapname);1438if (origin_nv != NULL) {1439nvlist_t *snapprops;1440snapprops = fnvlist_lookup_nvlist(origin_nv,1441"snapprops");1442snapprops = fnvlist_lookup_nvlist(snapprops,1443snapname);1444fnvlist_add_boolean(snapprops,1445"is_clone_origin");1446}1447}1448}1449again:1450needagain = progress = B_FALSE;1451for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;1452fspair = nvlist_next_nvpair(sdd->fss, fspair)) {1453nvlist_t *fslist, *parent_nv;1454const char *fsname;1455zfs_handle_t *zhp;1456int err;1457uint64_t origin_guid = 0;1458uint64_t parent_guid = 0;14591460fslist = fnvpair_value_nvlist(fspair);1461if (nvlist_lookup_boolean(fslist, "sent") == 0)1462continue;14631464fsname = fnvlist_lookup_string(fslist, "name");1465(void) nvlist_lookup_uint64(fslist, "origin", &origin_guid);1466(void) nvlist_lookup_uint64(fslist, "parentfromsnap",1467&parent_guid);14681469if (parent_guid != 0) {1470parent_nv = fsavl_find(sdd->fsavl, parent_guid, NULL);1471if (!nvlist_exists(parent_nv, "sent")) {1472/* Parent has not been sent; skip this one. */1473needagain = B_TRUE;1474continue;1475}1476}14771478if (origin_guid != 0) {1479nvlist_t *origin_nv = fsavl_find(sdd->fsavl,1480origin_guid, NULL);1481if (origin_nv != NULL &&1482!nvlist_exists(origin_nv, "sent")) {1483/*1484* Origin has not been sent yet;1485* skip this clone.1486*/1487needagain = B_TRUE;1488continue;1489}1490}14911492zhp = zfs_open(rzhp->zfs_hdl, fsname, ZFS_TYPE_DATASET);1493if (zhp == NULL)1494return (-1);1495err = dump_filesystem(zhp, sdd);1496fnvlist_add_boolean(fslist, "sent");1497progress = B_TRUE;1498zfs_close(zhp);1499if (err)1500return (err);1501}1502if (needagain) {1503assert(progress);1504goto again;1505}15061507/* Clean out the sent flags in case we reuse this fss. */1508for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;1509fspair = nvlist_next_nvpair(sdd->fss, fspair)) {1510nvlist_t *fslist;15111512fslist = fnvpair_value_nvlist(fspair);1513(void) nvlist_remove_all(fslist, "sent");1514}15151516return (0);1517}15181519nvlist_t *1520zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)1521{1522unsigned int version;1523int nread, i;1524unsigned long long checksum, packed_len;15251526/*1527* Decode token header, which is:1528* <token version>-<checksum of payload>-<uncompressed payload length>1529* Note that the only supported token version is 1.1530*/1531nread = sscanf(token, "%u-%llx-%llx-",1532&version, &checksum, &packed_len);1533if (nread != 3) {1534zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1535"resume token is corrupt (invalid format)"));1536return (NULL);1537}15381539if (version != ZFS_SEND_RESUME_TOKEN_VERSION) {1540zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1541"resume token is corrupt (invalid version %u)"),1542version);1543return (NULL);1544}15451546/* Convert hexadecimal representation to binary. */1547token = strrchr(token, '-') + 1;1548int len = strlen(token) / 2;1549unsigned char *compressed = zfs_alloc(hdl, len);1550for (i = 0; i < len; i++) {1551nread = sscanf(token + i * 2, "%2hhx", compressed + i);1552if (nread != 1) {1553free(compressed);1554zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1555"resume token is corrupt "1556"(payload is not hex-encoded)"));1557return (NULL);1558}1559}15601561/* Verify checksum. */1562zio_cksum_t cksum;1563fletcher_4_native_varsize(compressed, len, &cksum);1564if (cksum.zc_word[0] != checksum) {1565free(compressed);1566zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1567"resume token is corrupt (incorrect checksum)"));1568return (NULL);1569}15701571/* Uncompress. */1572void *packed = zfs_alloc(hdl, packed_len);1573uLongf packed_len_long = packed_len;1574if (uncompress(packed, &packed_len_long, compressed, len) != Z_OK ||1575packed_len_long != packed_len) {1576free(packed);1577free(compressed);1578zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1579"resume token is corrupt (decompression failed)"));1580return (NULL);1581}15821583/* Unpack nvlist. */1584nvlist_t *nv;1585int error = nvlist_unpack(packed, packed_len, &nv, KM_SLEEP);1586free(packed);1587free(compressed);1588if (error != 0) {1589zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1590"resume token is corrupt (nvlist_unpack failed)"));1591return (NULL);1592}1593return (nv);1594}15951596static enum lzc_send_flags1597lzc_flags_from_sendflags(const sendflags_t *flags)1598{1599enum lzc_send_flags lzc_flags = 0;16001601if (flags->largeblock)1602lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;1603if (flags->embed_data)1604lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;1605if (flags->compress)1606lzc_flags |= LZC_SEND_FLAG_COMPRESS;1607if (flags->raw)1608lzc_flags |= LZC_SEND_FLAG_RAW;1609if (flags->saved)1610lzc_flags |= LZC_SEND_FLAG_SAVED;16111612return (lzc_flags);1613}16141615static int1616estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,1617uint64_t resumeobj, uint64_t resumeoff, uint64_t bytes,1618const char *redactbook, char *errbuf, uint64_t *sizep)1619{1620uint64_t size;1621FILE *fout = flags->dryrun ? stdout : stderr;1622progress_arg_t pa = { 0 };1623int err = 0;1624pthread_t ptid;1625sigset_t oldmask;16261627{1628pa.pa_zhp = zhp;1629pa.pa_fd = fd;1630pa.pa_parsable = flags->parsable;1631pa.pa_estimate = B_TRUE;1632pa.pa_verbosity = flags->verbosity;16331634err = pthread_create(&ptid, NULL,1635send_progress_thread, &pa);1636if (err != 0) {1637zfs_error_aux(zhp->zfs_hdl, "%s", zfs_strerror(errno));1638return (zfs_error(zhp->zfs_hdl,1639EZFS_THREADCREATEFAILED, errbuf));1640}1641SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);1642}16431644err = lzc_send_space_resume_redacted(zhp->zfs_name, from,1645lzc_flags_from_sendflags(flags), resumeobj, resumeoff, bytes,1646redactbook, fd, &size);1647*sizep = size;16481649if (send_progress_thread_exit(zhp->zfs_hdl, ptid, &oldmask))1650return (-1);16511652if (!flags->progress && !flags->parsable)1653return (err);16541655if (err != 0) {1656zfs_error_aux(zhp->zfs_hdl, "%s", zfs_strerror(err));1657return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,1658errbuf));1659}1660send_print_verbose(fout, zhp->zfs_name, from, size,1661flags->parsable);16621663if (flags->parsable) {1664(void) fprintf(fout, "size\t%llu\n", (longlong_t)size);1665} else {1666char buf[16];1667zfs_nicenum(size, buf, sizeof (buf));1668(void) fprintf(fout, dgettext(TEXT_DOMAIN,1669"total estimated size is %s\n"), buf);1670}1671return (0);1672}16731674static boolean_t1675redact_snaps_contains(const uint64_t *snaps, uint64_t num_snaps, uint64_t guid)1676{1677for (int i = 0; i < num_snaps; i++) {1678if (snaps[i] == guid)1679return (B_TRUE);1680}1681return (B_FALSE);1682}16831684static boolean_t1685redact_snaps_equal(const uint64_t *snaps1, uint64_t num_snaps1,1686const uint64_t *snaps2, uint64_t num_snaps2)1687{1688if (num_snaps1 != num_snaps2)1689return (B_FALSE);1690for (int i = 0; i < num_snaps1; i++) {1691if (!redact_snaps_contains(snaps2, num_snaps2, snaps1[i]))1692return (B_FALSE);1693}1694return (B_TRUE);1695}16961697static int1698get_bookmarks(const char *path, nvlist_t **bmarksp)1699{1700nvlist_t *props = fnvlist_alloc();1701int error;17021703fnvlist_add_boolean(props, "redact_complete");1704fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS));1705error = lzc_get_bookmarks(path, props, bmarksp);1706fnvlist_free(props);1707return (error);1708}17091710static nvpair_t *1711find_redact_pair(nvlist_t *bmarks, const uint64_t *redact_snap_guids,1712int num_redact_snaps)1713{1714nvpair_t *pair;17151716for (pair = nvlist_next_nvpair(bmarks, NULL); pair;1717pair = nvlist_next_nvpair(bmarks, pair)) {17181719nvlist_t *bmark = fnvpair_value_nvlist(pair);1720nvlist_t *vallist = fnvlist_lookup_nvlist(bmark,1721zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS));1722uint_t len = 0;1723uint64_t *bmarksnaps = fnvlist_lookup_uint64_array(vallist,1724ZPROP_VALUE, &len);1725if (redact_snaps_equal(redact_snap_guids,1726num_redact_snaps, bmarksnaps, len)) {1727break;1728}1729}1730return (pair);1731}17321733static boolean_t1734get_redact_complete(nvpair_t *pair)1735{1736nvlist_t *bmark = fnvpair_value_nvlist(pair);1737nvlist_t *vallist = fnvlist_lookup_nvlist(bmark, "redact_complete");1738boolean_t complete = fnvlist_lookup_boolean_value(vallist,1739ZPROP_VALUE);17401741return (complete);1742}17431744/*1745* Check that the list of redaction snapshots in the bookmark matches the send1746* we're resuming, and return whether or not it's complete.1747*1748* Note that the caller needs to free the contents of *bookname with free() if1749* this function returns successfully.1750*/1751static int1752find_redact_book(libzfs_handle_t *hdl, const char *path,1753const uint64_t *redact_snap_guids, int num_redact_snaps,1754char **bookname)1755{1756char errbuf[ERRBUFLEN];1757nvlist_t *bmarks;17581759(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,1760"cannot resume send"));17611762int error = get_bookmarks(path, &bmarks);1763if (error != 0) {1764if (error == ESRCH) {1765zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1766"nonexistent redaction bookmark provided"));1767} else if (error == ENOENT) {1768zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1769"dataset to be sent no longer exists"));1770} else {1771zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1772"unknown error: %s"), zfs_strerror(error));1773}1774return (zfs_error(hdl, EZFS_BADPROP, errbuf));1775}1776nvpair_t *pair = find_redact_pair(bmarks, redact_snap_guids,1777num_redact_snaps);1778if (pair == NULL) {1779fnvlist_free(bmarks);1780zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1781"no appropriate redaction bookmark exists"));1782return (zfs_error(hdl, EZFS_BADPROP, errbuf));1783}1784boolean_t complete = get_redact_complete(pair);1785if (!complete) {1786fnvlist_free(bmarks);1787zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1788"incomplete redaction bookmark provided"));1789return (zfs_error(hdl, EZFS_BADPROP, errbuf));1790}1791*bookname = strndup(nvpair_name(pair), ZFS_MAX_DATASET_NAME_LEN);1792ASSERT3P(*bookname, !=, NULL);1793fnvlist_free(bmarks);1794return (0);1795}17961797static enum lzc_send_flags1798lzc_flags_from_resume_nvl(nvlist_t *resume_nvl)1799{1800enum lzc_send_flags lzc_flags = 0;18011802if (nvlist_exists(resume_nvl, "largeblockok"))1803lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;1804if (nvlist_exists(resume_nvl, "embedok"))1805lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;1806if (nvlist_exists(resume_nvl, "compressok"))1807lzc_flags |= LZC_SEND_FLAG_COMPRESS;1808if (nvlist_exists(resume_nvl, "rawok"))1809lzc_flags |= LZC_SEND_FLAG_RAW;1810if (nvlist_exists(resume_nvl, "savedok"))1811lzc_flags |= LZC_SEND_FLAG_SAVED;18121813return (lzc_flags);1814}18151816static int1817zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,1818int outfd, nvlist_t *resume_nvl)1819{1820char errbuf[ERRBUFLEN];1821const char *toname;1822const char *fromname = NULL;1823uint64_t resumeobj, resumeoff, toguid, fromguid, bytes;1824zfs_handle_t *zhp;1825int error = 0;1826char name[ZFS_MAX_DATASET_NAME_LEN];1827FILE *fout = (flags->verbosity > 0 && flags->dryrun) ? stdout : stderr;1828uint64_t *redact_snap_guids = NULL;1829int num_redact_snaps = 0;1830char *redact_book = NULL;1831uint64_t size = 0;18321833(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,1834"cannot resume send"));18351836if (flags->verbosity != 0) {1837(void) fprintf(fout, dgettext(TEXT_DOMAIN,1838"resume token contents:\n"));1839nvlist_print(fout, resume_nvl);1840}18411842if (nvlist_lookup_string(resume_nvl, "toname", &toname) != 0 ||1843nvlist_lookup_uint64(resume_nvl, "object", &resumeobj) != 0 ||1844nvlist_lookup_uint64(resume_nvl, "offset", &resumeoff) != 0 ||1845nvlist_lookup_uint64(resume_nvl, "bytes", &bytes) != 0 ||1846nvlist_lookup_uint64(resume_nvl, "toguid", &toguid) != 0) {1847zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1848"resume token is corrupt"));1849return (zfs_error(hdl, EZFS_FAULT, errbuf));1850}1851fromguid = 0;1852(void) nvlist_lookup_uint64(resume_nvl, "fromguid", &fromguid);18531854if (flags->saved) {1855(void) strlcpy(name, toname, sizeof (name));1856} else {1857error = guid_to_name(hdl, toname, toguid, B_FALSE, name);1858if (error != 0) {1859if (zfs_dataset_exists(hdl, toname, ZFS_TYPE_DATASET)) {1860zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1861"'%s' is no longer the same snapshot "1862"used in the initial send"), toname);1863} else {1864zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1865"'%s' used in the initial send no "1866"longer exists"), toname);1867}1868return (zfs_error(hdl, EZFS_BADPATH, errbuf));1869}1870}18711872zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);1873if (zhp == NULL) {1874zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1875"unable to access '%s'"), name);1876return (zfs_error(hdl, EZFS_BADPATH, errbuf));1877}18781879if (nvlist_lookup_uint64_array(resume_nvl, "book_redact_snaps",1880&redact_snap_guids, (uint_t *)&num_redact_snaps) != 0) {1881num_redact_snaps = -1;1882}18831884if (fromguid != 0) {1885if (guid_to_name_redact_snaps(hdl, toname, fromguid, B_TRUE,1886redact_snap_guids, num_redact_snaps, name) != 0) {1887zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1888"incremental source %#llx no longer exists"),1889(longlong_t)fromguid);1890return (zfs_error(hdl, EZFS_BADPATH, errbuf));1891}1892fromname = name;1893}18941895redact_snap_guids = NULL;18961897if (nvlist_lookup_uint64_array(resume_nvl,1898zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS), &redact_snap_guids,1899(uint_t *)&num_redact_snaps) == 0) {1900char path[ZFS_MAX_DATASET_NAME_LEN];19011902(void) strlcpy(path, toname, sizeof (path));1903char *at = strchr(path, '@');1904ASSERT3P(at, !=, NULL);19051906*at = '\0';19071908if ((error = find_redact_book(hdl, path, redact_snap_guids,1909num_redact_snaps, &redact_book)) != 0) {1910return (error);1911}1912}19131914enum lzc_send_flags lzc_flags = lzc_flags_from_sendflags(flags) |1915lzc_flags_from_resume_nvl(resume_nvl);19161917if (flags->verbosity != 0 || flags->progressastitle) {1918/*1919* Some of these may have come from the resume token, set them1920* here for size estimate purposes.1921*/1922sendflags_t tmpflags = *flags;1923if (lzc_flags & LZC_SEND_FLAG_LARGE_BLOCK)1924tmpflags.largeblock = B_TRUE;1925if (lzc_flags & LZC_SEND_FLAG_COMPRESS)1926tmpflags.compress = B_TRUE;1927if (lzc_flags & LZC_SEND_FLAG_EMBED_DATA)1928tmpflags.embed_data = B_TRUE;1929if (lzc_flags & LZC_SEND_FLAG_RAW)1930tmpflags.raw = B_TRUE;1931if (lzc_flags & LZC_SEND_FLAG_SAVED)1932tmpflags.saved = B_TRUE;1933error = estimate_size(zhp, fromname, outfd, &tmpflags,1934resumeobj, resumeoff, bytes, redact_book, errbuf, &size);1935}19361937if (!flags->dryrun) {1938progress_arg_t pa = { 0 };1939pthread_t tid;1940sigset_t oldmask;1941/*1942* If progress reporting is requested, spawn a new thread to1943* poll ZFS_IOC_SEND_PROGRESS at a regular interval.1944*/1945{1946pa.pa_zhp = zhp;1947pa.pa_fd = outfd;1948pa.pa_parsable = flags->parsable;1949pa.pa_estimate = B_FALSE;1950pa.pa_verbosity = flags->verbosity;1951pa.pa_size = size;1952pa.pa_astitle = flags->progressastitle;1953pa.pa_progress = flags->progress;19541955error = pthread_create(&tid, NULL,1956send_progress_thread, &pa);1957if (error != 0) {1958if (redact_book != NULL)1959free(redact_book);1960zfs_close(zhp);1961return (error);1962}1963SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);1964}19651966error = lzc_send_resume_redacted(zhp->zfs_name, fromname, outfd,1967lzc_flags, resumeobj, resumeoff, redact_book);1968if (redact_book != NULL)1969free(redact_book);19701971if (send_progress_thread_exit(hdl, tid, &oldmask)) {1972zfs_close(zhp);1973return (-1);1974}19751976char errbuf[ERRBUFLEN];1977(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,1978"warning: cannot send '%s'"), zhp->zfs_name);19791980zfs_close(zhp);19811982switch (error) {1983case 0:1984return (0);1985case EACCES:1986zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1987"source key must be loaded"));1988return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));1989case ESRCH:1990if (lzc_exists(zhp->zfs_name)) {1991zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1992"incremental source could not be found"));1993}1994return (zfs_error(hdl, EZFS_NOENT, errbuf));19951996case EXDEV:1997case ENOENT:1998case EDQUOT:1999case EFBIG:2000case EIO:2001case ENOLINK:2002case ENOSPC:2003case ENOSTR:2004case ENXIO:2005case EPIPE:2006case ERANGE:2007case EFAULT:2008case EROFS:2009zfs_error_aux(hdl, "%s", zfs_strerror(errno));2010return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));20112012default:2013return (zfs_standard_error(hdl, errno, errbuf));2014}2015} else {2016if (redact_book != NULL)2017free(redact_book);2018}20192020zfs_close(zhp);20212022return (error);2023}20242025struct zfs_send_resume_impl {2026libzfs_handle_t *hdl;2027sendflags_t *flags;2028nvlist_t *resume_nvl;2029};20302031static int2032zfs_send_resume_impl_cb(int outfd, void *arg)2033{2034struct zfs_send_resume_impl *zsri = arg;2035return (zfs_send_resume_impl_cb_impl(zsri->hdl, zsri->flags, outfd,2036zsri->resume_nvl));2037}20382039static int2040zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,2041nvlist_t *resume_nvl)2042{2043struct zfs_send_resume_impl zsri = {2044.hdl = hdl,2045.flags = flags,2046.resume_nvl = resume_nvl,2047};2048return (lzc_send_wrapper(zfs_send_resume_impl_cb, outfd, &zsri));2049}20502051int2052zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,2053const char *resume_token)2054{2055int ret;2056char errbuf[ERRBUFLEN];2057nvlist_t *resume_nvl;20582059(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,2060"cannot resume send"));20612062resume_nvl = zfs_send_resume_token_to_nvlist(hdl, resume_token);2063if (resume_nvl == NULL) {2064/*2065* zfs_error_aux has already been set by2066* zfs_send_resume_token_to_nvlist()2067*/2068return (zfs_error(hdl, EZFS_FAULT, errbuf));2069}20702071ret = zfs_send_resume_impl(hdl, flags, outfd, resume_nvl);2072fnvlist_free(resume_nvl);20732074return (ret);2075}20762077int2078zfs_send_saved(zfs_handle_t *zhp, sendflags_t *flags, int outfd,2079const char *resume_token)2080{2081int ret;2082libzfs_handle_t *hdl = zhp->zfs_hdl;2083nvlist_t *saved_nvl = NULL, *resume_nvl = NULL;2084uint64_t saved_guid = 0, resume_guid = 0;2085uint64_t obj = 0, off = 0, bytes = 0;2086char token_buf[ZFS_MAXPROPLEN];2087char errbuf[ERRBUFLEN];20882089(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,2090"saved send failed"));20912092ret = zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,2093token_buf, sizeof (token_buf), NULL, NULL, 0, B_TRUE);2094if (ret != 0)2095goto out;20962097saved_nvl = zfs_send_resume_token_to_nvlist(hdl, token_buf);2098if (saved_nvl == NULL) {2099/*2100* zfs_error_aux has already been set by2101* zfs_send_resume_token_to_nvlist()2102*/2103ret = zfs_error(hdl, EZFS_FAULT, errbuf);2104goto out;2105}21062107/*2108* If a resume token is provided we use the object and offset2109* from that instead of the default, which starts from the2110* beginning.2111*/2112if (resume_token != NULL) {2113resume_nvl = zfs_send_resume_token_to_nvlist(hdl,2114resume_token);2115if (resume_nvl == NULL) {2116ret = zfs_error(hdl, EZFS_FAULT, errbuf);2117goto out;2118}21192120if (nvlist_lookup_uint64(resume_nvl, "object", &obj) != 0 ||2121nvlist_lookup_uint64(resume_nvl, "offset", &off) != 0 ||2122nvlist_lookup_uint64(resume_nvl, "bytes", &bytes) != 0 ||2123nvlist_lookup_uint64(resume_nvl, "toguid",2124&resume_guid) != 0) {2125zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2126"provided resume token is corrupt"));2127ret = zfs_error(hdl, EZFS_FAULT, errbuf);2128goto out;2129}21302131if (nvlist_lookup_uint64(saved_nvl, "toguid",2132&saved_guid)) {2133zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2134"dataset's resume token is corrupt"));2135ret = zfs_error(hdl, EZFS_FAULT, errbuf);2136goto out;2137}21382139if (resume_guid != saved_guid) {2140zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2141"provided resume token does not match dataset"));2142ret = zfs_error(hdl, EZFS_BADBACKUP, errbuf);2143goto out;2144}2145}21462147(void) nvlist_remove_all(saved_nvl, "object");2148fnvlist_add_uint64(saved_nvl, "object", obj);21492150(void) nvlist_remove_all(saved_nvl, "offset");2151fnvlist_add_uint64(saved_nvl, "offset", off);21522153(void) nvlist_remove_all(saved_nvl, "bytes");2154fnvlist_add_uint64(saved_nvl, "bytes", bytes);21552156(void) nvlist_remove_all(saved_nvl, "toname");2157fnvlist_add_string(saved_nvl, "toname", zhp->zfs_name);21582159ret = zfs_send_resume_impl(hdl, flags, outfd, saved_nvl);21602161out:2162fnvlist_free(saved_nvl);2163fnvlist_free(resume_nvl);2164return (ret);2165}21662167/*2168* This function informs the target system that the recursive send is complete.2169* The record is also expected in the case of a send -p.2170*/2171static int2172send_conclusion_record(int fd, zio_cksum_t *zc)2173{2174dmu_replay_record_t drr;2175memset(&drr, 0, sizeof (dmu_replay_record_t));2176drr.drr_type = DRR_END;2177if (zc != NULL)2178drr.drr_u.drr_end.drr_checksum = *zc;2179if (write(fd, &drr, sizeof (drr)) == -1) {2180return (errno);2181}2182return (0);2183}21842185/*2186* This function is responsible for sending the records that contain the2187* necessary information for the target system's libzfs to be able to set the2188* properties of the filesystem being received, or to be able to prepare for2189* a recursive receive.2190*2191* The "zhp" argument is the handle of the snapshot we are sending2192* (the "tosnap"). The "from" argument is the short snapshot name (the part2193* after the @) of the incremental source.2194*/2195static int2196send_prelim_records(zfs_handle_t *zhp, const char *from, int fd,2197boolean_t gather_props, boolean_t recursive, boolean_t verbose,2198boolean_t dryrun, boolean_t raw, boolean_t replicate, boolean_t skipmissing,2199boolean_t backup, boolean_t holds, boolean_t props, boolean_t doall,2200nvlist_t **fssp, avl_tree_t **fsavlp)2201{2202int err = 0;2203char *packbuf = NULL;2204size_t buflen = 0;2205zio_cksum_t zc = { {0} };2206int featureflags = 0;2207/* name of filesystem/volume that contains snapshot we are sending */2208char tofs[ZFS_MAX_DATASET_NAME_LEN];2209/* short name of snap we are sending */2210const char *tosnap = "";22112212char errbuf[ERRBUFLEN];2213(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,2214"warning: cannot send '%s'"), zhp->zfs_name);2215if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM && zfs_prop_get_int(zhp,2216ZFS_PROP_VERSION) >= ZPL_VERSION_SA) {2217featureflags |= DMU_BACKUP_FEATURE_SA_SPILL;2218}22192220if (holds)2221featureflags |= DMU_BACKUP_FEATURE_HOLDS;22222223(void) strlcpy(tofs, zhp->zfs_name, ZFS_MAX_DATASET_NAME_LEN);2224char *at = strchr(tofs, '@');2225if (at != NULL) {2226*at = '\0';2227tosnap = at + 1;2228}22292230if (gather_props) {2231nvlist_t *hdrnv = fnvlist_alloc();2232nvlist_t *fss = NULL;22332234if (from != NULL)2235fnvlist_add_string(hdrnv, "fromsnap", from);2236fnvlist_add_string(hdrnv, "tosnap", tosnap);2237if (!recursive)2238fnvlist_add_boolean(hdrnv, "not_recursive");22392240if (raw) {2241fnvlist_add_boolean(hdrnv, "raw");2242}22432244if (gather_nvlist(zhp->zfs_hdl, tofs,2245from, tosnap, recursive, raw, doall, replicate, skipmissing,2246verbose, backup, holds, props, &fss, fsavlp) != 0) {2247return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,2248errbuf));2249}2250/*2251* Do not allow the size of the properties list to exceed2252* the limit2253*/2254if ((fnvlist_size(fss) + fnvlist_size(hdrnv)) >2255zhp->zfs_hdl->libzfs_max_nvlist) {2256(void) snprintf(errbuf, sizeof (errbuf),2257dgettext(TEXT_DOMAIN, "warning: cannot send '%s': "2258"the size of the list of snapshots and properties "2259"is too large to be received successfully.\n"2260"Select a smaller number of snapshots to send.\n"),2261zhp->zfs_name);2262return (zfs_error(zhp->zfs_hdl, EZFS_NOSPC,2263errbuf));2264}2265fnvlist_add_nvlist(hdrnv, "fss", fss);2266VERIFY0(nvlist_pack(hdrnv, &packbuf, &buflen, NV_ENCODE_XDR,22670));2268if (fssp != NULL) {2269*fssp = fss;2270} else {2271fnvlist_free(fss);2272}2273fnvlist_free(hdrnv);2274}22752276if (!dryrun) {2277dmu_replay_record_t drr;2278memset(&drr, 0, sizeof (dmu_replay_record_t));2279/* write first begin record */2280drr.drr_type = DRR_BEGIN;2281drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;2282DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.2283drr_versioninfo, DMU_COMPOUNDSTREAM);2284DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.2285drr_versioninfo, featureflags);2286if (snprintf(drr.drr_u.drr_begin.drr_toname,2287sizeof (drr.drr_u.drr_begin.drr_toname), "%s@%s", tofs,2288tosnap) >= sizeof (drr.drr_u.drr_begin.drr_toname)) {2289return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,2290errbuf));2291}2292drr.drr_payloadlen = buflen;22932294err = dump_record(&drr, packbuf, buflen, &zc, fd);2295free(packbuf);2296if (err != 0) {2297zfs_error_aux(zhp->zfs_hdl, "%s", zfs_strerror(err));2298return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,2299errbuf));2300}2301err = send_conclusion_record(fd, &zc);2302if (err != 0) {2303zfs_error_aux(zhp->zfs_hdl, "%s", zfs_strerror(err));2304return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,2305errbuf));2306}2307}2308return (0);2309}23102311/*2312* Generate a send stream. The "zhp" argument is the filesystem/volume2313* that contains the snapshot to send. The "fromsnap" argument is the2314* short name (the part after the '@') of the snapshot that is the2315* incremental source to send from (if non-NULL). The "tosnap" argument2316* is the short name of the snapshot to send.2317*2318* The content of the send stream is the snapshot identified by2319* 'tosnap'. Incremental streams are requested in two ways:2320* - from the snapshot identified by "fromsnap" (if non-null) or2321* - from the origin of the dataset identified by zhp, which must2322* be a clone. In this case, "fromsnap" is null and "fromorigin"2323* is TRUE.2324*2325* The send stream is recursive (i.e. dumps a hierarchy of snapshots) and2326* uses a special header (with a hdrtype field of DMU_COMPOUNDSTREAM)2327* if "replicate" is set. If "doall" is set, dump all the intermediate2328* snapshots. The DMU_COMPOUNDSTREAM header is used in the "doall"2329* case too. If "props" is set, send properties.2330*2331* Pre-wrapped (cf. lzc_send_wrapper()).2332*/2333static int2334zfs_send_cb_impl(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,2335sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,2336void *cb_arg, nvlist_t **debugnvp)2337{2338char errbuf[ERRBUFLEN];2339send_dump_data_t sdd = { 0 };2340int err = 0;2341nvlist_t *fss = NULL;2342avl_tree_t *fsavl = NULL;2343static uint64_t holdseq;2344int spa_version;2345FILE *fout;23462347(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,2348"cannot send '%s'"), zhp->zfs_name);23492350if (fromsnap && fromsnap[0] == '\0') {2351zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,2352"zero-length incremental source"));2353return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));2354}23552356if (fromsnap) {2357char full_fromsnap_name[ZFS_MAX_DATASET_NAME_LEN];2358if (snprintf(full_fromsnap_name, sizeof (full_fromsnap_name),2359"%s@%s", zhp->zfs_name, fromsnap) >=2360sizeof (full_fromsnap_name)) {2361err = EINVAL;2362goto stderr_out;2363}2364zfs_handle_t *fromsnapn = zfs_open(zhp->zfs_hdl,2365full_fromsnap_name, ZFS_TYPE_SNAPSHOT);2366if (fromsnapn == NULL) {2367err = -1;2368goto err_out;2369}2370zfs_close(fromsnapn);2371}23722373if (flags->replicate || flags->doall || flags->props ||2374flags->holds || flags->backup) {2375char full_tosnap_name[ZFS_MAX_DATASET_NAME_LEN];2376if (snprintf(full_tosnap_name, sizeof (full_tosnap_name),2377"%s@%s", zhp->zfs_name, tosnap) >=2378sizeof (full_tosnap_name)) {2379err = EINVAL;2380goto stderr_out;2381}2382zfs_handle_t *tosnap = zfs_open(zhp->zfs_hdl,2383full_tosnap_name, ZFS_TYPE_SNAPSHOT);2384if (tosnap == NULL) {2385err = -1;2386goto err_out;2387}2388err = send_prelim_records(tosnap, fromsnap, outfd,2389flags->replicate || flags->props || flags->holds,2390flags->replicate, flags->verbosity > 0, flags->dryrun,2391flags->raw, flags->replicate, flags->skipmissing,2392flags->backup, flags->holds, flags->props, flags->doall,2393&fss, &fsavl);2394zfs_close(tosnap);2395if (err != 0)2396goto err_out;2397}23982399/* dump each stream */2400sdd.fromsnap = fromsnap;2401sdd.tosnap = tosnap;2402sdd.outfd = outfd;2403sdd.replicate = flags->replicate;2404sdd.doall = flags->doall;2405sdd.fromorigin = flags->fromorigin;2406sdd.fss = fss;2407sdd.fsavl = fsavl;2408sdd.verbosity = flags->verbosity;2409sdd.parsable = flags->parsable;2410sdd.progress = flags->progress;2411sdd.progressastitle = flags->progressastitle;2412sdd.dryrun = flags->dryrun;2413sdd.large_block = flags->largeblock;2414sdd.embed_data = flags->embed_data;2415sdd.compress = flags->compress;2416sdd.raw = flags->raw;2417sdd.holds = flags->holds;2418sdd.filter_cb = filter_func;2419sdd.filter_cb_arg = cb_arg;2420if (debugnvp)2421sdd.debugnv = *debugnvp;2422if (sdd.verbosity != 0 && sdd.dryrun)2423sdd.std_out = B_TRUE;2424fout = sdd.std_out ? stdout : stderr;24252426/*2427* Some flags require that we place user holds on the datasets that are2428* being sent so they don't get destroyed during the send. We can skip2429* this step if the pool is imported read-only since the datasets cannot2430* be destroyed.2431*/2432if (!flags->dryrun && !zpool_get_prop_int(zfs_get_pool_handle(zhp),2433ZPOOL_PROP_READONLY, NULL) &&2434zfs_spa_version(zhp, &spa_version) == 0 &&2435spa_version >= SPA_VERSION_USERREFS &&2436(flags->doall || flags->replicate)) {2437++holdseq;2438(void) snprintf(sdd.holdtag, sizeof (sdd.holdtag),2439".send-%d-%llu", getpid(), (u_longlong_t)holdseq);2440sdd.cleanup_fd = open(ZFS_DEV, O_RDWR | O_CLOEXEC);2441if (sdd.cleanup_fd < 0) {2442err = errno;2443goto stderr_out;2444}2445sdd.snapholds = fnvlist_alloc();2446} else {2447sdd.cleanup_fd = -1;2448sdd.snapholds = NULL;2449}24502451if (flags->verbosity != 0 || sdd.snapholds != NULL) {2452/*2453* Do a verbose no-op dry run to get all the verbose output2454* or to gather snapshot hold's before generating any data,2455* then do a non-verbose real run to generate the streams.2456*/2457sdd.dryrun = B_TRUE;2458err = dump_filesystems(zhp, &sdd);24592460if (err != 0)2461goto stderr_out;24622463if (flags->verbosity != 0) {2464if (flags->parsable) {2465(void) fprintf(fout, "size\t%llu\n",2466(longlong_t)sdd.size);2467} else {2468char buf[16];2469zfs_nicebytes(sdd.size, buf, sizeof (buf));2470(void) fprintf(fout, dgettext(TEXT_DOMAIN,2471"total estimated size is %s\n"), buf);2472}2473}24742475/* Ensure no snaps found is treated as an error. */2476if (!sdd.seento) {2477err = ENOENT;2478goto err_out;2479}24802481/* Skip the second run if dryrun was requested. */2482if (flags->dryrun)2483goto err_out;24842485if (sdd.snapholds != NULL) {2486err = zfs_hold_nvl(zhp, sdd.cleanup_fd, sdd.snapholds);2487if (err != 0)2488goto stderr_out;24892490fnvlist_free(sdd.snapholds);2491sdd.snapholds = NULL;2492}24932494sdd.dryrun = B_FALSE;2495sdd.verbosity = 0;2496}24972498err = dump_filesystems(zhp, &sdd);2499fsavl_destroy(fsavl);2500fnvlist_free(fss);25012502/* Ensure no snaps found is treated as an error. */2503if (err == 0 && !sdd.seento)2504err = ENOENT;25052506if (sdd.cleanup_fd != -1) {2507VERIFY0(close(sdd.cleanup_fd));2508sdd.cleanup_fd = -1;2509}25102511if (!flags->dryrun && (flags->replicate || flags->doall ||2512flags->props || flags->backup || flags->holds)) {2513/*2514* write final end record. NB: want to do this even if2515* there was some error, because it might not be totally2516* failed.2517*/2518int err2 = send_conclusion_record(outfd, NULL);2519if (err2 != 0)2520return (zfs_standard_error(zhp->zfs_hdl, err2, errbuf));2521}25222523return (err || sdd.err);25242525stderr_out:2526err = zfs_standard_error(zhp->zfs_hdl, err, errbuf);2527err_out:2528fsavl_destroy(fsavl);2529fnvlist_free(fss);2530fnvlist_free(sdd.snapholds);25312532if (sdd.cleanup_fd != -1)2533VERIFY0(close(sdd.cleanup_fd));2534return (err);2535}25362537struct zfs_send {2538zfs_handle_t *zhp;2539const char *fromsnap;2540const char *tosnap;2541sendflags_t *flags;2542snapfilter_cb_t *filter_func;2543void *cb_arg;2544nvlist_t **debugnvp;2545};25462547static int2548zfs_send_cb(int outfd, void *arg)2549{2550struct zfs_send *zs = arg;2551return (zfs_send_cb_impl(zs->zhp, zs->fromsnap, zs->tosnap, zs->flags,2552outfd, zs->filter_func, zs->cb_arg, zs->debugnvp));2553}25542555int2556zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,2557sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,2558void *cb_arg, nvlist_t **debugnvp)2559{2560struct zfs_send arg = {2561.zhp = zhp,2562.fromsnap = fromsnap,2563.tosnap = tosnap,2564.flags = flags,2565.filter_func = filter_func,2566.cb_arg = cb_arg,2567.debugnvp = debugnvp,2568};2569return (lzc_send_wrapper(zfs_send_cb, outfd, &arg));2570}257125722573static zfs_handle_t *2574name_to_dir_handle(libzfs_handle_t *hdl, const char *snapname)2575{2576char dirname[ZFS_MAX_DATASET_NAME_LEN];2577(void) strlcpy(dirname, snapname, ZFS_MAX_DATASET_NAME_LEN);2578char *c = strchr(dirname, '@');2579if (c != NULL)2580*c = '\0';2581return (zfs_open(hdl, dirname, ZFS_TYPE_DATASET));2582}25832584/*2585* Returns B_TRUE if earlier is an earlier snapshot in later's timeline; either2586* an earlier snapshot in the same filesystem, or a snapshot before later's2587* origin, or it's origin's origin, etc.2588*/2589static boolean_t2590snapshot_is_before(zfs_handle_t *earlier, zfs_handle_t *later)2591{2592boolean_t ret;2593uint64_t later_txg =2594(later->zfs_type == ZFS_TYPE_FILESYSTEM ||2595later->zfs_type == ZFS_TYPE_VOLUME ?2596UINT64_MAX : zfs_prop_get_int(later, ZFS_PROP_CREATETXG));2597uint64_t earlier_txg = zfs_prop_get_int(earlier, ZFS_PROP_CREATETXG);25982599if (earlier_txg >= later_txg)2600return (B_FALSE);26012602zfs_handle_t *earlier_dir = name_to_dir_handle(earlier->zfs_hdl,2603earlier->zfs_name);2604zfs_handle_t *later_dir = name_to_dir_handle(later->zfs_hdl,2605later->zfs_name);26062607if (strcmp(earlier_dir->zfs_name, later_dir->zfs_name) == 0) {2608zfs_close(earlier_dir);2609zfs_close(later_dir);2610return (B_TRUE);2611}26122613char clonename[ZFS_MAX_DATASET_NAME_LEN];2614if (zfs_prop_get(later_dir, ZFS_PROP_ORIGIN, clonename,2615ZFS_MAX_DATASET_NAME_LEN, NULL, NULL, 0, B_TRUE) != 0) {2616zfs_close(earlier_dir);2617zfs_close(later_dir);2618return (B_FALSE);2619}26202621zfs_handle_t *origin = zfs_open(earlier->zfs_hdl, clonename,2622ZFS_TYPE_DATASET);2623uint64_t origin_txg = zfs_prop_get_int(origin, ZFS_PROP_CREATETXG);26242625/*2626* If "earlier" is exactly the origin, then2627* snapshot_is_before(earlier, origin) will return false (because2628* they're the same).2629*/2630if (origin_txg == earlier_txg &&2631strcmp(origin->zfs_name, earlier->zfs_name) == 0) {2632zfs_close(earlier_dir);2633zfs_close(later_dir);2634zfs_close(origin);2635return (B_TRUE);2636}2637zfs_close(earlier_dir);2638zfs_close(later_dir);26392640ret = snapshot_is_before(earlier, origin);2641zfs_close(origin);2642return (ret);2643}26442645/*2646* The "zhp" argument is the handle of the dataset to send (typically a2647* snapshot). The "from" argument is the full name of the snapshot or2648* bookmark that is the incremental source.2649*2650* Pre-wrapped (cf. lzc_send_wrapper()).2651*/2652static int2653zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,2654sendflags_t *flags, const char *redactbook)2655{2656int err;2657libzfs_handle_t *hdl = zhp->zfs_hdl;2658char *name = zhp->zfs_name;2659pthread_t ptid;2660progress_arg_t pa = { 0 };2661uint64_t size = 0;26622663char errbuf[ERRBUFLEN];2664(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,2665"warning: cannot send '%s'"), name);26662667if (from != NULL && strchr(from, '@')) {2668zfs_handle_t *from_zhp = zfs_open(hdl, from,2669ZFS_TYPE_DATASET);2670if (from_zhp == NULL)2671return (-1);2672if (!snapshot_is_before(from_zhp, zhp)) {2673zfs_close(from_zhp);2674zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2675"not an earlier snapshot from the same fs"));2676return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));2677}2678zfs_close(from_zhp);2679}26802681if (redactbook != NULL) {2682char bookname[ZFS_MAX_DATASET_NAME_LEN];2683nvlist_t *redact_snaps;2684zfs_handle_t *book_zhp;2685char *at, *pound;2686int dsnamelen;26872688pound = strchr(redactbook, '#');2689if (pound != NULL)2690redactbook = pound + 1;2691at = strchr(name, '@');2692if (at == NULL) {2693zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2694"cannot do a redacted send to a filesystem"));2695return (zfs_error(hdl, EZFS_BADTYPE, errbuf));2696}2697dsnamelen = at - name;2698if (snprintf(bookname, sizeof (bookname), "%.*s#%s",2699dsnamelen, name, redactbook)2700>= sizeof (bookname)) {2701zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2702"invalid bookmark name"));2703return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));2704}2705book_zhp = zfs_open(hdl, bookname, ZFS_TYPE_BOOKMARK);2706if (book_zhp == NULL)2707return (-1);2708if (nvlist_lookup_nvlist(book_zhp->zfs_props,2709zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS),2710&redact_snaps) != 0 || redact_snaps == NULL) {2711zfs_close(book_zhp);2712zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2713"not a redaction bookmark"));2714return (zfs_error(hdl, EZFS_BADTYPE, errbuf));2715}2716zfs_close(book_zhp);2717}27182719/*2720* Send fs properties2721*/2722if (flags->props || flags->holds || flags->backup) {2723/*2724* Note: the header generated by send_prelim_records()2725* assumes that the incremental source is in the same2726* filesystem/volume as the target (which is a requirement2727* when doing "zfs send -R"). But that isn't always the2728* case here (e.g. send from snap in origin, or send from2729* bookmark). We pass from=NULL, which will omit this2730* information from the prelim records; it isn't used2731* when receiving this type of stream.2732*/2733err = send_prelim_records(zhp, NULL, fd, B_TRUE, B_FALSE,2734flags->verbosity > 0, flags->dryrun, flags->raw,2735flags->replicate, B_FALSE, flags->backup, flags->holds,2736flags->props, flags->doall, NULL, NULL);2737if (err != 0)2738return (err);2739}27402741/*2742* Perform size estimate if verbose was specified.2743*/2744if (flags->verbosity != 0 || flags->progressastitle) {2745err = estimate_size(zhp, from, fd, flags, 0, 0, 0, redactbook,2746errbuf, &size);2747if (err != 0)2748return (err);2749}27502751if (flags->dryrun)2752return (0);27532754/*2755* If progress reporting is requested, spawn a new thread to poll2756* ZFS_IOC_SEND_PROGRESS at a regular interval.2757*/2758sigset_t oldmask;2759{2760pa.pa_zhp = zhp;2761pa.pa_fd = fd;2762pa.pa_parsable = flags->parsable;2763pa.pa_estimate = B_FALSE;2764pa.pa_verbosity = flags->verbosity;2765pa.pa_size = size;2766pa.pa_astitle = flags->progressastitle;2767pa.pa_progress = flags->progress;27682769err = pthread_create(&ptid, NULL,2770send_progress_thread, &pa);2771if (err != 0) {2772zfs_error_aux(zhp->zfs_hdl, "%s", zfs_strerror(errno));2773return (zfs_error(zhp->zfs_hdl,2774EZFS_THREADCREATEFAILED, errbuf));2775}2776SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);2777}27782779err = lzc_send_redacted(name, from, fd,2780lzc_flags_from_sendflags(flags), redactbook);27812782if (send_progress_thread_exit(hdl, ptid, &oldmask))2783return (-1);27842785if (err == 0 && (flags->props || flags->holds || flags->backup)) {2786/* Write the final end record. */2787err = send_conclusion_record(fd, NULL);2788if (err != 0)2789return (zfs_standard_error(hdl, err, errbuf));2790}2791if (err != 0) {2792switch (errno) {2793case EXDEV:2794zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2795"not an earlier snapshot from the same fs"));2796return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));27972798case ENOENT:2799case ESRCH:2800if (lzc_exists(name)) {2801zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2802"incremental source (%s) does not exist"),2803from);2804}2805return (zfs_error(hdl, EZFS_NOENT, errbuf));28062807case EACCES:2808zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2809"dataset key must be loaded"));2810return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));28112812case EBUSY:2813zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2814"target is busy; if a filesystem, "2815"it must not be mounted"));2816return (zfs_error(hdl, EZFS_BUSY, errbuf));28172818case EDQUOT:2819case EFAULT:2820case EFBIG:2821case EINVAL:2822case EIO:2823case ENOLINK:2824case ENOSPC:2825case ENOSTR:2826case ENXIO:2827case EPIPE:2828case ERANGE:2829case EROFS:2830zfs_error_aux(hdl, "%s", zfs_strerror(errno));2831return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));2832case ZFS_ERR_STREAM_LARGE_MICROZAP:2833zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2834"source snapshot contains large microzaps, "2835"need -L (--large-block) or -w (--raw) to "2836"generate stream"));2837return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));2838default:2839return (zfs_standard_error(hdl, errno, errbuf));2840}2841}2842return (err != 0);2843}28442845struct zfs_send_one {2846zfs_handle_t *zhp;2847const char *from;2848sendflags_t *flags;2849const char *redactbook;2850};28512852static int2853zfs_send_one_cb(int fd, void *arg)2854{2855struct zfs_send_one *zso = arg;2856return (zfs_send_one_cb_impl(zso->zhp, zso->from, fd, zso->flags,2857zso->redactbook));2858}28592860int2861zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,2862const char *redactbook)2863{2864struct zfs_send_one zso = {2865.zhp = zhp,2866.from = from,2867.flags = flags,2868.redactbook = redactbook,2869};2870return (lzc_send_wrapper(zfs_send_one_cb, fd, &zso));2871}28722873/*2874* Routines specific to "zfs recv"2875*/28762877static int2878recv_read(libzfs_handle_t *hdl, int fd, void *buf, int ilen,2879boolean_t byteswap, zio_cksum_t *zc)2880{2881char *cp = buf;2882int rv;2883int len = ilen;28842885do {2886rv = read(fd, cp, len);2887cp += rv;2888len -= rv;2889} while (rv > 0);28902891if (rv < 0 || len != 0) {2892zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,2893"failed to read from stream"));2894return (zfs_error(hdl, EZFS_BADSTREAM, dgettext(TEXT_DOMAIN,2895"cannot receive")));2896}28972898if (zc) {2899if (byteswap)2900fletcher_4_incremental_byteswap(buf, ilen, zc);2901else2902fletcher_4_incremental_native(buf, ilen, zc);2903}2904return (0);2905}29062907static int2908recv_read_nvlist(libzfs_handle_t *hdl, int fd, int len, nvlist_t **nvp,2909boolean_t byteswap, zio_cksum_t *zc)2910{2911char *buf;2912int err;29132914buf = zfs_alloc(hdl, len);29152916if (len > hdl->libzfs_max_nvlist) {2917zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "nvlist too large"));2918free(buf);2919return (ENOMEM);2920}29212922err = recv_read(hdl, fd, buf, len, byteswap, zc);2923if (err != 0) {2924free(buf);2925return (err);2926}29272928err = nvlist_unpack(buf, len, nvp, 0);2929free(buf);2930if (err != 0) {2931zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "2932"stream (malformed nvlist)"));2933return (EINVAL);2934}2935return (0);2936}29372938/*2939* Returns the grand origin (origin of origin of origin...) of a given handle.2940* If this dataset is not a clone, it simply returns a copy of the original2941* handle.2942*/2943static zfs_handle_t *2944recv_open_grand_origin(zfs_handle_t *zhp)2945{2946char origin[ZFS_MAX_DATASET_NAME_LEN];2947zprop_source_t src;2948zfs_handle_t *ozhp = zfs_handle_dup(zhp);29492950while (ozhp != NULL) {2951if (zfs_prop_get(ozhp, ZFS_PROP_ORIGIN, origin,2952sizeof (origin), &src, NULL, 0, B_FALSE) != 0)2953break;29542955(void) zfs_close(ozhp);2956ozhp = zfs_open(zhp->zfs_hdl, origin, ZFS_TYPE_FILESYSTEM);2957}29582959return (ozhp);2960}29612962static int2963recv_rename_impl(zfs_handle_t *zhp, const char *name, const char *newname)2964{2965int err;2966zfs_handle_t *ozhp = NULL;29672968/*2969* Attempt to rename the dataset. If it fails with EACCES we have2970* attempted to rename the dataset outside of its encryption root.2971* Force the dataset to become an encryption root and try again.2972*/2973err = lzc_rename(name, newname);2974if (err == EACCES) {2975ozhp = recv_open_grand_origin(zhp);2976if (ozhp == NULL) {2977err = ENOENT;2978goto out;2979}29802981err = lzc_change_key(ozhp->zfs_name, DCP_CMD_FORCE_NEW_KEY,2982NULL, NULL, 0);2983if (err != 0)2984goto out;29852986err = lzc_rename(name, newname);2987}29882989out:2990if (ozhp != NULL)2991zfs_close(ozhp);2992return (err);2993}29942995static int2996recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,2997int baselen, char *newname, recvflags_t *flags)2998{2999static int seq;3000int err;3001prop_changelist_t *clp = NULL;3002zfs_handle_t *zhp = NULL;30033004zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);3005if (zhp == NULL) {3006err = -1;3007goto out;3008}3009clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,3010flags->force ? MS_FORCE : 0);3011if (clp == NULL) {3012err = -1;3013goto out;3014}3015err = changelist_prefix(clp);3016if (err)3017goto out;30183019if (tryname) {3020(void) strlcpy(newname, tryname, ZFS_MAX_DATASET_NAME_LEN);3021if (flags->verbose) {3022(void) printf("attempting rename %s to %s\n",3023name, newname);3024}3025err = recv_rename_impl(zhp, name, newname);3026if (err == 0)3027changelist_rename(clp, name, tryname);3028} else {3029err = ENOENT;3030}30313032if (err != 0 && strncmp(name + baselen, "recv-", 5) != 0) {3033seq++;30343035(void) snprintf(newname, ZFS_MAX_DATASET_NAME_LEN,3036"%.*srecv-%u-%u", baselen, name, getpid(), seq);30373038if (flags->verbose) {3039(void) printf("failed - trying rename %s to %s\n",3040name, newname);3041}3042err = recv_rename_impl(zhp, name, newname);3043if (err == 0)3044changelist_rename(clp, name, newname);3045if (err && flags->verbose) {3046(void) printf("failed (%u) - "3047"will try again on next pass\n", errno);3048}3049err = EAGAIN;3050} else if (flags->verbose) {3051if (err == 0)3052(void) printf("success\n");3053else3054(void) printf("failed (%u)\n", errno);3055}30563057(void) changelist_postfix(clp);30583059out:3060if (clp != NULL)3061changelist_free(clp);3062if (zhp != NULL)3063zfs_close(zhp);30643065return (err);3066}30673068static int3069recv_promote(libzfs_handle_t *hdl, const char *fsname,3070const char *origin_fsname, recvflags_t *flags)3071{3072int err;3073zfs_cmd_t zc = {"\0"};3074zfs_handle_t *zhp = NULL, *ozhp = NULL;30753076if (flags->verbose)3077(void) printf("promoting %s\n", fsname);30783079(void) strlcpy(zc.zc_value, origin_fsname, sizeof (zc.zc_value));3080(void) strlcpy(zc.zc_name, fsname, sizeof (zc.zc_name));30813082/*3083* Attempt to promote the dataset. If it fails with EACCES the3084* promotion would cause this dataset to leave its encryption root.3085* Force the origin to become an encryption root and try again.3086*/3087err = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);3088if (err == EACCES) {3089zhp = zfs_open(hdl, fsname, ZFS_TYPE_DATASET);3090if (zhp == NULL) {3091err = -1;3092goto out;3093}30943095ozhp = recv_open_grand_origin(zhp);3096if (ozhp == NULL) {3097err = -1;3098goto out;3099}31003101err = lzc_change_key(ozhp->zfs_name, DCP_CMD_FORCE_NEW_KEY,3102NULL, NULL, 0);3103if (err != 0)3104goto out;31053106err = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);3107}31083109out:3110if (zhp != NULL)3111zfs_close(zhp);3112if (ozhp != NULL)3113zfs_close(ozhp);31143115return (err);3116}31173118static int3119recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,3120char *newname, recvflags_t *flags)3121{3122int err = 0;3123prop_changelist_t *clp;3124zfs_handle_t *zhp;3125boolean_t defer = B_FALSE;3126int spa_version;31273128zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);3129if (zhp == NULL)3130return (-1);3131zfs_type_t type = zfs_get_type(zhp);3132if (type == ZFS_TYPE_SNAPSHOT &&3133zfs_spa_version(zhp, &spa_version) == 0 &&3134spa_version >= SPA_VERSION_USERREFS)3135defer = B_TRUE;3136clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,3137flags->force ? MS_FORCE : 0);3138zfs_close(zhp);3139if (clp == NULL)3140return (-1);31413142err = changelist_prefix(clp);3143if (err)3144return (err);31453146if (flags->verbose)3147(void) printf("attempting destroy %s\n", name);3148if (type == ZFS_TYPE_SNAPSHOT) {3149nvlist_t *nv = fnvlist_alloc();3150fnvlist_add_boolean(nv, name);3151err = lzc_destroy_snaps(nv, defer, NULL);3152fnvlist_free(nv);3153} else {3154err = lzc_destroy(name);3155}3156if (err == 0) {3157if (flags->verbose)3158(void) printf("success\n");3159changelist_remove(clp, name);3160}31613162(void) changelist_postfix(clp);3163changelist_free(clp);31643165/*3166* Deferred destroy might destroy the snapshot or only mark it to be3167* destroyed later, and it returns success in either case.3168*/3169if (err != 0 || (defer && zfs_dataset_exists(hdl, name,3170ZFS_TYPE_SNAPSHOT))) {3171err = recv_rename(hdl, name, NULL, baselen, newname, flags);3172}31733174return (err);3175}31763177typedef struct guid_to_name_data {3178uint64_t guid;3179boolean_t bookmark_ok;3180char *name;3181char *skip;3182uint64_t *redact_snap_guids;3183uint64_t num_redact_snaps;3184} guid_to_name_data_t;31853186static boolean_t3187redact_snaps_match(zfs_handle_t *zhp, guid_to_name_data_t *gtnd)3188{3189uint64_t *bmark_snaps;3190uint_t bmark_num_snaps;3191nvlist_t *nvl;3192if (zhp->zfs_type != ZFS_TYPE_BOOKMARK)3193return (B_FALSE);31943195nvl = fnvlist_lookup_nvlist(zhp->zfs_props,3196zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS));3197bmark_snaps = fnvlist_lookup_uint64_array(nvl, ZPROP_VALUE,3198&bmark_num_snaps);3199if (bmark_num_snaps != gtnd->num_redact_snaps)3200return (B_FALSE);3201int i = 0;3202for (; i < bmark_num_snaps; i++) {3203int j = 0;3204for (; j < bmark_num_snaps; j++) {3205if (bmark_snaps[i] == gtnd->redact_snap_guids[j])3206break;3207}3208if (j == bmark_num_snaps)3209break;3210}3211return (i == bmark_num_snaps);3212}32133214static int3215guid_to_name_cb(zfs_handle_t *zhp, void *arg)3216{3217guid_to_name_data_t *gtnd = arg;3218const char *slash;3219int err;32203221if (gtnd->skip != NULL &&3222(slash = strrchr(zhp->zfs_name, '/')) != NULL &&3223strcmp(slash + 1, gtnd->skip) == 0) {3224zfs_close(zhp);3225return (0);3226}32273228if (zfs_prop_get_int(zhp, ZFS_PROP_GUID) == gtnd->guid &&3229(gtnd->num_redact_snaps == -1 || redact_snaps_match(zhp, gtnd))) {3230(void) strcpy(gtnd->name, zhp->zfs_name);3231zfs_close(zhp);3232return (EEXIST);3233}32343235err = zfs_iter_children_v2(zhp, 0, guid_to_name_cb, gtnd);3236if (err != EEXIST && gtnd->bookmark_ok)3237err = zfs_iter_bookmarks_v2(zhp, 0, guid_to_name_cb, gtnd);3238zfs_close(zhp);3239return (err);3240}32413242/*3243* Attempt to find the local dataset associated with this guid. In the case of3244* multiple matches, we attempt to find the "best" match by searching3245* progressively larger portions of the hierarchy. This allows one to send a3246* tree of datasets individually and guarantee that we will find the source3247* guid within that hierarchy, even if there are multiple matches elsewhere.3248*3249* If num_redact_snaps is not -1, we attempt to find a redaction bookmark with3250* the specified number of redaction snapshots. If num_redact_snaps isn't 0 or3251* -1, then redact_snap_guids will be an array of the guids of the snapshots the3252* redaction bookmark was created with. If num_redact_snaps is -1, then we will3253* attempt to find a snapshot or bookmark (if bookmark_ok is passed) with the3254* given guid. Note that a redaction bookmark can be returned if3255* num_redact_snaps == -1.3256*/3257static int3258guid_to_name_redact_snaps(libzfs_handle_t *hdl, const char *parent,3259uint64_t guid, boolean_t bookmark_ok, uint64_t *redact_snap_guids,3260uint64_t num_redact_snaps, char *name)3261{3262char pname[ZFS_MAX_DATASET_NAME_LEN];3263guid_to_name_data_t gtnd;32643265gtnd.guid = guid;3266gtnd.bookmark_ok = bookmark_ok;3267gtnd.name = name;3268gtnd.skip = NULL;3269gtnd.redact_snap_guids = redact_snap_guids;3270gtnd.num_redact_snaps = num_redact_snaps;32713272/*3273* Search progressively larger portions of the hierarchy, starting3274* with the filesystem specified by 'parent'. This will3275* select the "most local" version of the origin snapshot in the case3276* that there are multiple matching snapshots in the system.3277*/3278(void) strlcpy(pname, parent, sizeof (pname));3279char *cp = strrchr(pname, '@');3280if (cp == NULL)3281cp = strchr(pname, '\0');3282for (; cp != NULL; cp = strrchr(pname, '/')) {3283/* Chop off the last component and open the parent */3284*cp = '\0';3285zfs_handle_t *zhp = make_dataset_handle(hdl, pname);32863287if (zhp == NULL)3288continue;3289int err = guid_to_name_cb(zfs_handle_dup(zhp), >nd);3290if (err != EEXIST)3291err = zfs_iter_children_v2(zhp, 0, guid_to_name_cb,3292>nd);3293if (err != EEXIST && bookmark_ok)3294err = zfs_iter_bookmarks_v2(zhp, 0, guid_to_name_cb,3295>nd);3296zfs_close(zhp);3297if (err == EEXIST)3298return (0);32993300/*3301* Remember the last portion of the dataset so we skip it next3302* time through (as we've already searched that portion of the3303* hierarchy).3304*/3305gtnd.skip = strrchr(pname, '/') + 1;3306}33073308return (ENOENT);3309}33103311static int3312guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid,3313boolean_t bookmark_ok, char *name)3314{3315return (guid_to_name_redact_snaps(hdl, parent, guid, bookmark_ok, NULL,3316-1, name));3317}33183319/*3320* Return +1 if guid1 is before guid2, 0 if they are the same, and -1 if3321* guid1 is after guid2.3322*/3323static int3324created_before(libzfs_handle_t *hdl, avl_tree_t *avl,3325uint64_t guid1, uint64_t guid2)3326{3327nvlist_t *nvfs;3328const char *fsname = NULL, *snapname = NULL;3329char buf[ZFS_MAX_DATASET_NAME_LEN];3330int rv;3331zfs_handle_t *guid1hdl, *guid2hdl;3332uint64_t create1, create2;33333334if (guid2 == 0)3335return (0);3336if (guid1 == 0)3337return (1);33383339nvfs = fsavl_find(avl, guid1, &snapname);3340fsname = fnvlist_lookup_string(nvfs, "name");3341(void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);3342guid1hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);3343if (guid1hdl == NULL)3344return (-1);33453346nvfs = fsavl_find(avl, guid2, &snapname);3347fsname = fnvlist_lookup_string(nvfs, "name");3348(void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);3349guid2hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);3350if (guid2hdl == NULL) {3351zfs_close(guid1hdl);3352return (-1);3353}33543355create1 = zfs_prop_get_int(guid1hdl, ZFS_PROP_CREATETXG);3356create2 = zfs_prop_get_int(guid2hdl, ZFS_PROP_CREATETXG);33573358if (create1 < create2)3359rv = -1;3360else if (create1 > create2)3361rv = +1;3362else3363rv = 0;33643365zfs_close(guid1hdl);3366zfs_close(guid2hdl);33673368return (rv);3369}33703371/*3372* This function reestablishes the hierarchy of encryption roots after a3373* recursive incremental receive has completed. This must be done after the3374* second call to recv_incremental_replication() has renamed and promoted all3375* sent datasets to their final locations in the dataset hierarchy.3376*/3377static int3378recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs,3379nvlist_t *stream_nv, avl_tree_t *stream_avl)3380{3381int err;3382nvpair_t *fselem = NULL;3383nvlist_t *local_nv;3384avl_tree_t *local_avl;3385boolean_t recursive;33863387recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==3388ENOENT);33893390/* Using top_zfs, gather the nvlists for all local filesystems. */3391if ((err = gather_nvlist(hdl, top_zfs, NULL, NULL,3392recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE,3393B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0)3394return (err);33953396/*3397* Go through the nvlists of the local filesystems and check for3398* encryption roots.3399*/3400while ((fselem = nvlist_next_nvpair(local_nv, fselem)) != NULL) {3401zfs_handle_t *zhp = NULL;3402uint64_t crypt;3403nvlist_t *stream_props, *snaps, *stream_nvfs = NULL,3404*nvfs = NULL;3405boolean_t is_encroot, is_clone, stream_encroot;3406const char *stream_keylocation = NULL, *fsname;3407char keylocation[MAXNAMELEN];3408nvpair_t *snapelem;34093410nvfs = fnvpair_value_nvlist(fselem);3411snaps = fnvlist_lookup_nvlist(nvfs, "snaps");3412fsname = fnvlist_lookup_string(nvfs, "name");3413zhp = zfs_open(hdl, fsname, ZFS_TYPE_DATASET);3414if (zhp == NULL) {3415err = ENOENT;3416goto error;3417}34183419/* we don't need to do anything for unencrypted datasets */3420crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);3421if (crypt == ZIO_CRYPT_OFF) {3422zfs_close(zhp);3423continue;3424}34253426is_clone = zhp->zfs_dmustats.dds_origin[0] != '\0';3427(void) zfs_crypto_get_encryption_root(zhp, &is_encroot, NULL);3428keylocation[0] = '\0';34293430/*3431* Go through the snapshots of the local filesystem and find3432* the stream's filesystem.3433*/3434for (snapelem = nvlist_next_nvpair(snaps, NULL);3435snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) {3436uint64_t thisguid;34373438thisguid = fnvpair_value_uint64(snapelem);3439stream_nvfs = fsavl_find(stream_avl, thisguid, NULL);34403441if (stream_nvfs != NULL)3442break;3443}34443445if (stream_nvfs == NULL)3446continue;34473448stream_props = fnvlist_lookup_nvlist(stream_nvfs, "props");3449stream_encroot = nvlist_exists(stream_nvfs, "is_encroot");34503451/*3452* If the dataset is flagged as an encryption root, was not3453* received as a clone and is not currently an encryption root,3454* force it to become one. Fixup the keylocation if necessary.3455*/3456if (stream_encroot) {3457if (!is_clone && !is_encroot) {3458err = lzc_change_key(fsname,3459DCP_CMD_FORCE_NEW_KEY, NULL, NULL, 0);3460if (err != 0) {3461zfs_close(zhp);3462goto error;3463}3464}34653466stream_keylocation = fnvlist_lookup_string(stream_props,3467zfs_prop_to_name(ZFS_PROP_KEYLOCATION));34683469/*3470* Refresh the properties in case the call to3471* lzc_change_key() changed the value.3472*/3473zfs_refresh_properties(zhp);3474err = zfs_prop_get(zhp, ZFS_PROP_KEYLOCATION,3475keylocation, sizeof (keylocation), NULL, NULL,34760, B_TRUE);3477if (err != 0) {3478zfs_close(zhp);3479goto error;3480}34813482if (strcmp(keylocation, stream_keylocation) != 0) {3483err = zfs_prop_set(zhp,3484zfs_prop_to_name(ZFS_PROP_KEYLOCATION),3485stream_keylocation);3486if (err != 0) {3487zfs_close(zhp);3488goto error;3489}3490}3491}34923493/*3494* If the dataset is not flagged as an encryption root and is3495* currently an encryption root, force it to inherit from its3496* parent. The root of a raw send should never be3497* force-inherited.3498*/3499if (!stream_encroot && is_encroot &&3500strcmp(top_zfs, fsname) != 0) {3501err = lzc_change_key(fsname, DCP_CMD_FORCE_INHERIT,3502NULL, NULL, 0);3503if (err != 0) {3504zfs_close(zhp);3505goto error;3506}3507}35083509zfs_close(zhp);3510}35113512return (0);35133514error:3515return (err);3516}35173518static int3519recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,3520recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,3521nvlist_t *renamed)3522{3523nvlist_t *local_nv, *deleted = NULL;3524avl_tree_t *local_avl;3525nvpair_t *fselem, *nextfselem;3526const char *fromsnap;3527char newname[ZFS_MAX_DATASET_NAME_LEN];3528char guidname[32];3529int error;3530boolean_t needagain, progress, recursive;3531const char *s1, *s2;35323533if (flags->dryrun)3534return (0);35353536fromsnap = fnvlist_lookup_string(stream_nv, "fromsnap");35373538recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==3539ENOENT);35403541again:3542needagain = progress = B_FALSE;35433544deleted = fnvlist_alloc();35453546if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,3547recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE,3548B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0)3549return (error);35503551/*3552* Process deletes and renames3553*/3554for (fselem = nvlist_next_nvpair(local_nv, NULL);3555fselem; fselem = nextfselem) {3556nvlist_t *nvfs, *snaps;3557nvlist_t *stream_nvfs = NULL;3558nvpair_t *snapelem, *nextsnapelem;3559uint64_t fromguid = 0;3560uint64_t originguid = 0;3561uint64_t stream_originguid = 0;3562uint64_t parent_fromsnap_guid, stream_parent_fromsnap_guid;3563const char *fsname, *stream_fsname;35643565nextfselem = nvlist_next_nvpair(local_nv, fselem);35663567nvfs = fnvpair_value_nvlist(fselem);3568snaps = fnvlist_lookup_nvlist(nvfs, "snaps");3569fsname = fnvlist_lookup_string(nvfs, "name");3570parent_fromsnap_guid = fnvlist_lookup_uint64(nvfs,3571"parentfromsnap");3572(void) nvlist_lookup_uint64(nvfs, "origin", &originguid);35733574/*3575* First find the stream's fs, so we can check for3576* a different origin (due to "zfs promote")3577*/3578for (snapelem = nvlist_next_nvpair(snaps, NULL);3579snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) {3580uint64_t thisguid;35813582thisguid = fnvpair_value_uint64(snapelem);3583stream_nvfs = fsavl_find(stream_avl, thisguid, NULL);35843585if (stream_nvfs != NULL)3586break;3587}35883589/* check for promote */3590(void) nvlist_lookup_uint64(stream_nvfs, "origin",3591&stream_originguid);3592if (stream_nvfs && originguid != stream_originguid) {3593switch (created_before(hdl, local_avl,3594stream_originguid, originguid)) {3595case 1: {3596/* promote it! */3597nvlist_t *origin_nvfs;3598const char *origin_fsname;35993600origin_nvfs = fsavl_find(local_avl, originguid,3601NULL);3602origin_fsname = fnvlist_lookup_string(3603origin_nvfs, "name");3604error = recv_promote(hdl, fsname, origin_fsname,3605flags);3606if (error == 0)3607progress = B_TRUE;3608break;3609}3610default:3611break;3612case -1:3613fsavl_destroy(local_avl);3614fnvlist_free(local_nv);3615return (-1);3616}3617/*3618* We had/have the wrong origin, therefore our3619* list of snapshots is wrong. Need to handle3620* them on the next pass.3621*/3622needagain = B_TRUE;3623continue;3624}36253626for (snapelem = nvlist_next_nvpair(snaps, NULL);3627snapelem; snapelem = nextsnapelem) {3628uint64_t thisguid;3629const char *stream_snapname;3630nvlist_t *found, *props;36313632nextsnapelem = nvlist_next_nvpair(snaps, snapelem);36333634thisguid = fnvpair_value_uint64(snapelem);3635found = fsavl_find(stream_avl, thisguid,3636&stream_snapname);36373638/* check for delete */3639if (found == NULL) {3640char name[ZFS_MAX_DATASET_NAME_LEN];36413642if (!flags->force)3643continue;36443645(void) snprintf(name, sizeof (name), "%s@%s",3646fsname, nvpair_name(snapelem));36473648error = recv_destroy(hdl, name,3649strlen(fsname)+1, newname, flags);3650if (error)3651needagain = B_TRUE;3652else3653progress = B_TRUE;3654sprintf(guidname, "%llu",3655(u_longlong_t)thisguid);3656nvlist_add_boolean(deleted, guidname);3657continue;3658}36593660stream_nvfs = found;36613662if (0 == nvlist_lookup_nvlist(stream_nvfs, "snapprops",3663&props) && 0 == nvlist_lookup_nvlist(props,3664stream_snapname, &props)) {3665zfs_cmd_t zc = {"\0"};36663667zc.zc_cookie = B_TRUE; /* received */3668(void) snprintf(zc.zc_name, sizeof (zc.zc_name),3669"%s@%s", fsname, nvpair_name(snapelem));3670zcmd_write_src_nvlist(hdl, &zc, props);3671(void) zfs_ioctl(hdl,3672ZFS_IOC_SET_PROP, &zc);3673zcmd_free_nvlists(&zc);3674}36753676/* check for different snapname */3677if (strcmp(nvpair_name(snapelem),3678stream_snapname) != 0) {3679char name[ZFS_MAX_DATASET_NAME_LEN];3680char tryname[ZFS_MAX_DATASET_NAME_LEN];36813682(void) snprintf(name, sizeof (name), "%s@%s",3683fsname, nvpair_name(snapelem));3684(void) snprintf(tryname, sizeof (name), "%s@%s",3685fsname, stream_snapname);36863687error = recv_rename(hdl, name, tryname,3688strlen(fsname)+1, newname, flags);3689if (error)3690needagain = B_TRUE;3691else3692progress = B_TRUE;3693}36943695if (strcmp(stream_snapname, fromsnap) == 0)3696fromguid = thisguid;3697}36983699/* check for delete */3700if (stream_nvfs == NULL) {3701if (!flags->force)3702continue;37033704error = recv_destroy(hdl, fsname, strlen(tofs)+1,3705newname, flags);3706if (error)3707needagain = B_TRUE;3708else3709progress = B_TRUE;3710sprintf(guidname, "%llu",3711(u_longlong_t)parent_fromsnap_guid);3712nvlist_add_boolean(deleted, guidname);3713continue;3714}37153716if (fromguid == 0) {3717if (flags->verbose) {3718(void) printf("local fs %s does not have "3719"fromsnap (%s in stream); must have "3720"been deleted locally; ignoring\n",3721fsname, fromsnap);3722}3723continue;3724}37253726stream_fsname = fnvlist_lookup_string(stream_nvfs, "name");3727stream_parent_fromsnap_guid = fnvlist_lookup_uint64(3728stream_nvfs, "parentfromsnap");37293730s1 = strrchr(fsname, '/');3731s2 = strrchr(stream_fsname, '/');37323733/*3734* Check if we're going to rename based on parent guid change3735* and the current parent guid was also deleted. If it was then3736* rename will fail and is likely unneeded, so avoid this and3737* force an early retry to determine the new3738* parent_fromsnap_guid.3739*/3740if (stream_parent_fromsnap_guid != 0 &&3741parent_fromsnap_guid != 0 &&3742stream_parent_fromsnap_guid != parent_fromsnap_guid) {3743sprintf(guidname, "%llu",3744(u_longlong_t)parent_fromsnap_guid);3745if (nvlist_exists(deleted, guidname)) {3746progress = B_TRUE;3747needagain = B_TRUE;3748goto doagain;3749}3750}37513752/*3753* Check for rename. If the exact receive path is specified, it3754* does not count as a rename, but we still need to check the3755* datasets beneath it.3756*/3757if ((stream_parent_fromsnap_guid != 0 &&3758parent_fromsnap_guid != 0 &&3759stream_parent_fromsnap_guid != parent_fromsnap_guid) ||3760((flags->isprefix || strcmp(tofs, fsname) != 0) &&3761(s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) {3762nvlist_t *parent;3763char tryname[ZFS_MAX_DATASET_NAME_LEN];37643765parent = fsavl_find(local_avl,3766stream_parent_fromsnap_guid, NULL);3767/*3768* NB: parent might not be found if we used the3769* tosnap for stream_parent_fromsnap_guid,3770* because the parent is a newly-created fs;3771* we'll be able to rename it after we recv the3772* new fs.3773*/3774if (parent != NULL) {3775const char *pname;37763777pname = fnvlist_lookup_string(parent, "name");3778(void) snprintf(tryname, sizeof (tryname),3779"%s%s", pname, strrchr(stream_fsname, '/'));3780} else {3781tryname[0] = '\0';3782if (flags->verbose) {3783(void) printf("local fs %s new parent "3784"not found\n", fsname);3785}3786}37873788newname[0] = '\0';37893790error = recv_rename(hdl, fsname, tryname,3791strlen(tofs)+1, newname, flags);37923793if (renamed != NULL && newname[0] != '\0') {3794fnvlist_add_boolean(renamed, newname);3795}37963797if (error)3798needagain = B_TRUE;3799else3800progress = B_TRUE;3801}3802}38033804doagain:3805fsavl_destroy(local_avl);3806fnvlist_free(local_nv);3807fnvlist_free(deleted);38083809if (needagain && progress) {3810/* do another pass to fix up temporary names */3811if (flags->verbose)3812(void) printf("another pass:\n");3813goto again;3814}38153816return (needagain || error != 0);3817}38183819static int3820zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,3821recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,3822char **top_zfs, nvlist_t *cmdprops)3823{3824nvlist_t *stream_nv = NULL;3825avl_tree_t *stream_avl = NULL;3826const char *fromsnap = NULL;3827const char *sendsnap = NULL;3828char *cp;3829char tofs[ZFS_MAX_DATASET_NAME_LEN];3830char sendfs[ZFS_MAX_DATASET_NAME_LEN];3831char errbuf[ERRBUFLEN];3832dmu_replay_record_t drre;3833int error;3834boolean_t anyerr = B_FALSE;3835boolean_t softerr = B_FALSE;3836boolean_t recursive, raw;38373838(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,3839"cannot receive"));38403841assert(drr->drr_type == DRR_BEGIN);3842assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);3843assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==3844DMU_COMPOUNDSTREAM);38453846/*3847* Read in the nvlist from the stream.3848*/3849if (drr->drr_payloadlen != 0) {3850error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen,3851&stream_nv, flags->byteswap, zc);3852if (error) {3853error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);3854goto out;3855}3856}38573858recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==3859ENOENT);3860raw = (nvlist_lookup_boolean(stream_nv, "raw") == 0);38613862if (recursive && strchr(destname, '@')) {3863zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,3864"cannot specify snapshot name for multi-snapshot stream"));3865error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);3866goto out;3867}38683869/*3870* Read in the end record and verify checksum.3871*/3872if (0 != (error = recv_read(hdl, fd, &drre, sizeof (drre),3873flags->byteswap, NULL)))3874goto out;3875if (flags->byteswap) {3876drre.drr_type = BSWAP_32(drre.drr_type);3877drre.drr_u.drr_end.drr_checksum.zc_word[0] =3878BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[0]);3879drre.drr_u.drr_end.drr_checksum.zc_word[1] =3880BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[1]);3881drre.drr_u.drr_end.drr_checksum.zc_word[2] =3882BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[2]);3883drre.drr_u.drr_end.drr_checksum.zc_word[3] =3884BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[3]);3885}3886if (drre.drr_type != DRR_END) {3887error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);3888goto out;3889}3890if (!ZIO_CHECKSUM_EQUAL(drre.drr_u.drr_end.drr_checksum, *zc)) {3891zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,3892"incorrect header checksum"));3893error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);3894goto out;3895}38963897(void) nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap);38983899if (drr->drr_payloadlen != 0) {3900nvlist_t *stream_fss;39013902stream_fss = fnvlist_lookup_nvlist(stream_nv, "fss");3903if ((stream_avl = fsavl_create(stream_fss)) == NULL) {3904zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,3905"couldn't allocate avl tree"));3906error = zfs_error(hdl, EZFS_NOMEM, errbuf);3907goto out;3908}39093910if (fromsnap != NULL && recursive) {3911nvlist_t *renamed = NULL;3912nvpair_t *pair = NULL;39133914(void) strlcpy(tofs, destname, sizeof (tofs));3915if (flags->isprefix) {3916struct drr_begin *drrb = &drr->drr_u.drr_begin;3917int i;39183919if (flags->istail) {3920cp = strrchr(drrb->drr_toname, '/');3921if (cp == NULL) {3922(void) strlcat(tofs, "/",3923sizeof (tofs));3924i = 0;3925} else {3926i = (cp - drrb->drr_toname);3927}3928} else {3929i = strcspn(drrb->drr_toname, "/@");3930}3931/* zfs_receive_one() will create_parents() */3932(void) strlcat(tofs, &drrb->drr_toname[i],3933sizeof (tofs));3934*strchr(tofs, '@') = '\0';3935}39363937if (!flags->dryrun && !flags->nomount) {3938renamed = fnvlist_alloc();3939}39403941softerr = recv_incremental_replication(hdl, tofs, flags,3942stream_nv, stream_avl, renamed);39433944/* Unmount renamed filesystems before receiving. */3945while ((pair = nvlist_next_nvpair(renamed,3946pair)) != NULL) {3947zfs_handle_t *zhp;3948prop_changelist_t *clp = NULL;39493950zhp = zfs_open(hdl, nvpair_name(pair),3951ZFS_TYPE_FILESYSTEM);3952if (zhp != NULL) {3953clp = changelist_gather(zhp,3954ZFS_PROP_MOUNTPOINT, 0,3955flags->forceunmount ? MS_FORCE : 0);3956zfs_close(zhp);3957if (clp != NULL) {3958softerr |=3959changelist_prefix(clp);3960changelist_free(clp);3961}3962}3963}39643965fnvlist_free(renamed);3966}3967}39683969/*3970* Get the fs specified by the first path in the stream (the top level3971* specified by 'zfs send') and pass it to each invocation of3972* zfs_receive_one().3973*/3974(void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,3975sizeof (sendfs));3976if ((cp = strchr(sendfs, '@')) != NULL) {3977*cp = '\0';3978/*3979* Find the "sendsnap", the final snapshot in a replication3980* stream. zfs_receive_one() handles certain errors3981* differently, depending on if the contained stream is the3982* last one or not.3983*/3984sendsnap = (cp + 1);3985}39863987/* Finally, receive each contained stream */3988do {3989/*3990* we should figure out if it has a recoverable3991* error, in which case do a recv_skip() and drive on.3992* Note, if we fail due to already having this guid,3993* zfs_receive_one() will take care of it (ie,3994* recv_skip() and return 0).3995*/3996error = zfs_receive_impl(hdl, destname, NULL, flags, fd,3997sendfs, stream_nv, stream_avl, top_zfs, sendsnap, cmdprops);3998if (error == ENODATA) {3999error = 0;4000break;4001}4002anyerr |= error;4003} while (error == 0);40044005if (drr->drr_payloadlen != 0 && recursive && fromsnap != NULL) {4006/*4007* Now that we have the fs's they sent us, try the4008* renames again.4009*/4010softerr = recv_incremental_replication(hdl, tofs, flags,4011stream_nv, stream_avl, NULL);4012}40134014if (raw && *top_zfs != NULL && !flags->dryrun) {4015softerr = recv_fix_encryption_hierarchy(hdl, *top_zfs,4016stream_nv, stream_avl);4017}40184019out:4020fsavl_destroy(stream_avl);4021fnvlist_free(stream_nv);4022if (softerr)4023error = -2;4024if (anyerr)4025error = -1;4026return (error);4027}40284029static void4030trunc_prop_errs(int truncated)4031{4032ASSERT(truncated != 0);40334034if (truncated == 1)4035(void) fprintf(stderr, dgettext(TEXT_DOMAIN,4036"1 more property could not be set\n"));4037else4038(void) fprintf(stderr, dgettext(TEXT_DOMAIN,4039"%d more properties could not be set\n"), truncated);4040}40414042static int4043recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)4044{4045dmu_replay_record_t *drr;4046void *buf = zfs_alloc(hdl, SPA_MAXBLOCKSIZE);4047uint64_t payload_size;4048char errbuf[ERRBUFLEN];40494050(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,4051"cannot receive"));40524053/* XXX would be great to use lseek if possible... */4054drr = buf;40554056while (recv_read(hdl, fd, drr, sizeof (dmu_replay_record_t),4057byteswap, NULL) == 0) {4058if (byteswap)4059drr->drr_type = BSWAP_32(drr->drr_type);40604061switch (drr->drr_type) {4062case DRR_BEGIN:4063if (drr->drr_payloadlen != 0) {4064(void) recv_read(hdl, fd, buf,4065drr->drr_payloadlen, B_FALSE, NULL);4066}4067break;40684069case DRR_END:4070free(buf);4071return (0);40724073case DRR_OBJECT:4074if (byteswap) {4075drr->drr_u.drr_object.drr_bonuslen =4076BSWAP_32(drr->drr_u.drr_object.4077drr_bonuslen);4078drr->drr_u.drr_object.drr_raw_bonuslen =4079BSWAP_32(drr->drr_u.drr_object.4080drr_raw_bonuslen);4081}40824083payload_size =4084DRR_OBJECT_PAYLOAD_SIZE(&drr->drr_u.drr_object);4085(void) recv_read(hdl, fd, buf, payload_size,4086B_FALSE, NULL);4087break;40884089case DRR_WRITE:4090if (byteswap) {4091drr->drr_u.drr_write.drr_logical_size =4092BSWAP_64(4093drr->drr_u.drr_write.drr_logical_size);4094drr->drr_u.drr_write.drr_compressed_size =4095BSWAP_64(4096drr->drr_u.drr_write.drr_compressed_size);4097}4098payload_size =4099DRR_WRITE_PAYLOAD_SIZE(&drr->drr_u.drr_write);4100assert(payload_size <= SPA_MAXBLOCKSIZE);4101(void) recv_read(hdl, fd, buf,4102payload_size, B_FALSE, NULL);4103break;4104case DRR_SPILL:4105if (byteswap) {4106drr->drr_u.drr_spill.drr_length =4107BSWAP_64(drr->drr_u.drr_spill.drr_length);4108drr->drr_u.drr_spill.drr_compressed_size =4109BSWAP_64(drr->drr_u.drr_spill.4110drr_compressed_size);4111}41124113payload_size =4114DRR_SPILL_PAYLOAD_SIZE(&drr->drr_u.drr_spill);4115(void) recv_read(hdl, fd, buf, payload_size,4116B_FALSE, NULL);4117break;4118case DRR_WRITE_EMBEDDED:4119if (byteswap) {4120drr->drr_u.drr_write_embedded.drr_psize =4121BSWAP_32(drr->drr_u.drr_write_embedded.4122drr_psize);4123}4124(void) recv_read(hdl, fd, buf,4125P2ROUNDUP(drr->drr_u.drr_write_embedded.drr_psize,41268), B_FALSE, NULL);4127break;4128case DRR_OBJECT_RANGE:4129case DRR_WRITE_BYREF:4130case DRR_FREEOBJECTS:4131case DRR_FREE:4132break;41334134default:4135zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4136"invalid record type"));4137free(buf);4138return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));4139}4140}41414142free(buf);4143return (-1);4144}41454146static void4147recv_ecksum_set_aux(libzfs_handle_t *hdl, const char *target_snap,4148boolean_t resumable, boolean_t checksum)4149{4150char target_fs[ZFS_MAX_DATASET_NAME_LEN];41514152zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, (checksum ?4153"checksum mismatch" : "incomplete stream")));41544155if (!resumable)4156return;4157(void) strlcpy(target_fs, target_snap, sizeof (target_fs));4158*strchr(target_fs, '@') = '\0';4159zfs_handle_t *zhp = zfs_open(hdl, target_fs,4160ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);4161if (zhp == NULL)4162return;41634164char token_buf[ZFS_MAXPROPLEN];4165int error = zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,4166token_buf, sizeof (token_buf),4167NULL, NULL, 0, B_TRUE);4168if (error == 0) {4169zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4170"checksum mismatch or incomplete stream.\n"4171"Partially received snapshot is saved.\n"4172"A resuming stream can be generated on the sending "4173"system by running:\n"4174" zfs send -t %s"),4175token_buf);4176}4177zfs_close(zhp);4178}41794180/*4181* Prepare a new nvlist of properties that are to override (-o) or be excluded4182* (-x) from the received dataset4183* recvprops: received properties from the send stream4184* cmdprops: raw input properties from command line4185* origprops: properties, both locally-set and received, currently set on the4186* target dataset if it exists, NULL otherwise.4187* oxprops: valid output override (-o) and excluded (-x) properties4188*/4189static int4190zfs_setup_cmdline_props(libzfs_handle_t *hdl, zfs_type_t type,4191char *fsname, boolean_t zoned, boolean_t recursive, boolean_t newfs,4192boolean_t raw, boolean_t toplevel, nvlist_t *recvprops, nvlist_t *cmdprops,4193nvlist_t *origprops, nvlist_t **oxprops, uint8_t **wkeydata_out,4194uint_t *wkeylen_out, const char *errbuf)4195{4196nvpair_t *nvp;4197nvlist_t *oprops, *voprops;4198zfs_handle_t *zhp = NULL;4199zpool_handle_t *zpool_hdl = NULL;4200char *cp;4201int ret = 0;4202char namebuf[ZFS_MAX_DATASET_NAME_LEN];42034204if (nvlist_empty(cmdprops))4205return (0); /* No properties to override or exclude */42064207*oxprops = fnvlist_alloc();4208oprops = fnvlist_alloc();42094210strlcpy(namebuf, fsname, ZFS_MAX_DATASET_NAME_LEN);42114212/*4213* Get our dataset handle. The target dataset may not exist yet.4214*/4215if (zfs_dataset_exists(hdl, namebuf, ZFS_TYPE_DATASET)) {4216zhp = zfs_open(hdl, namebuf, ZFS_TYPE_DATASET);4217if (zhp == NULL) {4218ret = -1;4219goto error;4220}4221}42224223/* open the zpool handle */4224cp = strchr(namebuf, '/');4225if (cp != NULL)4226*cp = '\0';4227zpool_hdl = zpool_open(hdl, namebuf);4228if (zpool_hdl == NULL) {4229ret = -1;4230goto error;4231}42324233/* restore namebuf to match fsname for later use */4234if (cp != NULL)4235*cp = '/';42364237/*4238* first iteration: process excluded (-x) properties now and gather4239* added (-o) properties to be later processed by zfs_valid_proplist()4240*/4241nvp = NULL;4242while ((nvp = nvlist_next_nvpair(cmdprops, nvp)) != NULL) {4243const char *name = nvpair_name(nvp);4244zfs_prop_t prop = zfs_name_to_prop(name);42454246/*4247* It turns out, if we don't normalize "aliased" names4248* e.g. compress= against the "real" names (e.g. compression)4249* here, then setting/excluding them does not work as4250* intended.4251*4252* But since user-defined properties wouldn't have a valid4253* mapping here, we do this conditional dance.4254*/4255const char *newname = name;4256if (prop >= ZFS_PROP_TYPE)4257newname = zfs_prop_to_name(prop);42584259/* "origin" is processed separately, don't handle it here */4260if (prop == ZFS_PROP_ORIGIN)4261continue;42624263/* raw streams can't override encryption properties */4264if ((zfs_prop_encryption_key_param(prop) ||4265prop == ZFS_PROP_ENCRYPTION) && raw) {4266zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4267"encryption property '%s' cannot "4268"be set or excluded for raw streams."), name);4269ret = zfs_error(hdl, EZFS_BADPROP, errbuf);4270goto error;4271}42724273/*4274* For plain replicated send, we can ignore encryption4275* properties other than first stream4276*/4277if ((zfs_prop_encryption_key_param(prop) || prop ==4278ZFS_PROP_ENCRYPTION) && !newfs && recursive && !raw) {4279continue;4280}42814282/* incremental streams can only exclude encryption properties */4283if ((zfs_prop_encryption_key_param(prop) ||4284prop == ZFS_PROP_ENCRYPTION) && !newfs &&4285nvpair_type(nvp) != DATA_TYPE_BOOLEAN) {4286zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4287"encryption property '%s' cannot "4288"be set for incremental streams."), name);4289ret = zfs_error(hdl, EZFS_BADPROP, errbuf);4290goto error;4291}42924293switch (nvpair_type(nvp)) {4294case DATA_TYPE_BOOLEAN: /* -x property */4295/*4296* DATA_TYPE_BOOLEAN is the way we're asked to "exclude"4297* a property: this is done by forcing an explicit4298* inherit on the destination so the effective value is4299* not the one we received from the send stream.4300*/4301if (!zfs_prop_valid_for_type(prop, type, B_FALSE) &&4302!zfs_prop_user(name)) {4303(void) fprintf(stderr, dgettext(TEXT_DOMAIN,4304"Warning: %s: property '%s' does not "4305"apply to datasets of this type\n"),4306fsname, name);4307continue;4308}4309/*4310* We do this only if the property is not already4311* locally-set, in which case its value will take4312* priority over the received anyway.4313*/4314if (nvlist_exists(origprops, newname)) {4315nvlist_t *attrs;4316const char *source = NULL;43174318attrs = fnvlist_lookup_nvlist(origprops,4319newname);4320if (nvlist_lookup_string(attrs,4321ZPROP_SOURCE, &source) == 0 &&4322strcmp(source, ZPROP_SOURCE_VAL_RECVD) != 0)4323continue;4324}4325/*4326* We can't force an explicit inherit on non-inheritable4327* properties: if we're asked to exclude this kind of4328* values we remove them from "recvprops" input nvlist.4329*/4330if (!zfs_prop_user(name) && /* can be inherited too */4331!zfs_prop_inheritable(prop) &&4332nvlist_exists(recvprops, newname))4333fnvlist_remove(recvprops, newname);4334else4335fnvlist_add_boolean(*oxprops, newname);4336break;4337case DATA_TYPE_STRING: /* -o property=value */4338/*4339* we're trying to override a property that does not4340* make sense for this type of dataset, but we don't4341* want to fail if the receive is recursive: this comes4342* in handy when the send stream contains, for4343* instance, a child ZVOL and we're trying to receive4344* it with "-o atime=on"4345*/4346if (!zfs_prop_valid_for_type(prop, type, B_FALSE) &&4347!zfs_prop_user(name)) {4348if (recursive)4349continue;4350zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4351"property '%s' does not apply to datasets "4352"of this type"), name);4353ret = zfs_error(hdl, EZFS_BADPROP, errbuf);4354goto error;4355}4356fnvlist_add_string(oprops, newname,4357fnvpair_value_string(nvp));4358break;4359default:4360zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4361"property '%s' must be a string or boolean"), name);4362ret = zfs_error(hdl, EZFS_BADPROP, errbuf);4363goto error;4364}4365}43664367if (toplevel) {4368/* convert override strings properties to native */4369if ((voprops = zfs_valid_proplist(hdl, ZFS_TYPE_DATASET,4370oprops, zoned, zhp, zpool_hdl, B_FALSE, errbuf)) == NULL) {4371ret = zfs_error(hdl, EZFS_BADPROP, errbuf);4372goto error;4373}43744375/*4376* zfs_crypto_create() requires the parent name. Get it4377* by truncating the fsname copy stored in namebuf.4378*/4379cp = strrchr(namebuf, '/');4380if (cp != NULL)4381*cp = '\0';43824383if (!raw && !(!newfs && recursive) &&4384zfs_crypto_create(hdl, namebuf, voprops, NULL,4385B_FALSE, wkeydata_out, wkeylen_out) != 0) {4386fnvlist_free(voprops);4387ret = zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf);4388goto error;4389}43904391/* second pass: process "-o" properties */4392fnvlist_merge(*oxprops, voprops);4393fnvlist_free(voprops);4394} else {4395/* override props on child dataset are inherited */4396nvp = NULL;4397while ((nvp = nvlist_next_nvpair(oprops, nvp)) != NULL) {4398const char *name = nvpair_name(nvp);4399fnvlist_add_boolean(*oxprops, name);4400}4401}44024403error:4404if (zhp != NULL)4405zfs_close(zhp);4406if (zpool_hdl != NULL)4407zpool_close(zpool_hdl);4408fnvlist_free(oprops);4409return (ret);4410}44114412/*4413* Restores a backup of tosnap from the file descriptor specified by infd.4414*/4415static int4416zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,4417const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,4418dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,4419avl_tree_t *stream_avl, char **top_zfs,4420const char *finalsnap, nvlist_t *cmdprops)4421{4422struct timespec begin_time;4423int ioctl_err, ioctl_errno, err;4424char *cp;4425struct drr_begin *drrb = &drr->drr_u.drr_begin;4426char errbuf[ERRBUFLEN];4427const char *chopprefix;4428boolean_t newfs = B_FALSE;4429boolean_t stream_wantsnewfs, stream_resumingnewfs;4430boolean_t newprops = B_FALSE;4431uint64_t read_bytes = 0;4432uint64_t errflags = 0;4433uint64_t parent_snapguid = 0;4434prop_changelist_t *clp = NULL;4435nvlist_t *snapprops_nvlist = NULL;4436nvlist_t *snapholds_nvlist = NULL;4437zprop_errflags_t prop_errflags;4438nvlist_t *prop_errors = NULL;4439boolean_t recursive;4440const char *snapname = NULL;4441char destsnap[MAXPATHLEN * 2];4442char origin[MAXNAMELEN] = {0};4443char name[MAXPATHLEN];4444char tmp_keylocation[MAXNAMELEN] = {0};4445nvlist_t *rcvprops = NULL; /* props received from the send stream */4446nvlist_t *oxprops = NULL; /* override (-o) and exclude (-x) props */4447nvlist_t *origprops = NULL; /* original props (if destination exists) */4448zfs_type_t type = ZFS_TYPE_INVALID;4449boolean_t toplevel = B_FALSE;4450boolean_t zoned = B_FALSE;4451boolean_t hastoken = B_FALSE;4452boolean_t redacted;4453uint8_t *wkeydata = NULL;4454uint_t wkeylen = 0;44554456#ifndef CLOCK_MONOTONIC_RAW4457#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC4458#endif4459clock_gettime(CLOCK_MONOTONIC_RAW, &begin_time);44604461(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,4462"cannot receive"));44634464recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==4465ENOENT);44664467/* Did the user request holds be skipped via zfs recv -k? */4468boolean_t holds = flags->holds && !flags->skipholds;44694470if (stream_avl != NULL) {4471const char *keylocation = NULL;4472nvlist_t *lookup = NULL;4473nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,4474&snapname);44754476(void) nvlist_lookup_uint64(fs, "parentfromsnap",4477&parent_snapguid);4478err = nvlist_lookup_nvlist(fs, "props", &rcvprops);4479if (err) {4480rcvprops = fnvlist_alloc();4481newprops = B_TRUE;4482}44834484/*4485* The keylocation property may only be set on encryption roots,4486* but this dataset might not become an encryption root until4487* recv_fix_encryption_hierarchy() is called. That function4488* will fixup the keylocation anyway, so we temporarily unset4489* the keylocation for now to avoid any errors from the receive4490* ioctl.4491*/4492err = nvlist_lookup_string(rcvprops,4493zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation);4494if (err == 0) {4495strlcpy(tmp_keylocation, keylocation, MAXNAMELEN);4496(void) nvlist_remove_all(rcvprops,4497zfs_prop_to_name(ZFS_PROP_KEYLOCATION));4498}44994500if (flags->canmountoff) {4501fnvlist_add_uint64(rcvprops,4502zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0);4503} else if (newprops) { /* nothing in rcvprops, eliminate it */4504fnvlist_free(rcvprops);4505rcvprops = NULL;4506newprops = B_FALSE;4507}4508if (0 == nvlist_lookup_nvlist(fs, "snapprops", &lookup)) {4509snapprops_nvlist = fnvlist_lookup_nvlist(lookup,4510snapname);4511}4512if (holds) {4513if (0 == nvlist_lookup_nvlist(fs, "snapholds",4514&lookup)) {4515snapholds_nvlist = fnvlist_lookup_nvlist(4516lookup, snapname);4517}4518}4519}45204521cp = NULL;45224523/*4524* Determine how much of the snapshot name stored in the stream4525* we are going to tack on to the name they specified on the4526* command line, and how much we are going to chop off.4527*4528* If they specified a snapshot, chop the entire name stored in4529* the stream.4530*/4531if (flags->istail) {4532/*4533* A filesystem was specified with -e. We want to tack on only4534* the tail of the sent snapshot path.4535*/4536if (strchr(tosnap, '@')) {4537zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "4538"argument - snapshot not allowed with -e"));4539err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);4540goto out;4541}45424543chopprefix = strrchr(sendfs, '/');45444545if (chopprefix == NULL) {4546/*4547* The tail is the poolname, so we need to4548* prepend a path separator.4549*/4550int len = strlen(drrb->drr_toname);4551cp = umem_alloc(len + 2, UMEM_NOFAIL);4552cp[0] = '/';4553(void) strcpy(&cp[1], drrb->drr_toname);4554chopprefix = cp;4555} else {4556chopprefix = drrb->drr_toname + (chopprefix - sendfs);4557}4558} else if (flags->isprefix) {4559/*4560* A filesystem was specified with -d. We want to tack on4561* everything but the first element of the sent snapshot path4562* (all but the pool name).4563*/4564if (strchr(tosnap, '@')) {4565zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "4566"argument - snapshot not allowed with -d"));4567err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);4568goto out;4569}45704571chopprefix = strchr(drrb->drr_toname, '/');4572if (chopprefix == NULL)4573chopprefix = strchr(drrb->drr_toname, '@');4574} else if (strchr(tosnap, '@') == NULL) {4575/*4576* If a filesystem was specified without -d or -e, we want to4577* tack on everything after the fs specified by 'zfs send'.4578*/4579chopprefix = drrb->drr_toname + strlen(sendfs);4580} else {4581/* A snapshot was specified as an exact path (no -d or -e). */4582if (recursive) {4583zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4584"cannot specify snapshot name for multi-snapshot "4585"stream"));4586err = zfs_error(hdl, EZFS_BADSTREAM, errbuf);4587goto out;4588}4589chopprefix = drrb->drr_toname + strlen(drrb->drr_toname);4590}45914592ASSERT(strstr(drrb->drr_toname, sendfs) == drrb->drr_toname);4593ASSERT(chopprefix > drrb->drr_toname || strchr(sendfs, '/') == NULL);4594ASSERT(chopprefix <= drrb->drr_toname + strlen(drrb->drr_toname) ||4595strchr(sendfs, '/') == NULL);4596ASSERT(chopprefix[0] == '/' || chopprefix[0] == '@' ||4597chopprefix[0] == '\0');45984599/*4600* Determine name of destination snapshot.4601*/4602(void) strlcpy(destsnap, tosnap, sizeof (destsnap));4603(void) strlcat(destsnap, chopprefix, sizeof (destsnap));4604if (cp != NULL)4605umem_free(cp, strlen(cp) + 1);4606if (!zfs_name_valid(destsnap, ZFS_TYPE_SNAPSHOT)) {4607err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);4608goto out;4609}46104611/*4612* Determine the name of the origin snapshot.4613*/4614if (originsnap) {4615(void) strlcpy(origin, originsnap, sizeof (origin));4616if (flags->verbose)4617(void) printf("using provided clone origin %s\n",4618origin);4619} else if (drrb->drr_flags & DRR_FLAG_CLONE) {4620if (guid_to_name(hdl, destsnap,4621drrb->drr_fromguid, B_FALSE, origin) != 0) {4622zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4623"local origin for clone %s does not exist"),4624destsnap);4625err = zfs_error(hdl, EZFS_NOENT, errbuf);4626goto out;4627}4628if (flags->verbose)4629(void) printf("found clone origin %s\n", origin);4630}46314632if ((DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &4633DMU_BACKUP_FEATURE_DEDUP)) {4634(void) fprintf(stderr,4635gettext("ERROR: \"zfs receive\" no longer supports "4636"deduplicated send streams. Use\n"4637"the \"zstream redup\" command to convert this stream "4638"to a regular,\n"4639"non-deduplicated stream.\n"));4640err = zfs_error(hdl, EZFS_NOTSUP, errbuf);4641goto out;4642}46434644boolean_t resuming = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &4645DMU_BACKUP_FEATURE_RESUMING;4646boolean_t raw = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &4647DMU_BACKUP_FEATURE_RAW;4648boolean_t embedded = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &4649DMU_BACKUP_FEATURE_EMBED_DATA;4650stream_wantsnewfs = (drrb->drr_fromguid == 0 ||4651(drrb->drr_flags & DRR_FLAG_CLONE) || originsnap) && !resuming;4652stream_resumingnewfs = (drrb->drr_fromguid == 0 ||4653(drrb->drr_flags & DRR_FLAG_CLONE) || originsnap) && resuming;46544655if (stream_wantsnewfs) {4656/*4657* if the parent fs does not exist, look for it based on4658* the parent snap GUID4659*/4660(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,4661"cannot receive new filesystem stream"));46624663(void) strlcpy(name, destsnap, sizeof (name));4664cp = strrchr(name, '/');4665if (cp)4666*cp = '\0';4667if (cp &&4668!zfs_dataset_exists(hdl, name, ZFS_TYPE_DATASET)) {4669char suffix[ZFS_MAX_DATASET_NAME_LEN];4670(void) strlcpy(suffix, strrchr(destsnap, '/'),4671sizeof (suffix));4672if (guid_to_name(hdl, name, parent_snapguid,4673B_FALSE, destsnap) == 0) {4674*strchr(destsnap, '@') = '\0';4675(void) strlcat(destsnap, suffix,4676sizeof (destsnap));4677}4678}4679} else {4680/*4681* If the fs does not exist, look for it based on the4682* fromsnap GUID.4683*/4684if (resuming) {4685(void) snprintf(errbuf, sizeof (errbuf),4686dgettext(TEXT_DOMAIN,4687"cannot receive resume stream"));4688} else {4689(void) snprintf(errbuf, sizeof (errbuf),4690dgettext(TEXT_DOMAIN,4691"cannot receive incremental stream"));4692}46934694(void) strlcpy(name, destsnap, sizeof (name));4695*strchr(name, '@') = '\0';46964697/*4698* If the exact receive path was specified and this is the4699* topmost path in the stream, then if the fs does not exist we4700* should look no further.4701*/4702if ((flags->isprefix || (*(chopprefix = drrb->drr_toname +4703strlen(sendfs)) != '\0' && *chopprefix != '@')) &&4704!zfs_dataset_exists(hdl, name, ZFS_TYPE_DATASET)) {4705char snap[ZFS_MAX_DATASET_NAME_LEN];4706(void) strlcpy(snap, strchr(destsnap, '@'),4707sizeof (snap));4708if (guid_to_name(hdl, name, drrb->drr_fromguid,4709B_FALSE, destsnap) == 0) {4710*strchr(destsnap, '@') = '\0';4711(void) strlcat(destsnap, snap,4712sizeof (destsnap));4713}4714}4715}47164717(void) strlcpy(name, destsnap, sizeof (name));4718*strchr(name, '@') = '\0';47194720redacted = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &4721DMU_BACKUP_FEATURE_REDACTED;47224723if (flags->heal) {4724if (flags->isprefix || flags->istail || flags->force ||4725flags->canmountoff || flags->resumable || flags->nomount ||4726flags->skipholds) {4727zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4728"corrective recv can not be used when combined with"4729" this flag"));4730err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);4731goto out;4732}4733uint64_t guid =4734get_snap_guid(hdl, name, strchr(destsnap, '@') + 1);4735if (guid == 0) {4736zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4737"corrective recv must specify an existing snapshot"4738" to heal"));4739err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);4740goto out;4741} else if (guid != drrb->drr_toguid) {4742zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4743"local snapshot doesn't match the snapshot"4744" in the provided stream"));4745err = zfs_error(hdl, EZFS_WRONG_PARENT, errbuf);4746goto out;4747}4748} else if (zfs_dataset_exists(hdl, name, ZFS_TYPE_DATASET)) {4749zfs_cmd_t zc = {"\0"};4750zfs_handle_t *zhp = NULL;4751boolean_t encrypted;47524753(void) strcpy(zc.zc_name, name);47544755/*4756* Destination fs exists. It must be one of these cases:4757* - an incremental send stream4758* - the stream specifies a new fs (full stream or clone)4759* and they want us to blow away the existing fs (and4760* have therefore specified -F and removed any snapshots)4761* - we are resuming a failed receive.4762*/4763if (stream_wantsnewfs) {4764boolean_t is_volume = drrb->drr_type == DMU_OST_ZVOL;4765if (!flags->force) {4766zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4767"destination '%s' exists\n"4768"must specify -F to overwrite it"), name);4769err = zfs_error(hdl, EZFS_EXISTS, errbuf);4770goto out;4771}4772if (zfs_ioctl(hdl, ZFS_IOC_SNAPSHOT_LIST_NEXT,4773&zc) == 0) {4774zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4775"destination has snapshots (eg. %s)\n"4776"must destroy them to overwrite it"),4777zc.zc_name);4778err = zfs_error(hdl, EZFS_EXISTS, errbuf);4779goto out;4780}4781if (is_volume && strrchr(name, '/') == NULL) {4782zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4783"destination %s is the root dataset\n"4784"cannot overwrite with a ZVOL"),4785name);4786err = zfs_error(hdl, EZFS_EXISTS, errbuf);4787goto out;4788}4789if (is_volume &&4790zfs_ioctl(hdl, ZFS_IOC_DATASET_LIST_NEXT,4791&zc) == 0) {4792zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4793"destination has children (eg. %s)\n"4794"cannot overwrite with a ZVOL"),4795zc.zc_name);4796err = zfs_error(hdl, EZFS_WRONG_PARENT, errbuf);4797goto out;4798}4799}48004801if ((zhp = zfs_open(hdl, name,4802ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {4803err = -1;4804goto out;4805}48064807/*4808* When receiving full/newfs on existing dataset, then it4809* should be done with "-F" flag. Its enforced for initial4810* receive in previous checks in this function.4811* Similarly, on resuming full/newfs recv on existing dataset,4812* it should be done with "-F" flag.4813*4814* When dataset doesn't exist, then full/newfs recv is done on4815* newly created dataset and it's marked INCONSISTENT. But4816* When receiving on existing dataset, recv is first done on4817* %recv and its marked INCONSISTENT. Existing dataset is not4818* marked INCONSISTENT.4819* Resume of full/newfs receive with dataset not INCONSISTENT4820* indicates that its resuming newfs on existing dataset. So,4821* enforce "-F" flag in this case.4822*/4823if (stream_resumingnewfs &&4824!zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&4825!flags->force) {4826zfs_close(zhp);4827zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4828"Resuming recv on existing destination '%s'\n"4829"must specify -F to overwrite it"), name);4830err = zfs_error(hdl, EZFS_RESUME_EXISTS, errbuf);4831goto out;4832}48334834if (stream_wantsnewfs &&4835zhp->zfs_dmustats.dds_origin[0]) {4836zfs_close(zhp);4837zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4838"destination '%s' is a clone\n"4839"must destroy it to overwrite it"), name);4840err = zfs_error(hdl, EZFS_EXISTS, errbuf);4841goto out;4842}48434844/*4845* Raw sends can not be performed as an incremental on top4846* of existing unencrypted datasets. zfs recv -F can't be4847* used to blow away an existing encrypted filesystem. This4848* is because it would require the dsl dir to point to the4849* new key (or lack of a key) and the old key at the same4850* time. The -F flag may still be used for deleting4851* intermediate snapshots that would otherwise prevent the4852* receive from working.4853*/4854encrypted = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) !=4855ZIO_CRYPT_OFF;4856if (!stream_wantsnewfs && !encrypted && raw) {4857zfs_close(zhp);4858zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4859"cannot perform raw receive on top of "4860"existing unencrypted dataset"));4861err = zfs_error(hdl, EZFS_BADRESTORE, errbuf);4862goto out;4863}48644865if (stream_wantsnewfs && flags->force &&4866((raw && !encrypted) || encrypted)) {4867zfs_close(zhp);4868zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4869"zfs receive -F cannot be used to destroy an "4870"encrypted filesystem or overwrite an "4871"unencrypted one with an encrypted one"));4872err = zfs_error(hdl, EZFS_BADRESTORE, errbuf);4873goto out;4874}48754876if (!flags->dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&4877(stream_wantsnewfs || stream_resumingnewfs)) {4878/* We can't do online recv in this case */4879clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,4880flags->forceunmount ? MS_FORCE : 0);4881if (clp == NULL) {4882zfs_close(zhp);4883err = -1;4884goto out;4885}4886if (changelist_prefix(clp) != 0) {4887changelist_free(clp);4888zfs_close(zhp);4889err = -1;4890goto out;4891}4892}48934894/*4895* If we are resuming a newfs, set newfs here so that we will4896* mount it if the recv succeeds this time. We can tell4897* that it was a newfs on the first recv because the fs4898* itself will be inconsistent (if the fs existed when we4899* did the first recv, we would have received it into4900* .../%recv).4901*/4902if (resuming && zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT))4903newfs = B_TRUE;49044905/* we want to know if we're zoned when validating -o|-x props */4906zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);49074908/* may need this info later, get it now we have zhp around */4909if (zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN, NULL, 0,4910NULL, NULL, 0, B_TRUE) == 0)4911hastoken = B_TRUE;49124913/* gather existing properties on destination */4914origprops = fnvlist_alloc();4915fnvlist_merge(origprops, zhp->zfs_props);4916fnvlist_merge(origprops, zhp->zfs_user_props);49174918zfs_close(zhp);4919} else {4920zfs_handle_t *zhp;49214922/*4923* Destination filesystem does not exist. Therefore we better4924* be creating a new filesystem (either from a full backup, or4925* a clone). It would therefore be invalid if the user4926* specified only the pool name (i.e. if the destination name4927* contained no slash character).4928*/4929cp = strrchr(name, '/');49304931if (!stream_wantsnewfs || cp == NULL) {4932zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4933"destination '%s' does not exist"), name);4934err = zfs_error(hdl, EZFS_NOENT, errbuf);4935goto out;4936}49374938/*4939* Trim off the final dataset component so we perform the4940* recvbackup ioctl to the filesystems's parent.4941*/4942*cp = '\0';49434944if (flags->isprefix && !flags->istail && !flags->dryrun &&4945create_parents(hdl, destsnap, strlen(tosnap)) != 0) {4946err = zfs_error(hdl, EZFS_BADRESTORE, errbuf);4947goto out;4948}49494950/* validate parent */4951zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);4952if (zhp == NULL) {4953err = zfs_error(hdl, EZFS_BADRESTORE, errbuf);4954goto out;4955}4956if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {4957zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4958"parent '%s' is not a filesystem"), name);4959err = zfs_error(hdl, EZFS_WRONG_PARENT, errbuf);4960zfs_close(zhp);4961goto out;4962}49634964zfs_close(zhp);49654966newfs = B_TRUE;4967*cp = '/';4968}49694970if (flags->verbose) {4971(void) printf("%s %s%s stream of %s into %s\n",4972flags->dryrun ? "would receive" : "receiving",4973flags->heal ? "corrective " : "",4974drrb->drr_fromguid ? "incremental" : "full",4975drrb->drr_toname, destsnap);4976(void) fflush(stdout);4977}49784979/*4980* If this is the top-level dataset, record it so we can use it4981* for recursive operations later.4982*/4983if (top_zfs != NULL &&4984(*top_zfs == NULL || strcmp(*top_zfs, name) == 0)) {4985toplevel = B_TRUE;4986if (*top_zfs == NULL)4987*top_zfs = zfs_strdup(hdl, name);4988}49894990if (drrb->drr_type == DMU_OST_ZVOL) {4991type = ZFS_TYPE_VOLUME;4992} else if (drrb->drr_type == DMU_OST_ZFS) {4993type = ZFS_TYPE_FILESYSTEM;4994} else {4995zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,4996"invalid record type: 0x%d"), drrb->drr_type);4997err = zfs_error(hdl, EZFS_BADSTREAM, errbuf);4998goto out;4999}5000if ((err = zfs_setup_cmdline_props(hdl, type, name, zoned, recursive,5001stream_wantsnewfs, raw, toplevel, rcvprops, cmdprops, origprops,5002&oxprops, &wkeydata, &wkeylen, errbuf)) != 0)5003goto out;50045005/*5006* When sending with properties (zfs send -p), the encryption property5007* is not included because it is a SETONCE property and therefore5008* treated as read only. However, we are always able to determine its5009* value because raw sends will include it in the DRR_BDEGIN payload5010* and non-raw sends with properties are not allowed for encrypted5011* datasets. Therefore, if this is a non-raw properties stream, we can5012* infer that the value should be ZIO_CRYPT_OFF and manually add that5013* to the received properties.5014*/5015if (stream_wantsnewfs && !raw && rcvprops != NULL &&5016!nvlist_exists(cmdprops, zfs_prop_to_name(ZFS_PROP_ENCRYPTION))) {5017if (oxprops == NULL)5018oxprops = fnvlist_alloc();5019fnvlist_add_uint64(oxprops,5020zfs_prop_to_name(ZFS_PROP_ENCRYPTION), ZIO_CRYPT_OFF);5021}50225023if (flags->dryrun) {5024void *buf = zfs_alloc(hdl, SPA_MAXBLOCKSIZE);50255026/*5027* We have read the DRR_BEGIN record, but we have5028* not yet read the payload. For non-dryrun sends5029* this will be done by the kernel, so we must5030* emulate that here, before attempting to read5031* more records.5032*/5033err = recv_read(hdl, infd, buf, drr->drr_payloadlen,5034flags->byteswap, NULL);5035free(buf);5036if (err != 0)5037goto out;50385039err = recv_skip(hdl, infd, flags->byteswap);5040goto out;5041}50425043if (flags->heal) {5044err = ioctl_err = lzc_receive_with_heal(destsnap, rcvprops,5045oxprops, wkeydata, wkeylen, origin, flags->force,5046flags->heal, flags->resumable, raw, infd, drr_noswap, -1,5047&read_bytes, &errflags, NULL, &prop_errors);5048} else {5049err = ioctl_err = lzc_receive_with_cmdprops(destsnap, rcvprops,5050oxprops, wkeydata, wkeylen, origin, flags->force,5051flags->resumable, raw, infd, drr_noswap, -1, &read_bytes,5052&errflags, NULL, &prop_errors);5053}5054ioctl_errno = ioctl_err;5055prop_errflags = errflags;50565057if (err == 0) {5058nvpair_t *prop_err = NULL;50595060while ((prop_err = nvlist_next_nvpair(prop_errors,5061prop_err)) != NULL) {5062char tbuf[1024];5063zfs_prop_t prop;5064int intval;50655066prop = zfs_name_to_prop(nvpair_name(prop_err));5067(void) nvpair_value_int32(prop_err, &intval);5068if (strcmp(nvpair_name(prop_err),5069ZPROP_N_MORE_ERRORS) == 0) {5070trunc_prop_errs(intval);5071break;5072} else if (snapname == NULL || finalsnap == NULL ||5073strcmp(finalsnap, snapname) == 0 ||5074strcmp(nvpair_name(prop_err),5075zfs_prop_to_name(ZFS_PROP_REFQUOTA)) != 0) {5076/*5077* Skip the special case of, for example,5078* "refquota", errors on intermediate5079* snapshots leading up to a final one.5080* That's why we have all of the checks above.5081*5082* See zfs_ioctl.c's extract_delay_props() for5083* a list of props which can fail on5084* intermediate snapshots, but shouldn't5085* affect the overall receive.5086*/5087(void) snprintf(tbuf, sizeof (tbuf),5088dgettext(TEXT_DOMAIN,5089"cannot receive %s property on %s"),5090nvpair_name(prop_err), name);5091zfs_setprop_error(hdl, prop, intval, tbuf);5092}5093}5094}50955096if (err == 0 && snapprops_nvlist) {5097zfs_cmd_t zc = {"\0"};50985099(void) strlcpy(zc.zc_name, destsnap, sizeof (zc.zc_name));5100zc.zc_cookie = B_TRUE; /* received */5101zcmd_write_src_nvlist(hdl, &zc, snapprops_nvlist);5102(void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);5103zcmd_free_nvlists(&zc);5104}5105if (err == 0 && snapholds_nvlist) {5106nvpair_t *pair;5107nvlist_t *holds, *errors = NULL;5108int cleanup_fd = -1;51095110VERIFY0(nvlist_alloc(&holds, 0, KM_SLEEP));5111for (pair = nvlist_next_nvpair(snapholds_nvlist, NULL);5112pair != NULL;5113pair = nvlist_next_nvpair(snapholds_nvlist, pair)) {5114fnvlist_add_string(holds, destsnap, nvpair_name(pair));5115}5116(void) lzc_hold(holds, cleanup_fd, &errors);5117fnvlist_free(snapholds_nvlist);5118fnvlist_free(holds);5119}51205121if (err && (ioctl_errno == ENOENT || ioctl_errno == EEXIST)) {5122/*5123* It may be that this snapshot already exists,5124* in which case we want to consume & ignore it5125* rather than failing.5126*/5127avl_tree_t *local_avl;5128nvlist_t *local_nv, *fs;5129cp = strchr(destsnap, '@');51305131/*5132* XXX Do this faster by just iterating over snaps in5133* this fs. Also if zc_value does not exist, we will5134* get a strange "does not exist" error message.5135*/5136*cp = '\0';5137if (gather_nvlist(hdl, destsnap, NULL, NULL, B_FALSE, B_TRUE,5138B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE,5139B_TRUE, &local_nv, &local_avl) == 0) {5140*cp = '@';5141fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);5142fsavl_destroy(local_avl);5143fnvlist_free(local_nv);51445145if (fs != NULL) {5146if (flags->verbose) {5147(void) printf("snap %s already exists; "5148"ignoring\n", destsnap);5149}5150err = ioctl_err = recv_skip(hdl, infd,5151flags->byteswap);5152}5153}5154*cp = '@';5155}51565157if (ioctl_err != 0) {5158switch (ioctl_errno) {5159case ENODEV:5160cp = strchr(destsnap, '@');5161*cp = '\0';5162zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5163"most recent snapshot of %s does not\n"5164"match incremental source"), destsnap);5165(void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);5166*cp = '@';5167break;5168case ETXTBSY:5169zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5170"destination %s has been modified\n"5171"since most recent snapshot"), name);5172(void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);5173break;5174case EACCES:5175if (flags->heal) {5176zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5177"key must be loaded to do a non-raw "5178"corrective recv on an encrypted "5179"dataset."));5180} else if (raw && stream_wantsnewfs) {5181zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5182"failed to create encryption key"));5183} else if (raw && !stream_wantsnewfs) {5184zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5185"encryption key does not match "5186"existing key"));5187} else {5188zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5189"inherited key must be loaded"));5190}5191(void) zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf);5192break;5193case EEXIST:5194cp = strchr(destsnap, '@');5195if (newfs) {5196/* it's the containing fs that exists */5197*cp = '\0';5198}5199zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5200"destination already exists"));5201(void) zfs_error_fmt(hdl, EZFS_EXISTS,5202dgettext(TEXT_DOMAIN, "cannot restore to %s"),5203destsnap);5204*cp = '@';5205break;5206case EINVAL:5207if (embedded && !raw) {5208zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5209"incompatible embedded data stream "5210"feature with encrypted receive."));5211} else if (flags->resumable) {5212zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5213"kernel modules must be upgraded to "5214"receive this stream."));5215}5216(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5217break;5218case ECKSUM:5219case ZFS_ERR_STREAM_TRUNCATED:5220if (flags->heal)5221zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5222"corrective receive was not able to "5223"reconstruct the data needed for "5224"healing."));5225else5226recv_ecksum_set_aux(hdl, destsnap,5227flags->resumable, ioctl_err == ECKSUM);5228(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5229break;5230case ZFS_ERR_STREAM_LARGE_BLOCK_MISMATCH:5231zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5232"incremental send stream requires -L "5233"(--large-block), to match previous receive."));5234(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5235break;5236case ENOTSUP:5237if (flags->heal)5238zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5239"stream is not compatible with the "5240"data in the pool."));5241else5242zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5243"pool must be upgraded to receive this "5244"stream."));5245(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);5246break;5247case ZFS_ERR_CRYPTO_NOTSUP:5248zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5249"stream uses crypto parameters not compatible with "5250"this pool"));5251(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5252break;5253case EDQUOT:5254zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5255"destination %s space quota exceeded."), name);5256(void) zfs_error(hdl, EZFS_NOSPC, errbuf);5257break;5258case ZFS_ERR_FROM_IVSET_GUID_MISSING:5259zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5260"IV set guid missing. See errata %u at "5261"https://openzfs.github.io/openzfs-docs/msg/"5262"ZFS-8000-ER."),5263ZPOOL_ERRATA_ZOL_8308_ENCRYPTION);5264(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5265break;5266case ZFS_ERR_FROM_IVSET_GUID_MISMATCH:5267zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5268"IV set guid mismatch. See the 'zfs receive' "5269"man page section\n discussing the limitations "5270"of raw encrypted send streams."));5271(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5272break;5273case ZFS_ERR_SPILL_BLOCK_FLAG_MISSING:5274zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5275"Spill block flag missing for raw send.\n"5276"The zfs software on the sending system must "5277"be updated."));5278(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5279break;5280case ZFS_ERR_RESUME_EXISTS:5281cp = strchr(destsnap, '@');5282if (newfs) {5283/* it's the containing fs that exists */5284*cp = '\0';5285}5286zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5287"Resuming recv on existing dataset without force"));5288(void) zfs_error_fmt(hdl, EZFS_RESUME_EXISTS,5289dgettext(TEXT_DOMAIN, "cannot resume recv %s"),5290destsnap);5291*cp = '@';5292break;5293case E2BIG:5294zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5295"zfs receive required kernel memory allocation "5296"larger than the system can support. Please file "5297"an issue at the OpenZFS issue tracker:\n"5298"https://github.com/openzfs/zfs/issues/new"));5299(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);5300break;5301case EBUSY:5302if (hastoken) {5303zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5304"destination %s contains "5305"partially-complete state from "5306"\"zfs receive -s\"."), name);5307(void) zfs_error(hdl, EZFS_BUSY, errbuf);5308break;5309}5310zfs_fallthrough;5311default:5312(void) zfs_standard_error(hdl, ioctl_errno, errbuf);5313}5314}53155316/*5317* Mount the target filesystem (if created). Also mount any5318* children of the target filesystem if we did a replication5319* receive (indicated by stream_avl being non-NULL).5320*/5321if (clp) {5322if (!flags->nomount)5323err |= changelist_postfix(clp);5324changelist_free(clp);5325}53265327if ((newfs || stream_avl) && type == ZFS_TYPE_FILESYSTEM && !redacted)5328flags->domount = B_TRUE;53295330if (prop_errflags & ZPROP_ERR_NOCLEAR) {5331(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "5332"failed to clear unreceived properties on %s"), name);5333(void) fprintf(stderr, "\n");5334}5335if (prop_errflags & ZPROP_ERR_NORESTORE) {5336(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "5337"failed to restore original properties on %s"), name);5338(void) fprintf(stderr, "\n");5339}53405341if (err || ioctl_err) {5342err = -1;5343goto out;5344}53455346if (flags->verbose) {5347char buf1[64];5348char buf2[64];5349uint64_t bytes = read_bytes;5350struct timespec delta;5351clock_gettime(CLOCK_MONOTONIC_RAW, &delta);5352if (begin_time.tv_nsec > delta.tv_nsec) {5353delta.tv_nsec =53541000000000 + delta.tv_nsec - begin_time.tv_nsec;5355delta.tv_sec -= 1;5356} else5357delta.tv_nsec -= begin_time.tv_nsec;5358delta.tv_sec -= begin_time.tv_sec;5359if (delta.tv_sec == 0 && delta.tv_nsec == 0)5360delta.tv_nsec = 1;5361double delta_f = delta.tv_sec + (delta.tv_nsec / 1e9);5362zfs_nicebytes(bytes, buf1, sizeof (buf1));5363zfs_nicebytes(bytes / delta_f, buf2, sizeof (buf2));53645365(void) printf("received %s stream in %.2f seconds (%s/sec)\n",5366buf1, delta_f, buf2);5367}53685369err = 0;5370out:5371if (prop_errors != NULL)5372fnvlist_free(prop_errors);53735374if (tmp_keylocation[0] != '\0') {5375fnvlist_add_string(rcvprops,5376zfs_prop_to_name(ZFS_PROP_KEYLOCATION), tmp_keylocation);5377}53785379if (newprops)5380fnvlist_free(rcvprops);53815382fnvlist_free(oxprops);5383fnvlist_free(origprops);53845385return (err);5386}53875388/*5389* Check properties we were asked to override (both -o|-x)5390*/5391static boolean_t5392zfs_receive_checkprops(libzfs_handle_t *hdl, nvlist_t *props,5393const char *errbuf)5394{5395nvpair_t *nvp = NULL;5396zfs_prop_t prop;5397const char *name;53985399while ((nvp = nvlist_next_nvpair(props, nvp)) != NULL) {5400name = nvpair_name(nvp);5401prop = zfs_name_to_prop(name);54025403if (prop == ZPROP_USERPROP) {5404if (!zfs_prop_user(name)) {5405zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5406"%s: invalid property '%s'"), errbuf, name);5407return (B_FALSE);5408}5409continue;5410}5411/*5412* "origin" is readonly but is used to receive datasets as5413* clones so we don't raise an error here5414*/5415if (prop == ZFS_PROP_ORIGIN)5416continue;54175418/* encryption params have their own verification later */5419if (prop == ZFS_PROP_ENCRYPTION ||5420zfs_prop_encryption_key_param(prop))5421continue;54225423/*5424* cannot override readonly, set-once and other specific5425* settable properties5426*/5427if (zfs_prop_readonly(prop) || prop == ZFS_PROP_VERSION ||5428prop == ZFS_PROP_VOLSIZE) {5429zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5430"%s: invalid property '%s'"), errbuf, name);5431return (B_FALSE);5432}5433}54345435return (B_TRUE);5436}54375438static int5439zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,5440const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,5441nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs,5442const char *finalsnap, nvlist_t *cmdprops)5443{5444int err;5445dmu_replay_record_t drr, drr_noswap;5446struct drr_begin *drrb = &drr.drr_u.drr_begin;5447char errbuf[ERRBUFLEN];5448zio_cksum_t zcksum = { { 0 } };5449uint64_t featureflags;5450int hdrtype;54515452(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,5453"cannot receive"));54545455/* check cmdline props, raise an error if they cannot be received */5456if (!zfs_receive_checkprops(hdl, cmdprops, errbuf))5457return (zfs_error(hdl, EZFS_BADPROP, errbuf));54585459if (flags->isprefix &&5460!zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {5461zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "5462"(%s) does not exist"), tosnap);5463return (zfs_error(hdl, EZFS_NOENT, errbuf));5464}5465if (originsnap &&5466!zfs_dataset_exists(hdl, originsnap, ZFS_TYPE_DATASET)) {5467zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified origin fs "5468"(%s) does not exist"), originsnap);5469return (zfs_error(hdl, EZFS_NOENT, errbuf));5470}54715472/* read in the BEGIN record */5473if (0 != (err = recv_read(hdl, infd, &drr, sizeof (drr), B_FALSE,5474&zcksum)))5475return (err);54765477if (drr.drr_type == DRR_END || drr.drr_type == BSWAP_32(DRR_END)) {5478/* It's the double end record at the end of a package */5479return (ENODATA);5480}54815482/* the kernel needs the non-byteswapped begin record */5483drr_noswap = drr;54845485flags->byteswap = B_FALSE;5486if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {5487/*5488* We computed the checksum in the wrong byteorder in5489* recv_read() above; do it again correctly.5490*/5491memset(&zcksum, 0, sizeof (zio_cksum_t));5492fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum);5493flags->byteswap = B_TRUE;54945495drr.drr_type = BSWAP_32(drr.drr_type);5496drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen);5497drrb->drr_magic = BSWAP_64(drrb->drr_magic);5498drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo);5499drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);5500drrb->drr_type = BSWAP_32(drrb->drr_type);5501drrb->drr_flags = BSWAP_32(drrb->drr_flags);5502drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);5503drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);5504}55055506if (drrb->drr_magic != DMU_BACKUP_MAGIC || drr.drr_type != DRR_BEGIN) {5507zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "5508"stream (bad magic number)"));5509return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));5510}55115512featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);5513hdrtype = DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo);55145515if (!DMU_STREAM_SUPPORTED(featureflags) ||5516(hdrtype != DMU_SUBSTREAM && hdrtype != DMU_COMPOUNDSTREAM)) {5517/*5518* Let's be explicit about this one, since rather than5519* being a new feature we can't know, it's an old5520* feature we dropped.5521*/5522if (featureflags & DMU_BACKUP_FEATURE_DEDUP) {5523zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5524"stream has deprecated feature: dedup, try "5525"'zstream redup [send in a file] | zfs recv "5526"[...]'"));5527} else {5528zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,5529"stream has unsupported feature, feature flags = "5530"%llx (unknown flags = %llx)"),5531(u_longlong_t)featureflags,5532(u_longlong_t)((featureflags) &5533~DMU_BACKUP_FEATURE_MASK));5534}5535return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));5536}55375538/* Holds feature is set once in the compound stream header. */5539if (featureflags & DMU_BACKUP_FEATURE_HOLDS)5540flags->holds = B_TRUE;55415542if (strchr(drrb->drr_toname, '@') == NULL) {5543zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "5544"stream (bad snapshot name)"));5545return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));5546}55475548if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {5549char nonpackage_sendfs[ZFS_MAX_DATASET_NAME_LEN];5550if (sendfs == NULL) {5551/*5552* We were not called from zfs_receive_package(). Get5553* the fs specified by 'zfs send'.5554*/5555char *cp;5556(void) strlcpy(nonpackage_sendfs,5557drr.drr_u.drr_begin.drr_toname,5558sizeof (nonpackage_sendfs));5559if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)5560*cp = '\0';5561sendfs = nonpackage_sendfs;5562VERIFY0P(finalsnap);5563}5564return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,5565&drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,5566finalsnap, cmdprops));5567} else {5568assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==5569DMU_COMPOUNDSTREAM);5570return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,5571&zcksum, top_zfs, cmdprops));5572}5573}55745575/*5576* Restores a backup of tosnap from the file descriptor specified by infd.5577* Return 0 on total success, -2 if some things couldn't be5578* destroyed/renamed/promoted, -1 if some things couldn't be received.5579* (-1 will override -2, if -1 and the resumable flag was specified the5580* transfer can be resumed if the sending side supports it).5581*/5582int5583zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,5584recvflags_t *flags, int infd, avl_tree_t *stream_avl)5585{5586char *top_zfs = NULL;5587int err;5588struct stat sb;5589const char *originsnap = NULL;55905591/*5592* The only way fstat can fail is if we do not have a valid file5593* descriptor.5594*/5595if (fstat(infd, &sb) == -1) {5596perror("fstat");5597return (-2);5598}55995600if (props) {5601err = nvlist_lookup_string(props, "origin", &originsnap);5602if (err && err != ENOENT)5603return (err);5604}56055606err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,5607stream_avl, &top_zfs, NULL, props);56085609if (err == 0 && !flags->nomount && flags->domount && top_zfs) {5610zfs_handle_t *zhp = NULL;5611prop_changelist_t *clp = NULL;56125613zhp = zfs_open(hdl, top_zfs,5614ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);5615if (zhp == NULL) {5616err = -1;5617goto out;5618} else {5619if (zhp->zfs_type == ZFS_TYPE_VOLUME) {5620zfs_close(zhp);5621goto out;5622}56235624clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,5625CL_GATHER_MOUNT_ALWAYS,5626flags->forceunmount ? MS_FORCE : 0);5627zfs_close(zhp);5628if (clp == NULL) {5629err = -1;5630goto out;5631}56325633/* mount and share received datasets */5634err = changelist_postfix(clp);5635changelist_free(clp);5636if (err != 0)5637err = -1;5638}5639}56405641out:5642if (top_zfs)5643free(top_zfs);56445645return (err);5646}564756485649