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 2015 Nexenta Systems, Inc. All rights reserved.
  28  * Copyright 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  29  */
  30 
  31 #include <assert.h>
  32 #include <libintl.h>
  33 #include <libnvpair.h>
  34 #include <libzfs.h>
  35 #include <stdio.h>
  36 #include <stdlib.h>
  37 #include <string.h>
  38 #include <strings.h>
  39 #include <errno.h>
  40 #include <sys/mnttab.h>
  41 #include <sys/types.h>
  42 #include <sys/stat.h>
  43 #include <fcntl.h>
  44 #include <unistd.h>
  45 #include <sys/efi_partition.h>
  46 
  47 #include <libbe.h>
  48 #include <libbe_priv.h>
  49 
  50 char    *mnttab = MNTTAB;
  51 
  52 /*
  53  * Private function prototypes
  54  */
  55 static int set_bootfs(char *boot_rpool, char *be_root_ds);
  56 static int set_canmount(be_node_list_t *, char *);
  57 static boolean_t be_do_install_mbr(char *, nvlist_t *);
  58 static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *,
  59     char *, uint16_t);
  60 static int be_do_installboot(be_transaction_data_t *, uint16_t);
  61 static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
  62 static int get_ver_from_capfile(char *, char **);
  63 static int be_promote_zone_ds(char *, char *);
  64 static int be_promote_ds_callback(zfs_handle_t *, void *);
  65 
  66 /* ******************************************************************** */
  67 /*                      Public Functions                                */
  68 /* ******************************************************************** */
  69 
  70 /*
  71  * Function:    be_activate
  72  * Description: Calls _be_activate which activates the BE named in the
  73  *              attributes passed in through be_attrs. The process of
  74  *              activation sets the bootfs property of the root pool, resets
  75  *              the canmount property to noauto, and sets the default in the
  76  *              grub menu to the entry corresponding to the entry for the named
  77  *              BE.
  78  * Parameters:
  79  *              be_attrs - pointer to nvlist_t of attributes being passed in.
  80  *                      The follow attribute values are used by this function:
  81  *
  82  *                      BE_ATTR_ORIG_BE_NAME            *required
  83  * Return:
  84  *              BE_SUCCESS - Success
  85  *              be_errno_t - Failure
  86  * Scope:
  87  *              Public
  88  */
  89 int
  90 be_activate(nvlist_t *be_attrs)
  91 {
  92         int     ret = BE_SUCCESS;
  93         char    *be_name = NULL;
  94 
  95         /* Initialize libzfs handle */
  96         if (!be_zfs_init())
  97                 return (BE_ERR_INIT);
  98 
  99         /* Get the BE name to activate */
 100         if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
 101             != 0) {
 102                 be_print_err(gettext("be_activate: failed to "
 103                     "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
 104                 be_zfs_fini();
 105                 return (BE_ERR_INVAL);
 106         }
 107 
 108         /* Validate BE name */
 109         if (!be_valid_be_name(be_name)) {
 110                 be_print_err(gettext("be_activate: invalid BE name %s\n"),
 111                     be_name);
 112                 be_zfs_fini();
 113                 return (BE_ERR_INVAL);
 114         }
 115 
 116         ret = _be_activate(be_name);
 117 
 118         be_zfs_fini();
 119 
 120         return (ret);
 121 }
 122 
 123 /*
 124  * Function:    be_installboot
 125  * Description: Calls be_do_installboot to install/update bootloader on
 126  *              pool passed in through be_attrs. The primary consumer is
 127  *              bootadm command to avoid duplication of the code.
 128  * Parameters:
 129  *              be_attrs - pointer to nvlist_t of attributes being passed in.
 130  *                      The following attribute values are used:
 131  *
 132  *                      BE_ATTR_ORIG_BE_NAME            *required
 133  *                      BE_ATTR_ORIG_BE_POOL            *required
 134  *                      BE_ATTR_ORIG_BE_ROOT            *required
 135  *                      BE_ATTR_INSTALL_FLAGS           optional
 136  *
 137  * Return:
 138  *              BE_SUCCESS - Success
 139  *              be_errno_t - Failure
 140  * Scope:
 141  *              Public
 142  */
 143 int
 144 be_installboot(nvlist_t *be_attrs)
 145 {
 146         int             ret = BE_SUCCESS;
 147         uint16_t        flags = 0;
 148         uint16_t        verbose;
 149         be_transaction_data_t bt = { 0 };
 150 
 151         /* Get flags */
 152         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 153             BE_ATTR_INSTALL_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
 154                 be_print_err(gettext("be_installboot: failed to lookup "
 155                     "BE_ATTR_INSTALL_FLAGS attribute\n"));
 156                 return (BE_ERR_INVAL);
 157         }
 158 
 159         /* Set verbose early, so we get all messages */
 160         verbose = flags & BE_INSTALLBOOT_FLAG_VERBOSE;
 161         if (verbose == BE_INSTALLBOOT_FLAG_VERBOSE)
 162                 libbe_print_errors(B_TRUE);
 163 
 164         ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
 165             &bt.obe_name);
 166         if (ret != 0) {
 167                 be_print_err(gettext("be_installboot: failed to "
 168                     "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
 169                 return (BE_ERR_INVAL);
 170         }
 171 
 172         ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_POOL,
 173             &bt.obe_zpool);
 174         if (ret != 0) {
 175                 be_print_err(gettext("be_installboot: failed to "
 176                     "lookup BE_ATTR_ORIG_BE_POOL attribute\n"));
 177                 return (BE_ERR_INVAL);
 178         }
 179 
 180         ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_ROOT,
 181             &bt.obe_root_ds);
 182         if (ret != 0) {
 183                 be_print_err(gettext("be_installboot: failed to "
 184                     "lookup BE_ATTR_ORIG_BE_ROOT attribute\n"));
 185                 return (BE_ERR_INVAL);
 186         }
 187 
 188         /* Initialize libzfs handle */
 189         if (!be_zfs_init())
 190                 return (BE_ERR_INIT);
 191 
 192         ret = be_do_installboot(&bt, flags);
 193 
 194         be_zfs_fini();
 195 
 196         return (ret);
 197 }
 198 
 199 /* ******************************************************************** */
 200 /*                      Semi Private Functions                          */
 201 /* ******************************************************************** */
 202 
 203 /*
 204  * Function:    _be_activate
 205  * Description: This does the actual work described in be_activate.
 206  * Parameters:
 207  *              be_name - pointer to the name of BE to activate.
 208  *
 209  * Return:
 210  *              BE_SUCCESS - Success
 211  *              be_errnot_t - Failure
 212  * Scope:
 213  *              Public
 214  */
 215 int
 216 _be_activate(char *be_name)
 217 {
 218         be_transaction_data_t cb = { 0 };
 219         zfs_handle_t    *zhp = NULL;
 220         char            root_ds[MAXPATHLEN];
 221         char            active_ds[MAXPATHLEN];
 222         be_node_list_t  *be_nodes = NULL;
 223         uuid_t          uu = {0};
 224         int             entry, ret = BE_SUCCESS;
 225         int             zret = 0;
 226 
 227         /*
 228          * TODO: The BE needs to be validated to make sure that it is actually
 229          * a bootable BE.
 230          */
 231 
 232         if (be_name == NULL)
 233                 return (BE_ERR_INVAL);
 234 
 235         /* Set obe_name to be_name in the cb structure */
 236         cb.obe_name = be_name;
 237 
 238         /* find which zpool the be is in */
 239         if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
 240                 be_print_err(gettext("be_activate: failed to "
 241                     "find zpool for BE (%s)\n"), cb.obe_name);
 242                 return (BE_ERR_BE_NOENT);
 243         } else if (zret < 0) {
 244                 be_print_err(gettext("be_activate: "
 245                     "zpool_iter failed: %s\n"),
 246                     libzfs_error_description(g_zfs));
 247                 ret = zfs_err_to_be_err(g_zfs);
 248                 return (ret);
 249         }
 250 
 251         be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
 252         cb.obe_root_ds = strdup(root_ds);
 253 
 254         if (getzoneid() == GLOBAL_ZONEID) {
 255                 ret = be_do_installboot(&cb, BE_INSTALLBOOT_FLAG_NULL);
 256                 if (ret != BE_SUCCESS)
 257                         return (ret);
 258 
 259                 if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
 260                         if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
 261                             NULL, NULL, NULL)) != BE_SUCCESS) {
 262                                 be_print_err(gettext("be_activate: Failed to "
 263                                     "add BE (%s) to the menu\n"),
 264                                     cb.obe_name);
 265                                 goto done;
 266                         }
 267                 }
 268                 if (be_has_grub()) {
 269                         if ((ret = be_change_grub_default(cb.obe_name,
 270                             cb.obe_zpool)) != BE_SUCCESS) {
 271                                 be_print_err(gettext("be_activate: failed to "
 272                                     "change the default entry in menu.lst\n"));
 273                                 goto done;
 274                         }
 275                 }
 276         }
 277 
 278         if ((ret = _be_list(cb.obe_name, &be_nodes)) != BE_SUCCESS) {
 279                 return (ret);
 280         }
 281 
 282         if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
 283                 be_print_err(gettext("be_activate: failed to set "
 284                     "canmount dataset property\n"));
 285                 goto done;
 286         }
 287 
 288         if (getzoneid() == GLOBAL_ZONEID) {
 289                 if ((ret = set_bootfs(be_nodes->be_rpool,
 290                     root_ds)) != BE_SUCCESS) {
 291                         be_print_err(gettext("be_activate: failed to set "
 292                             "bootfs pool property for %s\n"), root_ds);
 293                         goto done;
 294                 }
 295         }
 296 
 297         if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
 298                 /*
 299                  * We don't need to close the zfs handle at this
 300                  * point because The callback funtion
 301                  * be_promote_ds_callback() will close it for us.
 302                  */
 303                 if (be_promote_ds_callback(zhp, NULL) != 0) {
 304                         be_print_err(gettext("be_activate: "
 305                             "failed to activate the "
 306                             "datasets for %s: %s\n"),
 307                             root_ds,
 308                             libzfs_error_description(g_zfs));
 309                         ret = BE_ERR_PROMOTE;
 310                         goto done;
 311                 }
 312         } else {
 313                 be_print_err(gettext("be_activate: failed to open "
 314                     "dataset (%s): %s\n"), root_ds,
 315                     libzfs_error_description(g_zfs));
 316                 ret = zfs_err_to_be_err(g_zfs);
 317                 goto done;
 318         }
 319 
 320         if (getzoneid() == GLOBAL_ZONEID &&
 321             be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
 322             (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
 323             != BE_SUCCESS) {
 324                 be_print_err(gettext("be_activate: failed to promote "
 325                     "the active zonepath datasets for zones in BE %s\n"),
 326                     cb.obe_name);
 327         }
 328 
 329         if (getzoneid() != GLOBAL_ZONEID) {
 330                 if (!be_zone_compare_uuids(root_ds)) {
 331                         be_print_err(gettext("be_activate: activating zone "
 332                             "root dataset from non-active global BE is not "
 333                             "supported\n"));
 334                         ret = BE_ERR_NOTSUP;
 335                         goto done;
 336                 }
 337                 if ((zhp = zfs_open(g_zfs, root_ds,
 338                     ZFS_TYPE_FILESYSTEM)) == NULL) {
 339                         be_print_err(gettext("be_activate: failed to open "
 340                             "dataset (%s): %s\n"), root_ds,
 341                             libzfs_error_description(g_zfs));
 342                         ret = zfs_err_to_be_err(g_zfs);
 343                         goto done;
 344                 }
 345                 /* Find current active zone root dataset */
 346                 if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
 347                     active_ds, sizeof (active_ds))) != BE_SUCCESS) {
 348                         be_print_err(gettext("be_activate: failed to find "
 349                             "active zone root dataset\n"));
 350                         ZFS_CLOSE(zhp);
 351                         goto done;
 352                 }
 353                 /* Do nothing if requested BE is already active */
 354                 if (strcmp(root_ds, active_ds) == 0) {
 355                         ret = BE_SUCCESS;
 356                         ZFS_CLOSE(zhp);
 357                         goto done;
 358                 }
 359 
 360                 /* Set active property for BE */
 361                 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
 362                         be_print_err(gettext("be_activate: failed to set "
 363                             "active property (%s): %s\n"), root_ds,
 364                             libzfs_error_description(g_zfs));
 365                         ret = zfs_err_to_be_err(g_zfs);
 366                         ZFS_CLOSE(zhp);
 367                         goto done;
 368                 }
 369                 ZFS_CLOSE(zhp);
 370 
 371                 /* Unset active property for old active root dataset */
 372                 if ((zhp = zfs_open(g_zfs, active_ds,
 373                     ZFS_TYPE_FILESYSTEM)) == NULL) {
 374                         be_print_err(gettext("be_activate: failed to open "
 375                             "dataset (%s): %s\n"), active_ds,
 376                             libzfs_error_description(g_zfs));
 377                         ret = zfs_err_to_be_err(g_zfs);
 378                         goto done;
 379                 }
 380                 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
 381                         be_print_err(gettext("be_activate: failed to unset "
 382                             "active property (%s): %s\n"), active_ds,
 383                             libzfs_error_description(g_zfs));
 384                         ret = zfs_err_to_be_err(g_zfs);
 385                         ZFS_CLOSE(zhp);
 386                         goto done;
 387                 }
 388                 ZFS_CLOSE(zhp);
 389         }
 390 done:
 391         be_free_list(be_nodes);
 392         return (ret);
 393 }
 394 
 395 /*
 396  * Function:    be_activate_current_be
 397  * Description: Set the currently "active" BE to be "active on boot"
 398  * Paramters:
 399  *              none
 400  * Returns:
 401  *              BE_SUCCESS - Success
 402  *              be_errnot_t - Failure
 403  * Scope:
 404  *              Semi-private (library wide use only)
 405  */
 406 int
 407 be_activate_current_be(void)
 408 {
 409         int ret = BE_SUCCESS;
 410         be_transaction_data_t bt = { 0 };
 411 
 412         if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
 413                 return (ret);
 414         }
 415 
 416         if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
 417                 be_print_err(gettext("be_activate_current_be: failed to "
 418                     "activate %s\n"), bt.obe_name);
 419                 return (ret);
 420         }
 421 
 422         return (BE_SUCCESS);
 423 }
 424 
 425 /*
 426  * Function:    be_is_active_on_boot
 427  * Description: Checks if the BE name passed in has the "active on boot"
 428  *              property set to B_TRUE.
 429  * Paramters:
 430  *              be_name - the name of the BE to check
 431  * Returns:
 432  *              B_TRUE - if active on boot.
 433  *              B_FALSE - if not active on boot.
 434  * Scope:
 435  *              Semi-private (library wide use only)
 436  */
 437 boolean_t
 438 be_is_active_on_boot(char *be_name)
 439 {
 440         be_node_list_t *be_node = NULL;
 441 
 442         if (be_name == NULL) {
 443                 be_print_err(gettext("be_is_active_on_boot: "
 444                     "be_name must not be NULL\n"));
 445                 return (B_FALSE);
 446         }
 447 
 448         if (_be_list(be_name, &be_node) != BE_SUCCESS) {
 449                 return (B_FALSE);
 450         }
 451 
 452         if (be_node == NULL) {
 453                 return (B_FALSE);
 454         }
 455 
 456         if (be_node->be_active_on_boot) {
 457                 be_free_list(be_node);
 458                 return (B_TRUE);
 459         } else {
 460                 be_free_list(be_node);
 461                 return (B_FALSE);
 462         }
 463 }
 464 
 465 /* ******************************************************************** */
 466 /*                      Private Functions                               */
 467 /* ******************************************************************** */
 468 
 469 /*
 470  * Function:    set_bootfs
 471  * Description: Sets the bootfs property on the boot pool to be the
 472  *              root dataset of the activated BE.
 473  * Parameters:
 474  *              boot_pool - The pool we're setting bootfs in.
 475  *              be_root_ds - The main dataset for the BE.
 476  * Return:
 477  *              BE_SUCCESS - Success
 478  *              be_errno_t - Failure
 479  * Scope:
 480  *              Private
 481  */
 482 static int
 483 set_bootfs(char *boot_rpool, char *be_root_ds)
 484 {
 485         zpool_handle_t *zhp;
 486         int err = BE_SUCCESS;
 487 
 488         if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
 489                 be_print_err(gettext("set_bootfs: failed to open pool "
 490                     "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
 491                 err = zfs_err_to_be_err(g_zfs);
 492                 return (err);
 493         }
 494 
 495         err = zpool_set_prop(zhp, "bootfs", be_root_ds);
 496         if (err) {
 497                 be_print_err(gettext("set_bootfs: failed to set "
 498                     "bootfs property for pool %s: %s\n"), boot_rpool,
 499                     libzfs_error_description(g_zfs));
 500                 err = zfs_err_to_be_err(g_zfs);
 501                 zpool_close(zhp);
 502                 return (err);
 503         }
 504 
 505         zpool_close(zhp);
 506         return (BE_SUCCESS);
 507 }
 508 
 509 /*
 510  * Function:    set_canmount
 511  * Description: Sets the canmount property on the datasets of the
 512  *              activated BE.
 513  * Parameters:
 514  *              be_nodes - The be_node_t returned from be_list
 515  *              value - The value of canmount we setting, on|off|noauto.
 516  * Return:
 517  *              BE_SUCCESS - Success
 518  *              be_errno_t - Failure
 519  * Scope:
 520  *              Private
 521  */
 522 static int
 523 set_canmount(be_node_list_t *be_nodes, char *value)
 524 {
 525         char            ds_path[MAXPATHLEN];
 526         zfs_handle_t    *zhp = NULL;
 527         be_node_list_t  *list = be_nodes;
 528         int             err = BE_SUCCESS;
 529 
 530         while (list != NULL) {
 531                 be_dataset_list_t *datasets = list->be_node_datasets;
 532 
 533                 be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
 534                     sizeof (ds_path));
 535 
 536                 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
 537                     NULL) {
 538                         be_print_err(gettext("set_canmount: failed to open "
 539                             "dataset (%s): %s\n"), ds_path,
 540                             libzfs_error_description(g_zfs));
 541                         err = zfs_err_to_be_err(g_zfs);
 542                         return (err);
 543                 }
 544                 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
 545                         /*
 546                          * it's already mounted so we can't change the
 547                          * canmount property anyway.
 548                          */
 549                         err = BE_SUCCESS;
 550                 } else {
 551                         err = zfs_prop_set(zhp,
 552                             zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
 553                         if (err) {
 554                                 ZFS_CLOSE(zhp);
 555                                 be_print_err(gettext("set_canmount: failed to "
 556                                     "set dataset property (%s): %s\n"),
 557                                     ds_path, libzfs_error_description(g_zfs));
 558                                 err = zfs_err_to_be_err(g_zfs);
 559                                 return (err);
 560                         }
 561                 }
 562                 ZFS_CLOSE(zhp);
 563 
 564                 while (datasets != NULL) {
 565                         be_make_root_ds(list->be_rpool,
 566                             datasets->be_dataset_name, ds_path,
 567                             sizeof (ds_path));
 568 
 569                         if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
 570                             == NULL) {
 571                                 be_print_err(gettext("set_canmount: failed to "
 572                                     "open dataset %s: %s\n"), ds_path,
 573                                     libzfs_error_description(g_zfs));
 574                                 err = zfs_err_to_be_err(g_zfs);
 575                                 return (err);
 576                         }
 577                         if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
 578                                 /*
 579                                  * it's already mounted so we can't change the
 580                                  * canmount property anyway.
 581                                  */
 582                                 err = BE_SUCCESS;
 583                                 ZFS_CLOSE(zhp);
 584                                 break;
 585                         }
 586                         err = zfs_prop_set(zhp,
 587                             zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
 588                         if (err) {
 589                                 ZFS_CLOSE(zhp);
 590                                 be_print_err(gettext("set_canmount: "
 591                                     "Failed to set property value %s "
 592                                     "for dataset %s: %s\n"), value, ds_path,
 593                                     libzfs_error_description(g_zfs));
 594                                 err = zfs_err_to_be_err(g_zfs);
 595                                 return (err);
 596                         }
 597                         ZFS_CLOSE(zhp);
 598                         datasets = datasets->be_next_dataset;
 599                 }
 600                 list = list->be_next_node;
 601         }
 602         return (err);
 603 }
 604 
 605 /*
 606  * Function:    be_get_grub_vers
 607  * Description: Gets the grub version number from /boot/grub/capability. If
 608  *              capability file doesn't exist NULL is returned.
 609  * Parameters:
 610  *              bt - The transaction data for the BE we're getting the grub
 611  *                   version for.
 612  *              cur_vers - used to return the current version of grub from
 613  *                         the root pool.
 614  *              new_vers - used to return the grub version of the BE we're
 615  *                         activating.
 616  * Return:
 617  *              BE_SUCCESS - Success
 618  *              be_errno_t - Failed to find version
 619  * Scope:
 620  *              Private
 621  */
 622 static int
 623 be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
 624 {
 625         zfs_handle_t    *zhp = NULL;
 626         zfs_handle_t    *pool_zhp = NULL;
 627         int ret = BE_SUCCESS;
 628         char cap_file[MAXPATHLEN];
 629         char *temp_mntpnt = NULL;
 630         char *zpool_mntpt = NULL;
 631         char *ptmp_mntpnt = NULL;
 632         char *orig_mntpnt = NULL;
 633         boolean_t be_mounted = B_FALSE;
 634         boolean_t pool_mounted = B_FALSE;
 635 
 636         if (!be_has_grub()) {
 637                 be_print_err(gettext("be_get_grub_vers: Not supported on "
 638                     "this architecture\n"));
 639                 return (BE_ERR_NOTSUP);
 640         }
 641 
 642         if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
 643             bt->obe_root_ds == NULL) {
 644                 be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
 645                 return (BE_ERR_INVAL);
 646         }
 647 
 648         if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
 649             NULL) {
 650                 be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
 651                     libzfs_error_description(g_zfs));
 652                 return (zfs_err_to_be_err(g_zfs));
 653         }
 654 
 655         /*
 656          * Check to see if the pool's dataset is mounted. If it isn't we'll
 657          * attempt to mount it.
 658          */
 659         if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
 660             &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
 661                 be_print_err(gettext("be_get_grub_vers: pool dataset "
 662                     "(%s) could not be mounted\n"), bt->obe_zpool);
 663                 ZFS_CLOSE(pool_zhp);
 664                 return (ret);
 665         }
 666 
 667         /*
 668          * Get the mountpoint for the root pool dataset.
 669          */
 670         if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
 671                 be_print_err(gettext("be_get_grub_vers: pool "
 672                     "dataset (%s) is not mounted. Can't read the "
 673                     "grub capability file.\n"), bt->obe_zpool);
 674                 ret = BE_ERR_NO_MENU;
 675                 goto cleanup;
 676         }
 677 
 678         /*
 679          * get the version of the most recent grub update.
 680          */
 681         (void) snprintf(cap_file, sizeof (cap_file), "%s%s",
 682             zpool_mntpt, BE_CAP_FILE);
 683         free(zpool_mntpt);
 684         zpool_mntpt = NULL;
 685 
 686         if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
 687                 goto cleanup;
 688 
 689         if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
 690             NULL) {
 691                 be_print_err(gettext("be_get_grub_vers: failed to "
 692                     "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
 693                     libzfs_error_description(g_zfs));
 694                 free(cur_vers);
 695                 ret = zfs_err_to_be_err(g_zfs);
 696                 goto cleanup;
 697         }
 698         if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
 699                 if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
 700                     BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
 701                         be_print_err(gettext("be_get_grub_vers: failed to "
 702                             "mount BE (%s)\n"), bt->obe_name);
 703                         free(*cur_vers);
 704                         *cur_vers = NULL;
 705                         ZFS_CLOSE(zhp);
 706                         goto cleanup;
 707                 }
 708                 be_mounted = B_TRUE;
 709         }
 710         ZFS_CLOSE(zhp);
 711 
 712         /*
 713          * Now get the grub version for the BE being activated.
 714          */
 715         (void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
 716             BE_CAP_FILE);
 717         ret = get_ver_from_capfile(cap_file, new_vers);
 718         if (ret != BE_SUCCESS) {
 719                 free(*cur_vers);
 720                 *cur_vers = NULL;
 721         }
 722         if (be_mounted)
 723                 (void) _be_unmount(bt->obe_name, 0);
 724 
 725 cleanup:
 726         if (pool_mounted) {
 727                 int iret = BE_SUCCESS;
 728                 iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
 729                 if (ret == BE_SUCCESS)
 730                         ret = iret;
 731                 free(orig_mntpnt);
 732                 free(ptmp_mntpnt);
 733         }
 734         ZFS_CLOSE(pool_zhp);
 735 
 736         free(temp_mntpnt);
 737         return (ret);
 738 }
 739 
 740 /*
 741  * Function:    get_ver_from_capfile
 742  * Description: Parses the capability file passed in looking for the VERSION
 743  *              line. If found the version is returned in vers, if not then
 744  *              NULL is returned in vers.
 745  *
 746  * Parameters:
 747  *              file - the path to the capability file we want to parse.
 748  *              vers - the version string that will be passed back.
 749  * Return:
 750  *              BE_SUCCESS - Success
 751  *              be_errno_t - Failed to find version
 752  * Scope:
 753  *              Private
 754  */
 755 static int
 756 get_ver_from_capfile(char *file, char **vers)
 757 {
 758         FILE *fp = NULL;
 759         char line[BUFSIZ];
 760         char *last = NULL;
 761         int err = BE_SUCCESS;
 762         errno = 0;
 763 
 764         if (!be_has_grub()) {
 765                 be_print_err(gettext("get_ver_from_capfile: Not supported "
 766                     "on this architecture\n"));
 767                 return (BE_ERR_NOTSUP);
 768         }
 769 
 770         /*
 771          * Set version string to NULL; the only case this shouldn't be set
 772          * to be NULL is when we've actually found a version in the capability
 773          * file, which is set below.
 774          */
 775         *vers = NULL;
 776 
 777         /*
 778          * If the capability file doesn't exist, we're returning success
 779          * because on older releases, the capability file did not exist
 780          * so this is a valid scenario.
 781          */
 782         if (access(file, F_OK) == 0) {
 783                 if ((fp = fopen(file, "r")) == NULL) {
 784                         err = errno;
 785                         be_print_err(gettext("get_ver_from_capfile: failed to "
 786                             "open file %s with error %s\n"), file,
 787                             strerror(err));
 788                         err = errno_to_be_err(err);
 789                         return (err);
 790                 }
 791 
 792                 while (fgets(line, BUFSIZ, fp)) {
 793                         char *tok = strtok_r(line, "=", &last);
 794 
 795                         if (tok == NULL || tok[0] == '#') {
 796                                 continue;
 797                         } else if (strcmp(tok, "VERSION") == 0) {
 798                                 *vers = strdup(last);
 799                                 break;
 800                         }
 801                 }
 802                 (void) fclose(fp);
 803         }
 804 
 805         return (BE_SUCCESS);
 806 }
 807 
 808 /*
 809  * To be able to boot EFI labeled disks, stage1 needs to be written
 810  * into the MBR. We do not do this if we're on disks with a traditional
 811  * fdisk partition table only, or if any foreign EFI partitions exist.
 812  * In the trivial case of a whole-disk vdev we always write stage1 into
 813  * the MBR.
 814  */
 815 static boolean_t
 816 be_do_install_mbr(char *diskname, nvlist_t *child)
 817 {
 818         struct uuid allowed_uuids[] = {
 819                 EFI_UNUSED,
 820                 EFI_RESV1,
 821                 EFI_BOOT,
 822                 EFI_ROOT,
 823                 EFI_SWAP,
 824                 EFI_USR,
 825                 EFI_BACKUP,
 826                 EFI_RESV2,
 827                 EFI_VAR,
 828                 EFI_HOME,
 829                 EFI_ALTSCTR,
 830                 EFI_RESERVED,
 831                 EFI_SYSTEM,
 832                 EFI_BIOS_BOOT,
 833                 EFI_SYMC_PUB,
 834                 EFI_SYMC_CDS
 835         };
 836 
 837         uint64_t whole;
 838         struct dk_gpt *gpt;
 839         struct uuid *u;
 840         int fd, npart, i, j;
 841 
 842         (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
 843             &whole);
 844 
 845         if (whole)
 846                 return (B_TRUE);
 847 
 848         if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
 849                 return (B_FALSE);
 850 
 851         if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
 852                 return (B_FALSE);
 853 
 854         for (i = 0; i != npart; i++) {
 855                 int match = 0;
 856 
 857                 u = &gpt->efi_parts[i].p_guid;
 858 
 859                 for (j = 0;
 860                     j != sizeof (allowed_uuids) / sizeof (struct uuid);
 861                     j++)
 862                         if (bcmp(u, &allowed_uuids[j],
 863                             sizeof (struct uuid)) == 0)
 864                                 match++;
 865 
 866                 if (match == 0)
 867                         return (B_FALSE);
 868         }
 869 
 870         return (B_TRUE);
 871 }
 872 
 873 static int
 874 be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
 875     char *stage2, uint16_t flags)
 876 {
 877         char install_cmd[MAXPATHLEN];
 878         char be_run_cmd_errbuf[BUFSIZ];
 879         char be_run_cmd_outbuf[BUFSIZ];
 880         char diskname[MAXPATHLEN];
 881         char *vname;
 882         char *path, *dsk_ptr;
 883         char *flag = "";
 884         int ret;
 885         vdev_stat_t *vs;
 886         uint_t vsc;
 887 
 888         if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
 889                 be_print_err(gettext("be_do_installboot: "
 890                     "failed to get device path\n"));
 891                 return (BE_ERR_NODEV);
 892         }
 893 
 894         if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS,
 895             (uint64_t **)&vs, &vsc) != 0) ||
 896             vs->vs_state < VDEV_STATE_DEGRADED) {
 897                 /*
 898                  * Don't try to run installgrub on a vdev that is not ONLINE
 899                  * or DEGRADED. Try to print a warning for each such vdev.
 900                  */
 901                 be_print_err(gettext("be_do_installboot: "
 902                     "vdev %s is %s, can't install boot loader\n"),
 903                     path, zpool_state_to_name(vs->vs_state, vs->vs_aux));
 904                 free(path);
 905                 return (BE_SUCCESS);
 906         }
 907 
 908         /*
 909          * Modify the vdev path to point to the raw disk.
 910          */
 911         path = strdup(path);
 912         if (path == NULL)
 913                 return (BE_ERR_NOMEM);
 914 
 915         dsk_ptr = strstr(path, "/dsk/");
 916         if (dsk_ptr != NULL) {
 917                 *dsk_ptr = '\0';
 918                 dsk_ptr++;
 919         } else {
 920                 dsk_ptr = "";
 921         }
 922 
 923         (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
 924         free(path);
 925 
 926         vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
 927         if (vname == NULL) {
 928                 be_print_err(gettext("be_do_installboot: "
 929                     "failed to get device name: %s\n"),
 930                     libzfs_error_description(g_zfs));
 931                 return (zfs_err_to_be_err(g_zfs));
 932         }
 933 
 934         if (be_is_isa("i386")) {
 935                 uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE;
 936                 uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR;
 937 
 938                 if (force == BE_INSTALLBOOT_FLAG_FORCE) {
 939                         if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
 940                             be_do_install_mbr(diskname, child))
 941                                 flag = "-F -m -f";
 942                         else
 943                                 flag = "-F";
 944                 } else {
 945                         if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
 946                             be_do_install_mbr(diskname, child))
 947                                 flag = "-m -f";
 948                 }
 949 
 950                 (void) snprintf(install_cmd, sizeof (install_cmd),
 951                     "%s %s %s %s %s", BE_INSTALL_GRUB, flag,
 952                     stage1, stage2, diskname);
 953         } else if (be_is_isa("sparc")) {
 954                 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
 955                     BE_INSTALLBOOT_FLAG_FORCE)
 956                         flag = "-f -F zfs";
 957                 else
 958                         flag = "-F zfs";
 959 
 960                 (void) snprintf(install_cmd, sizeof (install_cmd),
 961                     "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
 962         } else {
 963                 be_print_err(gettext("be_do_installboot: unsupported "
 964                     "architecture.\n"));
 965                 return (BE_ERR_BOOTFILE_INST);
 966         }
 967 
 968         *be_run_cmd_outbuf = '\0';
 969         *be_run_cmd_errbuf = '\0';
 970 
 971         ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
 972             be_run_cmd_outbuf, BUFSIZ);
 973 
 974         if (ret != BE_SUCCESS) {
 975                 be_print_err(gettext("be_do_installboot: install "
 976                     "failed for device %s.\n"), vname);
 977                 ret = BE_ERR_BOOTFILE_INST;
 978         }
 979 
 980         be_print_err(gettext("  Command: \"%s\"\n"), install_cmd);
 981         if (be_run_cmd_outbuf[0] != 0) {
 982                 be_print_err(gettext("  Output:\n"));
 983                 be_print_err("%s", be_run_cmd_outbuf);
 984         }
 985 
 986         if (be_run_cmd_errbuf[0] != 0) {
 987                 be_print_err(gettext("  Errors:\n"));
 988                 be_print_err("%s", be_run_cmd_errbuf);
 989         }
 990         free(vname);
 991 
 992         return (ret);
 993 }
 994 
 995 /*
 996  * Function:    be_do_copy_grub_cap
 997  * Description: This function will copy grub capability file to BE.
 998  *
 999  * Parameters:
1000  *              bt - The transaction data for the BE we're activating.
1001  * Return:
1002  *              BE_SUCCESS - Success
1003  *              be_errno_t - Failure
1004  *
1005  * Scope:
1006  *              Private
1007  */
1008 static int
1009 be_do_copy_grub_cap(be_transaction_data_t *bt)
1010 {
1011         zpool_handle_t  *zphp = NULL;
1012         zfs_handle_t    *zhp = NULL;
1013         char cap_file[MAXPATHLEN];
1014         char zpool_cap_file[MAXPATHLEN];
1015         char line[BUFSIZ];
1016         char *tmp_mntpnt = NULL;
1017         char *orig_mntpnt = NULL;
1018         char *pool_mntpnt = NULL;
1019         char *ptmp_mntpnt = NULL;
1020         FILE *cap_fp = NULL;
1021         FILE *zpool_cap_fp = NULL;
1022         int err = 0;
1023         int ret = BE_SUCCESS;
1024         boolean_t pool_mounted = B_FALSE;
1025         boolean_t be_mounted = B_FALSE;
1026 
1027         /*
1028          * Copy the grub capability file from the BE we're activating
1029          * into the root pool.
1030          */
1031         zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM);
1032         if (zhp == NULL) {
1033                 be_print_err(gettext("be_do_installboot: zfs_open "
1034                     "failed: %s\n"), libzfs_error_description(g_zfs));
1035                 zpool_close(zphp);
1036                 return (zfs_err_to_be_err(g_zfs));
1037         }
1038 
1039         /*
1040          * Check to see if the pool's dataset is mounted. If it isn't we'll
1041          * attempt to mount it.
1042          */
1043         if ((ret = be_mount_pool(zhp, &ptmp_mntpnt,
1044             &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
1045                 be_print_err(gettext("be_do_installboot: pool dataset "
1046                     "(%s) could not be mounted\n"), bt->obe_zpool);
1047                 ZFS_CLOSE(zhp);
1048                 zpool_close(zphp);
1049                 return (ret);
1050         }
1051 
1052         /*
1053          * Get the mountpoint for the root pool dataset.
1054          */
1055         if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1056                 be_print_err(gettext("be_do_installboot: pool "
1057                     "dataset (%s) is not mounted. Can't check the grub "
1058                     "version from the grub capability file.\n"), bt->obe_zpool);
1059                 ret = BE_ERR_NO_MENU;
1060                 goto done;
1061         }
1062 
1063         (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
1064             pool_mntpnt, BE_CAP_FILE);
1065 
1066         free(pool_mntpnt);
1067 
1068         if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1069             NULL) {
1070                 be_print_err(gettext("be_do_installboot: failed to "
1071                     "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1072                     libzfs_error_description(g_zfs));
1073                 ret = zfs_err_to_be_err(g_zfs);
1074                 goto done;
1075         }
1076 
1077         if (!zfs_is_mounted(zhp, &tmp_mntpnt)) {
1078                 if ((ret = _be_mount(bt->obe_name, &tmp_mntpnt,
1079                     BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1080                         be_print_err(gettext("be_do_installboot: failed to "
1081                             "mount BE (%s)\n"), bt->obe_name);
1082                         ZFS_CLOSE(zhp);
1083                         goto done;
1084                 }
1085                 be_mounted = B_TRUE;
1086         }
1087         ZFS_CLOSE(zhp);
1088 
1089         (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt,
1090             BE_CAP_FILE);
1091         free(tmp_mntpnt);
1092 
1093         if ((cap_fp = fopen(cap_file, "r")) == NULL) {
1094                 err = errno;
1095                 be_print_err(gettext("be_do_installboot: failed to open grub "
1096                     "capability file\n"));
1097                 ret = errno_to_be_err(err);
1098                 goto done;
1099         }
1100         if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
1101                 err = errno;
1102                 be_print_err(gettext("be_do_installboot: failed to open new "
1103                     "grub capability file\n"));
1104                 ret = errno_to_be_err(err);
1105                 (void) fclose(cap_fp);
1106                 goto done;
1107         }
1108 
1109         while (fgets(line, BUFSIZ, cap_fp)) {
1110                 (void) fputs(line, zpool_cap_fp);
1111         }
1112 
1113         (void) fclose(zpool_cap_fp);
1114         (void) fclose(cap_fp);
1115 
1116 done:
1117         if (be_mounted)
1118                 (void) _be_unmount(bt->obe_name, 0);
1119 
1120         if (pool_mounted) {
1121                 int iret = 0;
1122                 iret = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1123                 if (ret == BE_SUCCESS)
1124                         ret = iret;
1125                 free(orig_mntpnt);
1126                 free(ptmp_mntpnt);
1127         }
1128         return (ret);
1129 }
1130 
1131 /*
1132  * Function:    be_is_install_needed
1133  * Description: Check detached version files to detect if bootloader
1134  *              install/update is needed.
1135  *
1136  * Parameters:
1137  *              bt - The transaction data for the BE we're activating.
1138  *              update - set B_TRUE is update is needed.
1139  * Return:
1140  *              BE_SUCCESS - Success
1141  *              be_errno_t - Failure
1142  *
1143  * Scope:
1144  *              Private
1145  */
1146 static int
1147 be_is_install_needed(be_transaction_data_t *bt, boolean_t *update)
1148 {
1149         int     ret = BE_SUCCESS;
1150         char    *cur_vers = NULL, *new_vers = NULL;
1151 
1152         assert(bt != NULL);
1153         assert(update != NULL);
1154 
1155         if (!be_has_grub()) {
1156                 /*
1157                  * no detached versioning, let installboot to manage
1158                  * versioning.
1159                  */
1160                 *update = B_TRUE;
1161                 return (ret);
1162         }
1163 
1164         *update = B_FALSE;      /* set default */
1165 
1166         /*
1167          * We need to check to see if the version number from
1168          * the BE being activated is greater than the current
1169          * one.
1170          */
1171         ret = be_get_grub_vers(bt, &cur_vers, &new_vers);
1172         if (ret != BE_SUCCESS) {
1173                 be_print_err(gettext("be_activate: failed to get grub "
1174                     "versions from capability files.\n"));
1175                 return (ret);
1176         }
1177         /* update if we have both versions and can compare */
1178         if (cur_vers != NULL) {
1179                 if (new_vers != NULL) {
1180                         if (atof(cur_vers) < atof(new_vers))
1181                                 *update = B_TRUE;
1182                         free(new_vers);
1183                 }
1184                 free(cur_vers);
1185         } else if (new_vers != NULL) {
1186                 /* we only got new version - update */
1187                 *update = B_TRUE;
1188                 free(new_vers);
1189         }
1190         return (ret);
1191 }
1192 
1193 /*
1194  * Function:    be_do_installboot
1195  * Description: This function runs installgrub/installboot using the boot
1196  *              loader files from the BE we're activating and installing
1197  *              them on the pool the BE lives in.
1198  *
1199  * Parameters:
1200  *              bt - The transaction data for the BE we're activating.
1201  *              flags - flags for bootloader install
1202  * Return:
1203  *              BE_SUCCESS - Success
1204  *              be_errno_t - Failure
1205  *
1206  * Scope:
1207  *              Private
1208  */
1209 static int
1210 be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
1211 {
1212         zpool_handle_t  *zphp = NULL;
1213         zfs_handle_t    *zhp = NULL;
1214         nvlist_t **child, *nv, *config;
1215         uint_t c, children = 0;
1216         char *tmp_mntpt = NULL;
1217         char stage1[MAXPATHLEN];
1218         char stage2[MAXPATHLEN];
1219         char *vname;
1220         int ret = BE_SUCCESS;
1221         boolean_t be_mounted = B_FALSE;
1222         boolean_t update = B_FALSE;
1223 
1224         /*
1225          * check versions. This call is to support detached
1226          * version implementation like grub. Embedded versioning is
1227          * checked by actual installer.
1228          */
1229         if ((flags & BE_INSTALLBOOT_FLAG_FORCE) != BE_INSTALLBOOT_FLAG_FORCE) {
1230                 ret = be_is_install_needed(bt, &update);
1231                 if (ret != BE_SUCCESS || update == B_FALSE)
1232                         return (ret);
1233         }
1234 
1235         if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1236             NULL) {
1237                 be_print_err(gettext("be_do_installboot: failed to "
1238                     "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1239                     libzfs_error_description(g_zfs));
1240                 ret = zfs_err_to_be_err(g_zfs);
1241                 return (ret);
1242         }
1243         if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
1244                 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
1245                     BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1246                         be_print_err(gettext("be_do_installboot: failed to "
1247                             "mount BE (%s)\n"), bt->obe_name);
1248                         ZFS_CLOSE(zhp);
1249                         return (ret);
1250                 }
1251                 be_mounted = B_TRUE;
1252         }
1253         ZFS_CLOSE(zhp);
1254 
1255         if (be_has_grub()) {
1256                 (void) snprintf(stage1, sizeof (stage1), "%s%s",
1257                     tmp_mntpt, BE_GRUB_STAGE_1);
1258                 (void) snprintf(stage2, sizeof (stage2), "%s%s",
1259                     tmp_mntpt, BE_GRUB_STAGE_2);
1260         } else {
1261                 char *platform = be_get_platform();
1262 
1263                 if (platform == NULL) {
1264                         be_print_err(gettext("be_do_installboot: failed to "
1265                             "detect system platform name\n"));
1266                         if (be_mounted)
1267                                 (void) _be_unmount(bt->obe_name, 0);
1268                         free(tmp_mntpt);
1269                         return (BE_ERR_BOOTFILE_INST);
1270                 }
1271 
1272                 stage1[0] = '\0';       /* sparc has no stage1 */
1273                 (void) snprintf(stage2, sizeof (stage2),
1274                     "%s/usr/platform/%s%s", tmp_mntpt,
1275                     platform, BE_SPARC_BOOTBLK);
1276         }
1277 
1278         if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
1279                 be_print_err(gettext("be_do_installboot: failed to open "
1280                     "pool (%s): %s\n"), bt->obe_zpool,
1281                     libzfs_error_description(g_zfs));
1282                 ret = zfs_err_to_be_err(g_zfs);
1283                 if (be_mounted)
1284                         (void) _be_unmount(bt->obe_name, 0);
1285                 free(tmp_mntpt);
1286                 return (ret);
1287         }
1288 
1289         if ((config = zpool_get_config(zphp, NULL)) == NULL) {
1290                 be_print_err(gettext("be_do_installboot: failed to get zpool "
1291                     "configuration information. %s\n"),
1292                     libzfs_error_description(g_zfs));
1293                 ret = zfs_err_to_be_err(g_zfs);
1294                 goto done;
1295         }
1296 
1297         /*
1298          * Get the vdev tree
1299          */
1300         if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
1301                 be_print_err(gettext("be_do_installboot: failed to get vdev "
1302                     "tree: %s\n"), libzfs_error_description(g_zfs));
1303                 ret = zfs_err_to_be_err(g_zfs);
1304                 goto done;
1305         }
1306 
1307         if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1308             &children) != 0) {
1309                 be_print_err(gettext("be_do_installboot: failed to traverse "
1310                     "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
1311                 ret = zfs_err_to_be_err(g_zfs);
1312                 goto done;
1313         }
1314         for (c = 0; c < children; c++) {
1315                 uint_t i, nchildren = 0;
1316                 nvlist_t **nvchild;
1317                 vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE);
1318                 if (vname == NULL) {
1319                         be_print_err(gettext(
1320                             "be_do_installboot: "
1321                             "failed to get device name: %s\n"),
1322                             libzfs_error_description(g_zfs));
1323                         ret = zfs_err_to_be_err(g_zfs);
1324                         goto done;
1325                 }
1326                 if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') {
1327                         free(vname);
1328 
1329                         if (nvlist_lookup_nvlist_array(child[c],
1330                             ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) {
1331                                 be_print_err(gettext("be_do_installboot: "
1332                                     "failed to traverse the vdev tree: %s\n"),
1333                                     libzfs_error_description(g_zfs));
1334                                 ret = zfs_err_to_be_err(g_zfs);
1335                                 goto done;
1336                         }
1337 
1338                         for (i = 0; i < nchildren; i++) {
1339                                 ret = be_do_installboot_helper(zphp, nvchild[i],
1340                                     stage1, stage2, flags);
1341                                 if (ret != BE_SUCCESS)
1342                                         goto done;
1343                         }
1344                 } else {
1345                         free(vname);
1346 
1347                         ret = be_do_installboot_helper(zphp, child[c], stage1,
1348                             stage2, flags);
1349                         if (ret != BE_SUCCESS)
1350                                 goto done;
1351                 }
1352         }
1353 
1354         if (be_has_grub()) {
1355                 ret = be_do_copy_grub_cap(bt);
1356         }
1357 
1358 done:
1359         ZFS_CLOSE(zhp);
1360         if (be_mounted)
1361                 (void) _be_unmount(bt->obe_name, 0);
1362         zpool_close(zphp);
1363         free(tmp_mntpt);
1364         return (ret);
1365 }
1366 
1367 /*
1368  * Function:    be_promote_zone_ds
1369  * Description: This function finds the zones for the BE being activated
1370  *              and the active zonepath dataset for each zone. Then each
1371  *              active zonepath dataset is promoted.
1372  *
1373  * Parameters:
1374  *              be_name - the name of the global zone BE that we need to
1375  *                       find the zones for.
1376  *              be_root_ds - the root dataset for be_name.
1377  * Return:
1378  *              BE_SUCCESS - Success
1379  *              be_errno_t - Failure
1380  *
1381  * Scope:
1382  *              Private
1383  */
1384 static int
1385 be_promote_zone_ds(char *be_name, char *be_root_ds)
1386 {
1387         char            *zone_ds = NULL;
1388         char            *temp_mntpt = NULL;
1389         char            origin[MAXPATHLEN];
1390         char            zoneroot_ds[MAXPATHLEN];
1391         zfs_handle_t    *zhp = NULL;
1392         zfs_handle_t    *z_zhp = NULL;
1393         zoneList_t      zone_list = NULL;
1394         boolean_t       be_mounted = B_FALSE;
1395         int             zone_index = 0;
1396         int             err = BE_SUCCESS;
1397 
1398         if ((zhp = zfs_open(g_zfs, be_root_ds,
1399             ZFS_TYPE_FILESYSTEM)) == NULL) {
1400                 be_print_err(gettext("be_promote_zone_ds: Failed to open "
1401                     "dataset (%s): %s\n"), be_root_ds,
1402                     libzfs_error_description(g_zfs));
1403                 err = zfs_err_to_be_err(g_zfs);
1404                 return (err);
1405         }
1406 
1407         if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1408                 if ((err = _be_mount(be_name, &temp_mntpt,
1409                     BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1410                         be_print_err(gettext("be_promote_zone_ds: failed to "
1411                             "mount the BE for zones procesing.\n"));
1412                         ZFS_CLOSE(zhp);
1413                         return (err);
1414                 }
1415                 be_mounted = B_TRUE;
1416         }
1417 
1418         /*
1419          * Set the zone root to the temp mount point for the BE we just mounted.
1420          */
1421         z_set_zone_root(temp_mntpt);
1422 
1423         /*
1424          * If no zones are found, unmount the BE and move on.
1425          */
1426         if ((zone_list = z_get_nonglobal_branded_zone_list()) == NULL) {
1427                 if (be_mounted)
1428                         (void) _be_unmount(be_name, 0);
1429                 ZFS_CLOSE(zhp);
1430                 free(temp_mntpt);
1431                 return (BE_SUCCESS);
1432         }
1433         for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1434             != NULL; zone_index++) {
1435                 char *zone_path = NULL;
1436                 boolean_t auto_create;
1437 
1438                 if (z_zlist_is_zone_auto_create_be(zone_list, zone_index,
1439                     &auto_create) != 0) {
1440                         be_print_err(gettext("be_promote_zone_ds: "
1441                             "Failed to get auto-create-be brand property\n"));
1442                         err = -1; // XXX
1443                         goto done;
1444                 }
1445 
1446                 if (!auto_create)
1447                         continue;
1448 
1449                 /* Skip zones that aren't at least installed */
1450                 if (z_zlist_get_current_state(zone_list, zone_index) <
1451                     ZONE_STATE_INSTALLED)
1452                         continue;
1453 
1454                 if (((zone_path =
1455                     z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1456                     ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1457                     !be_zone_supported(zone_ds))
1458                         continue;
1459 
1460                 if (be_find_active_zone_root(zhp, zone_ds,
1461                     zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1462                         be_print_err(gettext("be_promote_zone_ds: "
1463                             "Zone does not have an active root "
1464                             "dataset, skipping this zone.\n"));
1465                         continue;
1466                 }
1467 
1468                 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1469                     ZFS_TYPE_FILESYSTEM)) == NULL) {
1470                         be_print_err(gettext("be_promote_zone_ds: "
1471                             "Failed to open dataset "
1472                             "(%s): %s\n"), zoneroot_ds,
1473                             libzfs_error_description(g_zfs));
1474                         err = zfs_err_to_be_err(g_zfs);
1475                         goto done;
1476                 }
1477 
1478                 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1479                     sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1480                         ZFS_CLOSE(z_zhp);
1481                         continue;
1482                 }
1483 
1484                 /*
1485                  * We don't need to close the zfs handle at this
1486                  * point because the callback funtion
1487                  * be_promote_ds_callback() will close it for us.
1488                  */
1489                 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1490                         be_print_err(gettext("be_promote_zone_ds: "
1491                             "failed to activate the "
1492                             "datasets for %s: %s\n"),
1493                             zoneroot_ds,
1494                             libzfs_error_description(g_zfs));
1495                         err = BE_ERR_PROMOTE;
1496                         goto done;
1497                 }
1498         }
1499 done:
1500         if (be_mounted)
1501                 (void) _be_unmount(be_name, 0);
1502         ZFS_CLOSE(zhp);
1503         free(temp_mntpt);
1504         z_free_zone_list(zone_list);
1505         return (err);
1506 }
1507 
1508 /*
1509  * Function:    be_promote_ds_callback
1510  * Description: This function is used to promote the datasets for the BE
1511  *              being activated as well as the datasets for the zones BE
1512  *              being activated.
1513  *
1514  * Parameters:
1515  *              zhp - the zfs handle for zone BE being activated.
1516  *              data - not used.
1517  * Return:
1518  *              0 - Success
1519  *              be_errno_t - Failure
1520  *
1521  * Scope:
1522  *              Private
1523  */
1524 static int
1525 /* LINTED */
1526 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1527 {
1528         char    origin[MAXPATHLEN];
1529         char    *sub_dataset = NULL;
1530         int     ret = 0;
1531 
1532         if (zhp != NULL) {
1533                 sub_dataset = strdup(zfs_get_name(zhp));
1534                 if (sub_dataset == NULL) {
1535                         ret = BE_ERR_NOMEM;
1536                         goto done;
1537                 }
1538         } else {
1539                 be_print_err(gettext("be_promote_ds_callback: "
1540                     "Invalid zfs handle passed into function\n"));
1541                 ret = BE_ERR_INVAL;
1542                 goto done;
1543         }
1544 
1545         /*
1546          * This loop makes sure that we promote the dataset to the
1547          * top of the tree so that it is no longer a decendent of any
1548          * dataset. The ZFS close and then open is used to make sure that
1549          * the promotion is updated before we move on.
1550          */
1551         while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1552             sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1553                 if (zfs_promote(zhp) != 0) {
1554                         if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1555                                 be_print_err(gettext("be_promote_ds_callback: "
1556                                     "promote of %s failed: %s\n"),
1557                                     zfs_get_name(zhp),
1558                                     libzfs_error_description(g_zfs));
1559                                 ret = zfs_err_to_be_err(g_zfs);
1560                                 goto done;
1561                         } else {
1562                                 /*
1563                                  * If the call to zfs_promote returns the
1564                                  * error EZFS_EXISTS we've hit a snapshot name
1565                                  * collision. This means we're probably
1566                                  * attemping to promote a zone dataset above a
1567                                  * parent dataset that belongs to another zone
1568                                  * which this zone was cloned from.
1569                                  *
1570                                  * TODO: If this is a zone dataset at some
1571                                  * point we should skip this if the zone
1572                                  * paths for the dataset and the snapshot
1573                                  * don't match.
1574                                  */
1575                                 be_print_err(gettext("be_promote_ds_callback: "
1576                                     "promote of %s failed due to snapshot "
1577                                     "name collision: %s\n"), zfs_get_name(zhp),
1578                                     libzfs_error_description(g_zfs));
1579                                 ret = zfs_err_to_be_err(g_zfs);
1580                                 goto done;
1581                         }
1582                 }
1583                 ZFS_CLOSE(zhp);
1584                 if ((zhp = zfs_open(g_zfs, sub_dataset,
1585                     ZFS_TYPE_FILESYSTEM)) == NULL) {
1586                         be_print_err(gettext("be_promote_ds_callback: "
1587                             "Failed to open dataset (%s): %s\n"), sub_dataset,
1588                             libzfs_error_description(g_zfs));
1589                         ret = zfs_err_to_be_err(g_zfs);
1590                         goto done;
1591                 }
1592         }
1593 
1594         /* Iterate down this dataset's children and promote them */
1595         ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1596 
1597 done:
1598         free(sub_dataset);
1599         ZFS_CLOSE(zhp);
1600         return (ret);
1601 }