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