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