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