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