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