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