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, 2015 by Delphix. All rights reserved.
  26  * Copyright (c) 2016 Martin Matuska. All rights reserved.
  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         nvlist_free(bt.nbe_zfs_props);
 357 
 358         be_zfs_fini();
 359 
 360         return (ret);
 361 }
 362 
 363 /*
 364  * Function:    be_destroy
 365  * Description: Destroy a BE and all of its children datasets, snapshots and
 366  *              zones that belong to the parent BE.
 367  * Parameters:
 368  *              be_attrs - pointer to nvlist_t of attributes being passed in.
 369  *                      The following attributes are used by this function:
 370  *
 371  *                      BE_ATTR_ORIG_BE_NAME            *required
 372  *                      BE_ATTR_DESTROY_FLAGS           *optional
 373  * Return:
 374  *              BE_SUCCESS - Success
 375  *              be_errno_t - Failure
 376  * Scope:
 377  *              Public
 378  */
 379 int
 380 be_destroy(nvlist_t *be_attrs)
 381 {
 382         zfs_handle_t            *zhp = NULL;
 383         be_transaction_data_t   bt = { 0 };
 384         be_transaction_data_t   cur_bt = { 0 };
 385         be_destroy_data_t       dd = { 0 };
 386         int                     ret = BE_SUCCESS;
 387         uint16_t                flags = 0;
 388         boolean_t               bs_found = B_FALSE;
 389         int                     zret;
 390         char                    obe_root_ds[MAXPATHLEN];
 391         char                    *mp = NULL;
 392 
 393         /* Initialize libzfs handle */
 394         if (!be_zfs_init())
 395                 return (BE_ERR_INIT);
 396 
 397         /* Get name of BE to delete */
 398         if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &bt.obe_name)
 399             != 0) {
 400                 be_print_err(gettext("be_destroy: failed to lookup "
 401                     "BE_ATTR_ORIG_BE_NAME attribute\n"));
 402                 return (BE_ERR_INVAL);
 403         }
 404 
 405         /*
 406          * Validate BE name. If valid, then check that the original BE is not
 407          * the active BE. If it is the 'active' BE then return an error code
 408          * since we can't destroy the active BE.
 409          */
 410         if (!be_valid_be_name(bt.obe_name)) {
 411                 be_print_err(gettext("be_destroy: invalid BE name %s\n"),
 412                     bt.obe_name);
 413                 return (BE_ERR_INVAL);
 414         } else if (bt.obe_name != NULL) {
 415                 if ((ret = be_find_current_be(&cur_bt)) != BE_SUCCESS) {
 416                         return (ret);
 417                 }
 418                 if (strcmp(cur_bt.obe_name, bt.obe_name) == 0) {
 419                         return (BE_ERR_DESTROY_CURR_BE);
 420                 }
 421         }
 422 
 423         /* Get destroy flags if provided */
 424         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 425             BE_ATTR_DESTROY_FLAGS, DATA_TYPE_UINT16, &flags, NULL)
 426             != 0) {
 427                 be_print_err(gettext("be_destroy: failed to lookup "
 428                     "BE_ATTR_DESTROY_FLAGS attribute\n"));
 429                 return (BE_ERR_INVAL);
 430         }
 431 
 432         dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
 433         dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
 434 
 435         /* Find which zpool obe_name lives in */
 436         if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
 437                 be_print_err(gettext("be_destroy: failed to find zpool "
 438                     "for BE (%s)\n"), bt.obe_name);
 439                 return (BE_ERR_BE_NOENT);
 440         } else if (zret < 0) {
 441                 be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"),
 442                     libzfs_error_description(g_zfs));
 443                 return (zfs_err_to_be_err(g_zfs));
 444         }
 445 
 446         /* Generate string for obe_name's root dataset */
 447         be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
 448             sizeof (obe_root_ds));
 449         bt.obe_root_ds = obe_root_ds;
 450 
 451         if (getzoneid() != GLOBAL_ZONEID) {
 452                 if (!be_zone_compare_uuids(bt.obe_root_ds)) {
 453                         if (be_is_active_on_boot(bt.obe_name)) {
 454                                 be_print_err(gettext("be_destroy: destroying "
 455                                     "active zone root dataset from non-active "
 456                                     "global BE is not supported\n"));
 457                                 return (BE_ERR_NOTSUP);
 458                         }
 459                 }
 460         }
 461 
 462         /*
 463          * Detect if the BE to destroy has the 'active on boot' property set.
 464          * If so, set the 'active on boot' property on the the 'active' BE.
 465          */
 466         if (be_is_active_on_boot(bt.obe_name)) {
 467                 if ((ret = be_activate_current_be()) != BE_SUCCESS) {
 468                         be_print_err(gettext("be_destroy: failed to "
 469                             "make the current BE 'active on boot'\n"));
 470                         return (ret);
 471                 }
 472         }
 473 
 474         /* Get handle to BE's root dataset */
 475         if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
 476             NULL) {
 477                 be_print_err(gettext("be_destroy: failed to "
 478                     "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
 479                     libzfs_error_description(g_zfs));
 480                 return (zfs_err_to_be_err(g_zfs));
 481         }
 482 
 483         /*
 484          * Check if BE has snapshots and BE_DESTROY_FLAG_SNAPSHOTS
 485          * is not set.
 486          */
 487         (void) zfs_iter_snapshots(zhp, B_FALSE, be_has_snapshot_callback,
 488             &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         nvlist_free(bt.nbe_zfs_props);
1172 
1173         free(bt.obe_altroot);
1174         free(new_mp);
1175 
1176         /*
1177          * If a failure occurred and we already created the datasets for
1178          * the new boot environment, destroy them.
1179          */
1180         if (ret != BE_SUCCESS && be_created) {
1181                 be_destroy_data_t       cdd = { 0 };
1182 
1183                 cdd.force_unmount = B_TRUE;
1184 
1185                 be_print_err(gettext("be_copy: "
1186                     "destroying partially created boot environment\n"));
1187 
1188                 if (getzoneid() == GLOBAL_ZONEID && be_get_uuid(bt.nbe_root_ds,
1189                     &cdd.gz_be_uuid) == 0)
1190                         (void) be_destroy_zones(bt.nbe_name, bt.nbe_root_ds,
1191                             &cdd);
1192 
1193                 (void) _be_destroy(bt.nbe_root_ds, &cdd);
1194         }
1195 
1196         be_zfs_fini();
1197 
1198         return (ret);
1199 }
1200 
1201 /* ******************************************************************** */
1202 /*                      Semi-Private Functions                          */
1203 /* ******************************************************************** */
1204 
1205 /*
1206  * Function:    be_find_zpool_callback
1207  * Description: Callback function used to find the pool that a BE lives in.
1208  * Parameters:
1209  *              zlp - zpool_handle_t pointer for the current pool being
1210  *                      looked at.
1211  *              data - be_transaction_data_t pointer providing information
1212  *                      about the BE that's being searched for.
1213  *                      This function uses the obe_name member of this
1214  *                      parameter to use as the BE name to search for.
1215  *                      Upon successfully locating the BE, it populates
1216  *                      obe_zpool with the pool name that the BE is found in.
1217  * Returns:
1218  *              1 - BE exists in this pool.
1219  *              0 - BE does not exist in this pool.
1220  * Scope:
1221  *              Semi-private (library wide use only)
1222  */
1223 int
1224 be_find_zpool_callback(zpool_handle_t *zlp, void *data)
1225 {
1226         be_transaction_data_t   *bt = data;
1227         const char              *zpool =  zpool_get_name(zlp);
1228         char                    be_root_ds[MAXPATHLEN];
1229 
1230         /*
1231          * Generate string for the BE's root dataset
1232          */
1233         be_make_root_ds(zpool, bt->obe_name, be_root_ds, sizeof (be_root_ds));
1234 
1235         /*
1236          * Check if dataset exists
1237          */
1238         if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1239                 /* BE's root dataset exists in zpool */
1240                 bt->obe_zpool = strdup(zpool);
1241                 zpool_close(zlp);
1242                 return (1);
1243         }
1244 
1245         zpool_close(zlp);
1246         return (0);
1247 }
1248 
1249 /*
1250  * Function:    be_exists_callback
1251  * Description: Callback function used to find out if a BE exists.
1252  * Parameters:
1253  *              zlp - zpool_handle_t pointer to the current pool being
1254  *                      looked at.
1255  *              data - BE name to look for.
1256  * Return:
1257  *              1 - BE exists in this pool.
1258  *              0 - BE does not exist in this pool.
1259  * Scope:
1260  *              Semi-private (library wide use only)
1261  */
1262 int
1263 be_exists_callback(zpool_handle_t *zlp, void *data)
1264 {
1265         const char      *zpool = zpool_get_name(zlp);
1266         char            *be_name = data;
1267         char            be_root_ds[MAXPATHLEN];
1268 
1269         /*
1270          * Generate string for the BE's root dataset
1271          */
1272         be_make_root_ds(zpool, be_name, be_root_ds, sizeof (be_root_ds));
1273 
1274         /*
1275          * Check if dataset exists
1276          */
1277         if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1278                 /* BE's root dataset exists in zpool */
1279                 zpool_close(zlp);
1280                 return (1);
1281         }
1282 
1283         zpool_close(zlp);
1284         return (0);
1285 }
1286 
1287 /*
1288  * Function:    be_has_snapshots_callback
1289  * Description: Callback function used to find out if a BE has snapshots.
1290  * Parameters:
1291  *              zlp - zpool_handle_t pointer to the current pool being
1292  *                      looked at.
1293  *              data - be_snap_found_t pointer.
1294  * Return:
1295  *              1 - BE has no snapshots.
1296  *              0 - BE has snapshots.
1297  * Scope:
1298  *              Private
1299  */
1300 static int
1301 be_has_snapshot_callback(zfs_handle_t *zhp, void *data)
1302 {
1303         boolean_t *bs = data;
1304         if (zfs_get_name(zhp) == NULL) {
1305                 zfs_close(zhp);
1306                 return (1);
1307         }
1308         *bs = B_TRUE;
1309         zfs_close(zhp);
1310         return (0);
1311 }
1312 
1313 /*
1314  * Function:    be_set_uuid
1315  * Description: This function generates a uuid, unparses it into
1316  *              string representation, and sets that string into
1317  *              a zfs user property for a root dataset of a BE.
1318  *              The name of the user property used to store the
1319  *              uuid is org.opensolaris.libbe:uuid
1320  *
1321  * Parameters:
1322  *              root_ds - Root dataset of the BE to set a uuid on.
1323  * Return:
1324  *              be_errno_t - Failure
1325  *              BE_SUCCESS - Success
1326  * Scope:
1327  *              Semi-private (library wide ues only)
1328  */
1329 int
1330 be_set_uuid(char *root_ds)
1331 {
1332         zfs_handle_t    *zhp = NULL;
1333         uuid_t          uu = { 0 };
1334         char            uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1335         int             ret = BE_SUCCESS;
1336 
1337         /* Generate a UUID and unparse it into string form */
1338         uuid_generate(uu);
1339         if (uuid_is_null(uu) != 0) {
1340                 be_print_err(gettext("be_set_uuid: failed to "
1341                     "generate uuid\n"));
1342                 return (BE_ERR_GEN_UUID);
1343         }
1344         uuid_unparse(uu, uu_string);
1345 
1346         /* Get handle to the BE's root dataset. */
1347         if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1348                 be_print_err(gettext("be_set_uuid: failed to "
1349                     "open BE root dataset (%s): %s\n"), root_ds,
1350                     libzfs_error_description(g_zfs));
1351                 return (zfs_err_to_be_err(g_zfs));
1352         }
1353 
1354         /* Set uuid property for the BE */
1355         if (zfs_prop_set(zhp, BE_UUID_PROPERTY, uu_string) != 0) {
1356                 be_print_err(gettext("be_set_uuid: failed to "
1357                     "set uuid property for BE: %s\n"),
1358                     libzfs_error_description(g_zfs));
1359                 ret = zfs_err_to_be_err(g_zfs);
1360         }
1361 
1362         ZFS_CLOSE(zhp);
1363 
1364         return (ret);
1365 }
1366 
1367 /*
1368  * Function:    be_get_uuid
1369  * Description: This function gets the uuid string from a BE root
1370  *              dataset, parses it into internal format, and returns
1371  *              it the caller via a reference pointer passed in.
1372  *
1373  * Parameters:
1374  *              rootds - Root dataset of the BE to get the uuid from.
1375  *              uu - reference pointer to a uuid_t to return uuid in.
1376  * Return:
1377  *              be_errno_t - Failure
1378  *              BE_SUCCESS - Success
1379  * Scope:
1380  *              Semi-private (library wide use only)
1381  */
1382 int
1383 be_get_uuid(const char *root_ds, uuid_t *uu)
1384 {
1385         zfs_handle_t    *zhp = NULL;
1386         nvlist_t        *userprops = NULL;
1387         nvlist_t        *propname = NULL;
1388         char            *uu_string = NULL;
1389         int             ret = BE_SUCCESS;
1390 
1391         /* Get handle to the BE's root dataset. */
1392         if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1393                 be_print_err(gettext("be_get_uuid: failed to "
1394                     "open BE root dataset (%s): %s\n"), root_ds,
1395                     libzfs_error_description(g_zfs));
1396                 return (zfs_err_to_be_err(g_zfs));
1397         }
1398 
1399         /* Get user properties for BE's root dataset */
1400         if ((userprops = zfs_get_user_props(zhp)) == NULL) {
1401                 be_print_err(gettext("be_get_uuid: failed to "
1402                     "get user properties for BE root dataset (%s): %s\n"),
1403                     root_ds, libzfs_error_description(g_zfs));
1404                 ret = zfs_err_to_be_err(g_zfs);
1405                 goto done;
1406         }
1407 
1408         /* Get UUID string from BE's root dataset user properties */
1409         if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propname) != 0 ||
1410             nvlist_lookup_string(propname, ZPROP_VALUE, &uu_string) != 0) {
1411                 /*
1412                  * This probably just means that the BE is simply too old
1413                  * to have a uuid or that we haven't created a uuid for
1414                  * this BE yet.
1415                  */
1416                 be_print_err(gettext("be_get_uuid: failed to "
1417                     "get uuid property from BE root dataset user "
1418                     "properties.\n"));
1419                 ret = BE_ERR_NO_UUID;
1420                 goto done;
1421         }
1422         /* Parse uuid string into internal format */
1423         if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) {
1424                 be_print_err(gettext("be_get_uuid: failed to "
1425                     "parse uuid\n"));
1426                 ret = BE_ERR_PARSE_UUID;
1427                 goto done;
1428         }
1429 
1430 done:
1431         ZFS_CLOSE(zhp);
1432         return (ret);
1433 }
1434 
1435 /* ******************************************************************** */
1436 /*                      Private Functions                               */
1437 /* ******************************************************************** */
1438 
1439 /*
1440  * Function:    _be_destroy
1441  * Description: Destroy a BE and all of its children datasets and snapshots.
1442  *              This function is called for both global BEs and non-global BEs.
1443  *              The root dataset of either the global BE or non-global BE to be
1444  *              destroyed is passed in.
1445  * Parameters:
1446  *              root_ds - pointer to the name of the root dataset of the
1447  *                      BE to destroy.
1448  *              dd - pointer to a be_destroy_data_t structure.
1449  *
1450  * Return:
1451  *              BE_SUCCESS - Success
1452  *              be_errno_t - Failure
1453  * Scope:
1454  *              Private
1455  */
1456 static int
1457 _be_destroy(const char *root_ds, be_destroy_data_t *dd)
1458 {
1459         zfs_handle_t    *zhp = NULL;
1460         char            origin[MAXPATHLEN];
1461         char            parent[MAXPATHLEN];
1462         char            *snap = NULL;
1463         boolean_t       has_origin = B_FALSE;
1464         int             ret = BE_SUCCESS;
1465 
1466         /* Get handle to BE's root dataset */
1467         if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1468             NULL) {
1469                 be_print_err(gettext("be_destroy: failed to "
1470                     "open BE root dataset (%s): %s\n"), root_ds,
1471                     libzfs_error_description(g_zfs));
1472                 return (zfs_err_to_be_err(g_zfs));
1473         }
1474 
1475         /*
1476          * Demote this BE in case it has dependent clones.  This call
1477          * will end up closing the zfs handle passed in whether it
1478          * succeeds or fails.
1479          */
1480         if (be_demote_callback(zhp, NULL) != 0) {
1481                 be_print_err(gettext("be_destroy: "
1482                     "failed to demote BE %s\n"), root_ds);
1483                 return (BE_ERR_DEMOTE);
1484         }
1485 
1486         /* Get handle to BE's root dataset */
1487         if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1488             NULL) {
1489                 be_print_err(gettext("be_destroy: failed to "
1490                     "open BE root dataset (%s): %s\n"), root_ds,
1491                     libzfs_error_description(g_zfs));
1492                 return (zfs_err_to_be_err(g_zfs));
1493         }
1494 
1495         /*
1496          * Get the origin of this BE's root dataset.  This will be used
1497          * later to destroy the snapshots originally used to create this BE.
1498          */
1499         if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
1500             NULL, 0, B_FALSE) == 0) {
1501                 (void) strlcpy(parent, origin, sizeof (parent));
1502                 if (be_get_snap(parent, &snap) != BE_SUCCESS) {
1503                         ZFS_CLOSE(zhp);
1504                         be_print_err(gettext("be_destroy: failed to "
1505                             "get snapshot name from origin %s\n"), origin);
1506                         return (BE_ERR_INVAL);
1507                 }
1508                 has_origin = B_TRUE;
1509         }
1510 
1511         /*
1512          * Destroy the BE's root and its hierarchical children.  This call
1513          * will end up closing the zfs handle passed in whether it succeeds
1514          * or fails.
1515          */
1516         if (be_destroy_callback(zhp, dd) != 0) {
1517                 be_print_err(gettext("be_destroy: failed to "
1518                     "destroy BE %s\n"), root_ds);
1519                 ret = zfs_err_to_be_err(g_zfs);
1520                 return (ret);
1521         }
1522 
1523         /* If BE has an origin */
1524         if (has_origin) {
1525 
1526                 /*
1527                  * If origin snapshot doesn't have any other
1528                  * dependents, delete the origin.
1529                  */
1530                 if ((zhp = zfs_open(g_zfs, origin, ZFS_TYPE_SNAPSHOT)) ==
1531                     NULL) {
1532                         be_print_err(gettext("be_destroy: failed to "
1533                             "open BE's origin (%s): %s\n"), origin,
1534                             libzfs_error_description(g_zfs));
1535                         ret = zfs_err_to_be_err(g_zfs);
1536                         return (ret);
1537                 }
1538 
1539                 /* If origin has dependents, don't delete it. */
1540                 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
1541                         ZFS_CLOSE(zhp);
1542                         return (ret);
1543                 }
1544                 ZFS_CLOSE(zhp);
1545 
1546                 /* Get handle to BE's parent's root dataset */
1547                 if ((zhp = zfs_open(g_zfs, parent, ZFS_TYPE_FILESYSTEM)) ==
1548                     NULL) {
1549                         be_print_err(gettext("be_destroy: failed to "
1550                             "open BE's parent root dataset (%s): %s\n"), parent,
1551                             libzfs_error_description(g_zfs));
1552                         ret = zfs_err_to_be_err(g_zfs);
1553                         return (ret);
1554                 }
1555 
1556                 /* Destroy the snapshot origin used to create this BE. */
1557                 /*
1558                  * The boolean set to B_FALSE and passed to zfs_destroy_snaps()
1559                  * tells zfs to process and destroy the snapshots now.
1560                  * Otherwise the call will potentially return where the
1561                  * snapshot isn't actually destroyed yet, and ZFS is waiting
1562                  * until all the references to the snapshot have been
1563                  * released before actually destroying the snapshot.
1564                  */
1565                 if (zfs_destroy_snaps(zhp, snap, B_FALSE) != 0) {
1566                         be_print_err(gettext("be_destroy: failed to "
1567                             "destroy original snapshots used to create "
1568                             "BE: %s\n"), libzfs_error_description(g_zfs));
1569 
1570                         /*
1571                          * If a failure happened because a clone exists,
1572                          * don't return a failure to the user.  Above, we're
1573                          * only checking that the root dataset's origin
1574                          * snapshot doesn't have dependent clones, but its
1575                          * possible that a subordinate dataset origin snapshot
1576                          * has a clone.  We really need to check for that
1577                          * before trying to destroy the origin snapshot.
1578                          */
1579                         if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1580                                 ret = zfs_err_to_be_err(g_zfs);
1581                                 ZFS_CLOSE(zhp);
1582                                 return (ret);
1583                         }
1584                 }
1585                 ZFS_CLOSE(zhp);
1586         }
1587 
1588         return (ret);
1589 }
1590 
1591 /*
1592  * Function:    be_destroy_zones
1593  * Description: Find valid zone's and call be_destroy_zone_roots to destroy its
1594  *              corresponding dataset and all of its children datasets
1595  *              and snapshots.
1596  * Parameters:
1597  *              be_name - name of global boot environment being destroyed
1598  *              be_root_ds - root dataset of global boot environment being
1599  *                      destroyed.
1600  *              dd - be_destroy_data_t pointer
1601  * Return:
1602  *              BE_SUCCESS - Success
1603  *              be_errno_t - Failure
1604  * Scope:
1605  *              Private
1606  *
1607  * NOTES - Requires that the BE being deleted has no dependent BEs.  If it
1608  *         does, the destroy will fail.
1609  */
1610 static int
1611 be_destroy_zones(char *be_name, char *be_root_ds, be_destroy_data_t *dd)
1612 {
1613         int             i;
1614         int             ret = BE_SUCCESS;
1615         int             force_umnt = BE_UNMOUNT_FLAG_NULL;
1616         char            *zonepath = NULL;
1617         char            *zonename = NULL;
1618         char            *zonepath_ds = NULL;
1619         char            *mp = NULL;
1620         zoneList_t      zlist = NULL;
1621         zoneBrandList_t *brands = 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 list of supported brands */
1630         if ((brands = be_get_supported_brandlist()) == NULL) {
1631                 be_print_err(gettext("be_destroy_zones: "
1632                     "no supported brands\n"));
1633                 return (BE_SUCCESS);
1634         }
1635 
1636         /* Get handle to BE's root dataset */
1637         if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1638             NULL) {
1639                 be_print_err(gettext("be_destroy_zones: failed to "
1640                     "open BE root dataset (%s): %s\n"), be_root_ds,
1641                     libzfs_error_description(g_zfs));
1642                 z_free_brand_list(brands);
1643                 return (zfs_err_to_be_err(g_zfs));
1644         }
1645 
1646         /*
1647          * If the global BE is not mounted, we must mount it here to
1648          * gather data about the non-global zones in it.
1649          */
1650         if (!zfs_is_mounted(zhp, &mp)) {
1651                 if ((ret = _be_mount(be_name, &mp,
1652                     BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1653                         be_print_err(gettext("be_destroy_zones: failed to "
1654                             "mount the BE (%s) for zones processing.\n"),
1655                             be_name);
1656                         ZFS_CLOSE(zhp);
1657                         z_free_brand_list(brands);
1658                         return (ret);
1659                 }
1660         }
1661         ZFS_CLOSE(zhp);
1662 
1663         z_set_zone_root(mp);
1664         free(mp);
1665 
1666         /* Get list of supported zones. */
1667         if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1668                 z_free_brand_list(brands);
1669                 return (BE_SUCCESS);
1670         }
1671 
1672         /* Unmount the BE before destroying the zones in it. */
1673         if (dd->force_unmount)
1674                 force_umnt = BE_UNMOUNT_FLAG_FORCE;
1675         if ((ret = _be_unmount(be_name, force_umnt)) != BE_SUCCESS) {
1676                 be_print_err(gettext("be_destroy_zones: failed to "
1677                     "unmount the BE (%s)\n"), be_name);
1678                 goto done;
1679         }
1680 
1681         /* Iterate through the zones and destroy them. */
1682         for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
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_brand_list(brands);
1720         z_free_zone_list(zlist);
1721 
1722         return (ret);
1723 }
1724 
1725 /*
1726  * Function:    be_destroy_zone_roots
1727  * Description: This function will open the zone's root container dataset
1728  *              and iterate the datasets within, looking for roots that
1729  *              belong to the given global BE and destroying them.
1730  *              If no other zone roots remain in the zone's root container
1731  *              dataset, the function will destroy it and the zone's
1732  *              zonepath dataset as well.
1733  * Parameters:
1734  *              zonepath_ds - pointer to zone's zonepath dataset.
1735  *              dd - pointer to a linked destroy data.
1736  * Returns:
1737  *              BE_SUCCESS - Success
1738  *              be_errno_t - Failure
1739  * Scope:
1740  *              Private
1741  */
1742 static int
1743 be_destroy_zone_roots(char *zonepath_ds, be_destroy_data_t *dd)
1744 {
1745         zfs_handle_t    *zhp;
1746         char            zone_container_ds[MAXPATHLEN];
1747         int             ret = BE_SUCCESS;
1748 
1749         /* Generate string for the root container dataset for this zone. */
1750         be_make_container_ds(zonepath_ds, zone_container_ds,
1751             sizeof (zone_container_ds));
1752 
1753         /* Get handle to this zone's root container dataset. */
1754         if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1755             == NULL) {
1756                 be_print_err(gettext("be_destroy_zone_roots: failed to "
1757                     "open zone root container dataset (%s): %s\n"),
1758                     zone_container_ds, libzfs_error_description(g_zfs));
1759                 return (zfs_err_to_be_err(g_zfs));
1760         }
1761 
1762         /*
1763          * Iterate through all of this zone's BEs, destroying the ones
1764          * that belong to the parent global BE.
1765          */
1766         if ((ret = zfs_iter_filesystems(zhp, be_destroy_zone_roots_callback,
1767             dd)) != 0) {
1768                 be_print_err(gettext("be_destroy_zone_roots: failed to "
1769                     "destroy zone roots under zonepath dataset %s: %s\n"),
1770                     zonepath_ds, libzfs_error_description(g_zfs));
1771                 ZFS_CLOSE(zhp);
1772                 return (ret);
1773         }
1774         ZFS_CLOSE(zhp);
1775 
1776         /* Get handle to this zone's root container dataset. */
1777         if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1778             == NULL) {
1779                 be_print_err(gettext("be_destroy_zone_roots: failed to "
1780                     "open zone root container dataset (%s): %s\n"),
1781                     zone_container_ds, libzfs_error_description(g_zfs));
1782                 return (zfs_err_to_be_err(g_zfs));
1783         }
1784 
1785         /*
1786          * If there are no more zone roots in this zone's root container,
1787          * dataset, destroy it and the zonepath dataset as well.
1788          */
1789         if (zfs_iter_filesystems(zhp, be_zone_root_exists_callback, NULL)
1790             == 0) {
1791                 /* Destroy the zone root container dataset */
1792                 if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1793                     zfs_destroy(zhp, B_FALSE) != 0) {
1794                         be_print_err(gettext("be_destroy_zone_roots: failed to "
1795                             "destroy zone root container dataset (%s): %s\n"),
1796                             zone_container_ds, libzfs_error_description(g_zfs));
1797                         goto done;
1798                 }
1799                 ZFS_CLOSE(zhp);
1800 
1801                 /* Get handle to zonepath dataset */
1802                 if ((zhp = zfs_open(g_zfs, zonepath_ds, ZFS_TYPE_FILESYSTEM))
1803                     == NULL) {
1804                         be_print_err(gettext("be_destroy_zone_roots: failed to "
1805                             "open zonepath dataset (%s): %s\n"),
1806                             zonepath_ds, libzfs_error_description(g_zfs));
1807                         goto done;
1808                 }
1809 
1810                 /* Destroy zonepath dataset */
1811                 if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1812                     zfs_destroy(zhp, B_FALSE) != 0) {
1813                         be_print_err(gettext("be_destroy_zone_roots: "
1814                             "failed to destroy zonepath dataest %s: %s\n"),
1815                             zonepath_ds, libzfs_error_description(g_zfs));
1816                         goto done;
1817                 }
1818         }
1819 
1820 done:
1821         ZFS_CLOSE(zhp);
1822         return (ret);
1823 }
1824 
1825 /*
1826  * Function:    be_destroy_zone_roots_callback
1827  * Description: This function is used as a callback to iterate over all of
1828  *              a zone's root datasets, finding the one's that
1829  *              correspond to the current BE. The name's
1830  *              of the zone root datasets are then destroyed by _be_destroy().
1831  * Parameters:
1832  *              zhp - zfs_handle_t pointer to current dataset being processed
1833  *              data - be_destroy_data_t pointer
1834  * Returns:
1835  *              0 - Success
1836  *              be_errno_t - Failure
1837  * Scope:
1838  *              Private
1839  */
1840 static int
1841 be_destroy_zone_roots_callback(zfs_handle_t *zhp, void *data)
1842 {
1843         be_destroy_data_t       *dd = data;
1844         uuid_t                  parent_uuid = { 0 };
1845         int                     ret = 0;
1846 
1847         if (be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid)
1848             != BE_SUCCESS) {
1849                 be_print_err(gettext("be_destroy_zone_roots_callback: "
1850                     "could not get parentuuid for zone root dataset %s\n"),
1851                     zfs_get_name(zhp));
1852                 ZFS_CLOSE(zhp);
1853                 return (0);
1854         }
1855 
1856         if (uuid_compare(dd->gz_be_uuid, parent_uuid) == 0) {
1857                 /*
1858                  * Found a zone root dataset belonging to the parent
1859                  * BE being destroyed.  Destroy this zone BE.
1860                  */
1861                 if ((ret = _be_destroy(zfs_get_name(zhp), dd)) != BE_SUCCESS) {
1862                         be_print_err(gettext("be_destroy_zone_root_callback: "
1863                             "failed to destroy zone root %s\n"),
1864                             zfs_get_name(zhp));
1865                         ZFS_CLOSE(zhp);
1866                         return (ret);
1867                 }
1868         }
1869         ZFS_CLOSE(zhp);
1870 
1871         return (ret);
1872 }
1873 
1874 /*
1875  * Function:    be_copy_zones
1876  * Description: Find valid zones and clone them to create their
1877  *              corresponding datasets for the BE being created.
1878  * Parameters:
1879  *              obe_name - name of source global BE being copied.
1880  *              obe_root_ds - root dataset of source global BE being copied.
1881  *              nbe_root_ds - root dataset of target global BE.
1882  * Return:
1883  *              BE_SUCCESS - Success
1884  *              be_errno_t - Failure
1885  * Scope:
1886  *              Private
1887  */
1888 static int
1889 be_copy_zones(char *obe_name, char *obe_root_ds, char *nbe_root_ds)
1890 {
1891         int             i, num_retries;
1892         int             ret = BE_SUCCESS;
1893         int             iret = 0;
1894         char            *zonename = NULL;
1895         char            *zonepath = NULL;
1896         char            *zone_be_name = NULL;
1897         char            *temp_mntpt = NULL;
1898         char            *new_zone_be_name = NULL;
1899         char            zoneroot[MAXPATHLEN];
1900         char            zoneroot_ds[MAXPATHLEN];
1901         char            zone_container_ds[MAXPATHLEN];
1902         char            new_zoneroot_ds[MAXPATHLEN];
1903         char            ss[MAXPATHLEN];
1904         uuid_t          uu = { 0 };
1905         char            uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1906         be_transaction_data_t bt = { 0 };
1907         zfs_handle_t    *obe_zhp = NULL;
1908         zfs_handle_t    *nbe_zhp = NULL;
1909         zfs_handle_t    *z_zhp = NULL;
1910         zoneList_t      zlist = NULL;
1911         zoneBrandList_t *brands = NULL;
1912         boolean_t       mounted_here = B_FALSE;
1913         char            *snap_name = NULL;
1914 
1915         /* If zones are not implemented, then get out. */
1916         if (!z_zones_are_implemented()) {
1917                 return (BE_SUCCESS);
1918         }
1919 
1920         /* Get list of supported brands */
1921         if ((brands = be_get_supported_brandlist()) == NULL) {
1922                 be_print_err(gettext("be_copy_zones: "
1923                     "no supported brands\n"));
1924                 return (BE_SUCCESS);
1925         }
1926 
1927         /* Get handle to origin BE's root dataset */
1928         if ((obe_zhp = zfs_open(g_zfs, obe_root_ds, ZFS_TYPE_FILESYSTEM))
1929             == NULL) {
1930                 be_print_err(gettext("be_copy_zones: failed to open "
1931                     "the origin BE root dataset (%s) for zones processing: "
1932                     "%s\n"), obe_root_ds, libzfs_error_description(g_zfs));
1933                 return (zfs_err_to_be_err(g_zfs));
1934         }
1935 
1936         /* Get handle to newly cloned BE's root dataset */
1937         if ((nbe_zhp = zfs_open(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM))
1938             == NULL) {
1939                 be_print_err(gettext("be_copy_zones: failed to open "
1940                     "the new BE root dataset (%s): %s\n"), nbe_root_ds,
1941                     libzfs_error_description(g_zfs));
1942                 ZFS_CLOSE(obe_zhp);
1943                 return (zfs_err_to_be_err(g_zfs));
1944         }
1945 
1946         /* Get the uuid of the newly cloned parent BE. */
1947         if (be_get_uuid(zfs_get_name(nbe_zhp), &uu) != BE_SUCCESS) {
1948                 be_print_err(gettext("be_copy_zones: "
1949                     "failed to get uuid for BE root "
1950                     "dataset %s\n"), zfs_get_name(nbe_zhp));
1951                 ZFS_CLOSE(nbe_zhp);
1952                 goto done;
1953         }
1954         ZFS_CLOSE(nbe_zhp);
1955         uuid_unparse(uu, uu_string);
1956 
1957         /*
1958          * If the origin BE is not mounted, we must mount it here to
1959          * gather data about the non-global zones in it.
1960          */
1961         if (!zfs_is_mounted(obe_zhp, &temp_mntpt)) {
1962                 if ((ret = _be_mount(obe_name, &temp_mntpt,
1963                     BE_MOUNT_FLAG_NULL)) != BE_SUCCESS) {
1964                         be_print_err(gettext("be_copy_zones: failed to "
1965                             "mount the BE (%s) for zones procesing.\n"),
1966                             obe_name);
1967                         goto done;
1968                 }
1969                 mounted_here = B_TRUE;
1970         }
1971 
1972         z_set_zone_root(temp_mntpt);
1973 
1974         /* Get list of supported zones. */
1975         if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1976                 ret = BE_SUCCESS;
1977                 goto done;
1978         }
1979 
1980         for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1981 
1982                 be_fs_list_data_t       fld = { 0 };
1983                 char                    zonepath_ds[MAXPATHLEN];
1984                 char                    *ds = NULL;
1985 
1986                 /* Get zonepath of zone */
1987                 zonepath = z_zlist_get_zonepath(zlist, i);
1988 
1989                 /* Skip zones that aren't at least installed */
1990                 if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1991                         continue;
1992 
1993                 /*
1994                  * Get the dataset of this zonepath.  If its not
1995                  * a dataset, skip it.
1996                  */
1997                 if ((ds = be_get_ds_from_dir(zonepath)) == NULL)
1998                         continue;
1999 
2000                 (void) strlcpy(zonepath_ds, ds, sizeof (zonepath_ds));
2001                 free(ds);
2002                 ds = NULL;
2003 
2004                 /* Get zoneroot directory */
2005                 be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
2006 
2007                 /* If zonepath dataset not supported, skip it. */
2008                 if (!be_zone_supported(zonepath_ds)) {
2009                         continue;
2010                 }
2011 
2012                 if ((ret = be_find_active_zone_root(obe_zhp, zonepath_ds,
2013                     zoneroot_ds, sizeof (zoneroot_ds))) != BE_SUCCESS) {
2014                         be_print_err(gettext("be_copy_zones: "
2015                             "failed to find active zone root for zone %s "
2016                             "in BE %s\n"), zonename, obe_name);
2017                         goto done;
2018                 }
2019 
2020                 be_make_container_ds(zonepath_ds, zone_container_ds,
2021                     sizeof (zone_container_ds));
2022 
2023                 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2024                     ZFS_TYPE_FILESYSTEM)) == NULL) {
2025                         be_print_err(gettext("be_copy_zones: "
2026                             "failed to open zone root dataset (%s): %s\n"),
2027                             zoneroot_ds, libzfs_error_description(g_zfs));
2028                         ret = zfs_err_to_be_err(g_zfs);
2029                         goto done;
2030                 }
2031 
2032                 zone_be_name =
2033                     be_get_zone_be_name(zoneroot_ds, zone_container_ds);
2034 
2035                 if ((new_zone_be_name = be_auto_zone_be_name(zone_container_ds,
2036                     zone_be_name)) == NULL) {
2037                         be_print_err(gettext("be_copy_zones: failed "
2038                             "to generate auto name for zone BE.\n"));
2039                         ret = BE_ERR_AUTONAME;
2040                         goto done;
2041                 }
2042 
2043                 if ((snap_name = be_auto_snap_name()) == NULL) {
2044                         be_print_err(gettext("be_copy_zones: failed to "
2045                             "generate snapshot name for zone BE.\n"));
2046                         ret = BE_ERR_AUTONAME;
2047                         goto done;
2048                 }
2049 
2050                 (void) snprintf(ss, sizeof (ss), "%s@%s", zoneroot_ds,
2051                     snap_name);
2052 
2053                 if (zfs_snapshot(g_zfs, ss, B_TRUE, NULL) != 0) {
2054                         be_print_err(gettext("be_copy_zones: "
2055                             "failed to snapshot zone BE (%s): %s\n"),
2056                             ss, libzfs_error_description(g_zfs));
2057                         if (libzfs_errno(g_zfs) == EZFS_EXISTS)
2058                                 ret = BE_ERR_ZONE_SS_EXISTS;
2059                         else
2060                                 ret = zfs_err_to_be_err(g_zfs);
2061 
2062                         goto done;
2063                 }
2064 
2065                 (void) snprintf(new_zoneroot_ds, sizeof (new_zoneroot_ds),
2066                     "%s/%s", zone_container_ds, new_zone_be_name);
2067 
2068                 bt.obe_name = zone_be_name;
2069                 bt.obe_root_ds = zoneroot_ds;
2070                 bt.obe_snap_name = snap_name;
2071                 bt.obe_altroot = temp_mntpt;
2072                 bt.nbe_name = new_zone_be_name;
2073                 bt.nbe_root_ds = new_zoneroot_ds;
2074 
2075                 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
2076                         be_print_err(gettext("be_copy_zones: "
2077                             "internal error: out of memory\n"));
2078                         ret = BE_ERR_NOMEM;
2079                         goto done;
2080                 }
2081 
2082                 /*
2083                  * The call to be_clone_fs_callback always closes the
2084                  * zfs_handle so there's no need to close z_zhp.
2085                  */
2086                 if ((iret = be_clone_fs_callback(z_zhp, &bt)) != 0) {
2087                         z_zhp = NULL;
2088                         if (iret != BE_ERR_BE_EXISTS) {
2089                                 be_print_err(gettext("be_copy_zones: "
2090                                     "failed to create zone BE clone for new "
2091                                     "zone BE %s\n"), new_zone_be_name);
2092                                 ret = iret;
2093                                 nvlist_free(bt.nbe_zfs_props);
2094                                 goto done;
2095                         }
2096                         /*
2097                          * We failed to create the new zone BE because a zone
2098                          * BE with the auto-name we generated above has since
2099                          * come into existence. Regenerate a new auto-name
2100                          * and retry.
2101                          */
2102                         for (num_retries = 1;
2103                             num_retries < BE_AUTO_NAME_MAX_TRY;
2104                             num_retries++) {
2105 
2106                                 /* Sleep 1 before retrying */
2107                                 (void) sleep(1);
2108 
2109                                 /* Generate new auto zone BE name */
2110                                 free(new_zone_be_name);
2111                                 if ((new_zone_be_name = be_auto_zone_be_name(
2112                                     zone_container_ds,
2113                                     zone_be_name)) == NULL) {
2114                                         be_print_err(gettext("be_copy_zones: "
2115                                             "failed to generate auto name "
2116                                             "for zone BE.\n"));
2117                                         ret = BE_ERR_AUTONAME;
2118                                         nvlist_free(bt.nbe_zfs_props);
2119                                         goto done;
2120                                 }
2121 
2122                                 (void) snprintf(new_zoneroot_ds,
2123                                     sizeof (new_zoneroot_ds),
2124                                     "%s/%s", zone_container_ds,
2125                                     new_zone_be_name);
2126                                 bt.nbe_name = new_zone_be_name;
2127                                 bt.nbe_root_ds = new_zoneroot_ds;
2128 
2129                                 /*
2130                                  * Get handle to original zone BE's root
2131                                  * dataset.
2132                                  */
2133                                 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2134                                     ZFS_TYPE_FILESYSTEM)) == NULL) {
2135                                         be_print_err(gettext("be_copy_zones: "
2136                                             "failed to open zone root "
2137                                             "dataset (%s): %s\n"),
2138                                             zoneroot_ds,
2139                                             libzfs_error_description(g_zfs));
2140                                         ret = zfs_err_to_be_err(g_zfs);
2141                                         nvlist_free(bt.nbe_zfs_props);
2142                                         goto done;
2143                                 }
2144 
2145                                 /*
2146                                  * Try to clone the zone BE again. This
2147                                  * call will end up closing the zfs
2148                                  * handle passed in whether it
2149                                  * succeeds or fails.
2150                                  */
2151                                 iret = be_clone_fs_callback(z_zhp, &bt);
2152                                 z_zhp = NULL;
2153                                 if (iret == 0) {
2154                                         break;
2155                                 } else if (iret != BE_ERR_BE_EXISTS) {
2156                                         be_print_err(gettext("be_copy_zones: "
2157                                             "failed to create zone BE clone "
2158                                             "for new zone BE %s\n"),
2159                                             new_zone_be_name);
2160                                         ret = iret;
2161                                         nvlist_free(bt.nbe_zfs_props);
2162                                         goto done;
2163                                 }
2164                         }
2165                         /*
2166                          * If we've exhausted the maximum number of
2167                          * tries, free the auto zone BE name and return
2168                          * error.
2169                          */
2170                         if (num_retries == BE_AUTO_NAME_MAX_TRY) {
2171                                 be_print_err(gettext("be_copy_zones: failed "
2172                                     "to create a unique auto zone BE name\n"));
2173                                 free(bt.nbe_name);
2174                                 bt.nbe_name = NULL;
2175                                 ret = BE_ERR_AUTONAME;
2176                                 nvlist_free(bt.nbe_zfs_props);
2177                                 goto done;
2178                         }
2179                 }
2180 
2181                 nvlist_free(bt.nbe_zfs_props);
2182 
2183                 z_zhp = NULL;
2184 
2185                 if ((z_zhp = zfs_open(g_zfs, new_zoneroot_ds,
2186                     ZFS_TYPE_FILESYSTEM)) == NULL) {
2187                         be_print_err(gettext("be_copy_zones: "
2188                             "failed to open the new zone BE root dataset "
2189                             "(%s): %s\n"), new_zoneroot_ds,
2190                             libzfs_error_description(g_zfs));
2191                         ret = zfs_err_to_be_err(g_zfs);
2192                         goto done;
2193                 }
2194 
2195                 if (zfs_prop_set(z_zhp, BE_ZONE_PARENTBE_PROPERTY,
2196                     uu_string) != 0) {
2197                         be_print_err(gettext("be_copy_zones: "
2198                             "failed to set parentbe property\n"));
2199                         ZFS_CLOSE(z_zhp);
2200                         ret = zfs_err_to_be_err(g_zfs);
2201                         goto done;
2202                 }
2203 
2204                 if (zfs_prop_set(z_zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
2205                         be_print_err(gettext("be_copy_zones: "
2206                             "failed to set active property\n"));
2207                         ZFS_CLOSE(z_zhp);
2208                         ret = zfs_err_to_be_err(g_zfs);
2209                         goto done;
2210                 }
2211 
2212                 /*
2213                  * Generate a list of file systems from the original
2214                  * zone BE that are legacy mounted.  We use this list
2215                  * to determine which entries in the vfstab we need to
2216                  * update for the new zone BE we've just created.
2217                  */
2218                 if ((ret = be_get_legacy_fs(obe_name, obe_root_ds,
2219                     zoneroot_ds, zoneroot, &fld)) != BE_SUCCESS) {
2220                         be_print_err(gettext("be_copy_zones: "
2221                             "failed to get legacy mounted file system "
2222                             "list for zone %s\n"), zonename);
2223                         ZFS_CLOSE(z_zhp);
2224                         goto done;
2225                 }
2226 
2227                 /*
2228                  * Update new zone BE's vfstab.
2229                  */
2230                 if ((ret = be_update_zone_vfstab(z_zhp, bt.nbe_name,
2231                     zonepath_ds, zonepath_ds, &fld)) != BE_SUCCESS) {
2232                         be_print_err(gettext("be_copy_zones: "
2233                             "failed to update new BE's vfstab (%s)\n"),
2234                             bt.nbe_name);
2235                         ZFS_CLOSE(z_zhp);
2236                         be_free_fs_list(&fld);
2237                         goto done;
2238                 }
2239 
2240                 be_free_fs_list(&fld);
2241                 ZFS_CLOSE(z_zhp);
2242         }
2243 
2244 done:
2245         free(snap_name);
2246         if (brands != NULL)
2247                 z_free_brand_list(brands);
2248         if (zlist != NULL)
2249                 z_free_zone_list(zlist);
2250 
2251         if (mounted_here)
2252                 (void) _be_unmount(obe_name, 0);
2253 
2254         ZFS_CLOSE(obe_zhp);
2255         return (ret);
2256 }
2257 
2258 /*
2259  * Function:    be_clone_fs_callback
2260  * Description: Callback function used to iterate through a BE's filesystems
2261  *              to clone them for the new BE.
2262  * Parameters:
2263  *              zhp - zfs_handle_t pointer for the filesystem being processed.
2264  *              data - be_transaction_data_t pointer providing information
2265  *                      about original BE and new BE.
2266  * Return:
2267  *              0 - Success
2268  *              be_errno_t - Failure
2269  * Scope:
2270  *              Private
2271  */
2272 static int
2273 be_clone_fs_callback(zfs_handle_t *zhp, void *data)
2274 {
2275         be_transaction_data_t   *bt = data;
2276         zfs_handle_t    *zhp_ss = NULL;
2277         char            prop_buf[MAXPATHLEN];
2278         char            zhp_name[ZFS_MAX_DATASET_NAME_LEN];
2279         char            clone_ds[MAXPATHLEN];
2280         char            ss[MAXPATHLEN];
2281         int             ret = 0;
2282 
2283         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
2284             ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) != 0) {
2285                 be_print_err(gettext("be_clone_fs_callback: "
2286                     "failed to get dataset mountpoint (%s): %s\n"),
2287                     zfs_get_name(zhp), libzfs_error_description(g_zfs));
2288                 ret = zfs_err_to_be_err(g_zfs);
2289                 ZFS_CLOSE(zhp);
2290                 return (ret);
2291         }
2292 
2293         if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) != 0 &&
2294             strcmp(prop_buf, "legacy") != 0) {
2295                 /*
2296                  * Since zfs can't currently handle setting the
2297                  * mountpoint for a zoned dataset we'll have to skip
2298                  * this dataset. This is because the mountpoint is not
2299                  * set to "legacy".
2300                  */
2301                 goto zoned;
2302         }
2303         /*
2304          * Get a copy of the dataset name from the zfs handle
2305          */
2306         (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2307 
2308         /*
2309          * Get the clone dataset name and prepare the zfs properties for it.
2310          */
2311         if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2312             sizeof (clone_ds))) != BE_SUCCESS) {
2313                 ZFS_CLOSE(zhp);
2314                 return (ret);
2315         }
2316 
2317         /*
2318          * Generate the name of the snapshot to use.
2319          */
2320         (void) snprintf(ss, sizeof (ss), "%s@%s", zhp_name,
2321             bt->obe_snap_name);
2322 
2323         /*
2324          * Get handle to snapshot.
2325          */
2326         if ((zhp_ss = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) {
2327                 be_print_err(gettext("be_clone_fs_callback: "
2328                     "failed to get handle to snapshot (%s): %s\n"), ss,
2329                     libzfs_error_description(g_zfs));
2330                 ret = zfs_err_to_be_err(g_zfs);
2331                 ZFS_CLOSE(zhp);
2332                 return (ret);
2333         }
2334 
2335         /*
2336          * Clone the dataset.
2337          */
2338         if (zfs_clone(zhp_ss, clone_ds, bt->nbe_zfs_props) != 0) {
2339                 be_print_err(gettext("be_clone_fs_callback: "
2340                     "failed to create clone dataset (%s): %s\n"),
2341                     clone_ds, libzfs_error_description(g_zfs));
2342 
2343                 ZFS_CLOSE(zhp_ss);
2344                 ZFS_CLOSE(zhp);
2345 
2346                 return (zfs_err_to_be_err(g_zfs));
2347         }
2348 
2349         ZFS_CLOSE(zhp_ss);
2350 
2351 zoned:
2352         /*
2353          * Iterate through zhp's children datasets (if any)
2354          * and clone them accordingly.
2355          */
2356         if ((ret = zfs_iter_filesystems(zhp, be_clone_fs_callback, bt)) != 0) {
2357                 /*
2358                  * Error occurred while processing a child dataset.
2359                  * Destroy this dataset and return error.
2360                  */
2361                 zfs_handle_t    *d_zhp = NULL;
2362 
2363                 ZFS_CLOSE(zhp);
2364 
2365                 if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2366                     == NULL) {
2367                         return (ret);
2368                 }
2369 
2370                 (void) zfs_destroy(d_zhp, B_FALSE);
2371                 ZFS_CLOSE(d_zhp);
2372                 return (ret);
2373         }
2374 
2375         ZFS_CLOSE(zhp);
2376         return (0);
2377 }
2378 
2379 /*
2380  * Function:    be_send_fs_callback
2381  * Description: Callback function used to iterate through a BE's filesystems
2382  *              to copy them for the new BE.
2383  * Parameters:
2384  *              zhp - zfs_handle_t pointer for the filesystem being processed.
2385  *              data - be_transaction_data_t pointer providing information
2386  *                      about original BE and new BE.
2387  * Return:
2388  *              0 - Success
2389  *              be_errnot_t - Failure
2390  * Scope:
2391  *              Private
2392  */
2393 static int
2394 be_send_fs_callback(zfs_handle_t *zhp, void *data)
2395 {
2396         be_transaction_data_t   *bt = data;
2397         recvflags_t     flags = { 0 };
2398         char            zhp_name[ZFS_MAX_DATASET_NAME_LEN];
2399         char            clone_ds[MAXPATHLEN];
2400         sendflags_t     send_flags = { 0 };
2401         int             pid, status, retval;
2402         int             srpipe[2];
2403         int             ret = 0;
2404 
2405         /*
2406          * Get a copy of the dataset name from the zfs handle
2407          */
2408         (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2409 
2410         /*
2411          * Get the clone dataset name and prepare the zfs properties for it.
2412          */
2413         if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2414             sizeof (clone_ds))) != BE_SUCCESS) {
2415                 ZFS_CLOSE(zhp);
2416                 return (ret);
2417         }
2418 
2419         /*
2420          * Create the new dataset.
2421          */
2422         if (zfs_create(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM, bt->nbe_zfs_props)
2423             != 0) {
2424                 be_print_err(gettext("be_send_fs_callback: "
2425                     "failed to create new dataset '%s': %s\n"),
2426                     clone_ds, libzfs_error_description(g_zfs));
2427                 ret = zfs_err_to_be_err(g_zfs);
2428                 ZFS_CLOSE(zhp);
2429                 return (ret);
2430         }
2431 
2432         /*
2433          * Destination file system is already created
2434          * hence we need to set the force flag on
2435          */
2436         flags.force = B_TRUE;
2437 
2438         /*
2439          * Initiate the pipe to be used for the send and recv
2440          */
2441         if (pipe(srpipe) != 0) {
2442                 int err = errno;
2443                 be_print_err(gettext("be_send_fs_callback: failed to "
2444                     "open pipe\n"));
2445                 ZFS_CLOSE(zhp);
2446                 return (errno_to_be_err(err));
2447         }
2448 
2449         /*
2450          * Fork off a child to send the dataset
2451          */
2452         if ((pid = fork()) == -1) {
2453                 int err = errno;
2454                 be_print_err(gettext("be_send_fs_callback: failed to fork\n"));
2455                 (void) close(srpipe[0]);
2456                 (void) close(srpipe[1]);
2457                 ZFS_CLOSE(zhp);
2458                 return (errno_to_be_err(err));
2459         } else if (pid == 0) { /* child process */
2460                 (void) close(srpipe[0]);
2461 
2462                 /* Send dataset */
2463                 if (zfs_send(zhp, NULL, bt->obe_snap_name, &send_flags,
2464                     srpipe[1], NULL, NULL, NULL) != 0) {
2465                         _exit(1);
2466                 }
2467                 ZFS_CLOSE(zhp);
2468 
2469                 _exit(0);
2470         }
2471 
2472         (void) close(srpipe[1]);
2473 
2474         /* Receive dataset */
2475         if (zfs_receive(g_zfs, clone_ds, NULL, &flags, srpipe[0], NULL) != 0) {
2476                 be_print_err(gettext("be_send_fs_callback: failed to "
2477                     "recv dataset (%s)\n"), clone_ds);
2478         }
2479         (void) close(srpipe[0]);
2480 
2481         /* wait for child to exit */
2482         do {
2483                 retval = waitpid(pid, &status, 0);
2484                 if (retval == -1) {
2485                         status = 0;
2486                 }
2487         } while (retval != pid);
2488 
2489         if (WEXITSTATUS(status) != 0) {
2490                 be_print_err(gettext("be_send_fs_callback: failed to "
2491                     "send dataset (%s)\n"), zhp_name);
2492                 ZFS_CLOSE(zhp);
2493                 return (BE_ERR_ZFS);
2494         }
2495 
2496 
2497         /*
2498          * Iterate through zhp's children datasets (if any)
2499          * and send them accordingly.
2500          */
2501         if ((ret = zfs_iter_filesystems(zhp, be_send_fs_callback, bt)) != 0) {
2502                 /*
2503                  * Error occurred while processing a child dataset.
2504                  * Destroy this dataset and return error.
2505                  */
2506                 zfs_handle_t    *d_zhp = NULL;
2507 
2508                 ZFS_CLOSE(zhp);
2509 
2510                 if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2511                     == NULL) {
2512                         return (ret);
2513                 }
2514 
2515                 (void) zfs_destroy(d_zhp, B_FALSE);
2516                 ZFS_CLOSE(d_zhp);
2517                 return (ret);
2518         }
2519 
2520         ZFS_CLOSE(zhp);
2521         return (0);
2522 }
2523 
2524 /*
2525  * Function:    be_destroy_callback
2526  * Description: Callback function used to destroy a BEs children datasets
2527  *              and snapshots.
2528  * Parameters:
2529  *              zhp - zfs_handle_t pointer to the filesystem being processed.
2530  *              data - Not used.
2531  * Returns:
2532  *              0 - Success
2533  *              be_errno_t - Failure
2534  * Scope:
2535  *              Private
2536  */
2537 static int
2538 be_destroy_callback(zfs_handle_t *zhp, void *data)
2539 {
2540         be_destroy_data_t       *dd = data;
2541         int ret = 0;
2542 
2543         /*
2544          * Iterate down this file system's hierarchical children
2545          * and destroy them first.
2546          */
2547         if ((ret = zfs_iter_filesystems(zhp, be_destroy_callback, dd)) != 0) {
2548                 ZFS_CLOSE(zhp);
2549                 return (ret);
2550         }
2551 
2552         if (dd->destroy_snaps) {
2553                 /*
2554                  * Iterate through this file system's snapshots and
2555                  * destroy them before destroying the file system itself.
2556                  */
2557                 if ((ret = zfs_iter_snapshots(zhp, B_FALSE, be_destroy_callback,
2558                     dd))
2559                     != 0) {
2560                         ZFS_CLOSE(zhp);
2561                         return (ret);
2562                 }
2563         }
2564 
2565         /* Attempt to unmount the dataset before destroying it */
2566         if (dd->force_unmount) {
2567                 if ((ret = zfs_unmount(zhp, NULL, MS_FORCE)) != 0) {
2568                         be_print_err(gettext("be_destroy_callback: "
2569                             "failed to unmount %s: %s\n"), zfs_get_name(zhp),
2570                             libzfs_error_description(g_zfs));
2571                         ret = zfs_err_to_be_err(g_zfs);
2572                         ZFS_CLOSE(zhp);
2573                         return (ret);
2574                 }
2575         }
2576 
2577         if (zfs_destroy(zhp, B_FALSE) != 0) {
2578                 be_print_err(gettext("be_destroy_callback: "
2579                     "failed to destroy %s: %s\n"), zfs_get_name(zhp),
2580                     libzfs_error_description(g_zfs));
2581                 ret = zfs_err_to_be_err(g_zfs);
2582                 ZFS_CLOSE(zhp);
2583                 return (ret);
2584         }
2585 
2586         ZFS_CLOSE(zhp);
2587         return (0);
2588 }
2589 
2590 /*
2591  * Function:    be_demote_callback
2592  * Description: This callback function is used to iterate through the file
2593  *              systems of a BE, looking for the right clone to promote such
2594  *              that this file system is left without any dependent clones.
2595  *              If the file system has no dependent clones, it doesn't need
2596  *              to get demoted, and the function will return success.
2597  *
2598  *              The demotion will be done in two passes.  The first pass
2599  *              will attempt to find the youngest snapshot that has a clone
2600  *              that is part of some other BE.  The second pass will attempt
2601  *              to find the youngest snapshot that has a clone that is not
2602  *              part of a BE.  Doing this helps ensure the aggregated set of
2603  *              file systems that compose a BE stay coordinated wrt BE
2604  *              snapshots and BE dependents.  It also prevents a random user
2605  *              generated clone of a BE dataset to become the parent of other
2606  *              BE datasets after demoting this dataset.
2607  *
2608  * Parameters:
2609  *              zhp - zfs_handle_t pointer to the current file system being
2610  *                      processed.
2611  *              data - not used.
2612  * Return:
2613  *              0 - Success
2614  *              be_errno_t - Failure
2615  * Scope:
2616  *              Private
2617  */
2618 static int
2619 /* LINTED */
2620 be_demote_callback(zfs_handle_t *zhp, void *data)
2621 {
2622         be_demote_data_t        dd = { 0 };
2623         int                     i, ret = 0;
2624 
2625         /*
2626          * Initialize be_demote_data for the first pass - this will find a
2627          * clone in another BE, if one exists.
2628          */
2629         dd.find_in_BE = B_TRUE;
2630 
2631         for (i = 0; i < 2; i++) {
2632 
2633                 if (zfs_iter_snapshots(zhp, B_FALSE,
2634                     be_demote_find_clone_callback, &dd) != 0) {
2635                         be_print_err(gettext("be_demote_callback: "
2636                             "failed to iterate snapshots for %s: %s\n"),
2637                             zfs_get_name(zhp), libzfs_error_description(g_zfs));
2638                         ret = zfs_err_to_be_err(g_zfs);
2639                         ZFS_CLOSE(zhp);
2640                         return (ret);
2641                 }
2642                 if (dd.clone_zhp != NULL) {
2643                         /* Found the clone to promote.  Promote it. */
2644                         if (zfs_promote(dd.clone_zhp) != 0) {
2645                                 be_print_err(gettext("be_demote_callback: "
2646                                     "failed to promote %s: %s\n"),
2647                                     zfs_get_name(dd.clone_zhp),
2648                                     libzfs_error_description(g_zfs));
2649                                 ret = zfs_err_to_be_err(g_zfs);
2650                                 ZFS_CLOSE(dd.clone_zhp);
2651                                 ZFS_CLOSE(zhp);
2652                                 return (ret);
2653                         }
2654 
2655                         ZFS_CLOSE(dd.clone_zhp);
2656                 }
2657 
2658                 /*
2659                  * Reinitialize be_demote_data for the second pass.
2660                  * This will find a user created clone outside of any BE
2661                  * namespace, if one exists.
2662                  */
2663                 dd.clone_zhp = NULL;
2664                 dd.origin_creation = 0;
2665                 dd.snapshot = NULL;
2666                 dd.find_in_BE = B_FALSE;
2667         }
2668 
2669         /* Iterate down this file system's children and demote them */
2670         if ((ret = zfs_iter_filesystems(zhp, be_demote_callback, NULL)) != 0) {
2671                 ZFS_CLOSE(zhp);
2672                 return (ret);
2673         }
2674 
2675         ZFS_CLOSE(zhp);
2676         return (0);
2677 }
2678 
2679 /*
2680  * Function:    be_demote_find_clone_callback
2681  * Description: This callback function is used to iterate through the
2682  *              snapshots of a dataset, looking for the youngest snapshot
2683  *              that has a clone.  If found, it returns a reference to the
2684  *              clone back to the caller in the callback data.
2685  * Parameters:
2686  *              zhp - zfs_handle_t pointer to current snapshot being looked at
2687  *              data - be_demote_data_t pointer used to store the clone that
2688  *                      is found.
2689  * Returns:
2690  *              0 - Successfully iterated through all snapshots.
2691  *              1 - Failed to iterate through all snapshots.
2692  * Scope:
2693  *              Private
2694  */
2695 static int
2696 be_demote_find_clone_callback(zfs_handle_t *zhp, void *data)
2697 {
2698         be_demote_data_t        *dd = data;
2699         time_t                  snap_creation;
2700         int                     zret = 0;
2701 
2702         /* If snapshot has no clones, no need to look at it */
2703         if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
2704                 ZFS_CLOSE(zhp);
2705                 return (0);
2706         }
2707 
2708         dd->snapshot = zfs_get_name(zhp);
2709 
2710         /* Get the creation time of this snapshot */
2711         snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
2712 
2713         /*
2714          * If this snapshot's creation time is greater than (or younger than)
2715          * the current youngest snapshot found, iterate this snapshot to
2716          * check if it has a clone that we're looking for.
2717          */
2718         if (snap_creation >= dd->origin_creation) {
2719                 /*
2720                  * Iterate the dependents of this snapshot to find a
2721                  * a clone that's a direct dependent.
2722                  */
2723                 if ((zret = zfs_iter_dependents(zhp, B_FALSE,
2724                     be_demote_get_one_clone, dd)) == -1) {
2725                         be_print_err(gettext("be_demote_find_clone_callback: "
2726                             "failed to iterate dependents of %s\n"),
2727                             zfs_get_name(zhp));
2728                         ZFS_CLOSE(zhp);
2729                         return (1);
2730                 } else if (zret == 1) {
2731                         /*
2732                          * Found a clone, update the origin_creation time
2733                          * in the callback data.
2734                          */
2735                         dd->origin_creation = snap_creation;
2736                 }
2737         }
2738 
2739         ZFS_CLOSE(zhp);
2740         return (0);
2741 }
2742 
2743 /*
2744  * Function:    be_demote_get_one_clone
2745  * Description: This callback function is used to iterate through a
2746  *              snapshot's dependencies to find a filesystem that is a
2747  *              direct clone of the snapshot being iterated.
2748  * Parameters:
2749  *              zhp - zfs_handle_t pointer to current dataset being looked at
2750  *              data - be_demote_data_t pointer used to store the clone
2751  *                      that is found, and also provides flag to note
2752  *                      whether or not the clone filesystem being searched
2753  *                      for needs to be found in a BE dataset hierarchy.
2754  * Return:
2755  *              1 - Success, found clone and its also a BE's root dataset.
2756  *              0 - Failure, clone not found.
2757  * Scope:
2758  *              Private
2759  */
2760 static int
2761 be_demote_get_one_clone(zfs_handle_t *zhp, void *data)
2762 {
2763         be_demote_data_t        *dd = data;
2764         char                    origin[ZFS_MAX_DATASET_NAME_LEN];
2765         char                    ds_path[ZFS_MAX_DATASET_NAME_LEN];
2766 
2767         if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2768                 ZFS_CLOSE(zhp);
2769                 return (0);
2770         }
2771 
2772         (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
2773 
2774         /*
2775          * Make sure this is a direct clone of the snapshot
2776          * we're iterating.
2777          */
2778         if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
2779             NULL, 0, B_FALSE) != 0) {
2780                 be_print_err(gettext("be_demote_get_one_clone: "
2781                     "failed to get origin of %s: %s\n"), ds_path,
2782                     libzfs_error_description(g_zfs));
2783                 ZFS_CLOSE(zhp);
2784                 return (0);
2785         }
2786         if (strcmp(origin, dd->snapshot) != 0) {
2787                 ZFS_CLOSE(zhp);
2788                 return (0);
2789         }
2790 
2791         if (dd->find_in_BE) {
2792                 if ((zpool_iter(g_zfs, be_check_be_roots_callback, ds_path))
2793                     > 0) {
2794                         if (dd->clone_zhp != NULL)
2795                                 ZFS_CLOSE(dd->clone_zhp);
2796                         dd->clone_zhp = zhp;
2797                         return (1);
2798                 }
2799 
2800                 ZFS_CLOSE(zhp);
2801                 return (0);
2802         }
2803 
2804         if (dd->clone_zhp != NULL)
2805                 ZFS_CLOSE(dd->clone_zhp);
2806 
2807         dd->clone_zhp = zhp;
2808         return (1);
2809 }
2810 
2811 /*
2812  * Function:    be_get_snap
2813  * Description: This function takes a snapshot dataset name and separates
2814  *              out the parent dataset portion from the snapshot name.
2815  *              I.e. it finds the '@' in the snapshot dataset name and
2816  *              replaces it with a '\0'.
2817  * Parameters:
2818  *              origin - char pointer to a snapshot dataset name.  Its
2819  *                      contents will be modified by this function.
2820  *              *snap - pointer to a char pointer.  Will be set to the
2821  *                      snapshot name portion upon success.
2822  * Return:
2823  *              BE_SUCCESS - Success
2824  *              1 - Failure
2825  * Scope:
2826  *              Private
2827  */
2828 static int
2829 be_get_snap(char *origin, char **snap)
2830 {
2831         char    *cp;
2832 
2833         /*
2834          * Separate out the origin's dataset and snapshot portions by
2835          * replacing the @ with a '\0'
2836          */
2837         cp = strrchr(origin, '@');
2838         if (cp != NULL) {
2839                 if (cp[1] != NULL && cp[1] != '\0') {
2840                         cp[0] = '\0';
2841                         *snap = cp+1;
2842                 } else {
2843                         return (1);
2844                 }
2845         } else {
2846                 return (1);
2847         }
2848 
2849         return (BE_SUCCESS);
2850 }
2851 
2852 /*
2853  * Function:    be_create_container_ds
2854  * Description: This function checks that the zpool passed has the BE
2855  *              container dataset, and if not, then creates it.
2856  * Parameters:
2857  *              zpool - name of pool to create BE container dataset in.
2858  * Return:
2859  *              B_TRUE - Successfully created BE container dataset, or it
2860  *                      already existed.
2861  *              B_FALSE - Failed to create container dataset.
2862  * Scope:
2863  *              Private
2864  */
2865 static boolean_t
2866 be_create_container_ds(char *zpool)
2867 {
2868         nvlist_t        *props = NULL;
2869         char            be_container_ds[MAXPATHLEN];
2870 
2871         /* Generate string for BE container dataset for this pool */
2872         be_make_container_ds(zpool, be_container_ds,
2873             sizeof (be_container_ds));
2874 
2875         if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2876 
2877                 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
2878                         be_print_err(gettext("be_create_container_ds: "
2879                             "nvlist_alloc failed\n"));
2880                         return (B_FALSE);
2881                 }
2882 
2883                 if (nvlist_add_string(props,
2884                     zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2885                     ZFS_MOUNTPOINT_LEGACY) != 0) {
2886                         be_print_err(gettext("be_create_container_ds: "
2887                             "internal error: out of memory\n"));
2888                         nvlist_free(props);
2889                         return (B_FALSE);
2890                 }
2891 
2892                 if (nvlist_add_string(props,
2893                     zfs_prop_to_name(ZFS_PROP_CANMOUNT), "off") != 0) {
2894                         be_print_err(gettext("be_create_container_ds: "
2895                             "internal error: out of memory\n"));
2896                         nvlist_free(props);
2897                         return (B_FALSE);
2898                 }
2899 
2900                 if (zfs_create(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM,
2901                     props) != 0) {
2902                         be_print_err(gettext("be_create_container_ds: "
2903                             "failed to create container dataset (%s): %s\n"),
2904                             be_container_ds, libzfs_error_description(g_zfs));
2905                         nvlist_free(props);
2906                         return (B_FALSE);
2907                 }
2908 
2909                 nvlist_free(props);
2910         }
2911 
2912         return (B_TRUE);
2913 }
2914 
2915 /*
2916  * Function:    be_prep_clone_send_fs
2917  * Description: This function takes a zfs handle to a dataset from the
2918  *              original BE, and generates the name of the clone dataset
2919  *              to create for the new BE.  It also prepares the zfs
2920  *              properties to be used for the new BE.
2921  * Parameters:
2922  *              zhp - pointer to zfs_handle_t of the file system being
2923  *                      cloned/copied.
2924  *              bt - be_transaction_data pointer providing information
2925  *                      about the original BE and new BE.
2926  *              clone_ds - buffer to store the name of the dataset
2927  *                      for the new BE.
2928  *              clone_ds_len - length of clone_ds buffer
2929  * Return:
2930  *              BE_SUCCESS - Success
2931  *              be_errno_t - Failure
2932  * Scope:
2933  *              Private
2934  */
2935 static int
2936 be_prep_clone_send_fs(zfs_handle_t *zhp, be_transaction_data_t *bt,
2937     char *clone_ds, int clone_ds_len)
2938 {
2939         zprop_source_t  sourcetype;
2940         char            source[ZFS_MAX_DATASET_NAME_LEN];
2941         char            zhp_name[ZFS_MAX_DATASET_NAME_LEN];
2942         char            mountpoint[MAXPATHLEN];
2943         char            *child_fs = NULL;
2944         char            *zhp_mountpoint = NULL;
2945         int             err = 0;
2946 
2947         /*
2948          * Get a copy of the dataset name zfs_name from zhp
2949          */
2950         (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2951 
2952         /*
2953          * Get file system name relative to the root.
2954          */
2955         if (strncmp(zhp_name, bt->obe_root_ds, strlen(bt->obe_root_ds))
2956             == 0) {
2957                 child_fs = zhp_name + strlen(bt->obe_root_ds);
2958 
2959                 /*
2960                  * if child_fs is NULL, this means we're processing the
2961                  * root dataset itself; set child_fs to the empty string.
2962                  */
2963                 if (child_fs == NULL)
2964                         child_fs = "";
2965         } else {
2966                 return (BE_ERR_INVAL);
2967         }
2968 
2969         /*
2970          * Generate the name of the clone file system.
2971          */
2972         (void) snprintf(clone_ds, clone_ds_len, "%s%s", bt->nbe_root_ds,
2973             child_fs);
2974 
2975         /* Get the mountpoint and source properties of the existing dataset */
2976         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2977             sizeof (mountpoint), &sourcetype, source, sizeof (source),
2978             B_FALSE) != 0) {
2979                 be_print_err(gettext("be_prep_clone_send_fs: "
2980                     "failed to get mountpoint for (%s): %s\n"),
2981                     zhp_name, libzfs_error_description(g_zfs));
2982                 return (zfs_err_to_be_err(g_zfs));
2983         }
2984 
2985         /*
2986          * Workaround for 6668667 where a mountpoint property of "/" comes
2987          * back as "".
2988          */
2989         if (strcmp(mountpoint, "") == 0) {
2990                 (void) snprintf(mountpoint, sizeof (mountpoint), "/");
2991         }
2992 
2993         /*
2994          * Figure out what to set as the mountpoint for the new dataset.
2995          * If the source of the mountpoint property is local, use the
2996          * mountpoint value itself.  Otherwise, remove it from the
2997          * zfs properties list so that it gets inherited.
2998          */
2999         if (sourcetype & ZPROP_SRC_LOCAL) {
3000                 /*
3001                  * If the BE that this file system is a part of is
3002                  * currently mounted, strip off the BE altroot portion
3003                  * from the mountpoint.
3004                  */
3005                 zhp_mountpoint = mountpoint;
3006 
3007                 if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
3008                     bt->obe_altroot != NULL && strcmp(bt->obe_altroot,
3009                     "/") != 0 && zfs_is_mounted(zhp, NULL)) {
3010 
3011                         int altroot_len = strlen(bt->obe_altroot);
3012 
3013                         if (strncmp(bt->obe_altroot, mountpoint, altroot_len)
3014                             == 0) {
3015                                 if (mountpoint[altroot_len] == '/')
3016                                         zhp_mountpoint = mountpoint +
3017                                             altroot_len;
3018                                 else if (mountpoint[altroot_len] == '\0')
3019                                         (void) snprintf(mountpoint,
3020                                             sizeof (mountpoint), "/");
3021                         }
3022                 }
3023 
3024                 if (nvlist_add_string(bt->nbe_zfs_props,
3025                     zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
3026                     zhp_mountpoint) != 0) {
3027                         be_print_err(gettext("be_prep_clone_send_fs: "
3028                             "internal error: out of memory\n"));
3029                         return (BE_ERR_NOMEM);
3030                 }
3031         } else {
3032                 err = nvlist_remove_all(bt->nbe_zfs_props,
3033                     zfs_prop_to_name(ZFS_PROP_MOUNTPOINT));
3034                 if (err != 0 && err != ENOENT) {
3035                         be_print_err(gettext("be_prep_clone_send_fs: "
3036                             "failed to remove mountpoint from "
3037                             "nvlist\n"));
3038                         return (BE_ERR_INVAL);
3039                 }
3040         }
3041 
3042         /*
3043          * Set the 'canmount' property
3044          */
3045         if (nvlist_add_string(bt->nbe_zfs_props,
3046             zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
3047                 be_print_err(gettext("be_prep_clone_send_fs: "
3048                     "internal error: out of memory\n"));
3049                 return (BE_ERR_NOMEM);
3050         }
3051 
3052         return (BE_SUCCESS);
3053 }
3054 
3055 /*
3056  * Function:    be_get_zone_be_name
3057  * Description: This function takes the zones root dataset, the container
3058  *              dataset and returns the zones BE name based on the zone
3059  *              root dataset.
3060  * Parameters:
3061  *              root_ds - the zones root dataset.
3062  *              container_ds - the container dataset for the zone.
3063  * Returns:
3064  *              char * - the BE name of this zone based on the root dataset.
3065  */
3066 static char *
3067 be_get_zone_be_name(char *root_ds, char *container_ds)
3068 {
3069         return (root_ds + (strlen(container_ds) + 1));
3070 }
3071 
3072 /*
3073  * Function:    be_zone_root_exists_callback
3074  * Description: This callback function is used to determine if a
3075  *              zone root container dataset has any children.  It always
3076  *              returns 1, signifying a hierarchical child of the zone
3077  *              root container dataset has been traversed and therefore
3078  *              it has children.
3079  * Parameters:
3080  *              zhp - zfs_handle_t pointer to current dataset being processed.
3081  *              data - not used.
3082  * Returns:
3083  *              1 - dataset exists
3084  * Scope:
3085  *              Private
3086  */
3087 static int
3088 /* LINTED */
3089 be_zone_root_exists_callback(zfs_handle_t *zhp, void *data)
3090 {
3091         ZFS_CLOSE(zhp);
3092         return (1);
3093 }