1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * 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.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  25  * Copyright (c) 2014 by Delphix. All rights reserved.
  26  * Copyright 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  27  */
  28 
  29 /*
  30  * System includes
  31  */
  32 
  33 #include <assert.h>
  34 #include <ctype.h>
  35 #include <errno.h>
  36 #include <libgen.h>
  37 #include <libintl.h>
  38 #include <libnvpair.h>
  39 #include <libzfs.h>
  40 #include <stdio.h>
  41 #include <stdlib.h>
  42 #include <string.h>
  43 #include <sys/mnttab.h>
  44 #include <sys/mount.h>
  45 #include <sys/stat.h>
  46 #include <sys/types.h>
  47 #include <sys/wait.h>
  48 #include <unistd.h>
  49 
  50 #include <libbe.h>
  51 #include <libbe_priv.h>
  52 
  53 /* Library wide variables */
  54 libzfs_handle_t *g_zfs = NULL;
  55 
  56 /* Private function prototypes */
  57 static int _be_destroy(const char *, be_destroy_data_t *);
  58 static int be_destroy_zones(char *, char *, be_destroy_data_t *);
  59 static int be_destroy_zone_roots(char *, be_destroy_data_t *);
  60 static int be_destroy_zone_roots_callback(zfs_handle_t *, void *);
  61 static int be_copy_zones(char *, char *, char *);
  62 static int be_clone_fs_callback(zfs_handle_t *, void *);
  63 static int be_destroy_callback(zfs_handle_t *, void *);
  64 static int be_send_fs_callback(zfs_handle_t *, void *);
  65 static int be_demote_callback(zfs_handle_t *, void *);
  66 static int be_demote_find_clone_callback(zfs_handle_t *, void *);
  67 static int be_has_snapshot_callback(zfs_handle_t *, void *);
  68 static int be_demote_get_one_clone(zfs_handle_t *, void *);
  69 static int be_get_snap(char *, char **);
  70 static int be_prep_clone_send_fs(zfs_handle_t *, be_transaction_data_t *,
  71     char *, int);
  72 static boolean_t be_create_container_ds(char *);
  73 static char *be_get_zone_be_name(char *root_ds, char *container_ds);
  74 static int be_zone_root_exists_callback(zfs_handle_t *, void *);
  75 
  76 /* ******************************************************************** */
  77 /*                      Public Functions                                */
  78 /* ******************************************************************** */
  79 
  80 /*
  81  * Function:    be_init
  82  * Description: Creates the initial datasets for a BE and leaves them
  83  *              unpopulated.  The resultant BE can be mounted but can't
  84  *              yet be activated or booted.
  85  * Parameters:
  86  *              be_attrs - pointer to nvlist_t of attributes being passed in.
  87  *                      The following attributes are used by this function:
  88  *
  89  *                      BE_ATTR_NEW_BE_NAME             *required
  90  *                      BE_ATTR_NEW_BE_POOL             *required
  91  *                      BE_ATTR_ZFS_PROPERTIES          *optional
  92  *                      BE_ATTR_FS_NAMES                *optional
  93  *                      BE_ATTR_FS_NUM                  *optional
  94  *                      BE_ATTR_SHARED_FS_NAMES         *optional
  95  *                      BE_ATTR_SHARED_FS_NUM           *optional
  96  * Return:
  97  *              BE_SUCCESS - Success
  98  *              be_errno_t - Failure
  99  * Scope:
 100  *              Public
 101  */
 102 int
 103 be_init(nvlist_t *be_attrs)
 104 {
 105         be_transaction_data_t   bt = { 0 };
 106         zpool_handle_t  *zlp;
 107         nvlist_t        *zfs_props = NULL;
 108         char            nbe_root_ds[MAXPATHLEN];
 109         char            child_fs[MAXPATHLEN];
 110         char            **fs_names = NULL;
 111         char            **shared_fs_names = NULL;
 112         uint16_t        fs_num = 0;
 113         uint16_t        shared_fs_num = 0;
 114         int             nelem;
 115         int             i;
 116         int             zret = 0, ret = BE_SUCCESS;
 117 
 118         /* Initialize libzfs handle */
 119         if (!be_zfs_init())
 120                 return (BE_ERR_INIT);
 121 
 122         /* Get new BE name */
 123         if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, &bt.nbe_name)
 124             != 0) {
 125                 be_print_err(gettext("be_init: failed to lookup "
 126                     "BE_ATTR_NEW_BE_NAME attribute\n"));
 127                 return (BE_ERR_INVAL);
 128         }
 129 
 130         /* Validate new BE name */
 131         if (!be_valid_be_name(bt.nbe_name)) {
 132                 be_print_err(gettext("be_init: invalid BE name %s\n"),
 133                     bt.nbe_name);
 134                 return (BE_ERR_INVAL);
 135         }
 136 
 137         /* Get zpool name */
 138         if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_POOL, &bt.nbe_zpool)
 139             != 0) {
 140                 be_print_err(gettext("be_init: failed to lookup "
 141                     "BE_ATTR_NEW_BE_POOL attribute\n"));
 142                 return (BE_ERR_INVAL);
 143         }
 144 
 145         /* Get file system attributes */
 146         nelem = 0;
 147         if (nvlist_lookup_pairs(be_attrs, 0,
 148             BE_ATTR_FS_NUM, DATA_TYPE_UINT16, &fs_num,
 149             BE_ATTR_FS_NAMES, DATA_TYPE_STRING_ARRAY, &fs_names, &nelem,
 150             NULL) != 0) {
 151                 be_print_err(gettext("be_init: failed to lookup fs "
 152                     "attributes\n"));
 153                 return (BE_ERR_INVAL);
 154         }
 155         if (nelem != fs_num) {
 156                 be_print_err(gettext("be_init: size of FS_NAMES array (%d) "
 157                     "does not match FS_NUM (%d)\n"), nelem, fs_num);
 158                 return (BE_ERR_INVAL);
 159         }
 160 
 161         /* Get shared file system attributes */
 162         nelem = 0;
 163         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 164             BE_ATTR_SHARED_FS_NUM, DATA_TYPE_UINT16, &shared_fs_num,
 165             BE_ATTR_SHARED_FS_NAMES, DATA_TYPE_STRING_ARRAY, &shared_fs_names,
 166             &nelem, NULL) != 0) {
 167                 be_print_err(gettext("be_init: failed to lookup "
 168                     "shared fs attributes\n"));
 169                 return (BE_ERR_INVAL);
 170         }
 171         if (nelem != shared_fs_num) {
 172                 be_print_err(gettext("be_init: size of SHARED_FS_NAMES "
 173                     "array does not match SHARED_FS_NUM\n"));
 174                 return (BE_ERR_INVAL);
 175         }
 176 
 177         /* Verify that nbe_zpool exists */
 178         if ((zlp = zpool_open(g_zfs, bt.nbe_zpool)) == NULL) {
 179                 be_print_err(gettext("be_init: failed to "
 180                     "find existing zpool (%s): %s\n"), bt.nbe_zpool,
 181                     libzfs_error_description(g_zfs));
 182                 return (zfs_err_to_be_err(g_zfs));
 183         }
 184         zpool_close(zlp);
 185 
 186         /*
 187          * Verify BE container dataset in nbe_zpool exists.
 188          * If not, create it.
 189          */
 190         if (!be_create_container_ds(bt.nbe_zpool))
 191                 return (BE_ERR_CREATDS);
 192 
 193         /*
 194          * Verify that nbe_name doesn't already exist in some pool.
 195          */
 196         if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name)) > 0) {
 197                 be_print_err(gettext("be_init: BE (%s) already exists\n"),
 198                     bt.nbe_name);
 199                 return (BE_ERR_BE_EXISTS);
 200         } else if (zret < 0) {
 201                 be_print_err(gettext("be_init: zpool_iter failed: %s\n"),
 202                     libzfs_error_description(g_zfs));
 203                 return (zfs_err_to_be_err(g_zfs));
 204         }
 205 
 206         /* Generate string for BE's root dataset */
 207         be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
 208             sizeof (nbe_root_ds));
 209 
 210         /*
 211          * Create property list for new BE root dataset.  If some
 212          * zfs properties were already provided by the caller, dup
 213          * that list.  Otherwise initialize a new property list.
 214          */
 215         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 216             BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
 217             != 0) {
 218                 be_print_err(gettext("be_init: failed to lookup "
 219                     "BE_ATTR_ZFS_PROPERTIES attribute\n"));
 220                 return (BE_ERR_INVAL);
 221         }
 222         if (zfs_props != NULL) {
 223                 /* Make sure its a unique nvlist */
 224                 if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
 225                     !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
 226                         be_print_err(gettext("be_init: ZFS property list "
 227                             "not unique\n"));
 228                         return (BE_ERR_INVAL);
 229                 }
 230 
 231                 /* Dup the list */
 232                 if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
 233                         be_print_err(gettext("be_init: failed to dup ZFS "
 234                             "property list\n"));
 235                         return (BE_ERR_NOMEM);
 236                 }
 237         } else {
 238                 /* Initialize new nvlist */
 239                 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
 240                         be_print_err(gettext("be_init: internal "
 241                             "error: out of memory\n"));
 242                         return (BE_ERR_NOMEM);
 243                 }
 244         }
 245 
 246         /* Set the mountpoint property for the root dataset */
 247         if (nvlist_add_string(bt.nbe_zfs_props,
 248             zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), "/") != 0) {
 249                 be_print_err(gettext("be_init: internal error "
 250                     "out of memory\n"));
 251                 ret = BE_ERR_NOMEM;
 252                 goto done;
 253         }
 254 
 255         /* Set the 'canmount' property */
 256         if (nvlist_add_string(bt.nbe_zfs_props,
 257             zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
 258                 be_print_err(gettext("be_init: internal error "
 259                     "out of memory\n"));
 260                 ret = BE_ERR_NOMEM;
 261                 goto done;
 262         }
 263 
 264         /* Create BE root dataset for the new BE */
 265         if (zfs_create(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM,
 266             bt.nbe_zfs_props) != 0) {
 267                 be_print_err(gettext("be_init: failed to "
 268                     "create BE root dataset (%s): %s\n"), nbe_root_ds,
 269                     libzfs_error_description(g_zfs));
 270                 ret = zfs_err_to_be_err(g_zfs);
 271                 goto done;
 272         }
 273 
 274         /* Set UUID for new BE */
 275         if ((ret = be_set_uuid(nbe_root_ds)) != BE_SUCCESS) {
 276                 be_print_err(gettext("be_init: failed to "
 277                     "set uuid for new BE\n"));
 278         }
 279 
 280         /*
 281          * Clear the mountpoint property so that the non-shared
 282          * file systems created below inherit their mountpoints.
 283          */
 284         (void) nvlist_remove(bt.nbe_zfs_props,
 285             zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), DATA_TYPE_STRING);
 286 
 287         /* Create the new BE's non-shared file systems */
 288         for (i = 0; i < fs_num && fs_names[i]; i++) {
 289                 /*
 290                  * If fs == "/", skip it;
 291                  * we already created the root dataset
 292                  */
 293                 if (strcmp(fs_names[i], "/") == 0)
 294                         continue;
 295 
 296                 /* Generate string for file system */
 297                 (void) snprintf(child_fs, sizeof (child_fs), "%s%s",
 298                     nbe_root_ds, fs_names[i]);
 299 
 300                 /* Create file system */
 301                 if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
 302                     bt.nbe_zfs_props) != 0) {
 303                         be_print_err(gettext("be_init: failed to create "
 304                             "BE's child dataset (%s): %s\n"), child_fs,
 305                             libzfs_error_description(g_zfs));
 306                         ret = zfs_err_to_be_err(g_zfs);
 307                         goto done;
 308                 }
 309         }
 310 
 311         /* Create the new BE's shared file systems */
 312         if (shared_fs_num > 0) {
 313                 nvlist_t        *props = NULL;
 314 
 315                 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
 316                         be_print_err(gettext("be_init: nvlist_alloc failed\n"));
 317                         ret = BE_ERR_NOMEM;
 318                         goto done;
 319                 }
 320 
 321                 for (i = 0; i < shared_fs_num; i++) {
 322                         /* Generate string for shared file system */
 323                         (void) snprintf(child_fs, sizeof (child_fs), "%s%s",
 324                             bt.nbe_zpool, shared_fs_names[i]);
 325 
 326                         if (nvlist_add_string(props,
 327                             zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
 328                             shared_fs_names[i]) != 0) {
 329                                 be_print_err(gettext("be_init: "
 330                                     "internal error: out of memory\n"));
 331                                 nvlist_free(props);
 332                                 ret = BE_ERR_NOMEM;
 333                                 goto done;
 334                         }
 335 
 336                         /* Create file system if it doesn't already exist */
 337                         if (zfs_dataset_exists(g_zfs, child_fs,
 338                             ZFS_TYPE_FILESYSTEM)) {
 339                                 continue;
 340                         }
 341                         if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
 342                             props) != 0) {
 343                                 be_print_err(gettext("be_init: failed to "
 344                                     "create BE's shared dataset (%s): %s\n"),
 345                                     child_fs, libzfs_error_description(g_zfs));
 346                                 ret = zfs_err_to_be_err(g_zfs);
 347                                 nvlist_free(props);
 348                                 goto done;
 349                         }
 350                 }
 351 
 352                 nvlist_free(props);
 353         }
 354 
 355 done:
 356         if (bt.nbe_zfs_props != NULL)
 357                 nvlist_free(bt.nbe_zfs_props);
 358 
 359         be_zfs_fini();
 360 
 361         return (ret);
 362 }
 363 
 364 /*
 365  * Function:    be_destroy
 366  * Description: Destroy a BE and all of its children datasets, snapshots and
 367  *              zones that belong to the parent BE.
 368  * Parameters:
 369  *              be_attrs - pointer to nvlist_t of attributes being passed in.
 370  *                      The following attributes are used by this function:
 371  *
 372  *                      BE_ATTR_ORIG_BE_NAME            *required
 373  *                      BE_ATTR_DESTROY_FLAGS           *optional
 374  * Return:
 375  *              BE_SUCCESS - Success
 376  *              be_errno_t - Failure
 377  * Scope:
 378  *              Public
 379  */
 380 int
 381 be_destroy(nvlist_t *be_attrs)
 382 {
 383         zfs_handle_t            *zhp = NULL;
 384         be_transaction_data_t   bt = { 0 };
 385         be_transaction_data_t   cur_bt = { 0 };
 386         be_destroy_data_t       dd = { 0 };
 387         int                     ret = BE_SUCCESS;
 388         uint16_t                flags = 0;
 389         boolean_t               bs_found = B_FALSE;
 390         int                     zret;
 391         char                    obe_root_ds[MAXPATHLEN];
 392         char                    *mp = NULL;
 393 
 394         /* Initialize libzfs handle */
 395         if (!be_zfs_init())
 396                 return (BE_ERR_INIT);
 397 
 398         /* Get name of BE to delete */
 399         if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &bt.obe_name)
 400             != 0) {
 401                 be_print_err(gettext("be_destroy: failed to lookup "
 402                     "BE_ATTR_ORIG_BE_NAME attribute\n"));
 403                 return (BE_ERR_INVAL);
 404         }
 405 
 406         /*
 407          * Validate BE name. If valid, then check that the original BE is not
 408          * the active BE. If it is the 'active' BE then return an error code
 409          * since we can't destroy the active BE.
 410          */
 411         if (!be_valid_be_name(bt.obe_name)) {
 412                 be_print_err(gettext("be_destroy: invalid BE name %s\n"),
 413                     bt.obe_name);
 414                 return (BE_ERR_INVAL);
 415         } else if (bt.obe_name != NULL) {
 416                 if ((ret = be_find_current_be(&cur_bt)) != BE_SUCCESS) {
 417                         return (ret);
 418                 }
 419                 if (strcmp(cur_bt.obe_name, bt.obe_name) == 0) {
 420                         return (BE_ERR_DESTROY_CURR_BE);
 421                 }
 422         }
 423 
 424         /* Get destroy flags if provided */
 425         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 426             BE_ATTR_DESTROY_FLAGS, DATA_TYPE_UINT16, &flags, NULL)
 427             != 0) {
 428                 be_print_err(gettext("be_destroy: failed to lookup "
 429                     "BE_ATTR_DESTROY_FLAGS attribute\n"));
 430                 return (BE_ERR_INVAL);
 431         }
 432 
 433         dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
 434         dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
 435 
 436         /* Find which zpool obe_name lives in */
 437         if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
 438                 be_print_err(gettext("be_destroy: failed to find zpool "
 439                     "for BE (%s)\n"), bt.obe_name);
 440                 return (BE_ERR_BE_NOENT);
 441         } else if (zret < 0) {
 442                 be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"),
 443                     libzfs_error_description(g_zfs));
 444                 return (zfs_err_to_be_err(g_zfs));
 445         }
 446 
 447         /* Generate string for obe_name's root dataset */
 448         be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
 449             sizeof (obe_root_ds));
 450         bt.obe_root_ds = obe_root_ds;
 451 
 452         if (getzoneid() != GLOBAL_ZONEID) {
 453                 if (!be_zone_compare_uuids(bt.obe_root_ds)) {
 454                         if (be_is_active_on_boot(bt.obe_name)) {
 455                                 be_print_err(gettext("be_destroy: destroying "
 456                                     "active zone root dataset from non-active "
 457                                     "global BE is not supported\n"));
 458                                 return (BE_ERR_NOTSUP);
 459                         }
 460                 }
 461         }
 462 
 463         /*
 464          * Detect if the BE to destroy has the 'active on boot' property set.
 465          * If so, set the 'active on boot' property on the the 'active' BE.
 466          */
 467         if (be_is_active_on_boot(bt.obe_name)) {
 468                 if ((ret = be_activate_current_be()) != BE_SUCCESS) {
 469                         be_print_err(gettext("be_destroy: failed to "
 470                             "make the current BE 'active on boot'\n"));
 471                         return (ret);
 472                 }
 473         }
 474 
 475         /* Get handle to BE's root dataset */
 476         if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
 477             NULL) {
 478                 be_print_err(gettext("be_destroy: failed to "
 479                     "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
 480                     libzfs_error_description(g_zfs));
 481                 return (zfs_err_to_be_err(g_zfs));
 482         }
 483 
 484         /*
 485          * Check if BE has snapshots and BE_DESTROY_FLAG_SNAPSHOTS
 486          * is not set.
 487          */
 488         (void) zfs_iter_snapshots(zhp, be_has_snapshot_callback, &bs_found);
 489         if (!dd.destroy_snaps && bs_found) {
 490                 ZFS_CLOSE(zhp);
 491                 return (BE_ERR_SS_EXISTS);
 492         }
 493 
 494         /* Get the UUID of the global BE */
 495         if (getzoneid() == GLOBAL_ZONEID) {
 496                 if (be_get_uuid(zfs_get_name(zhp),
 497                     &dd.gz_be_uuid) != BE_SUCCESS) {
 498                         be_print_err(gettext("be_destroy: BE has no "
 499                         "UUID (%s)\n"), zfs_get_name(zhp));
 500                 }
 501         }
 502 
 503         /*
 504          * If the global BE is mounted, make sure we've been given the
 505          * flag to forcibly unmount it.
 506          */
 507         if (zfs_is_mounted(zhp, &mp)) {
 508                 if (!(dd.force_unmount)) {
 509                         be_print_err(gettext("be_destroy: "
 510                             "%s is currently mounted at %s, cannot destroy\n"),
 511                             bt.obe_name, mp != NULL ? mp : "<unknown>");
 512 
 513                         free(mp);
 514                         ZFS_CLOSE(zhp);
 515                         return (BE_ERR_MOUNTED);
 516                 }
 517                 free(mp);
 518         }
 519 
 520         /*
 521          * Destroy the non-global zone BE's if we are in the global zone
 522          * and there is a UUID associated with the global zone BE
 523          */
 524         if (getzoneid() == GLOBAL_ZONEID && !uuid_is_null(dd.gz_be_uuid)) {
 525                 if ((ret = be_destroy_zones(bt.obe_name, bt.obe_root_ds, &dd))
 526                     != BE_SUCCESS) {
 527                         be_print_err(gettext("be_destroy: failed to "
 528                             "destroy one or more zones for BE %s\n"),
 529                             bt.obe_name);
 530                         goto done;
 531                 }
 532         }
 533 
 534         /* Unmount the BE if it was mounted */
 535         if (zfs_is_mounted(zhp, NULL)) {
 536                 if ((ret = _be_unmount(bt.obe_name, BE_UNMOUNT_FLAG_FORCE))
 537                     != BE_SUCCESS) {
 538                         be_print_err(gettext("be_destroy: "
 539                             "failed to unmount %s\n"), bt.obe_name);
 540                         ZFS_CLOSE(zhp);
 541                         return (ret);
 542                 }
 543         }
 544         ZFS_CLOSE(zhp);
 545 
 546         /* Destroy this BE */
 547         if ((ret = _be_destroy((const char *)bt.obe_root_ds, &dd))
 548             != BE_SUCCESS) {
 549                 goto done;
 550         }
 551 
 552         /* Remove BE's entry from the boot menu */
 553         if (getzoneid() == GLOBAL_ZONEID) {
 554                 if ((ret = be_remove_menu(bt.obe_name, bt.obe_zpool, NULL))
 555                     != BE_SUCCESS) {
 556                         be_print_err(gettext("be_destroy: failed to "
 557                             "remove BE %s from the boot menu\n"),
 558                             bt.obe_root_ds);
 559                         goto done;
 560                 }
 561         }
 562 
 563 done:
 564         be_zfs_fini();
 565 
 566         return (ret);
 567 }
 568 
 569 /*
 570  * Function:    be_copy
 571  * Description: This function makes a copy of an existing BE.  If the original
 572  *              BE and the new BE are in the same pool, it uses zfs cloning to
 573  *              create the new BE, otherwise it does a physical copy.
 574  *              If the original BE name isn't provided, it uses the currently
 575  *              booted BE.  If the new BE name isn't provided, it creates an
 576  *              auto named BE and returns that name to the caller.
 577  * Parameters:
 578  *              be_attrs - pointer to nvlist_t of attributes being passed in.
 579  *                      The following attributes are used by this function:
 580  *
 581  *                      BE_ATTR_ORIG_BE_NAME            *optional
 582  *                      BE_ATTR_SNAP_NAME               *optional
 583  *                      BE_ATTR_NEW_BE_NAME             *optional
 584  *                      BE_ATTR_NEW_BE_POOL             *optional
 585  *                      BE_ATTR_NEW_BE_DESC             *optional
 586  *                      BE_ATTR_ZFS_PROPERTIES          *optional
 587  *                      BE_ATTR_POLICY                  *optional
 588  *
 589  *                      If the BE_ATTR_NEW_BE_NAME was not passed in, upon
 590  *                      successful BE creation, the following attribute values
 591  *                      will be returned to the caller by setting them in the
 592  *                      be_attrs parameter passed in:
 593  *
 594  *                      BE_ATTR_SNAP_NAME
 595  *                      BE_ATTR_NEW_BE_NAME
 596  * Return:
 597  *              BE_SUCCESS - Success
 598  *              be_errno_t - Failure
 599  * Scope:
 600  *              Public
 601  */
 602 int
 603 be_copy(nvlist_t *be_attrs)
 604 {
 605         be_transaction_data_t   bt = { 0 };
 606         be_fs_list_data_t       fld = { 0 };
 607         zfs_handle_t    *zhp = NULL;
 608         zpool_handle_t  *zphp = NULL;
 609         nvlist_t        *zfs_props = NULL;
 610         uuid_t          uu = { 0 };
 611         uuid_t          parent_uu = { 0 };
 612         char            obe_root_ds[MAXPATHLEN];
 613         char            nbe_root_ds[MAXPATHLEN];
 614         char            ss[MAXPATHLEN];
 615         char            *new_mp = NULL;
 616         char            *obe_name = NULL;
 617         boolean_t       autoname = B_FALSE;
 618         boolean_t       be_created = B_FALSE;
 619         int             i;
 620         int             zret;
 621         int             ret = BE_SUCCESS;
 622         struct be_defaults be_defaults;
 623 
 624         /* Initialize libzfs handle */
 625         if (!be_zfs_init())
 626                 return (BE_ERR_INIT);
 627 
 628         /* Get original BE name */
 629         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 630             BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
 631                 be_print_err(gettext("be_copy: failed to lookup "
 632                     "BE_ATTR_ORIG_BE_NAME attribute\n"));
 633                 return (BE_ERR_INVAL);
 634         }
 635 
 636         if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
 637                 return (ret);
 638         }
 639 
 640         be_get_defaults(&be_defaults);
 641 
 642         /* If original BE name not provided, use current BE */
 643         if (obe_name != NULL) {
 644                 bt.obe_name = obe_name;
 645                 /* Validate original BE name */
 646                 if (!be_valid_be_name(bt.obe_name)) {
 647                         be_print_err(gettext("be_copy: "
 648                             "invalid BE name %s\n"), bt.obe_name);
 649                         return (BE_ERR_INVAL);
 650                 }
 651         }
 652 
 653         if (be_defaults.be_deflt_rpool_container) {
 654                 if ((zphp = zpool_open(g_zfs, bt.obe_zpool)) == NULL) {
 655                         be_print_err(gettext("be_get_node_data: failed to "
 656                             "open rpool (%s): %s\n"), bt.obe_zpool,
 657                             libzfs_error_description(g_zfs));
 658                         return (zfs_err_to_be_err(g_zfs));
 659                 }
 660                 if (be_find_zpool_callback(zphp, &bt) == 0) {
 661                         return (BE_ERR_BE_NOENT);
 662                 }
 663         } else {
 664                 /* Find which zpool obe_name lives in */
 665                 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) ==
 666                     0) {
 667                         be_print_err(gettext("be_copy: failed to "
 668                             "find zpool for BE (%s)\n"), bt.obe_name);
 669                         return (BE_ERR_BE_NOENT);
 670                 } else if (zret < 0) {
 671                         be_print_err(gettext("be_copy: "
 672                             "zpool_iter failed: %s\n"),
 673                             libzfs_error_description(g_zfs));
 674                         return (zfs_err_to_be_err(g_zfs));
 675                 }
 676         }
 677 
 678         /* Get snapshot name of original BE if one was provided */
 679         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 680             BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &bt.obe_snap_name, NULL)
 681             != 0) {
 682                 be_print_err(gettext("be_copy: failed to lookup "
 683                     "BE_ATTR_SNAP_NAME attribute\n"));
 684                 return (BE_ERR_INVAL);
 685         }
 686 
 687         /* Get new BE name */
 688         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 689             BE_ATTR_NEW_BE_NAME, DATA_TYPE_STRING, &bt.nbe_name, NULL)
 690             != 0) {
 691                 be_print_err(gettext("be_copy: failed to lookup "
 692                     "BE_ATTR_NEW_BE_NAME attribute\n"));
 693                 return (BE_ERR_INVAL);
 694         }
 695 
 696         /* Get zpool name to create new BE in */
 697         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 698             BE_ATTR_NEW_BE_POOL, DATA_TYPE_STRING, &bt.nbe_zpool, NULL) != 0) {
 699                 be_print_err(gettext("be_copy: failed to lookup "
 700                     "BE_ATTR_NEW_BE_POOL attribute\n"));
 701                 return (BE_ERR_INVAL);
 702         }
 703 
 704         /* Get new BE's description if one was provided */
 705         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 706             BE_ATTR_NEW_BE_DESC, DATA_TYPE_STRING, &bt.nbe_desc, NULL) != 0) {
 707                 be_print_err(gettext("be_copy: failed to lookup "
 708                     "BE_ATTR_NEW_BE_DESC attribute\n"));
 709                 return (BE_ERR_INVAL);
 710         }
 711 
 712         /* Get BE policy to create this snapshot under */
 713         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 714             BE_ATTR_POLICY, DATA_TYPE_STRING, &bt.policy, NULL) != 0) {
 715                 be_print_err(gettext("be_copy: failed to lookup "
 716                     "BE_ATTR_POLICY attribute\n"));
 717                 return (BE_ERR_INVAL);
 718         }
 719 
 720         /*
 721          * Create property list for new BE root dataset.  If some
 722          * zfs properties were already provided by the caller, dup
 723          * that list.  Otherwise initialize a new property list.
 724          */
 725         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 726             BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
 727             != 0) {
 728                 be_print_err(gettext("be_copy: failed to lookup "
 729                     "BE_ATTR_ZFS_PROPERTIES attribute\n"));
 730                 return (BE_ERR_INVAL);
 731         }
 732         if (zfs_props != NULL) {
 733                 /* Make sure its a unique nvlist */
 734                 if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
 735                     !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
 736                         be_print_err(gettext("be_copy: ZFS property list "
 737                             "not unique\n"));
 738                         return (BE_ERR_INVAL);
 739                 }
 740 
 741                 /* Dup the list */
 742                 if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
 743                         be_print_err(gettext("be_copy: "
 744                             "failed to dup ZFS property list\n"));
 745                         return (BE_ERR_NOMEM);
 746                 }
 747         } else {
 748                 /* Initialize new nvlist */
 749                 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
 750                         be_print_err(gettext("be_copy: internal "
 751                             "error: out of memory\n"));
 752                         return (BE_ERR_NOMEM);
 753                 }
 754         }
 755 
 756         /*
 757          * If new BE name provided, validate the BE name and then verify
 758          * that new BE name doesn't already exist in some pool.
 759          */
 760         if (bt.nbe_name) {
 761                 /* Validate original BE name */
 762                 if (!be_valid_be_name(bt.nbe_name)) {
 763                         be_print_err(gettext("be_copy: "
 764                             "invalid BE name %s\n"), bt.nbe_name);
 765                         ret = BE_ERR_INVAL;
 766                         goto done;
 767                 }
 768 
 769                 /* Verify it doesn't already exist */
 770                 if (getzoneid() == GLOBAL_ZONEID) {
 771                         if ((zret = zpool_iter(g_zfs, be_exists_callback,
 772                             bt.nbe_name)) > 0) {
 773                                 be_print_err(gettext("be_copy: BE (%s) already "
 774                                     "exists\n"), bt.nbe_name);
 775                                 ret = BE_ERR_BE_EXISTS;
 776                                 goto done;
 777                         } else if (zret < 0) {
 778                                 be_print_err(gettext("be_copy: zpool_iter "
 779                                     "failed: %s\n"),
 780                                     libzfs_error_description(g_zfs));
 781                                 ret = zfs_err_to_be_err(g_zfs);
 782                                 goto done;
 783                         }
 784                 } else {
 785                         be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
 786                             sizeof (nbe_root_ds));
 787                         if (zfs_dataset_exists(g_zfs, nbe_root_ds,
 788                             ZFS_TYPE_FILESYSTEM)) {
 789                                 be_print_err(gettext("be_copy: BE (%s) already "
 790                                     "exists\n"), bt.nbe_name);
 791                                 ret = BE_ERR_BE_EXISTS;
 792                                 goto done;
 793                         }
 794                 }
 795         } else {
 796                 /*
 797                  * If an auto named BE is desired, it must be in the same
 798                  * pool is the original BE.
 799                  */
 800                 if (bt.nbe_zpool != NULL) {
 801                         be_print_err(gettext("be_copy: cannot specify pool "
 802                             "name when creating an auto named BE\n"));
 803                         ret = BE_ERR_INVAL;
 804                         goto done;
 805                 }
 806 
 807                 /*
 808                  * Generate auto named BE
 809                  */
 810                 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
 811                     == NULL) {
 812                         be_print_err(gettext("be_copy: "
 813                             "failed to generate auto BE name\n"));
 814                         ret = BE_ERR_AUTONAME;
 815                         goto done;
 816                 }
 817 
 818                 autoname = B_TRUE;
 819         }
 820 
 821         /*
 822          * If zpool name to create new BE in is not provided,
 823          * create new BE in original BE's pool.
 824          */
 825         if (bt.nbe_zpool == NULL) {
 826                 bt.nbe_zpool = bt.obe_zpool;
 827         }
 828 
 829         /* Get root dataset names for obe_name and nbe_name */
 830         be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
 831             sizeof (obe_root_ds));
 832         be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
 833             sizeof (nbe_root_ds));
 834 
 835         bt.obe_root_ds = obe_root_ds;
 836         bt.nbe_root_ds = nbe_root_ds;
 837 
 838         /*
 839          * If an existing snapshot name has been provided to create from,
 840          * verify that it exists for the original BE's root dataset.
 841          */
 842         if (bt.obe_snap_name != NULL) {
 843 
 844                 /* Generate dataset name for snapshot to use. */
 845                 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds,
 846                     bt.obe_snap_name);
 847 
 848                 /* Verify snapshot exists */
 849                 if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) {
 850                         be_print_err(gettext("be_copy: "
 851                             "snapshot does not exist (%s): %s\n"), ss,
 852                             libzfs_error_description(g_zfs));
 853                         ret = BE_ERR_SS_NOENT;
 854                         goto done;
 855                 }
 856         } else {
 857                 /*
 858                  * Else snapshot name was not provided, generate an
 859                  * auto named snapshot to use as its origin.
 860                  */
 861                 if ((ret = _be_create_snapshot(bt.obe_name,
 862                     &bt.obe_snap_name, bt.policy)) != BE_SUCCESS) {
 863                         be_print_err(gettext("be_copy: "
 864                             "failed to create auto named snapshot\n"));
 865                         goto done;
 866                 }
 867 
 868                 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME,
 869                     bt.obe_snap_name) != 0) {
 870                         be_print_err(gettext("be_copy: "
 871                             "failed to add snap name to be_attrs\n"));
 872                         ret = BE_ERR_NOMEM;
 873                         goto done;
 874                 }
 875         }
 876 
 877         /* Get handle to original BE's root dataset. */
 878         if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM))
 879             == NULL) {
 880                 be_print_err(gettext("be_copy: failed to "
 881                     "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
 882                     libzfs_error_description(g_zfs));
 883                 ret = zfs_err_to_be_err(g_zfs);
 884                 goto done;
 885         }
 886 
 887         /* If original BE is currently mounted, record its altroot. */
 888         if (zfs_is_mounted(zhp, &bt.obe_altroot) && bt.obe_altroot == NULL) {
 889                 be_print_err(gettext("be_copy: failed to "
 890                     "get altroot of mounted BE %s: %s\n"),
 891                     bt.obe_name, libzfs_error_description(g_zfs));
 892                 ret = zfs_err_to_be_err(g_zfs);
 893                 goto done;
 894         }
 895 
 896         if (strcmp(bt.obe_zpool, bt.nbe_zpool) == 0) {
 897 
 898                 /* Do clone */
 899 
 900                 /*
 901                  * Iterate through original BE's datasets and clone
 902                  * them to create new BE.  This call will end up closing
 903                  * the zfs handle passed in whether it succeeds for fails.
 904                  */
 905                 if ((ret = be_clone_fs_callback(zhp, &bt)) != 0) {
 906                         zhp = NULL;
 907                         /* Creating clone BE failed */
 908                         if (!autoname || ret != BE_ERR_BE_EXISTS) {
 909                                 be_print_err(gettext("be_copy: "
 910                                     "failed to clone new BE (%s) from "
 911                                     "orig BE (%s)\n"),
 912                                     bt.nbe_name, bt.obe_name);
 913                                 ret = BE_ERR_CLONE;
 914                                 goto done;
 915                         }
 916 
 917                         /*
 918                          * We failed to create the new BE because a BE with
 919                          * the auto-name we generated above has since come
 920                          * into existence.  Regenerate a new auto-name
 921                          * and retry.
 922                          */
 923                         for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) {
 924 
 925                                 /* Sleep 1 before retrying */
 926                                 (void) sleep(1);
 927 
 928                                 /* Generate new auto BE name */
 929                                 free(bt.nbe_name);
 930                                 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
 931                                     == NULL) {
 932                                         be_print_err(gettext("be_copy: "
 933                                             "failed to generate auto "
 934                                             "BE name\n"));
 935                                         ret = BE_ERR_AUTONAME;
 936                                         goto done;
 937                                 }
 938 
 939                                 /*
 940                                  * Regenerate string for new BE's
 941                                  * root dataset name
 942                                  */
 943                                 be_make_root_ds(bt.nbe_zpool, bt.nbe_name,
 944                                     nbe_root_ds, sizeof (nbe_root_ds));
 945                                 bt.nbe_root_ds = nbe_root_ds;
 946 
 947                                 /*
 948                                  * Get handle to original BE's root dataset.
 949                                  */
 950                                 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds,
 951                                     ZFS_TYPE_FILESYSTEM)) == NULL) {
 952                                         be_print_err(gettext("be_copy: "
 953                                             "failed to open BE root dataset "
 954                                             "(%s): %s\n"), bt.obe_root_ds,
 955                                             libzfs_error_description(g_zfs));
 956                                         ret = zfs_err_to_be_err(g_zfs);
 957                                         goto done;
 958                                 }
 959 
 960                                 /*
 961                                  * Try to clone the BE again.  This
 962                                  * call will end up closing the zfs
 963                                  * handle passed in whether it
 964                                  * succeeds or fails.
 965                                  */
 966                                 ret = be_clone_fs_callback(zhp, &bt);
 967                                 zhp = NULL;
 968                                 if (ret == 0) {
 969                                         break;
 970                                 } else if (ret != BE_ERR_BE_EXISTS) {
 971                                         be_print_err(gettext("be_copy: "
 972                                             "failed to clone new BE "
 973                                             "(%s) from orig BE (%s)\n"),
 974                                             bt.nbe_name, bt.obe_name);
 975                                         ret = BE_ERR_CLONE;
 976                                         goto done;
 977                                 }
 978                         }
 979 
 980                         /*
 981                          * If we've exhausted the maximum number of
 982                          * tries, free the auto BE name and return
 983                          * error.
 984                          */
 985                         if (i == BE_AUTO_NAME_MAX_TRY) {
 986                                 be_print_err(gettext("be_copy: failed "
 987                                     "to create unique auto BE name\n"));
 988                                 free(bt.nbe_name);
 989                                 bt.nbe_name = NULL;
 990                                 ret = BE_ERR_AUTONAME;
 991                                 goto done;
 992                         }
 993                 }
 994                 zhp = NULL;
 995 
 996         } else {
 997 
 998                 /* Do copy (i.e. send BE datasets via zfs_send/recv) */
 999 
1000                 /*
1001                  * Verify BE container dataset in nbe_zpool exists.
1002                  * If not, create it.
1003                  */
1004                 if (!be_create_container_ds(bt.nbe_zpool)) {
1005                         ret = BE_ERR_CREATDS;
1006                         goto done;
1007                 }
1008 
1009                 /*
1010                  * Iterate through original BE's datasets and send
1011                  * them to the other pool.  This call will end up closing
1012                  * the zfs handle passed in whether it succeeds or fails.
1013                  */
1014                 if ((ret = be_send_fs_callback(zhp, &bt)) != 0) {
1015                         be_print_err(gettext("be_copy: failed to "
1016                             "send BE (%s) to pool (%s)\n"), bt.obe_name,
1017                             bt.nbe_zpool);
1018                         ret = BE_ERR_COPY;
1019                         zhp = NULL;
1020                         goto done;
1021                 }
1022                 zhp = NULL;
1023         }
1024 
1025         /*
1026          * Set flag to note that the dataset(s) for the new BE have been
1027          * successfully created so that if a failure happens from this point
1028          * on, we know to cleanup these datasets.
1029          */
1030         be_created = B_TRUE;
1031 
1032         /*
1033          * Validate that the new BE is mountable.
1034          * Do not attempt to mount non-global zone datasets
1035          * since they are not cloned yet.
1036          */
1037         if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES))
1038             != BE_SUCCESS) {
1039                 be_print_err(gettext("be_copy: failed to "
1040                     "mount newly created BE\n"));
1041                 (void) _be_unmount(bt.nbe_name, 0);
1042                 goto done;
1043         }
1044 
1045         /* Set UUID for new BE */
1046         if (getzoneid() == GLOBAL_ZONEID) {
1047                 if (be_set_uuid(bt.nbe_root_ds) != BE_SUCCESS) {
1048                         be_print_err(gettext("be_copy: failed to "
1049                             "set uuid for new BE\n"));
1050                 }
1051         } else {
1052                 if ((ret = be_zone_get_parent_uuid(bt.obe_root_ds,
1053                     &parent_uu)) != BE_SUCCESS) {
1054                         be_print_err(gettext("be_copy: failed to get "
1055                             "parentbe uuid from orig BE\n"));
1056                         ret = BE_ERR_ZONE_NO_PARENTBE;
1057                         goto done;
1058                 } else if ((ret = be_zone_set_parent_uuid(bt.nbe_root_ds,
1059                     parent_uu)) != BE_SUCCESS) {
1060                         be_print_err(gettext("be_copy: failed to set "
1061                             "parentbe uuid for newly created BE\n"));
1062                         goto done;
1063                 }
1064         }
1065 
1066         /*
1067          * Process zones outside of the private BE namespace.
1068          * This has to be done here because we need the uuid set in the
1069          * root dataset of the new BE. The uuid is use to set the parentbe
1070          * property for the new zones datasets.
1071          */
1072         if (getzoneid() == GLOBAL_ZONEID &&
1073             be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
1074                 if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds,
1075                     bt.nbe_root_ds)) != BE_SUCCESS) {
1076                         be_print_err(gettext("be_copy: failed to process "
1077                             "zones\n"));
1078                         goto done;
1079                 }
1080         }
1081 
1082         /*
1083          * Generate a list of file systems from the original BE that are
1084          * legacy mounted.  We use this list to determine which entries in
1085          * vfstab we need to update for the new BE we've just created.
1086          */
1087         if ((ret = be_get_legacy_fs(bt.obe_name, bt.obe_root_ds, NULL, NULL,
1088             &fld)) != BE_SUCCESS) {
1089                 be_print_err(gettext("be_copy: failed to "
1090                     "get legacy mounted file system list for %s\n"),
1091                     bt.obe_name);
1092                 goto done;
1093         }
1094 
1095         /*
1096          * Update new BE's vfstab.
1097          */
1098         if ((ret = be_update_vfstab(bt.nbe_name, bt.obe_zpool, bt.nbe_zpool,
1099             &fld, new_mp)) != BE_SUCCESS) {
1100                 be_print_err(gettext("be_copy: failed to "
1101                     "update new BE's vfstab (%s)\n"), bt.nbe_name);
1102                 goto done;
1103         }
1104 
1105         /* Unmount the new BE */
1106         if ((ret = _be_unmount(bt.nbe_name, 0)) != BE_SUCCESS) {
1107                 be_print_err(gettext("be_copy: failed to "
1108                     "unmount newly created BE\n"));
1109                 goto done;
1110         }
1111 
1112         /*
1113          * Add boot menu entry for newly created clone
1114          */
1115         if (getzoneid() == GLOBAL_ZONEID &&
1116             (ret = be_append_menu(bt.nbe_name, bt.nbe_zpool,
1117             NULL, bt.obe_root_ds, bt.nbe_desc)) != BE_SUCCESS) {
1118                 be_print_err(gettext("be_copy: failed to "
1119                     "add BE (%s) to boot menu\n"), bt.nbe_name);
1120                 goto done;
1121         }
1122 
1123         /*
1124          * If we succeeded in creating an auto named BE, set its policy
1125          * type and return the auto generated name to the caller by storing
1126          * it in the nvlist passed in by the caller.
1127          */
1128         if (autoname) {
1129                 /* Get handle to new BE's root dataset. */
1130                 if ((zhp = zfs_open(g_zfs, bt.nbe_root_ds,
1131                     ZFS_TYPE_FILESYSTEM)) == NULL) {
1132                         be_print_err(gettext("be_copy: failed to "
1133                             "open BE root dataset (%s): %s\n"), bt.nbe_root_ds,
1134                             libzfs_error_description(g_zfs));
1135                         ret = zfs_err_to_be_err(g_zfs);
1136                         goto done;
1137                 }
1138 
1139                 /*
1140                  * Set the policy type property into the new BE's root dataset
1141                  */
1142                 if (bt.policy == NULL) {
1143                         /* If no policy type provided, use default type */
1144                         bt.policy = be_default_policy();
1145                 }
1146 
1147                 if (zfs_prop_set(zhp, BE_POLICY_PROPERTY, bt.policy) != 0) {
1148                         be_print_err(gettext("be_copy: failed to "
1149                             "set BE policy for %s: %s\n"), bt.nbe_name,
1150                             libzfs_error_description(g_zfs));
1151                         ret = zfs_err_to_be_err(g_zfs);
1152                         goto done;
1153                 }
1154 
1155                 /*
1156                  * Return the auto generated name to the caller
1157                  */
1158                 if (bt.nbe_name) {
1159                         if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME,
1160                             bt.nbe_name) != 0) {
1161                                 be_print_err(gettext("be_copy: failed to "
1162                                     "add snap name to be_attrs\n"));
1163                         }
1164                 }
1165         }
1166 
1167 done:
1168         ZFS_CLOSE(zhp);
1169         be_free_fs_list(&fld);
1170 
1171         if (bt.nbe_zfs_props != NULL)
1172                 nvlist_free(bt.nbe_zfs_props);
1173 
1174         free(bt.obe_altroot);
1175         free(new_mp);
1176 
1177         /*
1178          * If a failure occurred and we already created the datasets for
1179          * the new boot environment, destroy them.
1180          */
1181         if (ret != BE_SUCCESS && be_created) {
1182                 be_destroy_data_t       cdd = { 0 };
1183 
1184                 cdd.force_unmount = B_TRUE;
1185 
1186                 be_print_err(gettext("be_copy: "
1187                     "destroying partially created boot environment\n"));
1188 
1189                 if (getzoneid() == GLOBAL_ZONEID && be_get_uuid(bt.nbe_root_ds,
1190                     &cdd.gz_be_uuid) == 0)
1191                         (void) be_destroy_zones(bt.nbe_name, bt.nbe_root_ds,
1192                             &cdd);
1193 
1194                 (void) _be_destroy(bt.nbe_root_ds, &cdd);
1195         }
1196 
1197         be_zfs_fini();
1198 
1199         return (ret);
1200 }
1201 
1202 /* ******************************************************************** */
1203 /*                      Semi-Private Functions                          */
1204 /* ******************************************************************** */
1205 
1206 /*
1207  * Function:    be_find_zpool_callback
1208  * Description: Callback function used to find the pool that a BE lives in.
1209  * Parameters:
1210  *              zlp - zpool_handle_t pointer for the current pool being
1211  *                      looked at.
1212  *              data - be_transaction_data_t pointer providing information
1213  *                      about the BE that's being searched for.
1214  *                      This function uses the obe_name member of this
1215  *                      parameter to use as the BE name to search for.
1216  *                      Upon successfully locating the BE, it populates
1217  *                      obe_zpool with the pool name that the BE is found in.
1218  * Returns:
1219  *              1 - BE exists in this pool.
1220  *              0 - BE does not exist in this pool.
1221  * Scope:
1222  *              Semi-private (library wide use only)
1223  */
1224 int
1225 be_find_zpool_callback(zpool_handle_t *zlp, void *data)
1226 {
1227         be_transaction_data_t   *bt = data;
1228         const char              *zpool =  zpool_get_name(zlp);
1229         char                    be_root_ds[MAXPATHLEN];
1230 
1231         /*
1232          * Generate string for the BE's root dataset
1233          */
1234         be_make_root_ds(zpool, bt->obe_name, be_root_ds, sizeof (be_root_ds));
1235 
1236         /*
1237          * Check if dataset exists
1238          */
1239         if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1240                 /* BE's root dataset exists in zpool */
1241                 bt->obe_zpool = strdup(zpool);
1242                 zpool_close(zlp);
1243                 return (1);
1244         }
1245 
1246         zpool_close(zlp);
1247         return (0);
1248 }
1249 
1250 /*
1251  * Function:    be_exists_callback
1252  * Description: Callback function used to find out if a BE exists.
1253  * Parameters:
1254  *              zlp - zpool_handle_t pointer to the current pool being
1255  *                      looked at.
1256  *              data - BE name to look for.
1257  * Return:
1258  *              1 - BE exists in this pool.
1259  *              0 - BE does not exist in this pool.
1260  * Scope:
1261  *              Semi-private (library wide use only)
1262  */
1263 int
1264 be_exists_callback(zpool_handle_t *zlp, void *data)
1265 {
1266         const char      *zpool = zpool_get_name(zlp);
1267         char            *be_name = data;
1268         char            be_root_ds[MAXPATHLEN];
1269 
1270         /*
1271          * Generate string for the BE's root dataset
1272          */
1273         be_make_root_ds(zpool, be_name, be_root_ds, sizeof (be_root_ds));
1274 
1275         /*
1276          * Check if dataset exists
1277          */
1278         if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1279                 /* BE's root dataset exists in zpool */
1280                 zpool_close(zlp);
1281                 return (1);
1282         }
1283 
1284         zpool_close(zlp);
1285         return (0);
1286 }
1287 
1288 /*
1289  * Function:    be_has_snapshots_callback
1290  * Description: Callback function used to find out if a BE has snapshots.
1291  * Parameters:
1292  *              zlp - zpool_handle_t pointer to the current pool being
1293  *                      looked at.
1294  *              data - be_snap_found_t pointer.
1295  * Return:
1296  *              1 - BE has no snapshots.
1297  *              0 - BE has snapshots.
1298  * Scope:
1299  *              Private
1300  */
1301 static int
1302 be_has_snapshot_callback(zfs_handle_t *zhp, void *data)
1303 {
1304         boolean_t *bs = data;
1305         if (zfs_get_name(zhp) == NULL) {
1306                 zfs_close(zhp);
1307                 return (1);
1308         }
1309         *bs = B_TRUE;
1310         zfs_close(zhp);
1311         return (0);
1312 }
1313 
1314 /*
1315  * Function:    be_set_uuid
1316  * Description: This function generates a uuid, unparses it into
1317  *              string representation, and sets that string into
1318  *              a zfs user property for a root dataset of a BE.
1319  *              The name of the user property used to store the
1320  *              uuid is org.opensolaris.libbe:uuid
1321  *
1322  * Parameters:
1323  *              root_ds - Root dataset of the BE to set a uuid on.
1324  * Return:
1325  *              be_errno_t - Failure
1326  *              BE_SUCCESS - Success
1327  * Scope:
1328  *              Semi-private (library wide ues only)
1329  */
1330 int
1331 be_set_uuid(char *root_ds)
1332 {
1333         zfs_handle_t    *zhp = NULL;
1334         uuid_t          uu = { 0 };
1335         char            uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1336         int             ret = BE_SUCCESS;
1337 
1338         /* Generate a UUID and unparse it into string form */
1339         uuid_generate(uu);
1340         if (uuid_is_null(uu) != 0) {
1341                 be_print_err(gettext("be_set_uuid: failed to "
1342                     "generate uuid\n"));
1343                 return (BE_ERR_GEN_UUID);
1344         }
1345         uuid_unparse(uu, uu_string);
1346 
1347         /* Get handle to the BE's root dataset. */
1348         if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1349                 be_print_err(gettext("be_set_uuid: failed to "
1350                     "open BE root dataset (%s): %s\n"), root_ds,
1351                     libzfs_error_description(g_zfs));
1352                 return (zfs_err_to_be_err(g_zfs));
1353         }
1354 
1355         /* Set uuid property for the BE */
1356         if (zfs_prop_set(zhp, BE_UUID_PROPERTY, uu_string) != 0) {
1357                 be_print_err(gettext("be_set_uuid: failed to "
1358                     "set uuid property for BE: %s\n"),
1359                     libzfs_error_description(g_zfs));
1360                 ret = zfs_err_to_be_err(g_zfs);
1361         }
1362 
1363         ZFS_CLOSE(zhp);
1364 
1365         return (ret);
1366 }
1367 
1368 /*
1369  * Function:    be_get_uuid
1370  * Description: This function gets the uuid string from a BE root
1371  *              dataset, parses it into internal format, and returns
1372  *              it the caller via a reference pointer passed in.
1373  *
1374  * Parameters:
1375  *              rootds - Root dataset of the BE to get the uuid from.
1376  *              uu - reference pointer to a uuid_t to return uuid in.
1377  * Return:
1378  *              be_errno_t - Failure
1379  *              BE_SUCCESS - Success
1380  * Scope:
1381  *              Semi-private (library wide use only)
1382  */
1383 int
1384 be_get_uuid(const char *root_ds, uuid_t *uu)
1385 {
1386         zfs_handle_t    *zhp = NULL;
1387         nvlist_t        *userprops = NULL;
1388         nvlist_t        *propname = NULL;
1389         char            *uu_string = NULL;
1390         int             ret = BE_SUCCESS;
1391 
1392         /* Get handle to the BE's root dataset. */
1393         if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1394                 be_print_err(gettext("be_get_uuid: failed to "
1395                     "open BE root dataset (%s): %s\n"), root_ds,
1396                     libzfs_error_description(g_zfs));
1397                 return (zfs_err_to_be_err(g_zfs));
1398         }
1399 
1400         /* Get user properties for BE's root dataset */
1401         if ((userprops = zfs_get_user_props(zhp)) == NULL) {
1402                 be_print_err(gettext("be_get_uuid: failed to "
1403                     "get user properties for BE root dataset (%s): %s\n"),
1404                     root_ds, libzfs_error_description(g_zfs));
1405                 ret = zfs_err_to_be_err(g_zfs);
1406                 goto done;
1407         }
1408 
1409         /* Get UUID string from BE's root dataset user properties */
1410         if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propname) != 0 ||
1411             nvlist_lookup_string(propname, ZPROP_VALUE, &uu_string) != 0) {
1412                 /*
1413                  * This probably just means that the BE is simply too old
1414                  * to have a uuid or that we haven't created a uuid for
1415                  * this BE yet.
1416                  */
1417                 be_print_err(gettext("be_get_uuid: failed to "
1418                     "get uuid property from BE root dataset user "
1419                     "properties.\n"));
1420                 ret = BE_ERR_NO_UUID;
1421                 goto done;
1422         }
1423         /* Parse uuid string into internal format */
1424         if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) {
1425                 be_print_err(gettext("be_get_uuid: failed to "
1426                     "parse uuid\n"));
1427                 ret = BE_ERR_PARSE_UUID;
1428                 goto done;
1429         }
1430 
1431 done:
1432         ZFS_CLOSE(zhp);
1433         return (ret);
1434 }
1435 
1436 /* ******************************************************************** */
1437 /*                      Private Functions                               */
1438 /* ******************************************************************** */
1439 
1440 /*
1441  * Function:    _be_destroy
1442  * Description: Destroy a BE and all of its children datasets and snapshots.
1443  *              This function is called for both global BEs and non-global BEs.
1444  *              The root dataset of either the global BE or non-global BE to be
1445  *              destroyed is passed in.
1446  * Parameters:
1447  *              root_ds - pointer to the name of the root dataset of the
1448  *                      BE to destroy.
1449  *              dd - pointer to a be_destroy_data_t structure.
1450  *
1451  * Return:
1452  *              BE_SUCCESS - Success
1453  *              be_errno_t - Failure
1454  * Scope:
1455  *              Private
1456  */
1457 static int
1458 _be_destroy(const char *root_ds, be_destroy_data_t *dd)
1459 {
1460         zfs_handle_t    *zhp = NULL;
1461         char            origin[MAXPATHLEN];
1462         char            parent[MAXPATHLEN];
1463         char            *snap = NULL;
1464         boolean_t       has_origin = B_FALSE;
1465         int             ret = BE_SUCCESS;
1466 
1467         /* Get handle to BE's root dataset */
1468         if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1469             NULL) {
1470                 be_print_err(gettext("be_destroy: failed to "
1471                     "open BE root dataset (%s): %s\n"), root_ds,
1472                     libzfs_error_description(g_zfs));
1473                 return (zfs_err_to_be_err(g_zfs));
1474         }
1475 
1476         /*
1477          * Demote this BE in case it has dependent clones.  This call
1478          * will end up closing the zfs handle passed in whether it
1479          * succeeds or fails.
1480          */
1481         if (be_demote_callback(zhp, NULL) != 0) {
1482                 be_print_err(gettext("be_destroy: "
1483                     "failed to demote BE %s\n"), root_ds);
1484                 return (BE_ERR_DEMOTE);
1485         }
1486 
1487         /* Get handle to BE's root dataset */
1488         if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1489             NULL) {
1490                 be_print_err(gettext("be_destroy: failed to "
1491                     "open BE root dataset (%s): %s\n"), root_ds,
1492                     libzfs_error_description(g_zfs));
1493                 return (zfs_err_to_be_err(g_zfs));
1494         }
1495 
1496         /*
1497          * Get the origin of this BE's root dataset.  This will be used
1498          * later to destroy the snapshots originally used to create this BE.
1499          */
1500         if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
1501             NULL, 0, B_FALSE) == 0) {
1502                 (void) strlcpy(parent, origin, sizeof (parent));
1503                 if (be_get_snap(parent, &snap) != BE_SUCCESS) {
1504                         ZFS_CLOSE(zhp);
1505                         be_print_err(gettext("be_destroy: failed to "
1506                             "get snapshot name from origin %s\n"), origin);
1507                         return (BE_ERR_INVAL);
1508                 }
1509                 has_origin = B_TRUE;
1510         }
1511 
1512         /*
1513          * Destroy the BE's root and its hierarchical children.  This call
1514          * will end up closing the zfs handle passed in whether it succeeds
1515          * or fails.
1516          */
1517         if (be_destroy_callback(zhp, dd) != 0) {
1518                 be_print_err(gettext("be_destroy: failed to "
1519                     "destroy BE %s\n"), root_ds);
1520                 ret = zfs_err_to_be_err(g_zfs);
1521                 return (ret);
1522         }
1523 
1524         /* If BE has an origin */
1525         if (has_origin) {
1526 
1527                 /*
1528                  * If origin snapshot doesn't have any other
1529                  * dependents, delete the origin.
1530                  */
1531                 if ((zhp = zfs_open(g_zfs, origin, ZFS_TYPE_SNAPSHOT)) ==
1532                     NULL) {
1533                         be_print_err(gettext("be_destroy: failed to "
1534                             "open BE's origin (%s): %s\n"), origin,
1535                             libzfs_error_description(g_zfs));
1536                         ret = zfs_err_to_be_err(g_zfs);
1537                         return (ret);
1538                 }
1539 
1540                 /* If origin has dependents, don't delete it. */
1541                 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
1542                         ZFS_CLOSE(zhp);
1543                         return (ret);
1544                 }
1545                 ZFS_CLOSE(zhp);
1546 
1547                 /* Get handle to BE's parent's root dataset */
1548                 if ((zhp = zfs_open(g_zfs, parent, ZFS_TYPE_FILESYSTEM)) ==
1549                     NULL) {
1550                         be_print_err(gettext("be_destroy: failed to "
1551                             "open BE's parent root dataset (%s): %s\n"), parent,
1552                             libzfs_error_description(g_zfs));
1553                         ret = zfs_err_to_be_err(g_zfs);
1554                         return (ret);
1555                 }
1556 
1557                 /* Destroy the snapshot origin used to create this BE. */
1558                 /*
1559                  * The boolean set to B_FALSE and passed to zfs_destroy_snaps()
1560                  * tells zfs to process and destroy the snapshots now.
1561                  * Otherwise the call will potentially return where the
1562                  * snapshot isn't actually destroyed yet, and ZFS is waiting
1563                  * until all the references to the snapshot have been
1564                  * released before actually destroying the snapshot.
1565                  */
1566                 if (zfs_destroy_snaps(zhp, snap, B_FALSE) != 0) {
1567                         be_print_err(gettext("be_destroy: failed to "
1568                             "destroy original snapshots used to create "
1569                             "BE: %s\n"), libzfs_error_description(g_zfs));
1570 
1571                         /*
1572                          * If a failure happened because a clone exists,
1573                          * don't return a failure to the user.  Above, we're
1574                          * only checking that the root dataset's origin
1575                          * snapshot doesn't have dependent clones, but its
1576                          * possible that a subordinate dataset origin snapshot
1577                          * has a clone.  We really need to check for that
1578                          * before trying to destroy the origin snapshot.
1579                          */
1580                         if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1581                                 ret = zfs_err_to_be_err(g_zfs);
1582                                 ZFS_CLOSE(zhp);
1583                                 return (ret);
1584                         }
1585                 }
1586                 ZFS_CLOSE(zhp);
1587         }
1588 
1589         return (ret);
1590 }
1591 
1592 /*
1593  * Function:    be_destroy_zones
1594  * Description: Find valid zone's and call be_destroy_zone_roots to destroy its
1595  *              corresponding dataset and all of its children datasets
1596  *              and snapshots.
1597  * Parameters:
1598  *              be_name - name of global boot environment being destroyed
1599  *              be_root_ds - root dataset of global boot environment being
1600  *                      destroyed.
1601  *              dd - be_destroy_data_t pointer
1602  * Return:
1603  *              BE_SUCCESS - Success
1604  *              be_errno_t - Failure
1605  * Scope:
1606  *              Private
1607  *
1608  * NOTES - Requires that the BE being deleted has no dependent BEs.  If it
1609  *         does, the destroy will fail.
1610  */
1611 static int
1612 be_destroy_zones(char *be_name, char *be_root_ds, be_destroy_data_t *dd)
1613 {
1614         int             i;
1615         int             ret = BE_SUCCESS;
1616         int             force_umnt = BE_UNMOUNT_FLAG_NULL;
1617         char            *zonepath = NULL;
1618         char            *zonename = NULL;
1619         char            *zonepath_ds = NULL;
1620         char            *mp = NULL;
1621         zoneList_t      zlist = NULL;
1622         zfs_handle_t    *zhp = NULL;
1623 
1624         /* If zones are not implemented, then get out. */
1625         if (!z_zones_are_implemented()) {
1626                 return (BE_SUCCESS);
1627         }
1628 
1629         /* Get handle to BE's root dataset */
1630         if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1631             NULL) {
1632                 be_print_err(gettext("be_destroy_zones: failed to "
1633                     "open BE root dataset (%s): %s\n"), be_root_ds,
1634                     libzfs_error_description(g_zfs));
1635                 return (zfs_err_to_be_err(g_zfs));
1636         }
1637 
1638         /*
1639          * If the global BE is not mounted, we must mount it here to
1640          * gather data about the non-global zones in it.
1641          */
1642         if (!zfs_is_mounted(zhp, &mp)) {
1643                 if ((ret = _be_mount(be_name, &mp,
1644                     BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1645                         be_print_err(gettext("be_destroy_zones: failed to "
1646                             "mount the BE (%s) for zones processing.\n"),
1647                             be_name);
1648                         ZFS_CLOSE(zhp);
1649                         return (ret);
1650                 }
1651         }
1652         ZFS_CLOSE(zhp);
1653 
1654         z_set_zone_root(mp);
1655         free(mp);
1656 
1657         /* Get list of zones. */
1658         if ((zlist = z_get_nonglobal_branded_zone_list()) == NULL)
1659                 return (BE_SUCCESS);
1660 
1661         /* Unmount the BE before destroying the zones in it. */
1662         if (dd->force_unmount)
1663                 force_umnt = BE_UNMOUNT_FLAG_FORCE;
1664         if ((ret = _be_unmount(be_name, force_umnt)) != BE_SUCCESS) {
1665                 be_print_err(gettext("be_destroy_zones: failed to "
1666                     "unmount the BE (%s)\n"), be_name);
1667                 goto done;
1668         }
1669 
1670         /* Iterate through the zones and destroy them. */
1671         for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1672                 boolean_t auto_create;
1673 
1674                 if (z_zlist_is_zone_auto_create_be(zlist, i, &auto_create) != 0) {
1675                         be_print_err(gettext("be_destroy_zones: failed to get "
1676                             "auto-create-be brand property\n"));
1677                         ret = -1; // XXX
1678                         goto done;
1679                 }
1680 
1681                 if (!auto_create)
1682                         continue;
1683 
1684                 /* Skip zones that aren't at least installed */
1685                 if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1686                         continue;
1687 
1688                 zonepath = z_zlist_get_zonepath(zlist, i);
1689 
1690                 /*
1691                  * Get the dataset of this zonepath.  If its not
1692                  * a dataset, skip it.
1693                  */
1694                 if ((zonepath_ds = be_get_ds_from_dir(zonepath)) == NULL)
1695                         continue;
1696 
1697                 /*
1698                  * Check if this zone is supported based on the
1699                  * dataset of its zonepath.
1700                  */
1701                 if (!be_zone_supported(zonepath_ds)) {
1702                         free(zonepath_ds);
1703                         continue;
1704                 }
1705 
1706                 /* Find the zone BE root datasets for this zone. */
1707                 if ((ret = be_destroy_zone_roots(zonepath_ds, dd))
1708                     != BE_SUCCESS) {
1709                         be_print_err(gettext("be_destroy_zones: failed to "
1710                             "find and destroy zone roots for zone %s\n"),
1711                             zonename);
1712                         free(zonepath_ds);
1713                         goto done;
1714                 }
1715                 free(zonepath_ds);
1716         }
1717 
1718 done:
1719         z_free_zone_list(zlist);
1720 
1721         return (ret);
1722 }
1723 
1724 /*
1725  * Function:    be_destroy_zone_roots
1726  * Description: This function will open the zone's root container dataset
1727  *              and iterate the datasets within, looking for roots that
1728  *              belong to the given global BE and destroying them.
1729  *              If no other zone roots remain in the zone's root container
1730  *              dataset, the function will destroy it and the zone's
1731  *              zonepath dataset as well.
1732  * Parameters:
1733  *              zonepath_ds - pointer to zone's zonepath dataset.
1734  *              dd - pointer to a linked destroy data.
1735  * Returns:
1736  *              BE_SUCCESS - Success
1737  *              be_errno_t - Failure
1738  * Scope:
1739  *              Private
1740  */
1741 static int
1742 be_destroy_zone_roots(char *zonepath_ds, be_destroy_data_t *dd)
1743 {
1744         zfs_handle_t    *zhp;
1745         char            zone_container_ds[MAXPATHLEN];
1746         int             ret = BE_SUCCESS;
1747 
1748         /* Generate string for the root container dataset for this zone. */
1749         be_make_container_ds(zonepath_ds, zone_container_ds,
1750             sizeof (zone_container_ds));
1751 
1752         /* Get handle to this zone's root container dataset. */
1753         if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1754             == NULL) {
1755                 be_print_err(gettext("be_destroy_zone_roots: failed to "
1756                     "open zone root container dataset (%s): %s\n"),
1757                     zone_container_ds, libzfs_error_description(g_zfs));
1758                 return (zfs_err_to_be_err(g_zfs));
1759         }
1760 
1761         /*
1762          * Iterate through all of this zone's BEs, destroying the ones
1763          * that belong to the parent global BE.
1764          */
1765         if ((ret = zfs_iter_filesystems(zhp, be_destroy_zone_roots_callback,
1766             dd)) != 0) {
1767                 be_print_err(gettext("be_destroy_zone_roots: failed to "
1768                     "destroy zone roots under zonepath dataset %s: %s\n"),
1769                     zonepath_ds, libzfs_error_description(g_zfs));
1770                 ZFS_CLOSE(zhp);
1771                 return (ret);
1772         }
1773         ZFS_CLOSE(zhp);
1774 
1775         /* Get handle to this zone's root container dataset. */
1776         if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1777             == NULL) {
1778                 be_print_err(gettext("be_destroy_zone_roots: failed to "
1779                     "open zone root container dataset (%s): %s\n"),
1780                     zone_container_ds, libzfs_error_description(g_zfs));
1781                 return (zfs_err_to_be_err(g_zfs));
1782         }
1783 
1784         /*
1785          * If there are no more zone roots in this zone's root container,
1786          * dataset, destroy it and the zonepath dataset as well.
1787          */
1788         if (zfs_iter_filesystems(zhp, be_zone_root_exists_callback, NULL)
1789             == 0) {
1790                 /* Destroy the zone root container dataset */
1791                 if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1792                     zfs_destroy(zhp, B_FALSE) != 0) {
1793                         be_print_err(gettext("be_destroy_zone_roots: failed to "
1794                             "destroy zone root container dataset (%s): %s\n"),
1795                             zone_container_ds, libzfs_error_description(g_zfs));
1796                         goto done;
1797                 }
1798                 ZFS_CLOSE(zhp);
1799 
1800                 /* Get handle to zonepath dataset */
1801                 if ((zhp = zfs_open(g_zfs, zonepath_ds, ZFS_TYPE_FILESYSTEM))
1802                     == NULL) {
1803                         be_print_err(gettext("be_destroy_zone_roots: failed to "
1804                             "open zonepath dataset (%s): %s\n"),
1805                             zonepath_ds, libzfs_error_description(g_zfs));
1806                         goto done;
1807                 }
1808 
1809                 /* Destroy zonepath dataset */
1810                 if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1811                     zfs_destroy(zhp, B_FALSE) != 0) {
1812                         be_print_err(gettext("be_destroy_zone_roots: "
1813                             "failed to destroy zonepath dataest %s: %s\n"),
1814                             zonepath_ds, libzfs_error_description(g_zfs));
1815                         goto done;
1816                 }
1817         }
1818 
1819 done:
1820         ZFS_CLOSE(zhp);
1821         return (ret);
1822 }
1823 
1824 /*
1825  * Function:    be_destroy_zone_roots_callback
1826  * Description: This function is used as a callback to iterate over all of
1827  *              a zone's root datasets, finding the one's that
1828  *              correspond to the current BE. The name's
1829  *              of the zone root datasets are then destroyed by _be_destroy().
1830  * Parameters:
1831  *              zhp - zfs_handle_t pointer to current dataset being processed
1832  *              data - be_destroy_data_t pointer
1833  * Returns:
1834  *              0 - Success
1835  *              be_errno_t - Failure
1836  * Scope:
1837  *              Private
1838  */
1839 static int
1840 be_destroy_zone_roots_callback(zfs_handle_t *zhp, void *data)
1841 {
1842         be_destroy_data_t       *dd = data;
1843         uuid_t                  parent_uuid = { 0 };
1844         int                     ret = 0;
1845 
1846         if (be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid)
1847             != BE_SUCCESS) {
1848                 be_print_err(gettext("be_destroy_zone_roots_callback: "
1849                     "could not get parentuuid for zone root dataset %s\n"),
1850                     zfs_get_name(zhp));
1851                 ZFS_CLOSE(zhp);
1852                 return (0);
1853         }
1854 
1855         if (uuid_compare(dd->gz_be_uuid, parent_uuid) == 0) {
1856                 /*
1857                  * Found a zone root dataset belonging to the parent
1858                  * BE being destroyed.  Destroy this zone BE.
1859                  */
1860                 if ((ret = _be_destroy(zfs_get_name(zhp), dd)) != BE_SUCCESS) {
1861                         be_print_err(gettext("be_destroy_zone_root_callback: "
1862                             "failed to destroy zone root %s\n"),
1863                             zfs_get_name(zhp));
1864                         ZFS_CLOSE(zhp);
1865                         return (ret);
1866                 }
1867         }
1868         ZFS_CLOSE(zhp);
1869 
1870         return (ret);
1871 }
1872 
1873 /*
1874  * Function:    be_copy_zones
1875  * Description: Find valid zones and clone them to create their
1876  *              corresponding datasets for the BE being created.
1877  * Parameters:
1878  *              obe_name - name of source global BE being copied.
1879  *              obe_root_ds - root dataset of source global BE being copied.
1880  *              nbe_root_ds - root dataset of target global BE.
1881  * Return:
1882  *              BE_SUCCESS - Success
1883  *              be_errno_t - Failure
1884  * Scope:
1885  *              Private
1886  */
1887 static int
1888 be_copy_zones(char *obe_name, char *obe_root_ds, char *nbe_root_ds)
1889 {
1890         int             i, num_retries;
1891         int             ret = BE_SUCCESS;
1892         int             iret = 0;
1893         char            *zonename = NULL;
1894         char            *zonepath = NULL;
1895         char            *zone_be_name = NULL;
1896         char            *temp_mntpt = NULL;
1897         char            *new_zone_be_name = NULL;
1898         char            zoneroot[MAXPATHLEN];
1899         char            zoneroot_ds[MAXPATHLEN];
1900         char            zone_container_ds[MAXPATHLEN];
1901         char            new_zoneroot_ds[MAXPATHLEN];
1902         char            ss[MAXPATHLEN];
1903         uuid_t          uu = { 0 };
1904         char            uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1905         be_transaction_data_t bt = { 0 };
1906         zfs_handle_t    *obe_zhp = NULL;
1907         zfs_handle_t    *nbe_zhp = NULL;
1908         zfs_handle_t    *z_zhp = NULL;
1909         zoneList_t      zlist = NULL;
1910         boolean_t       mounted_here = B_FALSE;
1911         char            *snap_name = NULL;
1912 
1913         /* If zones are not implemented, then get out. */
1914         if (!z_zones_are_implemented()) {
1915                 return (BE_SUCCESS);
1916         }
1917 
1918         /* Get handle to origin BE's root dataset */
1919         if ((obe_zhp = zfs_open(g_zfs, obe_root_ds, ZFS_TYPE_FILESYSTEM))
1920             == NULL) {
1921                 be_print_err(gettext("be_copy_zones: failed to open "
1922                     "the origin BE root dataset (%s) for zones processing: "
1923                     "%s\n"), obe_root_ds, libzfs_error_description(g_zfs));
1924                 return (zfs_err_to_be_err(g_zfs));
1925         }
1926 
1927         /* Get handle to newly cloned BE's root dataset */
1928         if ((nbe_zhp = zfs_open(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM))
1929             == NULL) {
1930                 be_print_err(gettext("be_copy_zones: failed to open "
1931                     "the new BE root dataset (%s): %s\n"), nbe_root_ds,
1932                     libzfs_error_description(g_zfs));
1933                 ZFS_CLOSE(obe_zhp);
1934                 return (zfs_err_to_be_err(g_zfs));
1935         }
1936 
1937         /* Get the uuid of the newly cloned parent BE. */
1938         if (be_get_uuid(zfs_get_name(nbe_zhp), &uu) != BE_SUCCESS) {
1939                 be_print_err(gettext("be_copy_zones: "
1940                     "failed to get uuid for BE root "
1941                     "dataset %s\n"), zfs_get_name(nbe_zhp));
1942                 ZFS_CLOSE(nbe_zhp);
1943                 goto done;
1944         }
1945         ZFS_CLOSE(nbe_zhp);
1946         uuid_unparse(uu, uu_string);
1947 
1948         /*
1949          * If the origin BE is not mounted, we must mount it here to
1950          * gather data about the non-global zones in it.
1951          */
1952         if (!zfs_is_mounted(obe_zhp, &temp_mntpt)) {
1953                 if ((ret = _be_mount(obe_name, &temp_mntpt,
1954                     BE_MOUNT_FLAG_NULL)) != BE_SUCCESS) {
1955                         be_print_err(gettext("be_copy_zones: failed to "
1956                             "mount the BE (%s) for zones procesing.\n"),
1957                             obe_name);
1958                         goto done;
1959                 }
1960                 mounted_here = B_TRUE;
1961         }
1962 
1963         z_set_zone_root(temp_mntpt);
1964 
1965         /* Get list of zones. */
1966         if ((zlist = z_get_nonglobal_branded_zone_list()) == NULL) {
1967                 ret = BE_SUCCESS;
1968                 goto done;
1969         }
1970 
1971         for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1972 
1973                 be_fs_list_data_t       fld = { 0 };
1974                 char                    zonepath_ds[MAXPATHLEN];
1975                 char                    *ds = NULL;
1976                 boolean_t               auto_create;
1977 
1978                 if (z_zlist_is_zone_auto_create_be(zlist, i, &auto_create) != 0) {
1979                         be_print_err(gettext("be_copy_zones: failed to get "
1980                             "auto-create-be brand property\n"));
1981                         ret = -1; // XXX
1982                 }
1983 
1984                 if (!auto_create)
1985                         continue;
1986 
1987                 /* Get zonepath of zone */
1988                 zonepath = z_zlist_get_zonepath(zlist, i);
1989 
1990                 /* Skip zones that aren't at least installed */
1991                 if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1992                         continue;
1993 
1994                 /*
1995                  * Get the dataset of this zonepath.  If its not
1996                  * a dataset, skip it.
1997                  */
1998                 if ((ds = be_get_ds_from_dir(zonepath)) == NULL)
1999                         continue;
2000 
2001                 (void) strlcpy(zonepath_ds, ds, sizeof (zonepath_ds));
2002                 free(ds);
2003                 ds = NULL;
2004 
2005                 /* Get zoneroot directory */
2006                 be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
2007 
2008                 /* If zonepath dataset not supported, skip it. */
2009                 if (!be_zone_supported(zonepath_ds)) {
2010                         continue;
2011                 }
2012 
2013                 if ((ret = be_find_active_zone_root(obe_zhp, zonepath_ds,
2014                     zoneroot_ds, sizeof (zoneroot_ds))) != BE_SUCCESS) {
2015                         be_print_err(gettext("be_copy_zones: "
2016                             "failed to find active zone root for zone %s "
2017                             "in BE %s\n"), zonename, obe_name);
2018                         goto done;
2019                 }
2020 
2021                 be_make_container_ds(zonepath_ds, zone_container_ds,
2022                     sizeof (zone_container_ds));
2023 
2024                 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2025                     ZFS_TYPE_FILESYSTEM)) == NULL) {
2026                         be_print_err(gettext("be_copy_zones: "
2027                             "failed to open zone root dataset (%s): %s\n"),
2028                             zoneroot_ds, libzfs_error_description(g_zfs));
2029                         ret = zfs_err_to_be_err(g_zfs);
2030                         goto done;
2031                 }
2032 
2033                 zone_be_name =
2034                     be_get_zone_be_name(zoneroot_ds, zone_container_ds);
2035 
2036                 if ((new_zone_be_name = be_auto_zone_be_name(zone_container_ds,
2037                     zone_be_name)) == NULL) {
2038                         be_print_err(gettext("be_copy_zones: failed "
2039                             "to generate auto name for zone BE.\n"));
2040                         ret = BE_ERR_AUTONAME;
2041                         goto done;
2042                 }
2043 
2044                 if ((snap_name = be_auto_snap_name()) == NULL) {
2045                         be_print_err(gettext("be_copy_zones: failed to "
2046                             "generate snapshot name for zone BE.\n"));
2047                         ret = BE_ERR_AUTONAME;
2048                         goto done;
2049                 }
2050 
2051                 (void) snprintf(ss, sizeof (ss), "%s@%s", zoneroot_ds,
2052                     snap_name);
2053 
2054                 if (zfs_snapshot(g_zfs, ss, B_TRUE, NULL) != 0) {
2055                         be_print_err(gettext("be_copy_zones: "
2056                             "failed to snapshot zone BE (%s): %s\n"),
2057                             ss, libzfs_error_description(g_zfs));
2058                         if (libzfs_errno(g_zfs) == EZFS_EXISTS)
2059                                 ret = BE_ERR_ZONE_SS_EXISTS;
2060                         else
2061                                 ret = zfs_err_to_be_err(g_zfs);
2062 
2063                         goto done;
2064                 }
2065 
2066                 (void) snprintf(new_zoneroot_ds, sizeof (new_zoneroot_ds),
2067                     "%s/%s", zone_container_ds, new_zone_be_name);
2068 
2069                 bt.obe_name = zone_be_name;
2070                 bt.obe_root_ds = zoneroot_ds;
2071                 bt.obe_snap_name = snap_name;
2072                 bt.obe_altroot = temp_mntpt;
2073                 bt.nbe_name = new_zone_be_name;
2074                 bt.nbe_root_ds = new_zoneroot_ds;
2075 
2076                 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
2077                         be_print_err(gettext("be_copy_zones: "
2078                             "internal error: out of memory\n"));
2079                         ret = BE_ERR_NOMEM;
2080                         goto done;
2081                 }
2082 
2083                 /*
2084                  * The call to be_clone_fs_callback always closes the
2085                  * zfs_handle so there's no need to close z_zhp.
2086                  */
2087                 if ((iret = be_clone_fs_callback(z_zhp, &bt)) != 0) {
2088                         z_zhp = NULL;
2089                         if (iret != BE_ERR_BE_EXISTS) {
2090                                 be_print_err(gettext("be_copy_zones: "
2091                                     "failed to create zone BE clone for new "
2092                                     "zone BE %s\n"), new_zone_be_name);
2093                                 ret = iret;
2094                                 if (bt.nbe_zfs_props != NULL)
2095                                         nvlist_free(bt.nbe_zfs_props);
2096                                 goto done;
2097                         }
2098                         /*
2099                          * We failed to create the new zone BE because a zone
2100                          * BE with the auto-name we generated above has since
2101                          * come into existence. Regenerate a new auto-name
2102                          * and retry.
2103                          */
2104                         for (num_retries = 1;
2105                             num_retries < BE_AUTO_NAME_MAX_TRY;
2106                             num_retries++) {
2107 
2108                                 /* Sleep 1 before retrying */
2109                                 (void) sleep(1);
2110 
2111                                 /* Generate new auto zone BE name */
2112                                 free(new_zone_be_name);
2113                                 if ((new_zone_be_name = be_auto_zone_be_name(
2114                                     zone_container_ds,
2115                                     zone_be_name)) == NULL) {
2116                                         be_print_err(gettext("be_copy_zones: "
2117                                             "failed to generate auto name "
2118                                             "for zone BE.\n"));
2119                                         ret = BE_ERR_AUTONAME;
2120                                         if (bt.nbe_zfs_props != NULL)
2121                                                 nvlist_free(bt.nbe_zfs_props);
2122                                         goto done;
2123                                 }
2124 
2125                                 (void) snprintf(new_zoneroot_ds,
2126                                     sizeof (new_zoneroot_ds),
2127                                     "%s/%s", zone_container_ds,
2128                                     new_zone_be_name);
2129                                 bt.nbe_name = new_zone_be_name;
2130                                 bt.nbe_root_ds = new_zoneroot_ds;
2131 
2132                                 /*
2133                                  * Get handle to original zone BE's root
2134                                  * dataset.
2135                                  */
2136                                 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2137                                     ZFS_TYPE_FILESYSTEM)) == NULL) {
2138                                         be_print_err(gettext("be_copy_zones: "
2139                                             "failed to open zone root "
2140                                             "dataset (%s): %s\n"),
2141                                             zoneroot_ds,
2142                                             libzfs_error_description(g_zfs));
2143                                         ret = zfs_err_to_be_err(g_zfs);
2144                                         if (bt.nbe_zfs_props != NULL)
2145                                                 nvlist_free(bt.nbe_zfs_props);
2146                                         goto done;
2147                                 }
2148 
2149                                 /*
2150                                  * Try to clone the zone BE again. This
2151                                  * call will end up closing the zfs
2152                                  * handle passed in whether it
2153                                  * succeeds or fails.
2154                                  */
2155                                 iret = be_clone_fs_callback(z_zhp, &bt);
2156                                 z_zhp = NULL;
2157                                 if (iret == 0) {
2158                                         break;
2159                                 } else if (iret != BE_ERR_BE_EXISTS) {
2160                                         be_print_err(gettext("be_copy_zones: "
2161                                             "failed to create zone BE clone "
2162                                             "for new zone BE %s\n"),
2163                                             new_zone_be_name);
2164                                         ret = iret;
2165                                         if (bt.nbe_zfs_props != NULL)
2166                                                 nvlist_free(bt.nbe_zfs_props);
2167                                         goto done;
2168                                 }
2169                         }
2170                         /*
2171                          * If we've exhausted the maximum number of
2172                          * tries, free the auto zone BE name and return
2173                          * error.
2174                          */
2175                         if (num_retries == BE_AUTO_NAME_MAX_TRY) {
2176                                 be_print_err(gettext("be_copy_zones: failed "
2177                                     "to create a unique auto zone BE name\n"));
2178                                 free(bt.nbe_name);
2179                                 bt.nbe_name = NULL;
2180                                 ret = BE_ERR_AUTONAME;
2181                                 if (bt.nbe_zfs_props != NULL)
2182                                         nvlist_free(bt.nbe_zfs_props);
2183                                 goto done;
2184                         }
2185                 }
2186 
2187                 if (bt.nbe_zfs_props != NULL)
2188                         nvlist_free(bt.nbe_zfs_props);
2189 
2190                 z_zhp = NULL;
2191 
2192                 if ((z_zhp = zfs_open(g_zfs, new_zoneroot_ds,
2193                     ZFS_TYPE_FILESYSTEM)) == NULL) {
2194                         be_print_err(gettext("be_copy_zones: "
2195                             "failed to open the new zone BE root dataset "
2196                             "(%s): %s\n"), new_zoneroot_ds,
2197                             libzfs_error_description(g_zfs));
2198                         ret = zfs_err_to_be_err(g_zfs);
2199                         goto done;
2200                 }
2201 
2202                 if (zfs_prop_set(z_zhp, BE_ZONE_PARENTBE_PROPERTY,
2203                     uu_string) != 0) {
2204                         be_print_err(gettext("be_copy_zones: "
2205                             "failed to set parentbe property\n"));
2206                         ZFS_CLOSE(z_zhp);
2207                         ret = zfs_err_to_be_err(g_zfs);
2208                         goto done;
2209                 }
2210 
2211                 if (zfs_prop_set(z_zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
2212                         be_print_err(gettext("be_copy_zones: "
2213                             "failed to set active property\n"));
2214                         ZFS_CLOSE(z_zhp);
2215                         ret = zfs_err_to_be_err(g_zfs);
2216                         goto done;
2217                 }
2218 
2219                 /*
2220                  * Generate a list of file systems from the original
2221                  * zone BE that are legacy mounted.  We use this list
2222                  * to determine which entries in the vfstab we need to
2223                  * update for the new zone BE we've just created.
2224                  */
2225                 if ((ret = be_get_legacy_fs(obe_name, obe_root_ds,
2226                     zoneroot_ds, zoneroot, &fld)) != BE_SUCCESS) {
2227                         be_print_err(gettext("be_copy_zones: "
2228                             "failed to get legacy mounted file system "
2229                             "list for zone %s\n"), zonename);
2230                         ZFS_CLOSE(z_zhp);
2231                         goto done;
2232                 }
2233 
2234                 /*
2235                  * Update new zone BE's vfstab.
2236                  */
2237                 if ((ret = be_update_zone_vfstab(z_zhp, bt.nbe_name,
2238                     zonepath_ds, zonepath_ds, &fld)) != BE_SUCCESS) {
2239                         be_print_err(gettext("be_copy_zones: "
2240                             "failed to update new BE's vfstab (%s)\n"),
2241                             bt.nbe_name);
2242                         ZFS_CLOSE(z_zhp);
2243                         be_free_fs_list(&fld);
2244                         goto done;
2245                 }
2246 
2247                 be_free_fs_list(&fld);
2248                 ZFS_CLOSE(z_zhp);
2249         }
2250 
2251 done:
2252         free(snap_name);
2253         if (zlist != NULL)
2254                 z_free_zone_list(zlist);
2255 
2256         if (mounted_here)
2257                 (void) _be_unmount(obe_name, 0);
2258 
2259         ZFS_CLOSE(obe_zhp);
2260         return (ret);
2261 }
2262 
2263 /*
2264  * Function:    be_clone_fs_callback
2265  * Description: Callback function used to iterate through a BE's filesystems
2266  *              to clone them for the new BE.
2267  * Parameters:
2268  *              zhp - zfs_handle_t pointer for the filesystem being processed.
2269  *              data - be_transaction_data_t pointer providing information
2270  *                      about original BE and new BE.
2271  * Return:
2272  *              0 - Success
2273  *              be_errno_t - Failure
2274  * Scope:
2275  *              Private
2276  */
2277 static int
2278 be_clone_fs_callback(zfs_handle_t *zhp, void *data)
2279 {
2280         be_transaction_data_t   *bt = data;
2281         zfs_handle_t    *zhp_ss = NULL;
2282         char            prop_buf[MAXPATHLEN];
2283         char            zhp_name[ZFS_MAXNAMELEN];
2284         char            clone_ds[MAXPATHLEN];
2285         char            ss[MAXPATHLEN];
2286         int             ret = 0;
2287 
2288         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
2289             ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) != 0) {
2290                 be_print_err(gettext("be_clone_fs_callback: "
2291                     "failed to get dataset mountpoint (%s): %s\n"),
2292                     zfs_get_name(zhp), libzfs_error_description(g_zfs));
2293                 ret = zfs_err_to_be_err(g_zfs);
2294                 ZFS_CLOSE(zhp);
2295                 return (ret);
2296         }
2297 
2298         if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) != 0 &&
2299             strcmp(prop_buf, "legacy") != 0) {
2300                 /*
2301                  * Since zfs can't currently handle setting the
2302                  * mountpoint for a zoned dataset we'll have to skip
2303                  * this dataset. This is because the mountpoint is not
2304                  * set to "legacy".
2305                  */
2306                 goto zoned;
2307         }
2308         /*
2309          * Get a copy of the dataset name from the zfs handle
2310          */
2311         (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2312 
2313         /*
2314          * Get the clone dataset name and prepare the zfs properties for it.
2315          */
2316         if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2317             sizeof (clone_ds))) != BE_SUCCESS) {
2318                 ZFS_CLOSE(zhp);
2319                 return (ret);
2320         }
2321 
2322         /*
2323          * Generate the name of the snapshot to use.
2324          */
2325         (void) snprintf(ss, sizeof (ss), "%s@%s", zhp_name,
2326             bt->obe_snap_name);
2327 
2328         /*
2329          * Get handle to snapshot.
2330          */
2331         if ((zhp_ss = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) {
2332                 be_print_err(gettext("be_clone_fs_callback: "
2333                     "failed to get handle to snapshot (%s): %s\n"), ss,
2334                     libzfs_error_description(g_zfs));
2335                 ret = zfs_err_to_be_err(g_zfs);
2336                 ZFS_CLOSE(zhp);
2337                 return (ret);
2338         }
2339 
2340         /*
2341          * Clone the dataset.
2342          */
2343         if (zfs_clone(zhp_ss, clone_ds, bt->nbe_zfs_props) != 0) {
2344                 be_print_err(gettext("be_clone_fs_callback: "
2345                     "failed to create clone dataset (%s): %s\n"),
2346                     clone_ds, libzfs_error_description(g_zfs));
2347 
2348                 ZFS_CLOSE(zhp_ss);
2349                 ZFS_CLOSE(zhp);
2350 
2351                 return (zfs_err_to_be_err(g_zfs));
2352         }
2353 
2354         ZFS_CLOSE(zhp_ss);
2355 
2356 zoned:
2357         /*
2358          * Iterate through zhp's children datasets (if any)
2359          * and clone them accordingly.
2360          */
2361         if ((ret = zfs_iter_filesystems(zhp, be_clone_fs_callback, bt)) != 0) {
2362                 /*
2363                  * Error occurred while processing a child dataset.
2364                  * Destroy this dataset and return error.
2365                  */
2366                 zfs_handle_t    *d_zhp = NULL;
2367 
2368                 ZFS_CLOSE(zhp);
2369 
2370                 if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2371                     == NULL) {
2372                         return (ret);
2373                 }
2374 
2375                 (void) zfs_destroy(d_zhp, B_FALSE);
2376                 ZFS_CLOSE(d_zhp);
2377                 return (ret);
2378         }
2379 
2380         ZFS_CLOSE(zhp);
2381         return (0);
2382 }
2383 
2384 /*
2385  * Function:    be_send_fs_callback
2386  * Description: Callback function used to iterate through a BE's filesystems
2387  *              to copy them for the new BE.
2388  * Parameters:
2389  *              zhp - zfs_handle_t pointer for the filesystem being processed.
2390  *              data - be_transaction_data_t pointer providing information
2391  *                      about original BE and new BE.
2392  * Return:
2393  *              0 - Success
2394  *              be_errnot_t - Failure
2395  * Scope:
2396  *              Private
2397  */
2398 static int
2399 be_send_fs_callback(zfs_handle_t *zhp, void *data)
2400 {
2401         be_transaction_data_t   *bt = data;
2402         recvflags_t     flags = { 0 };
2403         char            zhp_name[ZFS_MAXNAMELEN];
2404         char            clone_ds[MAXPATHLEN];
2405         sendflags_t     send_flags = { 0 };
2406         int             pid, status, retval;
2407         int             srpipe[2];
2408         int             ret = 0;
2409 
2410         /*
2411          * Get a copy of the dataset name from the zfs handle
2412          */
2413         (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2414 
2415         /*
2416          * Get the clone dataset name and prepare the zfs properties for it.
2417          */
2418         if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2419             sizeof (clone_ds))) != BE_SUCCESS) {
2420                 ZFS_CLOSE(zhp);
2421                 return (ret);
2422         }
2423 
2424         /*
2425          * Create the new dataset.
2426          */
2427         if (zfs_create(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM, bt->nbe_zfs_props)
2428             != 0) {
2429                 be_print_err(gettext("be_send_fs_callback: "
2430                     "failed to create new dataset '%s': %s\n"),
2431                     clone_ds, libzfs_error_description(g_zfs));
2432                 ret = zfs_err_to_be_err(g_zfs);
2433                 ZFS_CLOSE(zhp);
2434                 return (ret);
2435         }
2436 
2437         /*
2438          * Destination file system is already created
2439          * hence we need to set the force flag on
2440          */
2441         flags.force = B_TRUE;
2442 
2443         /*
2444          * Initiate the pipe to be used for the send and recv
2445          */
2446         if (pipe(srpipe) != 0) {
2447                 int err = errno;
2448                 be_print_err(gettext("be_send_fs_callback: failed to "
2449                     "open pipe\n"));
2450                 ZFS_CLOSE(zhp);
2451                 return (errno_to_be_err(err));
2452         }
2453 
2454         /*
2455          * Fork off a child to send the dataset
2456          */
2457         if ((pid = fork()) == -1) {
2458                 int err = errno;
2459                 be_print_err(gettext("be_send_fs_callback: failed to fork\n"));
2460                 (void) close(srpipe[0]);
2461                 (void) close(srpipe[1]);
2462                 ZFS_CLOSE(zhp);
2463                 return (errno_to_be_err(err));
2464         } else if (pid == 0) { /* child process */
2465                 (void) close(srpipe[0]);
2466 
2467                 /* Send dataset */
2468                 if (zfs_send(zhp, NULL, bt->obe_snap_name, &send_flags,
2469                     srpipe[1], NULL, NULL, NULL) != 0) {
2470                         _exit(1);
2471                 }
2472                 ZFS_CLOSE(zhp);
2473 
2474                 _exit(0);
2475         }
2476 
2477         (void) close(srpipe[1]);
2478 
2479         /* Receive dataset */
2480         if (zfs_receive(g_zfs, clone_ds, NULL, &flags, srpipe[0], NULL) != 0) {
2481                 be_print_err(gettext("be_send_fs_callback: failed to "
2482                     "recv dataset (%s)\n"), clone_ds);
2483         }
2484         (void) close(srpipe[0]);
2485 
2486         /* wait for child to exit */
2487         do {
2488                 retval = waitpid(pid, &status, 0);
2489                 if (retval == -1) {
2490                         status = 0;
2491                 }
2492         } while (retval != pid);
2493 
2494         if (WEXITSTATUS(status) != 0) {
2495                 be_print_err(gettext("be_send_fs_callback: failed to "
2496                     "send dataset (%s)\n"), zhp_name);
2497                 ZFS_CLOSE(zhp);
2498                 return (BE_ERR_ZFS);
2499         }
2500 
2501 
2502         /*
2503          * Iterate through zhp's children datasets (if any)
2504          * and send them accordingly.
2505          */
2506         if ((ret = zfs_iter_filesystems(zhp, be_send_fs_callback, bt)) != 0) {
2507                 /*
2508                  * Error occurred while processing a child dataset.
2509                  * Destroy this dataset and return error.
2510                  */
2511                 zfs_handle_t    *d_zhp = NULL;
2512 
2513                 ZFS_CLOSE(zhp);
2514 
2515                 if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2516                     == NULL) {
2517                         return (ret);
2518                 }
2519 
2520                 (void) zfs_destroy(d_zhp, B_FALSE);
2521                 ZFS_CLOSE(d_zhp);
2522                 return (ret);
2523         }
2524 
2525         ZFS_CLOSE(zhp);
2526         return (0);
2527 }
2528 
2529 /*
2530  * Function:    be_destroy_callback
2531  * Description: Callback function used to destroy a BEs children datasets
2532  *              and snapshots.
2533  * Parameters:
2534  *              zhp - zfs_handle_t pointer to the filesystem being processed.
2535  *              data - Not used.
2536  * Returns:
2537  *              0 - Success
2538  *              be_errno_t - Failure
2539  * Scope:
2540  *              Private
2541  */
2542 static int
2543 be_destroy_callback(zfs_handle_t *zhp, void *data)
2544 {
2545         be_destroy_data_t       *dd = data;
2546         int ret = 0;
2547 
2548         /*
2549          * Iterate down this file system's hierarchical children
2550          * and destroy them first.
2551          */
2552         if ((ret = zfs_iter_filesystems(zhp, be_destroy_callback, dd)) != 0) {
2553                 ZFS_CLOSE(zhp);
2554                 return (ret);
2555         }
2556 
2557         if (dd->destroy_snaps) {
2558                 /*
2559                  * Iterate through this file system's snapshots and
2560                  * destroy them before destroying the file system itself.
2561                  */
2562                 if ((ret = zfs_iter_snapshots(zhp, be_destroy_callback, dd))
2563                     != 0) {
2564                         ZFS_CLOSE(zhp);
2565                         return (ret);
2566                 }
2567         }
2568 
2569         /* Attempt to unmount the dataset before destroying it */
2570         if (dd->force_unmount) {
2571                 if ((ret = zfs_unmount(zhp, NULL, MS_FORCE)) != 0) {
2572                         be_print_err(gettext("be_destroy_callback: "
2573                             "failed to unmount %s: %s\n"), zfs_get_name(zhp),
2574                             libzfs_error_description(g_zfs));
2575                         ret = zfs_err_to_be_err(g_zfs);
2576                         ZFS_CLOSE(zhp);
2577                         return (ret);
2578                 }
2579         }
2580 
2581         if (zfs_destroy(zhp, B_FALSE) != 0) {
2582                 be_print_err(gettext("be_destroy_callback: "
2583                     "failed to destroy %s: %s\n"), zfs_get_name(zhp),
2584                     libzfs_error_description(g_zfs));
2585                 ret = zfs_err_to_be_err(g_zfs);
2586                 ZFS_CLOSE(zhp);
2587                 return (ret);
2588         }
2589 
2590         ZFS_CLOSE(zhp);
2591         return (0);
2592 }
2593 
2594 /*
2595  * Function:    be_demote_callback
2596  * Description: This callback function is used to iterate through the file
2597  *              systems of a BE, looking for the right clone to promote such
2598  *              that this file system is left without any dependent clones.
2599  *              If the file system has no dependent clones, it doesn't need
2600  *              to get demoted, and the function will return success.
2601  *
2602  *              The demotion will be done in two passes.  The first pass
2603  *              will attempt to find the youngest snapshot that has a clone
2604  *              that is part of some other BE.  The second pass will attempt
2605  *              to find the youngest snapshot that has a clone that is not
2606  *              part of a BE.  Doing this helps ensure the aggregated set of
2607  *              file systems that compose a BE stay coordinated wrt BE
2608  *              snapshots and BE dependents.  It also prevents a random user
2609  *              generated clone of a BE dataset to become the parent of other
2610  *              BE datasets after demoting this dataset.
2611  *
2612  * Parameters:
2613  *              zhp - zfs_handle_t pointer to the current file system being
2614  *                      processed.
2615  *              data - not used.
2616  * Return:
2617  *              0 - Success
2618  *              be_errno_t - Failure
2619  * Scope:
2620  *              Private
2621  */
2622 static int
2623 /* LINTED */
2624 be_demote_callback(zfs_handle_t *zhp, void *data)
2625 {
2626         be_demote_data_t        dd = { 0 };
2627         int                     i, ret = 0;
2628 
2629         /*
2630          * Initialize be_demote_data for the first pass - this will find a
2631          * clone in another BE, if one exists.
2632          */
2633         dd.find_in_BE = B_TRUE;
2634 
2635         for (i = 0; i < 2; i++) {
2636 
2637                 if (zfs_iter_snapshots(zhp, be_demote_find_clone_callback, &dd)
2638                     != 0) {
2639                         be_print_err(gettext("be_demote_callback: "
2640                             "failed to iterate snapshots for %s: %s\n"),
2641                             zfs_get_name(zhp), libzfs_error_description(g_zfs));
2642                         ret = zfs_err_to_be_err(g_zfs);
2643                         ZFS_CLOSE(zhp);
2644                         return (ret);
2645                 }
2646                 if (dd.clone_zhp != NULL) {
2647                         /* Found the clone to promote.  Promote it. */
2648                         if (zfs_promote(dd.clone_zhp) != 0) {
2649                                 be_print_err(gettext("be_demote_callback: "
2650                                     "failed to promote %s: %s\n"),
2651                                     zfs_get_name(dd.clone_zhp),
2652                                     libzfs_error_description(g_zfs));
2653                                 ret = zfs_err_to_be_err(g_zfs);
2654                                 ZFS_CLOSE(dd.clone_zhp);
2655                                 ZFS_CLOSE(zhp);
2656                                 return (ret);
2657                         }
2658 
2659                         ZFS_CLOSE(dd.clone_zhp);
2660                 }
2661 
2662                 /*
2663                  * Reinitialize be_demote_data for the second pass.
2664                  * This will find a user created clone outside of any BE
2665                  * namespace, if one exists.
2666                  */
2667                 dd.clone_zhp = NULL;
2668                 dd.origin_creation = 0;
2669                 dd.snapshot = NULL;
2670                 dd.find_in_BE = B_FALSE;
2671         }
2672 
2673         /* Iterate down this file system's children and demote them */
2674         if ((ret = zfs_iter_filesystems(zhp, be_demote_callback, NULL)) != 0) {
2675                 ZFS_CLOSE(zhp);
2676                 return (ret);
2677         }
2678 
2679         ZFS_CLOSE(zhp);
2680         return (0);
2681 }
2682 
2683 /*
2684  * Function:    be_demote_find_clone_callback
2685  * Description: This callback function is used to iterate through the
2686  *              snapshots of a dataset, looking for the youngest snapshot
2687  *              that has a clone.  If found, it returns a reference to the
2688  *              clone back to the caller in the callback data.
2689  * Parameters:
2690  *              zhp - zfs_handle_t pointer to current snapshot being looked at
2691  *              data - be_demote_data_t pointer used to store the clone that
2692  *                      is found.
2693  * Returns:
2694  *              0 - Successfully iterated through all snapshots.
2695  *              1 - Failed to iterate through all snapshots.
2696  * Scope:
2697  *              Private
2698  */
2699 static int
2700 be_demote_find_clone_callback(zfs_handle_t *zhp, void *data)
2701 {
2702         be_demote_data_t        *dd = data;
2703         time_t                  snap_creation;
2704         int                     zret = 0;
2705 
2706         /* If snapshot has no clones, no need to look at it */
2707         if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
2708                 ZFS_CLOSE(zhp);
2709                 return (0);
2710         }
2711 
2712         dd->snapshot = zfs_get_name(zhp);
2713 
2714         /* Get the creation time of this snapshot */
2715         snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
2716 
2717         /*
2718          * If this snapshot's creation time is greater than (or younger than)
2719          * the current youngest snapshot found, iterate this snapshot to
2720          * check if it has a clone that we're looking for.
2721          */
2722         if (snap_creation >= dd->origin_creation) {
2723                 /*
2724                  * Iterate the dependents of this snapshot to find a
2725                  * a clone that's a direct dependent.
2726                  */
2727                 if ((zret = zfs_iter_dependents(zhp, B_FALSE,
2728                     be_demote_get_one_clone, dd)) == -1) {
2729                         be_print_err(gettext("be_demote_find_clone_callback: "
2730                             "failed to iterate dependents of %s\n"),
2731                             zfs_get_name(zhp));
2732                         ZFS_CLOSE(zhp);
2733                         return (1);
2734                 } else if (zret == 1) {
2735                         /*
2736                          * Found a clone, update the origin_creation time
2737                          * in the callback data.
2738                          */
2739                         dd->origin_creation = snap_creation;
2740                 }
2741         }
2742 
2743         ZFS_CLOSE(zhp);
2744         return (0);
2745 }
2746 
2747 /*
2748  * Function:    be_demote_get_one_clone
2749  * Description: This callback function is used to iterate through a
2750  *              snapshot's dependencies to find a filesystem that is a
2751  *              direct clone of the snapshot being iterated.
2752  * Parameters:
2753  *              zhp - zfs_handle_t pointer to current dataset being looked at
2754  *              data - be_demote_data_t pointer used to store the clone
2755  *                      that is found, and also provides flag to note
2756  *                      whether or not the clone filesystem being searched
2757  *                      for needs to be found in a BE dataset hierarchy.
2758  * Return:
2759  *              1 - Success, found clone and its also a BE's root dataset.
2760  *              0 - Failure, clone not found.
2761  * Scope:
2762  *              Private
2763  */
2764 static int
2765 be_demote_get_one_clone(zfs_handle_t *zhp, void *data)
2766 {
2767         be_demote_data_t        *dd = data;
2768         char                    origin[ZFS_MAXNAMELEN];
2769         char                    ds_path[ZFS_MAXNAMELEN];
2770 
2771         if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2772                 ZFS_CLOSE(zhp);
2773                 return (0);
2774         }
2775 
2776         (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
2777 
2778         /*
2779          * Make sure this is a direct clone of the snapshot
2780          * we're iterating.
2781          */
2782         if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
2783             NULL, 0, B_FALSE) != 0) {
2784                 be_print_err(gettext("be_demote_get_one_clone: "
2785                     "failed to get origin of %s: %s\n"), ds_path,
2786                     libzfs_error_description(g_zfs));
2787                 ZFS_CLOSE(zhp);
2788                 return (0);
2789         }
2790         if (strcmp(origin, dd->snapshot) != 0) {
2791                 ZFS_CLOSE(zhp);
2792                 return (0);
2793         }
2794 
2795         if (dd->find_in_BE) {
2796                 if ((zpool_iter(g_zfs, be_check_be_roots_callback, ds_path))
2797                     > 0) {
2798                         if (dd->clone_zhp != NULL)
2799                                 ZFS_CLOSE(dd->clone_zhp);
2800                         dd->clone_zhp = zhp;
2801                         return (1);
2802                 }
2803 
2804                 ZFS_CLOSE(zhp);
2805                 return (0);
2806         }
2807 
2808         if (dd->clone_zhp != NULL)
2809                 ZFS_CLOSE(dd->clone_zhp);
2810 
2811         dd->clone_zhp = zhp;
2812         return (1);
2813 }
2814 
2815 /*
2816  * Function:    be_get_snap
2817  * Description: This function takes a snapshot dataset name and separates
2818  *              out the parent dataset portion from the snapshot name.
2819  *              I.e. it finds the '@' in the snapshot dataset name and
2820  *              replaces it with a '\0'.
2821  * Parameters:
2822  *              origin - char pointer to a snapshot dataset name.  Its
2823  *                      contents will be modified by this function.
2824  *              *snap - pointer to a char pointer.  Will be set to the
2825  *                      snapshot name portion upon success.
2826  * Return:
2827  *              BE_SUCCESS - Success
2828  *              1 - Failure
2829  * Scope:
2830  *              Private
2831  */
2832 static int
2833 be_get_snap(char *origin, char **snap)
2834 {
2835         char    *cp;
2836 
2837         /*
2838          * Separate out the origin's dataset and snapshot portions by
2839          * replacing the @ with a '\0'
2840          */
2841         cp = strrchr(origin, '@');
2842         if (cp != NULL) {
2843                 if (cp[1] != NULL && cp[1] != '\0') {
2844                         cp[0] = '\0';
2845                         *snap = cp+1;
2846                 } else {
2847                         return (1);
2848                 }
2849         } else {
2850                 return (1);
2851         }
2852 
2853         return (BE_SUCCESS);
2854 }
2855 
2856 /*
2857  * Function:    be_create_container_ds
2858  * Description: This function checks that the zpool passed has the BE
2859  *              container dataset, and if not, then creates it.
2860  * Parameters:
2861  *              zpool - name of pool to create BE container dataset in.
2862  * Return:
2863  *              B_TRUE - Successfully created BE container dataset, or it
2864  *                      already existed.
2865  *              B_FALSE - Failed to create container dataset.
2866  * Scope:
2867  *              Private
2868  */
2869 static boolean_t
2870 be_create_container_ds(char *zpool)
2871 {
2872         nvlist_t        *props = NULL;
2873         char            be_container_ds[MAXPATHLEN];
2874 
2875         /* Generate string for BE container dataset for this pool */
2876         be_make_container_ds(zpool, be_container_ds,
2877             sizeof (be_container_ds));
2878 
2879         if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2880 
2881                 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
2882                         be_print_err(gettext("be_create_container_ds: "
2883                             "nvlist_alloc failed\n"));
2884                         return (B_FALSE);
2885                 }
2886 
2887                 if (nvlist_add_string(props,
2888                     zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2889                     ZFS_MOUNTPOINT_LEGACY) != 0) {
2890                         be_print_err(gettext("be_create_container_ds: "
2891                             "internal error: out of memory\n"));
2892                         nvlist_free(props);
2893                         return (B_FALSE);
2894                 }
2895 
2896                 if (nvlist_add_string(props,
2897                     zfs_prop_to_name(ZFS_PROP_CANMOUNT), "off") != 0) {
2898                         be_print_err(gettext("be_create_container_ds: "
2899                             "internal error: out of memory\n"));
2900                         nvlist_free(props);
2901                         return (B_FALSE);
2902                 }
2903 
2904                 if (zfs_create(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM,
2905                     props) != 0) {
2906                         be_print_err(gettext("be_create_container_ds: "
2907                             "failed to create container dataset (%s): %s\n"),
2908                             be_container_ds, libzfs_error_description(g_zfs));
2909                         nvlist_free(props);
2910                         return (B_FALSE);
2911                 }
2912 
2913                 nvlist_free(props);
2914         }
2915 
2916         return (B_TRUE);
2917 }
2918 
2919 /*
2920  * Function:    be_prep_clone_send_fs
2921  * Description: This function takes a zfs handle to a dataset from the
2922  *              original BE, and generates the name of the clone dataset
2923  *              to create for the new BE.  It also prepares the zfs
2924  *              properties to be used for the new BE.
2925  * Parameters:
2926  *              zhp - pointer to zfs_handle_t of the file system being
2927  *                      cloned/copied.
2928  *              bt - be_transaction_data pointer providing information
2929  *                      about the original BE and new BE.
2930  *              clone_ds - buffer to store the name of the dataset
2931  *                      for the new BE.
2932  *              clone_ds_len - length of clone_ds buffer
2933  * Return:
2934  *              BE_SUCCESS - Success
2935  *              be_errno_t - Failure
2936  * Scope:
2937  *              Private
2938  */
2939 static int
2940 be_prep_clone_send_fs(zfs_handle_t *zhp, be_transaction_data_t *bt,
2941     char *clone_ds, int clone_ds_len)
2942 {
2943         zprop_source_t  sourcetype;
2944         char            source[ZFS_MAXNAMELEN];
2945         char            zhp_name[ZFS_MAXNAMELEN];
2946         char            mountpoint[MAXPATHLEN];
2947         char            *child_fs = NULL;
2948         char            *zhp_mountpoint = NULL;
2949         int             err = 0;
2950 
2951         /*
2952          * Get a copy of the dataset name zfs_name from zhp
2953          */
2954         (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2955 
2956         /*
2957          * Get file system name relative to the root.
2958          */
2959         if (strncmp(zhp_name, bt->obe_root_ds, strlen(bt->obe_root_ds))
2960             == 0) {
2961                 child_fs = zhp_name + strlen(bt->obe_root_ds);
2962 
2963                 /*
2964                  * if child_fs is NULL, this means we're processing the
2965                  * root dataset itself; set child_fs to the empty string.
2966                  */
2967                 if (child_fs == NULL)
2968                         child_fs = "";
2969         } else {
2970                 return (BE_ERR_INVAL);
2971         }
2972 
2973         /*
2974          * Generate the name of the clone file system.
2975          */
2976         (void) snprintf(clone_ds, clone_ds_len, "%s%s", bt->nbe_root_ds,
2977             child_fs);
2978 
2979         /* Get the mountpoint and source properties of the existing dataset */
2980         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2981             sizeof (mountpoint), &sourcetype, source, sizeof (source),
2982             B_FALSE) != 0) {
2983                 be_print_err(gettext("be_prep_clone_send_fs: "
2984                     "failed to get mountpoint for (%s): %s\n"),
2985                     zhp_name, libzfs_error_description(g_zfs));
2986                 return (zfs_err_to_be_err(g_zfs));
2987         }
2988 
2989         /*
2990          * Workaround for 6668667 where a mountpoint property of "/" comes
2991          * back as "".
2992          */
2993         if (strcmp(mountpoint, "") == 0) {
2994                 (void) snprintf(mountpoint, sizeof (mountpoint), "/");
2995         }
2996 
2997         /*
2998          * Figure out what to set as the mountpoint for the new dataset.
2999          * If the source of the mountpoint property is local, use the
3000          * mountpoint value itself.  Otherwise, remove it from the
3001          * zfs properties list so that it gets inherited.
3002          */
3003         if (sourcetype & ZPROP_SRC_LOCAL) {
3004                 /*
3005                  * If the BE that this file system is a part of is
3006                  * currently mounted, strip off the BE altroot portion
3007                  * from the mountpoint.
3008                  */
3009                 zhp_mountpoint = mountpoint;
3010 
3011                 if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
3012                     bt->obe_altroot != NULL && strcmp(bt->obe_altroot,
3013                     "/") != 0 && zfs_is_mounted(zhp, NULL)) {
3014 
3015                         int altroot_len = strlen(bt->obe_altroot);
3016 
3017                         if (strncmp(bt->obe_altroot, mountpoint, altroot_len)
3018                             == 0) {
3019                                 if (mountpoint[altroot_len] == '/')
3020                                         zhp_mountpoint = mountpoint +
3021                                             altroot_len;
3022                                 else if (mountpoint[altroot_len] == '\0')
3023                                         (void) snprintf(mountpoint,
3024                                             sizeof (mountpoint), "/");
3025                         }
3026                 }
3027 
3028                 if (nvlist_add_string(bt->nbe_zfs_props,
3029                     zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
3030                     zhp_mountpoint) != 0) {
3031                         be_print_err(gettext("be_prep_clone_send_fs: "
3032                             "internal error: out of memory\n"));
3033                         return (BE_ERR_NOMEM);
3034                 }
3035         } else {
3036                 err = nvlist_remove_all(bt->nbe_zfs_props,
3037                     zfs_prop_to_name(ZFS_PROP_MOUNTPOINT));
3038                 if (err != 0 && err != ENOENT) {
3039                         be_print_err(gettext("be_prep_clone_send_fs: "
3040                             "failed to remove mountpoint from "
3041                             "nvlist\n"));
3042                         return (BE_ERR_INVAL);
3043                 }
3044         }
3045 
3046         /*
3047          * Set the 'canmount' property
3048          */
3049         if (nvlist_add_string(bt->nbe_zfs_props,
3050             zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
3051                 be_print_err(gettext("be_prep_clone_send_fs: "
3052                     "internal error: out of memory\n"));
3053                 return (BE_ERR_NOMEM);
3054         }
3055 
3056         return (BE_SUCCESS);
3057 }
3058 
3059 /*
3060  * Function:    be_get_zone_be_name
3061  * Description: This function takes the zones root dataset, the container
3062  *              dataset and returns the zones BE name based on the zone
3063  *              root dataset.
3064  * Parameters:
3065  *              root_ds - the zones root dataset.
3066  *              container_ds - the container dataset for the zone.
3067  * Returns:
3068  *              char * - the BE name of this zone based on the root dataset.
3069  */
3070 static char *
3071 be_get_zone_be_name(char *root_ds, char *container_ds)
3072 {
3073         return (root_ds + (strlen(container_ds) + 1));
3074 }
3075 
3076 /*
3077  * Function:    be_zone_root_exists_callback
3078  * Description: This callback function is used to determine if a
3079  *              zone root container dataset has any children.  It always
3080  *              returns 1, signifying a hierarchical child of the zone
3081  *              root container dataset has been traversed and therefore
3082  *              it has children.
3083  * Parameters:
3084  *              zhp - zfs_handle_t pointer to current dataset being processed.
3085  *              data - not used.
3086  * Returns:
3087  *              1 - dataset exists
3088  * Scope:
3089  *              Private
3090  */
3091 static int
3092 /* LINTED */
3093 be_zone_root_exists_callback(zfs_handle_t *zhp, void *data)
3094 {
3095         ZFS_CLOSE(zhp);
3096         return (1);
3097 }