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