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