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