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 free(path); 904 return (BE_SUCCESS); 905 } 906 907 /* 908 * Modify the vdev path to point to the raw disk. 909 */ 910 path = strdup(path); 911 if (path == NULL) 912 return (BE_ERR_NOMEM); 913 914 dsk_ptr = strstr(path, "/dsk/"); 915 if (dsk_ptr != NULL) { 916 *dsk_ptr = '\0'; 917 dsk_ptr++; 918 } else { 919 dsk_ptr = ""; 920 } 921 922 (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr); 923 free(path); 924 925 vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE); 926 if (vname == NULL) { 927 be_print_err(gettext("be_do_installboot: " 928 "failed to get device name: %s\n"), 929 libzfs_error_description(g_zfs)); 930 return (zfs_err_to_be_err(g_zfs)); 931 } 932 933 if (be_is_isa("i386")) { 934 uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE; 935 uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR; 936 937 if (force == BE_INSTALLBOOT_FLAG_FORCE) { 938 if (mbr == BE_INSTALLBOOT_FLAG_MBR || 939 be_do_install_mbr(diskname, child)) 940 flag = "-F -m -f"; 941 else 942 flag = "-F"; 943 } else { 944 if (mbr == BE_INSTALLBOOT_FLAG_MBR || 945 be_do_install_mbr(diskname, child)) 946 flag = "-m -f"; 947 } 948 949 (void) snprintf(install_cmd, sizeof (install_cmd), 950 "%s %s %s %s %s", BE_INSTALL_GRUB, flag, 951 stage1, stage2, diskname); 952 } else if (be_is_isa("sparc")) { 953 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) == 954 BE_INSTALLBOOT_FLAG_FORCE) 955 flag = "-f -F zfs"; 956 else 957 flag = "-F zfs"; 958 959 (void) snprintf(install_cmd, sizeof (install_cmd), 960 "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname); 961 } else { 962 be_print_err(gettext("be_do_installboot: unsupported " 963 "architecture.\n")); 964 return (BE_ERR_BOOTFILE_INST); 965 } 966 967 *be_run_cmd_outbuf = '\0'; 968 *be_run_cmd_errbuf = '\0'; 969 970 ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ, 971 be_run_cmd_outbuf, BUFSIZ); 972 973 if (ret != BE_SUCCESS) { 974 be_print_err(gettext("be_do_installboot: install " 975 "failed for device %s.\n"), vname); 976 ret = BE_ERR_BOOTFILE_INST; 977 } 978 979 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd); 980 if (be_run_cmd_outbuf[0] != 0) { 981 be_print_err(gettext(" Output:\n")); 982 be_print_err("%s", be_run_cmd_outbuf); 983 } 984 985 if (be_run_cmd_errbuf[0] != 0) { 986 be_print_err(gettext(" Errors:\n")); 987 be_print_err("%s", be_run_cmd_errbuf); 988 } 989 free(vname); 990 991 return (ret); 992 } 993 994 /* 995 * Function: be_do_copy_grub_cap 996 * Description: This function will copy grub capability file to BE. 997 * 998 * Parameters: 999 * bt - The transaction data for the BE we're activating. 1000 * Return: 1001 * BE_SUCCESS - Success 1002 * be_errno_t - Failure 1003 * 1004 * Scope: 1005 * Private 1006 */ 1007 static int 1008 be_do_copy_grub_cap(be_transaction_data_t *bt) 1009 { 1010 zpool_handle_t *zphp = NULL; 1011 zfs_handle_t *zhp = NULL; 1012 char cap_file[MAXPATHLEN]; 1013 char zpool_cap_file[MAXPATHLEN]; 1014 char line[BUFSIZ]; 1015 char *tmp_mntpnt = NULL; 1016 char *orig_mntpnt = NULL; 1017 char *pool_mntpnt = NULL; 1018 char *ptmp_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 * Copy the grub capability file from the BE we're activating 1028 * into the root pool. 1029 */ 1030 zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM); 1031 if (zhp == NULL) { 1032 be_print_err(gettext("be_do_installboot: zfs_open " 1033 "failed: %s\n"), libzfs_error_description(g_zfs)); 1034 zpool_close(zphp); 1035 return (zfs_err_to_be_err(g_zfs)); 1036 } 1037 1038 /* 1039 * Check to see if the pool's dataset is mounted. If it isn't we'll 1040 * attempt to mount it. 1041 */ 1042 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, 1043 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) { 1044 be_print_err(gettext("be_do_installboot: pool dataset " 1045 "(%s) could not be mounted\n"), bt->obe_zpool); 1046 ZFS_CLOSE(zhp); 1047 zpool_close(zphp); 1048 return (ret); 1049 } 1050 1051 /* 1052 * Get the mountpoint for the root pool dataset. 1053 */ 1054 if (!zfs_is_mounted(zhp, &pool_mntpnt)) { 1055 be_print_err(gettext("be_do_installboot: pool " 1056 "dataset (%s) is not mounted. Can't check the grub " 1057 "version from the grub capability file.\n"), bt->obe_zpool); 1058 ret = BE_ERR_NO_MENU; 1059 goto done; 1060 } 1061 1062 (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s", 1063 pool_mntpnt, BE_CAP_FILE); 1064 1065 free(pool_mntpnt); 1066 1067 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) == 1068 NULL) { 1069 be_print_err(gettext("be_do_installboot: failed to " 1070 "open BE root dataset (%s): %s\n"), bt->obe_root_ds, 1071 libzfs_error_description(g_zfs)); 1072 ret = zfs_err_to_be_err(g_zfs); 1073 goto done; 1074 } 1075 1076 if (!zfs_is_mounted(zhp, &tmp_mntpnt)) { 1077 if ((ret = _be_mount(bt->obe_name, &tmp_mntpnt, 1078 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) { 1079 be_print_err(gettext("be_do_installboot: failed to " 1080 "mount BE (%s)\n"), bt->obe_name); 1081 ZFS_CLOSE(zhp); 1082 goto done; 1083 } 1084 be_mounted = B_TRUE; 1085 } 1086 ZFS_CLOSE(zhp); 1087 1088 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt, 1089 BE_CAP_FILE); 1090 free(tmp_mntpnt); 1091 1092 if ((cap_fp = fopen(cap_file, "r")) == NULL) { 1093 err = errno; 1094 be_print_err(gettext("be_do_installboot: failed to open grub " 1095 "capability file\n")); 1096 ret = errno_to_be_err(err); 1097 goto done; 1098 } 1099 if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) { 1100 err = errno; 1101 be_print_err(gettext("be_do_installboot: failed to open new " 1102 "grub capability file\n")); 1103 ret = errno_to_be_err(err); 1104 (void) fclose(cap_fp); 1105 goto done; 1106 } 1107 1108 while (fgets(line, BUFSIZ, cap_fp)) { 1109 (void) fputs(line, zpool_cap_fp); 1110 } 1111 1112 (void) fclose(zpool_cap_fp); 1113 (void) fclose(cap_fp); 1114 1115 done: 1116 if (be_mounted) 1117 (void) _be_unmount(bt->obe_name, 0); 1118 1119 if (pool_mounted) { 1120 int iret = 0; 1121 iret = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt); 1122 if (ret == BE_SUCCESS) 1123 ret = iret; 1124 free(orig_mntpnt); 1125 free(ptmp_mntpnt); 1126 } 1127 return (ret); 1128 } 1129 1130 /* 1131 * Function: be_is_install_needed 1132 * Description: Check detached version files to detect if bootloader 1133 * install/update is needed. 1134 * 1135 * Parameters: 1136 * bt - The transaction data for the BE we're activating. 1137 * update - set B_TRUE is update is needed. 1138 * Return: 1139 * BE_SUCCESS - Success 1140 * be_errno_t - Failure 1141 * 1142 * Scope: 1143 * Private 1144 */ 1145 static int 1146 be_is_install_needed(be_transaction_data_t *bt, boolean_t *update) 1147 { 1148 int ret = BE_SUCCESS; 1149 char *cur_vers = NULL, *new_vers = NULL; 1150 1151 assert(bt != NULL); 1152 assert(update != NULL); 1153 1154 if (!be_has_grub()) { 1155 /* 1156 * no detached versioning, let installboot to manage 1157 * versioning. 1158 */ 1159 *update = B_TRUE; 1160 return (ret); 1161 } 1162 1163 *update = B_FALSE; /* set default */ 1164 1165 /* 1166 * We need to check to see if the version number from 1167 * the BE being activated is greater than the current 1168 * one. 1169 */ 1170 ret = be_get_grub_vers(bt, &cur_vers, &new_vers); 1171 if (ret != BE_SUCCESS) { 1172 be_print_err(gettext("be_activate: failed to get grub " 1173 "versions from capability files.\n")); 1174 return (ret); 1175 } 1176 /* update if we have both versions and can compare */ 1177 if (cur_vers != NULL) { 1178 if (new_vers != NULL) { 1179 if (atof(cur_vers) < atof(new_vers)) 1180 *update = B_TRUE; 1181 free(new_vers); 1182 } 1183 free(cur_vers); 1184 } else if (new_vers != NULL) { 1185 /* we only got new version - update */ 1186 *update = B_TRUE; 1187 free(new_vers); 1188 } 1189 return (ret); 1190 } 1191 1192 /* 1193 * Function: be_do_installboot 1194 * Description: This function runs installgrub/installboot using the boot 1195 * loader files from the BE we're activating and installing 1196 * them on the pool the BE lives in. 1197 * 1198 * Parameters: 1199 * bt - The transaction data for the BE we're activating. 1200 * flags - flags for bootloader install 1201 * Return: 1202 * BE_SUCCESS - Success 1203 * be_errno_t - Failure 1204 * 1205 * Scope: 1206 * Private 1207 */ 1208 static int 1209 be_do_installboot(be_transaction_data_t *bt, uint16_t flags) 1210 { 1211 zpool_handle_t *zphp = NULL; 1212 zfs_handle_t *zhp = NULL; 1213 nvlist_t **child, *nv, *config; 1214 uint_t c, children = 0; 1215 char *tmp_mntpt = NULL; 1216 char stage1[MAXPATHLEN]; 1217 char stage2[MAXPATHLEN]; 1218 char *vname; 1219 int ret = BE_SUCCESS; 1220 boolean_t be_mounted = B_FALSE; 1221 boolean_t update = B_FALSE; 1222 1223 /* 1224 * check versions. This call is to support detached 1225 * version implementation like grub. Embedded versioning is 1226 * checked by actual installer. 1227 */ 1228 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) != BE_INSTALLBOOT_FLAG_FORCE) { 1229 ret = be_is_install_needed(bt, &update); 1230 if (ret != BE_SUCCESS || update == B_FALSE) 1231 return (ret); 1232 } 1233 1234 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) == 1235 NULL) { 1236 be_print_err(gettext("be_do_installboot: failed to " 1237 "open BE root dataset (%s): %s\n"), bt->obe_root_ds, 1238 libzfs_error_description(g_zfs)); 1239 ret = zfs_err_to_be_err(g_zfs); 1240 return (ret); 1241 } 1242 if (!zfs_is_mounted(zhp, &tmp_mntpt)) { 1243 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt, 1244 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) { 1245 be_print_err(gettext("be_do_installboot: failed to " 1246 "mount BE (%s)\n"), bt->obe_name); 1247 ZFS_CLOSE(zhp); 1248 return (ret); 1249 } 1250 be_mounted = B_TRUE; 1251 } 1252 ZFS_CLOSE(zhp); 1253 1254 if (be_has_grub()) { 1255 (void) snprintf(stage1, sizeof (stage1), "%s%s", 1256 tmp_mntpt, BE_GRUB_STAGE_1); 1257 (void) snprintf(stage2, sizeof (stage2), "%s%s", 1258 tmp_mntpt, BE_GRUB_STAGE_2); 1259 } else { 1260 char *platform = be_get_platform(); 1261 1262 if (platform == NULL) { 1263 be_print_err(gettext("be_do_installboot: failed to " 1264 "detect system platform name\n")); 1265 if (be_mounted) 1266 (void) _be_unmount(bt->obe_name, 0); 1267 free(tmp_mntpt); 1268 return (BE_ERR_BOOTFILE_INST); 1269 } 1270 1271 stage1[0] = '\0'; /* sparc has no stage1 */ 1272 (void) snprintf(stage2, sizeof (stage2), 1273 "%s/usr/platform/%s%s", tmp_mntpt, 1274 platform, BE_SPARC_BOOTBLK); 1275 } 1276 1277 if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) { 1278 be_print_err(gettext("be_do_installboot: failed to open " 1279 "pool (%s): %s\n"), bt->obe_zpool, 1280 libzfs_error_description(g_zfs)); 1281 ret = zfs_err_to_be_err(g_zfs); 1282 if (be_mounted) 1283 (void) _be_unmount(bt->obe_name, 0); 1284 free(tmp_mntpt); 1285 return (ret); 1286 } 1287 1288 if ((config = zpool_get_config(zphp, NULL)) == NULL) { 1289 be_print_err(gettext("be_do_installboot: failed to get zpool " 1290 "configuration information. %s\n"), 1291 libzfs_error_description(g_zfs)); 1292 ret = zfs_err_to_be_err(g_zfs); 1293 goto done; 1294 } 1295 1296 /* 1297 * Get the vdev tree 1298 */ 1299 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) { 1300 be_print_err(gettext("be_do_installboot: failed to get vdev " 1301 "tree: %s\n"), libzfs_error_description(g_zfs)); 1302 ret = zfs_err_to_be_err(g_zfs); 1303 goto done; 1304 } 1305 1306 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1307 &children) != 0) { 1308 be_print_err(gettext("be_do_installboot: failed to traverse " 1309 "the vdev tree: %s\n"), libzfs_error_description(g_zfs)); 1310 ret = zfs_err_to_be_err(g_zfs); 1311 goto done; 1312 } 1313 for (c = 0; c < children; c++) { 1314 uint_t i, nchildren = 0; 1315 nvlist_t **nvchild; 1316 vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE); 1317 if (vname == NULL) { 1318 be_print_err(gettext( 1319 "be_do_installboot: " 1320 "failed to get device name: %s\n"), 1321 libzfs_error_description(g_zfs)); 1322 ret = zfs_err_to_be_err(g_zfs); 1323 goto done; 1324 } 1325 if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') { 1326 free(vname); 1327 1328 if (nvlist_lookup_nvlist_array(child[c], 1329 ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) { 1330 be_print_err(gettext("be_do_installboot: " 1331 "failed to traverse the vdev tree: %s\n"), 1332 libzfs_error_description(g_zfs)); 1333 ret = zfs_err_to_be_err(g_zfs); 1334 goto done; 1335 } 1336 1337 for (i = 0; i < nchildren; i++) { 1338 ret = be_do_installboot_helper(zphp, nvchild[i], 1339 stage1, stage2, flags); 1340 if (ret != BE_SUCCESS) 1341 goto done; 1342 } 1343 } else { 1344 free(vname); 1345 1346 ret = be_do_installboot_helper(zphp, child[c], stage1, 1347 stage2, flags); 1348 if (ret != BE_SUCCESS) 1349 goto done; 1350 } 1351 } 1352 1353 if (be_has_grub()) { 1354 ret = be_do_copy_grub_cap(bt); 1355 } 1356 1357 done: 1358 ZFS_CLOSE(zhp); 1359 if (be_mounted) 1360 (void) _be_unmount(bt->obe_name, 0); 1361 zpool_close(zphp); 1362 free(tmp_mntpt); 1363 return (ret); 1364 } 1365 1366 /* 1367 * Function: be_promote_zone_ds 1368 * Description: This function finds the zones for the BE being activated 1369 * and the active zonepath dataset for each zone. Then each 1370 * active zonepath dataset is promoted. 1371 * 1372 * Parameters: 1373 * be_name - the name of the global zone BE that we need to 1374 * find the zones for. 1375 * be_root_ds - the root dataset for be_name. 1376 * Return: 1377 * BE_SUCCESS - Success 1378 * be_errno_t - Failure 1379 * 1380 * Scope: 1381 * Private 1382 */ 1383 static int 1384 be_promote_zone_ds(char *be_name, char *be_root_ds) 1385 { 1386 char *zone_ds = NULL; 1387 char *temp_mntpt = NULL; 1388 char origin[MAXPATHLEN]; 1389 char zoneroot_ds[MAXPATHLEN]; 1390 zfs_handle_t *zhp = NULL; 1391 zfs_handle_t *z_zhp = NULL; 1392 zoneList_t zone_list = NULL; 1393 zoneBrandList_t *brands = NULL; 1394 boolean_t be_mounted = B_FALSE; 1395 int zone_index = 0; 1396 int err = BE_SUCCESS; 1397 1398 /* 1399 * Get the supported zone brands so we can pass that 1400 * to z_get_nonglobal_zone_list_by_brand. Currently 1401 * only the ipkg and labeled brand zones are supported 1402 * 1403 */ 1404 if ((brands = be_get_supported_brandlist()) == NULL) { 1405 be_print_err(gettext("be_promote_zone_ds: no supported " 1406 "brands\n")); 1407 return (BE_SUCCESS); 1408 } 1409 1410 if ((zhp = zfs_open(g_zfs, be_root_ds, 1411 ZFS_TYPE_FILESYSTEM)) == NULL) { 1412 be_print_err(gettext("be_promote_zone_ds: Failed to open " 1413 "dataset (%s): %s\n"), be_root_ds, 1414 libzfs_error_description(g_zfs)); 1415 err = zfs_err_to_be_err(g_zfs); 1416 z_free_brand_list(brands); 1417 return (err); 1418 } 1419 1420 if (!zfs_is_mounted(zhp, &temp_mntpt)) { 1421 if ((err = _be_mount(be_name, &temp_mntpt, 1422 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) { 1423 be_print_err(gettext("be_promote_zone_ds: failed to " 1424 "mount the BE for zones procesing.\n")); 1425 ZFS_CLOSE(zhp); 1426 z_free_brand_list(brands); 1427 return (err); 1428 } 1429 be_mounted = B_TRUE; 1430 } 1431 1432 /* 1433 * Set the zone root to the temp mount point for the BE we just mounted. 1434 */ 1435 z_set_zone_root(temp_mntpt); 1436 1437 /* 1438 * Get all the zones based on the brands we're looking for. If no zones 1439 * are found that we're interested in unmount the BE and move on. 1440 */ 1441 if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) { 1442 if (be_mounted) 1443 (void) _be_unmount(be_name, 0); 1444 ZFS_CLOSE(zhp); 1445 z_free_brand_list(brands); 1446 free(temp_mntpt); 1447 return (BE_SUCCESS); 1448 } 1449 for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index) 1450 != NULL; zone_index++) { 1451 char *zone_path = NULL; 1452 1453 /* Skip zones that aren't at least installed */ 1454 if (z_zlist_get_current_state(zone_list, zone_index) < 1455 ZONE_STATE_INSTALLED) 1456 continue; 1457 1458 if (((zone_path = 1459 z_zlist_get_zonepath(zone_list, zone_index)) == NULL) || 1460 ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) || 1461 !be_zone_supported(zone_ds)) 1462 continue; 1463 1464 if (be_find_active_zone_root(zhp, zone_ds, 1465 zoneroot_ds, sizeof (zoneroot_ds)) != 0) { 1466 be_print_err(gettext("be_promote_zone_ds: " 1467 "Zone does not have an active root " 1468 "dataset, skipping this zone.\n")); 1469 continue; 1470 } 1471 1472 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds, 1473 ZFS_TYPE_FILESYSTEM)) == NULL) { 1474 be_print_err(gettext("be_promote_zone_ds: " 1475 "Failed to open dataset " 1476 "(%s): %s\n"), zoneroot_ds, 1477 libzfs_error_description(g_zfs)); 1478 err = zfs_err_to_be_err(g_zfs); 1479 goto done; 1480 } 1481 1482 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin, 1483 sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) { 1484 ZFS_CLOSE(z_zhp); 1485 continue; 1486 } 1487 1488 /* 1489 * We don't need to close the zfs handle at this 1490 * point because the callback funtion 1491 * be_promote_ds_callback() will close it for us. 1492 */ 1493 if (be_promote_ds_callback(z_zhp, NULL) != 0) { 1494 be_print_err(gettext("be_promote_zone_ds: " 1495 "failed to activate the " 1496 "datasets for %s: %s\n"), 1497 zoneroot_ds, 1498 libzfs_error_description(g_zfs)); 1499 err = BE_ERR_PROMOTE; 1500 goto done; 1501 } 1502 } 1503 done: 1504 if (be_mounted) 1505 (void) _be_unmount(be_name, 0); 1506 ZFS_CLOSE(zhp); 1507 free(temp_mntpt); 1508 z_free_brand_list(brands); 1509 z_free_zone_list(zone_list); 1510 return (err); 1511 } 1512 1513 /* 1514 * Function: be_promote_ds_callback 1515 * Description: This function is used to promote the datasets for the BE 1516 * being activated as well as the datasets for the zones BE 1517 * being activated. 1518 * 1519 * Parameters: 1520 * zhp - the zfs handle for zone BE being activated. 1521 * data - not used. 1522 * Return: 1523 * 0 - Success 1524 * be_errno_t - Failure 1525 * 1526 * Scope: 1527 * Private 1528 */ 1529 static int 1530 /* LINTED */ 1531 be_promote_ds_callback(zfs_handle_t *zhp, void *data) 1532 { 1533 char origin[MAXPATHLEN]; 1534 char *sub_dataset = NULL; 1535 int ret = 0; 1536 1537 if (zhp != NULL) { 1538 sub_dataset = strdup(zfs_get_name(zhp)); 1539 if (sub_dataset == NULL) { 1540 ret = BE_ERR_NOMEM; 1541 goto done; 1542 } 1543 } else { 1544 be_print_err(gettext("be_promote_ds_callback: " 1545 "Invalid zfs handle passed into function\n")); 1546 ret = BE_ERR_INVAL; 1547 goto done; 1548 } 1549 1550 /* 1551 * This loop makes sure that we promote the dataset to the 1552 * top of the tree so that it is no longer a decendent of any 1553 * dataset. The ZFS close and then open is used to make sure that 1554 * the promotion is updated before we move on. 1555 */ 1556 while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, 1557 sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) { 1558 if (zfs_promote(zhp) != 0) { 1559 if (libzfs_errno(g_zfs) != EZFS_EXISTS) { 1560 be_print_err(gettext("be_promote_ds_callback: " 1561 "promote of %s failed: %s\n"), 1562 zfs_get_name(zhp), 1563 libzfs_error_description(g_zfs)); 1564 ret = zfs_err_to_be_err(g_zfs); 1565 goto done; 1566 } else { 1567 /* 1568 * If the call to zfs_promote returns the 1569 * error EZFS_EXISTS we've hit a snapshot name 1570 * collision. This means we're probably 1571 * attemping to promote a zone dataset above a 1572 * parent dataset that belongs to another zone 1573 * which this zone was cloned from. 1574 * 1575 * TODO: If this is a zone dataset at some 1576 * point we should skip this if the zone 1577 * paths for the dataset and the snapshot 1578 * don't match. 1579 */ 1580 be_print_err(gettext("be_promote_ds_callback: " 1581 "promote of %s failed due to snapshot " 1582 "name collision: %s\n"), zfs_get_name(zhp), 1583 libzfs_error_description(g_zfs)); 1584 ret = zfs_err_to_be_err(g_zfs); 1585 goto done; 1586 } 1587 } 1588 ZFS_CLOSE(zhp); 1589 if ((zhp = zfs_open(g_zfs, sub_dataset, 1590 ZFS_TYPE_FILESYSTEM)) == NULL) { 1591 be_print_err(gettext("be_promote_ds_callback: " 1592 "Failed to open dataset (%s): %s\n"), sub_dataset, 1593 libzfs_error_description(g_zfs)); 1594 ret = zfs_err_to_be_err(g_zfs); 1595 goto done; 1596 } 1597 } 1598 1599 /* Iterate down this dataset's children and promote them */ 1600 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL); 1601 1602 done: 1603 free(sub_dataset); 1604 ZFS_CLOSE(zhp); 1605 return (ret); 1606 } 1607