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