1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  28  */
  29 
  30 #include <assert.h>
  31 #include <libintl.h>
  32 #include <libnvpair.h>
  33 #include <libzfs.h>
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 #include <string.h>
  37 #include <errno.h>
  38 #include <sys/mnttab.h>
  39 #include <sys/types.h>
  40 #include <sys/stat.h>
  41 #include <unistd.h>
  42 
  43 #include <libbe.h>
  44 #include <libbe_priv.h>
  45 
  46 char    *mnttab = MNTTAB;
  47 
  48 /*
  49  * Private function prototypes
  50  */
  51 static int set_bootfs(char *boot_rpool, char *be_root_ds);
  52 static int set_canmount(be_node_list_t *, char *);
  53 static int be_do_installgrub(be_transaction_data_t *);
  54 static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
  55 static int get_ver_from_capfile(char *, char **);
  56 static int be_promote_zone_ds(char *, char *);
  57 static int be_promote_ds_callback(zfs_handle_t *, void *);
  58 
  59 /* ******************************************************************** */
  60 /*                      Public Functions                                */
  61 /* ******************************************************************** */
  62 
  63 /*
  64  * Function:    be_activate
  65  * Description: Calls _be_activate which activates the BE named in the
  66  *              attributes passed in through be_attrs. The process of
  67  *              activation sets the bootfs property of the root pool, resets
  68  *              the canmount property to noauto, and sets the default in the
  69  *              grub menu to the entry corresponding to the entry for the named
  70  *              BE.
  71  * Parameters:
  72  *              be_attrs - pointer to nvlist_t of attributes being passed in.
  73  *                      The follow attribute values are used by this function:
  74  *
  75  *                      BE_ATTR_ORIG_BE_NAME            *required
  76  * Return:
  77  *              BE_SUCCESS - Success
  78  *              be_errno_t - Failure
  79  * Scope:
  80  *              Public
  81  */
  82 int
  83 be_activate(nvlist_t *be_attrs)
  84 {
  85         int     ret = BE_SUCCESS;
  86         char    *be_name = NULL;
  87 
  88         /* Initialize libzfs handle */
  89         if (!be_zfs_init())
  90                 return (BE_ERR_INIT);
  91 
  92         /* Get the BE name to activate */
  93         if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
  94             != 0) {
  95                 be_print_err(gettext("be_activate: failed to "
  96                     "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
  97                 be_zfs_fini();
  98                 return (BE_ERR_INVAL);
  99         }
 100 
 101         /* Validate BE name */
 102         if (!be_valid_be_name(be_name)) {
 103                 be_print_err(gettext("be_activate: invalid BE name %s\n"),
 104                     be_name);
 105                 be_zfs_fini();
 106                 return (BE_ERR_INVAL);
 107         }
 108 
 109         ret = _be_activate(be_name);
 110 
 111         be_zfs_fini();
 112 
 113         return (ret);
 114 }
 115 
 116 /* ******************************************************************** */
 117 /*                      Semi Private Functions                          */
 118 /* ******************************************************************** */
 119 
 120 /*
 121  * Function:    _be_activate
 122  * Description: This does the actual work described in be_activate.
 123  * Parameters:
 124  *              be_name - pointer to the name of BE to activate.
 125  *
 126  * Return:
 127  *              BE_SUCCESS - Success
 128  *              be_errnot_t - Failure
 129  * Scope:
 130  *              Public
 131  */
 132 int
 133 _be_activate(char *be_name)
 134 {
 135         be_transaction_data_t cb = { 0 };
 136         zfs_handle_t    *zhp = NULL;
 137         char            root_ds[MAXPATHLEN];
 138         char            active_ds[MAXPATHLEN];
 139         char            *cur_vers = NULL, *new_vers = NULL;
 140         be_node_list_t  *be_nodes = NULL;
 141         uuid_t          uu = {0};
 142         int             entry, ret = BE_SUCCESS;
 143         int             zret = 0;
 144 
 145         /*
 146          * TODO: The BE needs to be validated to make sure that it is actually
 147          * a bootable BE.
 148          */
 149 
 150         if (be_name == NULL)
 151                 return (BE_ERR_INVAL);
 152 
 153         /* Set obe_name to be_name in the cb structure */
 154         cb.obe_name = be_name;
 155 
 156         /* find which zpool the be is in */
 157         if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
 158                 be_print_err(gettext("be_activate: failed to "
 159                     "find zpool for BE (%s)\n"), cb.obe_name);
 160                 return (BE_ERR_BE_NOENT);
 161         } else if (zret < 0) {
 162                 be_print_err(gettext("be_activate: "
 163                     "zpool_iter failed: %s\n"),
 164                     libzfs_error_description(g_zfs));
 165                 ret = zfs_err_to_be_err(g_zfs);
 166                 return (ret);
 167         }
 168 
 169         be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
 170         cb.obe_root_ds = strdup(root_ds);
 171 
 172         if (getzoneid() == GLOBAL_ZONEID) {
 173                 if (be_has_grub() && (ret = be_get_grub_vers(&cb, &cur_vers,
 174                     &new_vers)) != BE_SUCCESS) {
 175                         be_print_err(gettext("be_activate: failed to get grub "
 176                             "versions from capability files.\n"));
 177                         return (ret);
 178                 }
 179                 if (cur_vers != NULL) {
 180                         /*
 181                          * We need to check to see if the version number from
 182                          * the BE being activated is greater than the current
 183                          * one.
 184                          */
 185                         if (new_vers != NULL &&
 186                             atof(cur_vers) < atof(new_vers)) {
 187                                 if ((ret = be_do_installgrub(&cb))
 188                                     != BE_SUCCESS) {
 189                                         free(new_vers);
 190                                         free(cur_vers);
 191                                         return (ret);
 192                                 }
 193                                 free(new_vers);
 194                         }
 195                         free(cur_vers);
 196                 } else if (new_vers != NULL) {
 197                         if ((ret = be_do_installgrub(&cb)) != BE_SUCCESS) {
 198                                 free(new_vers);
 199                                 return (ret);
 200                         }
 201                         free(new_vers);
 202                 }
 203                 if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
 204                         if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
 205                             NULL, NULL, NULL)) != BE_SUCCESS) {
 206                                 be_print_err(gettext("be_activate: Failed to "
 207                                     "add BE (%s) to the GRUB menu\n"),
 208                                     cb.obe_name);
 209                                 goto done;
 210                         }
 211                 }
 212                 if (be_has_grub()) {
 213                         if ((ret = be_change_grub_default(cb.obe_name,
 214                             cb.obe_zpool)) != BE_SUCCESS) {
 215                                 be_print_err(gettext("be_activate: failed to "
 216                                     "change the default entry in menu.lst\n"));
 217                                 goto done;
 218                         }
 219                 }
 220         }
 221 
 222         if ((ret = _be_list(cb.obe_name, &be_nodes)) != BE_SUCCESS) {
 223                 return (ret);
 224         }
 225 
 226         if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
 227                 be_print_err(gettext("be_activate: failed to set "
 228                     "canmount dataset property\n"));
 229                 goto done;
 230         }
 231 
 232         if (getzoneid() == GLOBAL_ZONEID) {
 233                 if ((ret = set_bootfs(be_nodes->be_rpool,
 234                     root_ds)) != BE_SUCCESS) {
 235                         be_print_err(gettext("be_activate: failed to set "
 236                             "bootfs pool property for %s\n"), root_ds);
 237                         goto done;
 238                 }
 239         }
 240 
 241         if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
 242                 /*
 243                  * We don't need to close the zfs handle at this
 244                  * point because The callback funtion
 245                  * be_promote_ds_callback() will close it for us.
 246                  */
 247                 if (be_promote_ds_callback(zhp, NULL) != 0) {
 248                         be_print_err(gettext("be_activate: "
 249                             "failed to activate the "
 250                             "datasets for %s: %s\n"),
 251                             root_ds,
 252                             libzfs_error_description(g_zfs));
 253                         ret = BE_ERR_PROMOTE;
 254                         goto done;
 255                 }
 256         } else {
 257                 be_print_err(gettext("be_activate: failed to open "
 258                     "dataset (%s): %s\n"), root_ds,
 259                     libzfs_error_description(g_zfs));
 260                 ret = zfs_err_to_be_err(g_zfs);
 261                 goto done;
 262         }
 263 
 264         if (getzoneid() == GLOBAL_ZONEID &&
 265             be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
 266             (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
 267             != BE_SUCCESS) {
 268                 be_print_err(gettext("be_activate: failed to promote "
 269                     "the active zonepath datasets for zones in BE %s\n"),
 270                     cb.obe_name);
 271         }
 272 
 273         if (getzoneid() != GLOBAL_ZONEID) {
 274                 if (!be_zone_compare_uuids(root_ds)) {
 275                         be_print_err(gettext("be_activate: activating zone "
 276                             "root dataset from non-active global BE is not "
 277                             "supported\n"));
 278                         ret = BE_ERR_NOTSUP;
 279                         goto done;
 280                 }
 281                 if ((zhp = zfs_open(g_zfs, root_ds,
 282                     ZFS_TYPE_FILESYSTEM)) == NULL) {
 283                         be_print_err(gettext("be_activate: failed to open "
 284                             "dataset (%s): %s\n"), root_ds,
 285                             libzfs_error_description(g_zfs));
 286                         ret = zfs_err_to_be_err(g_zfs);
 287                         goto done;
 288                 }
 289                 /* Find current active zone root dataset */
 290                 if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
 291                     active_ds, sizeof (active_ds))) != BE_SUCCESS) {
 292                         be_print_err(gettext("be_activate: failed to find "
 293                             "active zone root dataset\n"));
 294                         ZFS_CLOSE(zhp);
 295                         goto done;
 296                 }
 297                 /* Do nothing if requested BE is already active */
 298                 if (strcmp(root_ds, active_ds) == 0) {
 299                         ret = BE_SUCCESS;
 300                         ZFS_CLOSE(zhp);
 301                         goto done;
 302                 }
 303 
 304                 /* Set active property for BE */
 305                 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
 306                         be_print_err(gettext("be_activate: failed to set "
 307                             "active property (%s): %s\n"), root_ds,
 308                             libzfs_error_description(g_zfs));
 309                         ret = zfs_err_to_be_err(g_zfs);
 310                         ZFS_CLOSE(zhp);
 311                         goto done;
 312                 }
 313                 ZFS_CLOSE(zhp);
 314 
 315                 /* Unset active property for old active root dataset */
 316                 if ((zhp = zfs_open(g_zfs, active_ds,
 317                     ZFS_TYPE_FILESYSTEM)) == NULL) {
 318                         be_print_err(gettext("be_activate: failed to open "
 319                             "dataset (%s): %s\n"), active_ds,
 320                             libzfs_error_description(g_zfs));
 321                         ret = zfs_err_to_be_err(g_zfs);
 322                         goto done;
 323                 }
 324                 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
 325                         be_print_err(gettext("be_activate: failed to unset "
 326                             "active property (%s): %s\n"), active_ds,
 327                             libzfs_error_description(g_zfs));
 328                         ret = zfs_err_to_be_err(g_zfs);
 329                         ZFS_CLOSE(zhp);
 330                         goto done;
 331                 }
 332                 ZFS_CLOSE(zhp);
 333         }
 334 done:
 335         be_free_list(be_nodes);
 336         return (ret);
 337 }
 338 
 339 /*
 340  * Function:    be_activate_current_be
 341  * Description: Set the currently "active" BE to be "active on boot"
 342  * Paramters:
 343  *              none
 344  * Returns:
 345  *              BE_SUCCESS - Success
 346  *              be_errnot_t - Failure
 347  * Scope:
 348  *              Semi-private (library wide use only)
 349  */
 350 int
 351 be_activate_current_be(void)
 352 {
 353         int ret = BE_SUCCESS;
 354         be_transaction_data_t bt = { 0 };
 355 
 356         if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
 357                 return (ret);
 358         }
 359 
 360         if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
 361                 be_print_err(gettext("be_activate_current_be: failed to "
 362                     "activate %s\n"), bt.obe_name);
 363                 return (ret);
 364         }
 365 
 366         return (BE_SUCCESS);
 367 }
 368 
 369 /*
 370  * Function:    be_is_active_on_boot
 371  * Description: Checks if the BE name passed in has the "active on boot"
 372  *              property set to B_TRUE.
 373  * Paramters:
 374  *              be_name - the name of the BE to check
 375  * Returns:
 376  *              B_TRUE - if active on boot.
 377  *              B_FALSE - if not active on boot.
 378  * Scope:
 379  *              Semi-private (library wide use only)
 380  */
 381 boolean_t
 382 be_is_active_on_boot(char *be_name)
 383 {
 384         be_node_list_t *be_node = NULL;
 385 
 386         if (be_name == NULL) {
 387                 be_print_err(gettext("be_is_active_on_boot: "
 388                     "be_name must not be NULL\n"));
 389                 return (B_FALSE);
 390         }
 391 
 392         if (_be_list(be_name, &be_node) != BE_SUCCESS) {
 393                 return (B_FALSE);
 394         }
 395 
 396         if (be_node == NULL) {
 397                 return (B_FALSE);
 398         }
 399 
 400         if (be_node->be_active_on_boot) {
 401                 be_free_list(be_node);
 402                 return (B_TRUE);
 403         } else {
 404                 be_free_list(be_node);
 405                 return (B_FALSE);
 406         }
 407 }
 408 
 409 /* ******************************************************************** */
 410 /*                      Private Functions                               */
 411 /* ******************************************************************** */
 412 
 413 /*
 414  * Function:    set_bootfs
 415  * Description: Sets the bootfs property on the boot pool to be the
 416  *              root dataset of the activated BE.
 417  * Parameters:
 418  *              boot_pool - The pool we're setting bootfs in.
 419  *              be_root_ds - The main dataset for the BE.
 420  * Return:
 421  *              BE_SUCCESS - Success
 422  *              be_errno_t - Failure
 423  * Scope:
 424  *              Private
 425  */
 426 static int
 427 set_bootfs(char *boot_rpool, char *be_root_ds)
 428 {
 429         zpool_handle_t *zhp;
 430         int err = BE_SUCCESS;
 431 
 432         if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
 433                 be_print_err(gettext("set_bootfs: failed to open pool "
 434                     "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
 435                 err = zfs_err_to_be_err(g_zfs);
 436                 return (err);
 437         }
 438 
 439         err = zpool_set_prop(zhp, "bootfs", be_root_ds);
 440         if (err) {
 441                 be_print_err(gettext("set_bootfs: failed to set "
 442                     "bootfs property for pool %s: %s\n"), boot_rpool,
 443                     libzfs_error_description(g_zfs));
 444                 err = zfs_err_to_be_err(g_zfs);
 445                 zpool_close(zhp);
 446                 return (err);
 447         }
 448 
 449         zpool_close(zhp);
 450         return (BE_SUCCESS);
 451 }
 452 
 453 /*
 454  * Function:    set_canmount
 455  * Description: Sets the canmount property on the datasets of the
 456  *              activated BE.
 457  * Parameters:
 458  *              be_nodes - The be_node_t returned from be_list
 459  *              value - The value of canmount we setting, on|off|noauto.
 460  * Return:
 461  *              BE_SUCCESS - Success
 462  *              be_errno_t - Failure
 463  * Scope:
 464  *              Private
 465  */
 466 static int
 467 set_canmount(be_node_list_t *be_nodes, char *value)
 468 {
 469         char            ds_path[MAXPATHLEN];
 470         zfs_handle_t    *zhp = NULL;
 471         be_node_list_t  *list = be_nodes;
 472         int             err = BE_SUCCESS;
 473 
 474         while (list != NULL) {
 475                 be_dataset_list_t *datasets = list->be_node_datasets;
 476 
 477                 be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
 478                     sizeof (ds_path));
 479 
 480                 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
 481                     NULL) {
 482                         be_print_err(gettext("set_canmount: failed to open "
 483                             "dataset (%s): %s\n"), ds_path,
 484                             libzfs_error_description(g_zfs));
 485                         err = zfs_err_to_be_err(g_zfs);
 486                         return (err);
 487                 }
 488                 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
 489                         /*
 490                          * it's already mounted so we can't change the
 491                          * canmount property anyway.
 492                          */
 493                         err = BE_SUCCESS;
 494                 } else {
 495                         err = zfs_prop_set(zhp,
 496                             zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
 497                         if (err) {
 498                                 ZFS_CLOSE(zhp);
 499                                 be_print_err(gettext("set_canmount: failed to "
 500                                     "set dataset property (%s): %s\n"),
 501                                     ds_path, libzfs_error_description(g_zfs));
 502                                 err = zfs_err_to_be_err(g_zfs);
 503                                 return (err);
 504                         }
 505                 }
 506                 ZFS_CLOSE(zhp);
 507 
 508                 while (datasets != NULL) {
 509                         be_make_root_ds(list->be_rpool,
 510                             datasets->be_dataset_name, ds_path,
 511                             sizeof (ds_path));
 512 
 513                         if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
 514                             == NULL) {
 515                                 be_print_err(gettext("set_canmount: failed to "
 516                                     "open dataset %s: %s\n"), ds_path,
 517                                     libzfs_error_description(g_zfs));
 518                                 err = zfs_err_to_be_err(g_zfs);
 519                                 return (err);
 520                         }
 521                         if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
 522                                 /*
 523                                  * it's already mounted so we can't change the
 524                                  * canmount property anyway.
 525                                  */
 526                                 err = BE_SUCCESS;
 527                                 ZFS_CLOSE(zhp);
 528                                 break;
 529                         }
 530                         err = zfs_prop_set(zhp,
 531                             zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
 532                         if (err) {
 533                                 ZFS_CLOSE(zhp);
 534                                 be_print_err(gettext("set_canmount: "
 535                                     "Failed to set property value %s "
 536                                     "for dataset %s: %s\n"), value, ds_path,
 537                                     libzfs_error_description(g_zfs));
 538                                 err = zfs_err_to_be_err(g_zfs);
 539                                 return (err);
 540                         }
 541                         ZFS_CLOSE(zhp);
 542                         datasets = datasets->be_next_dataset;
 543                 }
 544                 list = list->be_next_node;
 545         }
 546         return (err);
 547 }
 548 
 549 /*
 550  * Function:    be_get_grub_vers
 551  * Description: Gets the grub version number from /boot/grub/capability. If
 552  *              capability file doesn't exist NULL is returned.
 553  * Parameters:
 554  *              bt - The transaction data for the BE we're getting the grub
 555  *                   version for.
 556  *              cur_vers - used to return the current version of grub from
 557  *                         the root pool.
 558  *              new_vers - used to return the grub version of the BE we're
 559  *                         activating.
 560  * Return:
 561  *              BE_SUCCESS - Success
 562  *              be_errno_t - Failed to find version
 563  * Scope:
 564  *              Private
 565  */
 566 static int
 567 be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
 568 {
 569         zfs_handle_t    *zhp = NULL;
 570         zfs_handle_t    *pool_zhp = NULL;
 571         int ret = BE_SUCCESS;
 572         char cap_file[MAXPATHLEN];
 573         char *temp_mntpnt = NULL;
 574         char *zpool_mntpt = NULL;
 575         char *ptmp_mntpnt = NULL;
 576         char *orig_mntpnt = NULL;
 577         boolean_t be_mounted = B_FALSE;
 578         boolean_t pool_mounted = B_FALSE;
 579 
 580         if (!be_has_grub()) {
 581                 be_print_err(gettext("be_get_grub_vers: Not supported on "
 582                     "this architecture\n"));
 583                 return (BE_ERR_NOTSUP);
 584         }
 585 
 586         if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
 587             bt->obe_root_ds == NULL) {
 588                 be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
 589                 return (BE_ERR_INVAL);
 590         }
 591 
 592         if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
 593             NULL) {
 594                 be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
 595                     libzfs_error_description(g_zfs));
 596                 return (zfs_err_to_be_err(g_zfs));
 597         }
 598 
 599         /*
 600          * Check to see if the pool's dataset is mounted. If it isn't we'll
 601          * attempt to mount it.
 602          */
 603         if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
 604             &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
 605                 be_print_err(gettext("be_get_grub_vers: pool dataset "
 606                     "(%s) could not be mounted\n"), bt->obe_zpool);
 607                 ZFS_CLOSE(pool_zhp);
 608                 return (ret);
 609         }
 610 
 611         /*
 612          * Get the mountpoint for the root pool dataset.
 613          */
 614         if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
 615                 be_print_err(gettext("be_get_grub_vers: pool "
 616                     "dataset (%s) is not mounted. Can't set the "
 617                     "default BE in the grub menu.\n"), bt->obe_zpool);
 618                 ret = BE_ERR_NO_MENU;
 619                 goto cleanup;
 620         }
 621 
 622         /*
 623          * get the version of the most recent grub update.
 624          */
 625         (void) snprintf(cap_file, sizeof (cap_file), "%s%s",
 626             zpool_mntpt, BE_CAP_FILE);
 627         free(zpool_mntpt);
 628         zpool_mntpt = NULL;
 629 
 630         if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
 631                 goto cleanup;
 632 
 633         if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
 634             NULL) {
 635                 be_print_err(gettext("be_get_grub_vers: failed to "
 636                     "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
 637                     libzfs_error_description(g_zfs));
 638                 free(cur_vers);
 639                 ret = zfs_err_to_be_err(g_zfs);
 640                 goto cleanup;
 641         }
 642         if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
 643                 if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
 644                     BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
 645                         be_print_err(gettext("be_get_grub_vers: failed to "
 646                             "mount BE (%s)\n"), bt->obe_name);
 647                         free(*cur_vers);
 648                         *cur_vers = NULL;
 649                         ZFS_CLOSE(zhp);
 650                         goto cleanup;
 651                 }
 652                 be_mounted = B_TRUE;
 653         }
 654         ZFS_CLOSE(zhp);
 655 
 656         /*
 657          * Now get the grub version for the BE being activated.
 658          */
 659         (void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
 660             BE_CAP_FILE);
 661         ret = get_ver_from_capfile(cap_file, new_vers);
 662         if (ret != BE_SUCCESS) {
 663                 free(*cur_vers);
 664                 *cur_vers = NULL;
 665         }
 666         if (be_mounted)
 667                 (void) _be_unmount(bt->obe_name, 0);
 668 
 669 cleanup:
 670         if (pool_mounted) {
 671                 int iret = BE_SUCCESS;
 672                 iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
 673                 if (ret == BE_SUCCESS)
 674                         ret = iret;
 675                 free(orig_mntpnt);
 676                 free(ptmp_mntpnt);
 677         }
 678         ZFS_CLOSE(pool_zhp);
 679 
 680         free(temp_mntpnt);
 681         return (ret);
 682 }
 683 
 684 /*
 685  * Function:    get_ver_from_capfile
 686  * Description: Parses the capability file passed in looking for the VERSION
 687  *              line. If found the version is returned in vers, if not then
 688  *              NULL is returned in vers.
 689  *
 690  * Parameters:
 691  *              file - the path to the capability file we want to parse.
 692  *              vers - the version string that will be passed back.
 693  * Return:
 694  *              BE_SUCCESS - Success
 695  *              be_errno_t - Failed to find version
 696  * Scope:
 697  *              Private
 698  */
 699 static int
 700 get_ver_from_capfile(char *file, char **vers)
 701 {
 702         FILE *fp = NULL;
 703         char line[BUFSIZ];
 704         char *last = NULL;
 705         int err = BE_SUCCESS;
 706         errno = 0;
 707 
 708         if (!be_has_grub()) {
 709                 be_print_err(gettext("get_ver_from_capfile: Not supported "
 710                     "on this architecture\n"));
 711                 return (BE_ERR_NOTSUP);
 712         }
 713 
 714         /*
 715          * Set version string to NULL; the only case this shouldn't be set
 716          * to be NULL is when we've actually found a version in the capability
 717          * file, which is set below.
 718          */
 719         *vers = NULL;
 720 
 721         /*
 722          * If the capability file doesn't exist, we're returning success
 723          * because on older releases, the capability file did not exist
 724          * so this is a valid scenario.
 725          */
 726         if (access(file, F_OK) == 0) {
 727                 if ((fp = fopen(file, "r")) == NULL) {
 728                         err = errno;
 729                         be_print_err(gettext("get_ver_from_capfile: failed to "
 730                             "open file %s with error %s\n"), file,
 731                             strerror(err));
 732                         err = errno_to_be_err(err);
 733                         return (err);
 734                 }
 735 
 736                 while (fgets(line, BUFSIZ, fp)) {
 737                         char *tok = strtok_r(line, "=", &last);
 738 
 739                         if (tok == NULL || tok[0] == '#') {
 740                                 continue;
 741                         } else if (strcmp(tok, "VERSION") == 0) {
 742                                 *vers = strdup(last);
 743                                 break;
 744                         }
 745                 }
 746                 (void) fclose(fp);
 747         }
 748 
 749         return (BE_SUCCESS);
 750 }
 751 
 752 /*
 753  * Function:    be_do_installgrub
 754  * Description: This function runs installgrub using the grub loader files
 755  *              from the BE we're activating and installing them on the
 756  *              pool the BE lives in.
 757  *
 758  * Parameters:
 759  *              bt - The transaction data for the BE we're activating.
 760  * Return:
 761  *              BE_SUCCESS - Success
 762  *              be_errno_t - Failure
 763  *
 764  * Scope:
 765  *              Private
 766  */
 767 static int
 768 be_do_installgrub(be_transaction_data_t *bt)
 769 {
 770         zpool_handle_t  *zphp = NULL;
 771         zfs_handle_t    *zhp = NULL;
 772         nvlist_t **child, *nv, *config;
 773         uint_t c, children = 0;
 774         char *tmp_mntpt = NULL;
 775         char *pool_mntpnt = NULL;
 776         char *ptmp_mntpnt = NULL;
 777         char *orig_mntpnt = NULL;
 778         FILE *cap_fp = NULL;
 779         FILE *zpool_cap_fp = NULL;
 780         char line[BUFSIZ];
 781         char cap_file[MAXPATHLEN];
 782         char zpool_cap_file[MAXPATHLEN];
 783         char stage1[MAXPATHLEN];
 784         char stage2[MAXPATHLEN];
 785         char installgrub_cmd[MAXPATHLEN];
 786         char *vname;
 787         char be_run_cmd_errbuf[BUFSIZ];
 788         int ret = BE_SUCCESS;
 789         int err = 0;
 790         boolean_t be_mounted = B_FALSE;
 791         boolean_t pool_mounted = B_FALSE;
 792 
 793         if (!be_has_grub()) {
 794                 be_print_err(gettext("be_do_installgrub: Not supported "
 795                     "on this architecture\n"));
 796                 return (BE_ERR_NOTSUP);
 797         }
 798 
 799         if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
 800             NULL) {
 801                 be_print_err(gettext("be_do_installgrub: failed to "
 802                     "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
 803                     libzfs_error_description(g_zfs));
 804                 ret = zfs_err_to_be_err(g_zfs);
 805                 return (ret);
 806         }
 807         if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
 808                 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
 809                     BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
 810                         be_print_err(gettext("be_do_installgrub: failed to "
 811                             "mount BE (%s)\n"), bt->obe_name);
 812                         ZFS_CLOSE(zhp);
 813                         return (ret);
 814                 }
 815                 be_mounted = B_TRUE;
 816         }
 817         ZFS_CLOSE(zhp);
 818 
 819         (void) snprintf(stage1, sizeof (stage1), "%s%s", tmp_mntpt, BE_STAGE_1);
 820         (void) snprintf(stage2, sizeof (stage2), "%s%s", tmp_mntpt, BE_STAGE_2);
 821 
 822         if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
 823                 be_print_err(gettext("be_do_installgrub: failed to open "
 824                     "pool (%s): %s\n"), bt->obe_zpool,
 825                     libzfs_error_description(g_zfs));
 826                 ret = zfs_err_to_be_err(g_zfs);
 827                 if (be_mounted)
 828                         (void) _be_unmount(bt->obe_name, 0);
 829                 free(tmp_mntpt);
 830                 return (ret);
 831         }
 832 
 833         if ((config = zpool_get_config(zphp, NULL)) == NULL) {
 834                 be_print_err(gettext("be_do_installgrub: failed to get zpool "
 835                     "configuration information. %s\n"),
 836                     libzfs_error_description(g_zfs));
 837                 ret = zfs_err_to_be_err(g_zfs);
 838                 goto done;
 839         }
 840 
 841         /*
 842          * Get the vdev tree
 843          */
 844         if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
 845                 be_print_err(gettext("be_do_installgrub: failed to get vdev "
 846                     "tree: %s\n"), libzfs_error_description(g_zfs));
 847                 ret = zfs_err_to_be_err(g_zfs);
 848                 goto done;
 849         }
 850 
 851         if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
 852             &children) != 0) {
 853                 be_print_err(gettext("be_do_installgrub: failed to traverse "
 854                     "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
 855                 ret = zfs_err_to_be_err(g_zfs);
 856                 goto done;
 857         }
 858         for (c = 0; c < children; c++) {
 859                 uint_t i, nchildren = 0;
 860                 nvlist_t **nvchild;
 861                 vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE);
 862                 if (vname == NULL) {
 863                         be_print_err(gettext(
 864                             "be_do_installgrub: "
 865                             "failed to get device name: %s\n"),
 866                             libzfs_error_description(g_zfs));
 867                         ret = zfs_err_to_be_err(g_zfs);
 868                         goto done;
 869                 }
 870                 if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') {
 871 
 872                         if (nvlist_lookup_nvlist_array(child[c],
 873                             ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) {
 874                                 be_print_err(gettext("be_do_installgrub: "
 875                                     "failed to traverse the vdev tree: %s\n"),
 876                                     libzfs_error_description(g_zfs));
 877                                 ret = zfs_err_to_be_err(g_zfs);
 878                                 goto done;
 879                         }
 880 
 881                         for (i = 0; i < nchildren; i++) {
 882                                 vname = zpool_vdev_name(g_zfs, zphp,
 883                                     nvchild[i], B_FALSE);
 884                                 if (vname == NULL) {
 885                                         be_print_err(gettext(
 886                                             "be_do_installgrub: "
 887                                             "failed to get device name: %s\n"),
 888                                             libzfs_error_description(g_zfs));
 889                                         ret = zfs_err_to_be_err(g_zfs);
 890                                         goto done;
 891                                 }
 892 
 893                                 (void) snprintf(installgrub_cmd,
 894                                     sizeof (installgrub_cmd),
 895                                     "%s %s %s /dev/rdsk/%s",
 896                                     BE_INSTALL_GRUB, stage1, stage2, vname);
 897                                 if (be_run_cmd(installgrub_cmd,
 898                                     be_run_cmd_errbuf, BUFSIZ, NULL, 0) !=
 899                                     BE_SUCCESS) {
 900                                         be_print_err(gettext(
 901                                             "be_do_installgrub: installgrub "
 902                                             "failed for device %s.\n"), vname);
 903                                         /* Assume localized cmd err output. */
 904                                         be_print_err(gettext(
 905                                             "  Command: \"%s\"\n"),
 906                                             installgrub_cmd);
 907                                         be_print_err("%s", be_run_cmd_errbuf);
 908                                         free(vname);
 909                                         ret = BE_ERR_BOOTFILE_INST;
 910                                         goto done;
 911                                 }
 912                                 free(vname);
 913                         }
 914                 } else {
 915                         (void) snprintf(installgrub_cmd,
 916                             sizeof (installgrub_cmd), "%s %s %s /dev/rdsk/%s",
 917                             BE_INSTALL_GRUB, stage1, stage2, vname);
 918                         if (be_run_cmd(installgrub_cmd, be_run_cmd_errbuf,
 919                             BUFSIZ, NULL, 0) != BE_SUCCESS) {
 920                                 be_print_err(gettext(
 921                                     "be_do_installgrub: installgrub "
 922                                     "failed for device %s.\n"), vname);
 923                                 /* Assume localized cmd err output. */
 924                                 be_print_err(gettext("  Command: \"%s\"\n"),
 925                                     installgrub_cmd);
 926                                 be_print_err("%s", be_run_cmd_errbuf);
 927                                 free(vname);
 928                                 ret = BE_ERR_BOOTFILE_INST;
 929                                 goto done;
 930                         }
 931                         free(vname);
 932                 }
 933         }
 934 
 935         /*
 936          * Copy the grub capability file from the BE we're activating into
 937          * the root pool.
 938          */
 939         (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpt,
 940             BE_CAP_FILE);
 941 
 942         if ((zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
 943             NULL) {
 944                 be_print_err(gettext("be_do_installgrub: zfs_open "
 945                     "failed: %s\n"), libzfs_error_description(g_zfs));
 946                 zpool_close(zphp);
 947                 return (zfs_err_to_be_err(g_zfs));
 948         }
 949 
 950         /*
 951          * Check to see if the pool's dataset is mounted. If it isn't we'll
 952          * attempt to mount it.
 953          */
 954         if ((ret = be_mount_pool(zhp, &ptmp_mntpnt,
 955             &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
 956                 be_print_err(gettext("be_do_installgrub: pool dataset "
 957                     "(%s) could not be mounted\n"), bt->obe_zpool);
 958                 ZFS_CLOSE(zhp);
 959                 zpool_close(zphp);
 960                 return (ret);
 961         }
 962 
 963         /*
 964          * Get the mountpoint for the root pool dataset.
 965          */
 966         if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
 967                 be_print_err(gettext("be_do_installgrub: pool "
 968                     "dataset (%s) is not mounted. Can't check the grub "
 969                     "version from the grub capability file.\n"), bt->obe_zpool);
 970                 ret = BE_ERR_NO_MENU;
 971                 goto done;
 972         }
 973 
 974         (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
 975             pool_mntpnt, BE_CAP_FILE);
 976 
 977         free(pool_mntpnt);
 978         pool_mntpnt = NULL;
 979 
 980         if ((cap_fp = fopen(cap_file, "r")) == NULL) {
 981                 err = errno;
 982                 be_print_err(gettext("be_do_installgrub: failed to open grub "
 983                     "capability file\n"));
 984                 ret = errno_to_be_err(err);
 985                 goto done;
 986         }
 987         if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
 988                 err = errno;
 989                 be_print_err(gettext("be_do_installgrub: failed to open new "
 990                     "grub capability file\n"));
 991                 ret = errno_to_be_err(err);
 992                 (void) fclose(cap_fp);
 993                 goto done;
 994         }
 995 
 996         while (fgets(line, BUFSIZ, cap_fp)) {
 997                 (void) fputs(line, zpool_cap_fp);
 998         }
 999 
1000         (void) fclose(zpool_cap_fp);
1001         (void) fclose(cap_fp);
1002 
1003 done:
1004         if (pool_mounted) {
1005                 int iret = 0;
1006                 iret = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1007                 if (ret == BE_SUCCESS)
1008                         ret = iret;
1009                 free(orig_mntpnt);
1010                 free(ptmp_mntpnt);
1011         }
1012         ZFS_CLOSE(zhp);
1013         if (be_mounted)
1014                 (void) _be_unmount(bt->obe_name, 0);
1015         zpool_close(zphp);
1016         free(tmp_mntpt);
1017         return (ret);
1018 }
1019 
1020 /*
1021  * Function:    be_promote_zone_ds
1022  * Description: This function finds the zones for the BE being activated
1023  *              and the active zonepath dataset for each zone. Then each
1024  *              active zonepath dataset is promoted.
1025  *
1026  * Parameters:
1027  *              be_name - the name of the global zone BE that we need to
1028  *                       find the zones for.
1029  *              be_root_ds - the root dataset for be_name.
1030  * Return:
1031  *              BE_SUCCESS - Success
1032  *              be_errno_t - Failure
1033  *
1034  * Scope:
1035  *              Private
1036  */
1037 static int
1038 be_promote_zone_ds(char *be_name, char *be_root_ds)
1039 {
1040         char            *zone_ds = NULL;
1041         char            *temp_mntpt = NULL;
1042         char            origin[MAXPATHLEN];
1043         char            zoneroot_ds[MAXPATHLEN];
1044         zfs_handle_t    *zhp = NULL;
1045         zfs_handle_t    *z_zhp = NULL;
1046         zoneList_t      zone_list = NULL;
1047         zoneBrandList_t *brands = NULL;
1048         boolean_t       be_mounted = B_FALSE;
1049         int             zone_index = 0;
1050         int             err = BE_SUCCESS;
1051 
1052         /*
1053          * Get the supported zone brands so we can pass that
1054          * to z_get_nonglobal_zone_list_by_brand. Currently
1055          * only the ipkg and labeled brand zones are supported
1056          *
1057          */
1058         if ((brands = be_get_supported_brandlist()) == NULL) {
1059                 be_print_err(gettext("be_promote_zone_ds: no supported "
1060                     "brands\n"));
1061                 return (BE_SUCCESS);
1062         }
1063 
1064         if ((zhp = zfs_open(g_zfs, be_root_ds,
1065             ZFS_TYPE_FILESYSTEM)) == NULL) {
1066                 be_print_err(gettext("be_promote_zone_ds: Failed to open "
1067                     "dataset (%s): %s\n"), be_root_ds,
1068                     libzfs_error_description(g_zfs));
1069                 err = zfs_err_to_be_err(g_zfs);
1070                 z_free_brand_list(brands);
1071                 return (err);
1072         }
1073 
1074         if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1075                 if ((err = _be_mount(be_name, &temp_mntpt,
1076                     BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1077                         be_print_err(gettext("be_promote_zone_ds: failed to "
1078                             "mount the BE for zones procesing.\n"));
1079                         ZFS_CLOSE(zhp);
1080                         z_free_brand_list(brands);
1081                         return (err);
1082                 }
1083                 be_mounted = B_TRUE;
1084         }
1085 
1086         /*
1087          * Set the zone root to the temp mount point for the BE we just mounted.
1088          */
1089         z_set_zone_root(temp_mntpt);
1090 
1091         /*
1092          * Get all the zones based on the brands we're looking for. If no zones
1093          * are found that we're interested in unmount the BE and move on.
1094          */
1095         if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1096                 if (be_mounted)
1097                         (void) _be_unmount(be_name, 0);
1098                 ZFS_CLOSE(zhp);
1099                 z_free_brand_list(brands);
1100                 free(temp_mntpt);
1101                 return (BE_SUCCESS);
1102         }
1103         for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1104             != NULL; zone_index++) {
1105                 char *zone_path = NULL;
1106 
1107                 /* Skip zones that aren't at least installed */
1108                 if (z_zlist_get_current_state(zone_list, zone_index) <
1109                     ZONE_STATE_INSTALLED)
1110                         continue;
1111 
1112                 if (((zone_path =
1113                     z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1114                     ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1115                     !be_zone_supported(zone_ds))
1116                         continue;
1117 
1118                 if (be_find_active_zone_root(zhp, zone_ds,
1119                     zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1120                         be_print_err(gettext("be_promote_zone_ds: "
1121                             "Zone does not have an active root "
1122                             "dataset, skipping this zone.\n"));
1123                         continue;
1124                 }
1125 
1126                 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1127                     ZFS_TYPE_FILESYSTEM)) == NULL) {
1128                         be_print_err(gettext("be_promote_zone_ds: "
1129                             "Failed to open dataset "
1130                             "(%s): %s\n"), zoneroot_ds,
1131                             libzfs_error_description(g_zfs));
1132                         err = zfs_err_to_be_err(g_zfs);
1133                         goto done;
1134                 }
1135 
1136                 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1137                     sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1138                         ZFS_CLOSE(z_zhp);
1139                         continue;
1140                 }
1141 
1142                 /*
1143                  * We don't need to close the zfs handle at this
1144                  * point because the callback funtion
1145                  * be_promote_ds_callback() will close it for us.
1146                  */
1147                 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1148                         be_print_err(gettext("be_promote_zone_ds: "
1149                             "failed to activate the "
1150                             "datasets for %s: %s\n"),
1151                             zoneroot_ds,
1152                             libzfs_error_description(g_zfs));
1153                         err = BE_ERR_PROMOTE;
1154                         goto done;
1155                 }
1156         }
1157 done:
1158         if (be_mounted)
1159                 (void) _be_unmount(be_name, 0);
1160         ZFS_CLOSE(zhp);
1161         free(temp_mntpt);
1162         z_free_brand_list(brands);
1163         z_free_zone_list(zone_list);
1164         return (err);
1165 }
1166 
1167 /*
1168  * Function:    be_promote_ds_callback
1169  * Description: This function is used to promote the datasets for the BE
1170  *              being activated as well as the datasets for the zones BE
1171  *              being activated.
1172  *
1173  * Parameters:
1174  *              zhp - the zfs handle for zone BE being activated.
1175  *              data - not used.
1176  * Return:
1177  *              0 - Success
1178  *              be_errno_t - Failure
1179  *
1180  * Scope:
1181  *              Private
1182  */
1183 static int
1184 /* LINTED */
1185 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1186 {
1187         char    origin[MAXPATHLEN];
1188         char    *sub_dataset = NULL;
1189         int     ret = 0;
1190 
1191         if (zhp != NULL) {
1192                 sub_dataset = strdup(zfs_get_name(zhp));
1193                 if (sub_dataset == NULL) {
1194                         ret = BE_ERR_NOMEM;
1195                         goto done;
1196                 }
1197         } else {
1198                 be_print_err(gettext("be_promote_ds_callback: "
1199                     "Invalid zfs handle passed into function\n"));
1200                 ret = BE_ERR_INVAL;
1201                 goto done;
1202         }
1203 
1204         /*
1205          * This loop makes sure that we promote the dataset to the
1206          * top of the tree so that it is no longer a decendent of any
1207          * dataset. The ZFS close and then open is used to make sure that
1208          * the promotion is updated before we move on.
1209          */
1210         while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1211             sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1212                 if (zfs_promote(zhp) != 0) {
1213                         if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1214                                 be_print_err(gettext("be_promote_ds_callback: "
1215                                     "promote of %s failed: %s\n"),
1216                                     zfs_get_name(zhp),
1217                                     libzfs_error_description(g_zfs));
1218                                 ret = zfs_err_to_be_err(g_zfs);
1219                                 goto done;
1220                         } else {
1221                                 /*
1222                                  * If the call to zfs_promote returns the
1223                                  * error EZFS_EXISTS we've hit a snapshot name
1224                                  * collision. This means we're probably
1225                                  * attemping to promote a zone dataset above a
1226                                  * parent dataset that belongs to another zone
1227                                  * which this zone was cloned from.
1228                                  *
1229                                  * TODO: If this is a zone dataset at some
1230                                  * point we should skip this if the zone
1231                                  * paths for the dataset and the snapshot
1232                                  * don't match.
1233                                  */
1234                                 be_print_err(gettext("be_promote_ds_callback: "
1235                                     "promote of %s failed due to snapshot "
1236                                     "name collision: %s\n"), zfs_get_name(zhp),
1237                                     libzfs_error_description(g_zfs));
1238                                 ret = zfs_err_to_be_err(g_zfs);
1239                                 goto done;
1240                         }
1241                 }
1242                 ZFS_CLOSE(zhp);
1243                 if ((zhp = zfs_open(g_zfs, sub_dataset,
1244                     ZFS_TYPE_FILESYSTEM)) == NULL) {
1245                         be_print_err(gettext("be_promote_ds_callback: "
1246                             "Failed to open dataset (%s): %s\n"), sub_dataset,
1247                             libzfs_error_description(g_zfs));
1248                         ret = zfs_err_to_be_err(g_zfs);
1249                         goto done;
1250                 }
1251         }
1252 
1253         /* Iterate down this dataset's children and promote them */
1254         ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1255 
1256 done:
1257         free(sub_dataset);
1258         ZFS_CLOSE(zhp);
1259         return (ret);
1260 }