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