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