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