6080 libbe should support installboot
[illumos-gate.git] / usr / src / lib / libbe / common / be_activate.c
blob985a5850944351c66086b7313649e5a0106e21d5
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
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>
46 #include <libbe.h>
47 #include <libbe_priv.h>
49 char *mnttab = MNTTAB;
52 * Private function prototypes
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 *);
65 /* ******************************************************************** */
66 /* Public Functions */
67 /* ******************************************************************** */
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:
81 * BE_ATTR_ORIG_BE_NAME *required
82 * Return:
83 * BE_SUCCESS - Success
84 * be_errno_t - Failure
85 * Scope:
86 * Public
88 int
89 be_activate(nvlist_t *be_attrs)
91 int ret = BE_SUCCESS;
92 char *be_name = NULL;
94 /* Initialize libzfs handle */
95 if (!be_zfs_init())
96 return (BE_ERR_INIT);
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);
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);
115 ret = _be_activate(be_name);
117 be_zfs_fini();
119 return (ret);
122 /* ******************************************************************** */
123 /* Semi Private Functions */
124 /* ******************************************************************** */
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.
132 * Return:
133 * BE_SUCCESS - Success
134 * be_errnot_t - Failure
135 * Scope:
136 * Public
139 _be_activate(char *be_name)
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;
151 * TODO: The BE needs to be validated to make sure that it is actually
152 * a bootable BE.
155 if (be_name == NULL)
156 return (BE_ERR_INVAL);
158 /* Set obe_name to be_name in the cb structure */
159 cb.obe_name = be_name;
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);
174 be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
175 cb.obe_root_ds = strdup(root_ds);
177 if (getzoneid() == GLOBAL_ZONEID) {
178 if ((ret = be_do_installboot(&cb)) != BE_SUCCESS)
179 return (ret);
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;
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;
200 if ((ret = _be_list(cb.obe_name, &be_nodes)) != BE_SUCCESS) {
201 return (ret);
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;
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;
219 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
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.
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;
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;
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);
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;
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;
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;
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;
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;
291 ZFS_CLOSE(zhp);
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;
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;
310 ZFS_CLOSE(zhp);
312 done:
313 be_free_list(be_nodes);
314 return (ret);
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)
329 be_activate_current_be(void)
331 int ret = BE_SUCCESS;
332 be_transaction_data_t bt = { 0 };
334 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
335 return (ret);
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);
344 return (BE_SUCCESS);
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)
359 boolean_t
360 be_is_active_on_boot(char *be_name)
362 be_node_list_t *be_node = NULL;
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);
370 if (_be_list(be_name, &be_node) != BE_SUCCESS) {
371 return (B_FALSE);
374 if (be_node == NULL) {
375 return (B_FALSE);
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);
387 /* ******************************************************************** */
388 /* Private Functions */
389 /* ******************************************************************** */
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
404 static int
405 set_bootfs(char *boot_rpool, char *be_root_ds)
407 zpool_handle_t *zhp;
408 int err = BE_SUCCESS;
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);
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);
427 zpool_close(zhp);
428 return (BE_SUCCESS);
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
444 static int
445 set_canmount(be_node_list_t *be_nodes, char *value)
447 char ds_path[MAXPATHLEN];
448 zfs_handle_t *zhp = NULL;
449 be_node_list_t *list = be_nodes;
450 int err = BE_SUCCESS;
452 while (list != NULL) {
453 be_dataset_list_t *datasets = list->be_node_datasets;
455 be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
456 sizeof (ds_path));
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);
466 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
468 * it's already mounted so we can't change the
469 * canmount property anyway.
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);
484 ZFS_CLOSE(zhp);
486 while (datasets != NULL) {
487 be_make_root_ds(list->be_rpool,
488 datasets->be_dataset_name, ds_path,
489 sizeof (ds_path));
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);
499 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
501 * it's already mounted so we can't change the
502 * canmount property anyway.
504 err = BE_SUCCESS;
505 ZFS_CLOSE(zhp);
506 break;
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);
519 ZFS_CLOSE(zhp);
520 datasets = datasets->be_next_dataset;
522 list = list->be_next_node;
524 return (err);
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
544 static int
545 be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
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;
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);
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);
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));
578 * Check to see if the pool's dataset is mounted. If it isn't we'll
579 * attempt to mount it.
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);
590 * Get the mountpoint for the root pool dataset.
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;
601 * get the version of the most recent grub update.
603 (void) snprintf(cap_file, sizeof (cap_file), "%s%s",
604 zpool_mntpt, BE_CAP_FILE);
605 free(zpool_mntpt);
606 zpool_mntpt = NULL;
608 if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
609 goto cleanup;
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;
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;
630 be_mounted = B_TRUE;
632 ZFS_CLOSE(zhp);
635 * Now get the grub version for the BE being activated.
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;
644 if (be_mounted)
645 (void) _be_unmount(bt->obe_name, 0);
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);
656 ZFS_CLOSE(pool_zhp);
658 free(temp_mntpnt);
659 return (ret);
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.
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
677 static int
678 get_ver_from_capfile(char *file, char **vers)
680 FILE *fp = NULL;
681 char line[BUFSIZ];
682 char *last = NULL;
683 int err = BE_SUCCESS;
684 errno = 0;
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);
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.
697 *vers = NULL;
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.
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);
714 while (fgets(line, BUFSIZ, fp)) {
715 char *tok = strtok_r(line, "=", &last);
717 if (tok == NULL || tok[0] == '#') {
718 continue;
719 } else if (strcmp(tok, "VERSION") == 0) {
720 *vers = strdup(last);
721 break;
724 (void) fclose(fp);
727 return (BE_SUCCESS);
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.
737 static boolean_t
738 be_do_install_mbr(char *diskname, nvlist_t *child)
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
759 uint64_t whole;
760 struct dk_gpt *gpt;
761 struct uuid *u;
762 int fd, npart, i, j;
764 (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
765 &whole);
767 if (whole)
768 return (B_TRUE);
770 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
771 return (B_FALSE);
773 if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
774 return (B_FALSE);
776 for (i = 0; i != npart; i++) {
777 int match = 0;
779 u = &gpt->efi_parts[i].p_guid;
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++;
788 if (match == 0)
789 return (B_FALSE);
792 return (B_TRUE);
795 static int
796 be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
797 char *stage2)
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 = "";
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);
813 * Modify the vdev path to point to the raw disk.
815 path = strdup(path);
816 if (path == NULL)
817 return (BE_ERR_NOMEM);
819 dsk_ptr = strstr(path, "/dsk/");
820 if (dsk_ptr != NULL) {
821 *dsk_ptr = '\0';
822 dsk_ptr++;
823 } else {
824 dsk_ptr = "";
827 (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
828 free(path);
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));
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);
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);
861 free(vname);
863 return (BE_SUCCESS);
867 * Function: be_do_copy_grub_cap
868 * Description: This function will copy grub capability file to BE.
870 * Parameters:
871 * bt - The transaction data for the BE we're activating.
872 * Return:
873 * BE_SUCCESS - Success
874 * be_errno_t - Failure
876 * Scope:
877 * Private
879 static int
880 be_do_copy_grub_cap(be_transaction_data_t *bt)
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;
899 * Copy the grub capability file from the BE we're activating
900 * into the root pool.
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));
911 * Check to see if the pool's dataset is mounted. If it isn't we'll
912 * attempt to mount it.
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);
924 * Get the mountpoint for the root pool dataset.
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;
934 (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
935 pool_mntpnt, BE_CAP_FILE);
937 free(pool_mntpnt);
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;
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;
956 be_mounted = B_TRUE;
958 ZFS_CLOSE(zhp);
960 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt,
961 BE_CAP_FILE);
962 free(tmp_mntpnt);
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;
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;
980 while (fgets(line, BUFSIZ, cap_fp)) {
981 (void) fputs(line, zpool_cap_fp);
984 (void) fclose(zpool_cap_fp);
985 (void) fclose(cap_fp);
987 done:
988 if (be_mounted)
989 (void) _be_unmount(bt->obe_name, 0);
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);
999 return (ret);
1003 * Function: be_is_install_needed
1004 * Description: Check detached version files to detect if bootloader
1005 * install/update is needed.
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
1014 * Scope:
1015 * Private
1017 static int
1018 be_is_install_needed(be_transaction_data_t *bt, boolean_t *update)
1020 int ret = BE_SUCCESS;
1021 char *cur_vers = NULL, *new_vers = NULL;
1023 assert(bt != NULL);
1024 assert(update != NULL);
1026 if (!be_has_grub()) {
1028 * no detached versioning, let installboot to manage
1029 * versioning.
1031 *update = B_TRUE;
1032 return (ret);
1035 *update = B_FALSE; /* set default */
1038 * We need to check to see if the version number from
1039 * the BE being activated is greater than the current
1040 * one.
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);
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);
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);
1061 return (ret);
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.
1070 * Parameters:
1071 * bt - The transaction data for the BE we're activating.
1072 * Return:
1073 * BE_SUCCESS - Success
1074 * be_errno_t - Failure
1076 * Scope:
1077 * Private
1079 static int
1080 be_do_installboot(be_transaction_data_t *bt)
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;
1095 * check versions. This call is to support detached
1096 * version implementation like grub. Embedded versioning is
1097 * checked by actual installer.
1099 ret = be_is_install_needed(bt, &update);
1100 if (ret != BE_SUCCESS || update == B_FALSE)
1101 return (ret);
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);
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);
1119 be_mounted = B_TRUE;
1121 ZFS_CLOSE(zhp);
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();
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);
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);
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);
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;
1166 * Get the vdev tree
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;
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;
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;
1194 if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') {
1195 free(vname);
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;
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;
1212 } else {
1213 free(vname);
1215 ret = be_do_installboot_helper(zphp, child[c], stage1,
1216 stage2);
1217 if (ret != BE_SUCCESS)
1218 goto done;
1222 if (be_has_grub()) {
1223 ret = be_do_copy_grub_cap(bt);
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);
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.
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
1249 * Scope:
1250 * Private
1252 static int
1253 be_promote_zone_ds(char *be_name, char *be_root_ds)
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;
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
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);
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);
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);
1298 be_mounted = B_TRUE;
1302 * Set the zone root to the temp mount point for the BE we just mounted.
1304 z_set_zone_root(temp_mntpt);
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.
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);
1318 for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1319 != NULL; zone_index++) {
1320 char *zone_path = NULL;
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;
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;
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;
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;
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;
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.
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;
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);
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.
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
1395 * Scope:
1396 * Private
1398 static int
1399 /* LINTED */
1400 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1402 char origin[MAXPATHLEN];
1403 char *sub_dataset = NULL;
1404 int ret = 0;
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;
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;
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.
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 {
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.
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.
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;
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;
1468 /* Iterate down this dataset's children and promote them */
1469 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1471 done:
1472 free(sub_dataset);
1473 ZFS_CLOSE(zhp);
1474 return (ret);