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