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