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