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