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