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]
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
30 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
31 * Copyright 2016 Toomas Soome <tsoome@me.com>
32 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
37 #include <libnvpair.h>
44 #include <sys/mnttab.h>
45 #include <sys/types.h>
49 #include <sys/efi_partition.h>
52 #include <libbe_priv.h>
54 char *mnttab
= MNTTAB
;
57 * Private function prototypes
59 static int set_bootfs(char *boot_rpool
, char *be_root_ds
);
60 static int set_canmount(be_node_list_t
*, char *);
61 static boolean_t
be_do_install_mbr(char *, nvlist_t
*);
62 static int be_do_installboot_helper(zpool_handle_t
*, nvlist_t
*, char *,
64 static int be_do_installboot(be_transaction_data_t
*, uint16_t);
65 static int be_promote_zone_ds(char *, char *);
66 static int be_promote_ds_callback(zfs_handle_t
*, void *);
68 /* ******************************************************************** */
69 /* Public Functions */
70 /* ******************************************************************** */
73 * Function: be_activate
74 * Description: Calls _be_activate which activates the BE named in the
75 * attributes passed in through be_attrs. The process of
76 * activation sets the bootfs property of the root pool, resets
77 * the canmount property to noauto, and sets the default in the
78 * menu to the entry corresponding to the entry for the named BE.
80 * be_attrs - pointer to nvlist_t of attributes being passed in.
81 * The follow attribute values are used by this function:
83 * BE_ATTR_ORIG_BE_NAME *required
85 * BE_SUCCESS - Success
86 * be_errno_t - Failure
91 be_activate(nvlist_t
*be_attrs
)
96 /* Initialize libzfs handle */
100 /* Get the BE name to activate */
101 if (nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, &be_name
)
103 be_print_err(gettext("be_activate: failed to "
104 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
106 return (BE_ERR_INVAL
);
109 /* Validate BE name */
110 if (!be_valid_be_name(be_name
)) {
111 be_print_err(gettext("be_activate: invalid BE name %s\n"),
114 return (BE_ERR_INVAL
);
117 ret
= _be_activate(be_name
);
125 * Function: be_installboot
126 * Description: Calls be_do_installboot to install/update bootloader on
127 * pool passed in through be_attrs. The primary consumer is
128 * bootadm command to avoid duplication of the code.
130 * be_attrs - pointer to nvlist_t of attributes being passed in.
131 * The following attribute values are used:
133 * BE_ATTR_ORIG_BE_NAME *required
134 * BE_ATTR_ORIG_BE_POOL *required
135 * BE_ATTR_ORIG_BE_ROOT *required
136 * BE_ATTR_INSTALL_FLAGS optional
139 * BE_SUCCESS - Success
140 * be_errno_t - Failure
145 be_installboot(nvlist_t
*be_attrs
)
147 int ret
= BE_SUCCESS
;
150 be_transaction_data_t bt
= { 0 };
153 if (nvlist_lookup_pairs(be_attrs
, NV_FLAG_NOENTOK
,
154 BE_ATTR_INSTALL_FLAGS
, DATA_TYPE_UINT16
, &flags
, NULL
) != 0) {
155 be_print_err(gettext("be_installboot: failed to lookup "
156 "BE_ATTR_INSTALL_FLAGS attribute\n"));
157 return (BE_ERR_INVAL
);
160 /* Set verbose early, so we get all messages */
161 verbose
= flags
& BE_INSTALLBOOT_FLAG_VERBOSE
;
162 if (verbose
== BE_INSTALLBOOT_FLAG_VERBOSE
)
163 libbe_print_errors(B_TRUE
);
165 ret
= nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
,
168 be_print_err(gettext("be_installboot: failed to "
169 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
170 return (BE_ERR_INVAL
);
173 ret
= nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_POOL
,
176 be_print_err(gettext("be_installboot: failed to "
177 "lookup BE_ATTR_ORIG_BE_POOL attribute\n"));
178 return (BE_ERR_INVAL
);
181 ret
= nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_ROOT
,
184 be_print_err(gettext("be_installboot: failed to "
185 "lookup BE_ATTR_ORIG_BE_ROOT attribute\n"));
186 return (BE_ERR_INVAL
);
189 /* Initialize libzfs handle */
191 return (BE_ERR_INIT
);
193 ret
= be_do_installboot(&bt
, flags
);
200 /* ******************************************************************** */
201 /* Semi Private Functions */
202 /* ******************************************************************** */
205 * Function: _be_activate
206 * Description: This does the actual work described in be_activate.
208 * be_name - pointer to the name of BE to activate.
211 * BE_SUCCESS - Success
212 * be_errnot_t - Failure
217 _be_activate(char *be_name
)
219 be_transaction_data_t cb
= { 0 };
220 zfs_handle_t
*zhp
= NULL
;
221 char root_ds
[MAXPATHLEN
];
222 char active_ds
[MAXPATHLEN
];
223 be_node_list_t
*be_nodes
= NULL
;
225 int entry
, ret
= BE_SUCCESS
;
229 * TODO: The BE needs to be validated to make sure that it is actually
234 return (BE_ERR_INVAL
);
236 /* Set obe_name to be_name in the cb structure */
237 cb
.obe_name
= be_name
;
239 /* find which zpool the be is in */
240 if ((zret
= zpool_iter(g_zfs
, be_find_zpool_callback
, &cb
)) == 0) {
241 be_print_err(gettext("be_activate: failed to "
242 "find zpool for BE (%s)\n"), cb
.obe_name
);
243 return (BE_ERR_BE_NOENT
);
244 } else if (zret
< 0) {
245 be_print_err(gettext("be_activate: "
246 "zpool_iter failed: %s\n"),
247 libzfs_error_description(g_zfs
));
248 ret
= zfs_err_to_be_err(g_zfs
);
252 be_make_root_ds(cb
.obe_zpool
, cb
.obe_name
, root_ds
, sizeof (root_ds
));
253 cb
.obe_root_ds
= strdup(root_ds
);
255 if (getzoneid() == GLOBAL_ZONEID
) {
256 ret
= be_do_installboot(&cb
, BE_INSTALLBOOT_FLAG_NULL
);
257 if (ret
!= BE_SUCCESS
)
260 if (!be_has_menu_entry(root_ds
, cb
.obe_zpool
, &entry
)) {
261 if ((ret
= be_append_menu(cb
.obe_name
, cb
.obe_zpool
,
262 NULL
, NULL
, NULL
)) != BE_SUCCESS
) {
263 be_print_err(gettext("be_activate: Failed to "
264 "add BE (%s) to the menu\n"),
271 if ((ret
= _be_list(cb
.obe_name
, &be_nodes
, BE_LIST_DEFAULT
))
276 if ((ret
= set_canmount(be_nodes
, "noauto")) != BE_SUCCESS
) {
277 be_print_err(gettext("be_activate: failed to set "
278 "canmount dataset property\n"));
282 if (getzoneid() == GLOBAL_ZONEID
) {
283 if ((ret
= set_bootfs(be_nodes
->be_rpool
,
284 root_ds
)) != BE_SUCCESS
) {
285 be_print_err(gettext("be_activate: failed to set "
286 "bootfs pool property for %s\n"), root_ds
);
291 if ((zhp
= zfs_open(g_zfs
, root_ds
, ZFS_TYPE_FILESYSTEM
)) != NULL
) {
293 * We don't need to close the zfs handle at this
294 * point because The callback funtion
295 * be_promote_ds_callback() will close it for us.
297 if (be_promote_ds_callback(zhp
, NULL
) != 0) {
298 be_print_err(gettext("be_activate: "
299 "failed to activate the "
300 "datasets for %s: %s\n"),
302 libzfs_error_description(g_zfs
));
303 ret
= BE_ERR_PROMOTE
;
307 be_print_err(gettext("be_activate: failed to open "
308 "dataset (%s): %s\n"), root_ds
,
309 libzfs_error_description(g_zfs
));
310 ret
= zfs_err_to_be_err(g_zfs
);
314 if (getzoneid() == GLOBAL_ZONEID
&&
315 be_get_uuid(cb
.obe_root_ds
, &uu
) == BE_SUCCESS
&&
316 (ret
= be_promote_zone_ds(cb
.obe_name
, cb
.obe_root_ds
))
318 be_print_err(gettext("be_activate: failed to promote "
319 "the active zonepath datasets for zones in BE %s\n"),
323 if (getzoneid() != GLOBAL_ZONEID
) {
324 if (!be_zone_compare_uuids(root_ds
)) {
325 be_print_err(gettext("be_activate: activating zone "
326 "root dataset from non-active global BE is not "
331 if ((zhp
= zfs_open(g_zfs
, root_ds
,
332 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
333 be_print_err(gettext("be_activate: failed to open "
334 "dataset (%s): %s\n"), root_ds
,
335 libzfs_error_description(g_zfs
));
336 ret
= zfs_err_to_be_err(g_zfs
);
339 /* Find current active zone root dataset */
340 if ((ret
= be_find_active_zone_root(zhp
, cb
.obe_zpool
,
341 active_ds
, sizeof (active_ds
))) != BE_SUCCESS
) {
342 be_print_err(gettext("be_activate: failed to find "
343 "active zone root dataset\n"));
347 /* Do nothing if requested BE is already active */
348 if (strcmp(root_ds
, active_ds
) == 0) {
354 /* Set active property for BE */
355 if (zfs_prop_set(zhp
, BE_ZONE_ACTIVE_PROPERTY
, "on") != 0) {
356 be_print_err(gettext("be_activate: failed to set "
357 "active property (%s): %s\n"), root_ds
,
358 libzfs_error_description(g_zfs
));
359 ret
= zfs_err_to_be_err(g_zfs
);
365 /* Unset active property for old active root dataset */
366 if ((zhp
= zfs_open(g_zfs
, active_ds
,
367 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
368 be_print_err(gettext("be_activate: failed to open "
369 "dataset (%s): %s\n"), active_ds
,
370 libzfs_error_description(g_zfs
));
371 ret
= zfs_err_to_be_err(g_zfs
);
374 if (zfs_prop_set(zhp
, BE_ZONE_ACTIVE_PROPERTY
, "off") != 0) {
375 be_print_err(gettext("be_activate: failed to unset "
376 "active property (%s): %s\n"), active_ds
,
377 libzfs_error_description(g_zfs
));
378 ret
= zfs_err_to_be_err(g_zfs
);
385 be_free_list(be_nodes
);
390 * Function: be_activate_current_be
391 * Description: Set the currently "active" BE to be "active on boot"
395 * BE_SUCCESS - Success
396 * be_errnot_t - Failure
398 * Semi-private (library wide use only)
401 be_activate_current_be(void)
403 int ret
= BE_SUCCESS
;
404 be_transaction_data_t bt
= { 0 };
406 if ((ret
= be_find_current_be(&bt
)) != BE_SUCCESS
) {
410 if ((ret
= _be_activate(bt
.obe_name
)) != BE_SUCCESS
) {
411 be_print_err(gettext("be_activate_current_be: failed to "
412 "activate %s\n"), bt
.obe_name
);
420 * Function: be_is_active_on_boot
421 * Description: Checks if the BE name passed in has the "active on boot"
422 * property set to B_TRUE.
424 * be_name - the name of the BE to check
426 * B_TRUE - if active on boot.
427 * B_FALSE - if not active on boot.
429 * Semi-private (library wide use only)
432 be_is_active_on_boot(char *be_name
)
434 be_node_list_t
*be_node
= NULL
;
436 if (be_name
== NULL
) {
437 be_print_err(gettext("be_is_active_on_boot: "
438 "be_name must not be NULL\n"));
442 if (_be_list(be_name
, &be_node
, BE_LIST_DEFAULT
) != BE_SUCCESS
) {
446 if (be_node
== NULL
) {
450 if (be_node
->be_active_on_boot
) {
451 be_free_list(be_node
);
454 be_free_list(be_node
);
459 /* ******************************************************************** */
460 /* Private Functions */
461 /* ******************************************************************** */
464 * Function: set_bootfs
465 * Description: Sets the bootfs property on the boot pool to be the
466 * root dataset of the activated BE.
468 * boot_pool - The pool we're setting bootfs in.
469 * be_root_ds - The main dataset for the BE.
471 * BE_SUCCESS - Success
472 * be_errno_t - Failure
477 set_bootfs(char *boot_rpool
, char *be_root_ds
)
480 int err
= BE_SUCCESS
;
482 if ((zhp
= zpool_open(g_zfs
, boot_rpool
)) == NULL
) {
483 be_print_err(gettext("set_bootfs: failed to open pool "
484 "(%s): %s\n"), boot_rpool
, libzfs_error_description(g_zfs
));
485 err
= zfs_err_to_be_err(g_zfs
);
489 err
= zpool_set_prop(zhp
, "bootfs", be_root_ds
);
491 be_print_err(gettext("set_bootfs: failed to set "
492 "bootfs property for pool %s: %s\n"), boot_rpool
,
493 libzfs_error_description(g_zfs
));
494 err
= zfs_err_to_be_err(g_zfs
);
504 * Function: set_canmount
505 * Description: Sets the canmount property on the datasets of the
508 * be_nodes - The be_node_t returned from be_list
509 * value - The value of canmount we setting, on|off|noauto.
511 * BE_SUCCESS - Success
512 * be_errno_t - Failure
517 set_canmount(be_node_list_t
*be_nodes
, char *value
)
519 char ds_path
[MAXPATHLEN
];
520 zfs_handle_t
*zhp
= NULL
;
521 be_node_list_t
*list
= be_nodes
;
522 int err
= BE_SUCCESS
;
524 while (list
!= NULL
) {
525 be_dataset_list_t
*datasets
= list
->be_node_datasets
;
527 be_make_root_ds(list
->be_rpool
, list
->be_node_name
, ds_path
,
530 if ((zhp
= zfs_open(g_zfs
, ds_path
, ZFS_TYPE_DATASET
)) ==
532 be_print_err(gettext("set_canmount: failed to open "
533 "dataset (%s): %s\n"), ds_path
,
534 libzfs_error_description(g_zfs
));
535 err
= zfs_err_to_be_err(g_zfs
);
538 if (zfs_prop_get_int(zhp
, ZFS_PROP_MOUNTED
)) {
540 * it's already mounted so we can't change the
541 * canmount property anyway.
545 err
= zfs_prop_set(zhp
,
546 zfs_prop_to_name(ZFS_PROP_CANMOUNT
), value
);
549 be_print_err(gettext("set_canmount: failed to "
550 "set dataset property (%s): %s\n"),
551 ds_path
, libzfs_error_description(g_zfs
));
552 err
= zfs_err_to_be_err(g_zfs
);
558 while (datasets
!= NULL
) {
559 be_make_root_ds(list
->be_rpool
,
560 datasets
->be_dataset_name
, ds_path
,
563 if ((zhp
= zfs_open(g_zfs
, ds_path
, ZFS_TYPE_DATASET
))
565 be_print_err(gettext("set_canmount: failed to "
566 "open dataset %s: %s\n"), ds_path
,
567 libzfs_error_description(g_zfs
));
568 err
= zfs_err_to_be_err(g_zfs
);
571 if (zfs_prop_get_int(zhp
, ZFS_PROP_MOUNTED
)) {
573 * it's already mounted so we can't change the
574 * canmount property anyway.
580 err
= zfs_prop_set(zhp
,
581 zfs_prop_to_name(ZFS_PROP_CANMOUNT
), value
);
584 be_print_err(gettext("set_canmount: "
585 "Failed to set property value %s "
586 "for dataset %s: %s\n"), value
, ds_path
,
587 libzfs_error_description(g_zfs
));
588 err
= zfs_err_to_be_err(g_zfs
);
592 datasets
= datasets
->be_next_dataset
;
594 list
= list
->be_next_node
;
600 * To be able to boot EFI labeled disks, stage1 needs to be written
601 * into the MBR. We do not do this if we're on disks with a traditional
602 * fdisk partition table only, or if any foreign EFI partitions exist.
603 * In the trivial case of a whole-disk vdev we always write stage1 into
607 be_do_install_mbr(char *diskname
, nvlist_t
*child
)
609 struct uuid allowed_uuids
[] = {
633 (void) nvlist_lookup_uint64(child
, ZPOOL_CONFIG_WHOLE_DISK
,
639 if ((fd
= open(diskname
, O_RDONLY
|O_NDELAY
)) < 0)
642 if ((npart
= efi_alloc_and_read(fd
, &gpt
)) <= 0)
645 for (i
= 0; i
!= npart
; i
++) {
648 u
= &gpt
->efi_parts
[i
].p_guid
;
651 j
!= sizeof (allowed_uuids
) / sizeof (struct uuid
);
653 if (bcmp(u
, &allowed_uuids
[j
],
654 sizeof (struct uuid
)) == 0)
665 be_do_installboot_helper(zpool_handle_t
*zphp
, nvlist_t
*child
, char *stage1
,
666 char *stage2
, uint16_t flags
)
668 char install_cmd
[MAXPATHLEN
];
669 char be_run_cmd_errbuf
[BUFSIZ
];
670 char be_run_cmd_outbuf
[BUFSIZ
];
671 char diskname
[MAXPATHLEN
];
673 char *path
, *type
, *dsk_ptr
;
679 if (nvlist_lookup_string(child
, ZPOOL_CONFIG_TYPE
, &type
) != 0) {
680 be_print_err(gettext("%s: failed to get device type\n"),
682 return (BE_ERR_NODEV
);
684 /* Skip indirect devices. */
685 if (strcmp(type
, VDEV_TYPE_INDIRECT
) == 0)
686 return (BE_ERR_NOTSUP
);
688 if (nvlist_lookup_string(child
, ZPOOL_CONFIG_PATH
, &path
) != 0) {
689 be_print_err(gettext("%s: failed to get device path\n"),
691 return (BE_ERR_NODEV
);
694 if ((nvlist_lookup_uint64_array(child
, ZPOOL_CONFIG_VDEV_STATS
,
695 (uint64_t **)&vs
, &vsc
) != 0) ||
696 vs
->vs_state
< VDEV_STATE_DEGRADED
) {
698 * Don't try to run installboot on a vdev that is not ONLINE
699 * or DEGRADED. Try to print a warning for each such vdev.
701 be_print_err(gettext("%s: vdev %s is %s, can't install "
702 "boot loader\n"), __func__
, path
,
703 zpool_state_to_name(vs
->vs_state
, vs
->vs_aux
));
708 * Modify the vdev path to point to the raw disk.
712 return (BE_ERR_NOMEM
);
714 dsk_ptr
= strstr(path
, "/dsk/");
715 if (dsk_ptr
!= NULL
) {
722 (void) snprintf(diskname
, sizeof (diskname
), "%s/r%s", path
, dsk_ptr
);
725 vname
= zpool_vdev_name(g_zfs
, zphp
, child
, B_FALSE
);
727 be_print_err(gettext("%s: failed to get device name: %s\n"),
728 __func__
, libzfs_error_description(g_zfs
));
729 return (zfs_err_to_be_err(g_zfs
));
732 if (be_is_isa("i386")) {
733 uint16_t force
= flags
& BE_INSTALLBOOT_FLAG_FORCE
;
734 uint16_t mbr
= flags
& BE_INSTALLBOOT_FLAG_MBR
;
736 if (force
== BE_INSTALLBOOT_FLAG_FORCE
) {
737 if (mbr
== BE_INSTALLBOOT_FLAG_MBR
||
738 be_do_install_mbr(diskname
, child
))
743 if (mbr
== BE_INSTALLBOOT_FLAG_MBR
||
744 be_do_install_mbr(diskname
, child
))
748 (void) snprintf(install_cmd
, sizeof (install_cmd
),
749 "%s %s %s %s %s", BE_INSTALL_BOOT
, flag
,
750 stage1
, stage2
, diskname
);
751 } else if (be_is_isa("sparc")) {
752 if ((flags
& BE_INSTALLBOOT_FLAG_FORCE
) ==
753 BE_INSTALLBOOT_FLAG_FORCE
)
758 (void) snprintf(install_cmd
, sizeof (install_cmd
),
759 "%s %s %s %s", BE_INSTALL_BOOT
, flag
, stage2
, diskname
);
761 be_print_err(gettext("%s: unsupported architecture.\n"),
763 return (BE_ERR_BOOTFILE_INST
);
766 *be_run_cmd_outbuf
= '\0';
767 *be_run_cmd_errbuf
= '\0';
769 ret
= be_run_cmd(install_cmd
, be_run_cmd_errbuf
, BUFSIZ
,
770 be_run_cmd_outbuf
, BUFSIZ
);
772 if (ret
!= BE_SUCCESS
) {
773 be_print_err(gettext("%s: install failed for device %s.\n"),
775 ret
= BE_ERR_BOOTFILE_INST
;
778 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd
);
779 if (be_run_cmd_outbuf
[0] != 0) {
780 be_print_err(gettext(" Output:\n"));
781 be_print_err("%s", be_run_cmd_outbuf
);
784 if (be_run_cmd_errbuf
[0] != 0) {
785 be_print_err(gettext(" Errors:\n"));
786 be_print_err("%s", be_run_cmd_errbuf
);
794 be_do_installboot_walk(zpool_handle_t
*zphp
, nvlist_t
*nv
, char *stage1
,
795 char *stage2
, uint16_t flags
)
797 boolean_t verbose
= do_print
;
802 /* It is OK to have no children. */
803 (void) nvlist_lookup_nvlist_array(nv
, ZPOOL_CONFIG_CHILDREN
, &child
,
806 for (int c
= 0; c
< children
; c
++) {
810 /* ensure update on child status */
811 vname
= zpool_vdev_name(g_zfs
, zphp
, child
[c
], verbose
);
813 be_print_err(gettext("%s: "
814 "failed to get device name: %s\n"), __func__
,
815 libzfs_error_description(g_zfs
));
816 return (zfs_err_to_be_err(g_zfs
));
818 be_print_err(gettext("%s: child %d of %d device %s\n"),
819 __func__
, c
, children
, vname
);
822 rv
= be_do_installboot_walk(zphp
, child
[c
], stage1
, stage2
,
826 /* ignore unsupported devices */
828 gettext("%s: device %s is not supported\n"),
832 /* catch at least one success */
844 return (ret
== -1? BE_ERR_NOTSUP
: ret
);
845 return (be_do_installboot_helper(zphp
, nv
, stage1
, stage2
, flags
));
849 * Function: be_do_installboot
850 * Description: This function runs installboot using the boot
851 * loader files from the BE we're activating and installing
852 * them on the pool the BE lives in.
855 * bt - The transaction data for the BE we're activating.
856 * flags - flags for bootloader install
858 * BE_SUCCESS - Success
859 * be_errno_t - Failure
865 be_do_installboot(be_transaction_data_t
*bt
, uint16_t flags
)
867 zpool_handle_t
*zphp
= NULL
;
868 zfs_handle_t
*zhp
= NULL
;
869 nvlist_t
*nv
, *config
;
870 char *tmp_mntpt
= NULL
;
871 char stage1
[MAXPATHLEN
];
872 char stage2
[MAXPATHLEN
];
873 int ret
= BE_SUCCESS
;
874 boolean_t be_mounted
= B_FALSE
;
876 if ((zhp
= zfs_open(g_zfs
, bt
->obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
878 be_print_err(gettext("%s: failed to "
879 "open BE root dataset (%s): %s\n"), __func__
,
880 bt
->obe_root_ds
, libzfs_error_description(g_zfs
));
881 ret
= zfs_err_to_be_err(g_zfs
);
884 if (!zfs_is_mounted(zhp
, &tmp_mntpt
)) {
885 if ((ret
= _be_mount(bt
->obe_name
, &tmp_mntpt
,
886 BE_MOUNT_FLAG_NO_ZONES
)) != BE_SUCCESS
) {
887 be_print_err(gettext("%s: failed to "
888 "mount BE (%s)\n"), __func__
, bt
->obe_name
);
896 if (be_is_isa("i386")) {
897 (void) snprintf(stage1
, sizeof (stage1
), "%s%s",
898 tmp_mntpt
, BE_LOADER_STAGE_1
);
899 (void) snprintf(stage2
, sizeof (stage2
), "%s%s",
900 tmp_mntpt
, BE_LOADER_STAGE_2
);
901 } else if (be_is_isa("sparc")) {
902 char *platform
= be_get_platform();
904 if (platform
== NULL
) {
905 be_print_err(gettext("%s: failed to detect system "
906 "platform name\n"), __func__
);
908 (void) _be_unmount(bt
->obe_name
, 0);
910 return (BE_ERR_BOOTFILE_INST
);
912 stage1
[0] = '\0'; /* sparc has no stage1 */
913 (void) snprintf(stage2
, sizeof (stage2
),
914 "%s/usr/platform/%s%s", tmp_mntpt
,
915 platform
, BE_SPARC_BOOTBLK
);
917 be_print_err(gettext("%s: unsupported architecture.\n"),
919 return (BE_ERR_BOOTFILE_INST
);
922 if ((zphp
= zpool_open(g_zfs
, bt
->obe_zpool
)) == NULL
) {
923 be_print_err(gettext("%s: failed to open "
924 "pool (%s): %s\n"), __func__
, bt
->obe_zpool
,
925 libzfs_error_description(g_zfs
));
926 ret
= zfs_err_to_be_err(g_zfs
);
928 (void) _be_unmount(bt
->obe_name
, 0);
933 if ((config
= zpool_get_config(zphp
, NULL
)) == NULL
) {
934 be_print_err(gettext("%s: failed to get zpool "
935 "configuration information. %s\n"), __func__
,
936 libzfs_error_description(g_zfs
));
937 ret
= zfs_err_to_be_err(g_zfs
);
944 if (nvlist_lookup_nvlist(config
, ZPOOL_CONFIG_VDEV_TREE
, &nv
) != 0) {
945 be_print_err(gettext("%s: failed to get vdev "
946 "tree: %s\n"), __func__
, libzfs_error_description(g_zfs
));
947 ret
= zfs_err_to_be_err(g_zfs
);
951 ret
= be_do_installboot_walk(zphp
, nv
, stage1
, stage2
, flags
);
956 (void) _be_unmount(bt
->obe_name
, 0);
963 * Function: be_promote_zone_ds
964 * Description: This function finds the zones for the BE being activated
965 * and the active zonepath dataset for each zone. Then each
966 * active zonepath dataset is promoted.
969 * be_name - the name of the global zone BE that we need to
970 * find the zones for.
971 * be_root_ds - the root dataset for be_name.
973 * BE_SUCCESS - Success
974 * be_errno_t - Failure
980 be_promote_zone_ds(char *be_name
, char *be_root_ds
)
982 char *zone_ds
= NULL
;
983 char *temp_mntpt
= NULL
;
984 char origin
[MAXPATHLEN
];
985 char zoneroot_ds
[MAXPATHLEN
];
986 zfs_handle_t
*zhp
= NULL
;
987 zfs_handle_t
*z_zhp
= NULL
;
988 boolean_t be_mounted
= B_FALSE
;
989 int err
= BE_SUCCESS
;
993 if ((zhp
= zfs_open(g_zfs
, be_root_ds
,
994 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
995 be_print_err(gettext("be_promote_zone_ds: Failed to open "
996 "dataset (%s): %s\n"), be_root_ds
,
997 libzfs_error_description(g_zfs
));
998 err
= zfs_err_to_be_err(g_zfs
);
1002 if (!zfs_is_mounted(zhp
, &temp_mntpt
)) {
1003 if ((err
= _be_mount(be_name
, &temp_mntpt
,
1004 BE_MOUNT_FLAG_NO_ZONES
)) != BE_SUCCESS
) {
1005 be_print_err(gettext("be_promote_zone_ds: failed to "
1006 "mount the BE for zones procesing.\n"));
1010 be_mounted
= B_TRUE
;
1014 * Set the zone root to the temp mount point for the BE we just mounted.
1016 zonecfg_set_root((const char *)temp_mntpt
);
1018 cookie
= setzoneent();
1019 while((ze
= getzoneent_private(cookie
)) != NULL
) {
1021 if (strcmp(ze
->zone_name
, "global") == 0)
1024 /* Skip zones that aren't at least installed */
1025 if (ze
->zone_state
< ZONE_STATE_INSTALLED
)
1028 if (((zone_ds
= be_get_ds_from_dir(ze
->zone_path
)) == NULL
) ||
1029 !be_zone_supported(zone_ds
)) {
1035 if (be_find_active_zone_root(zhp
, zone_ds
,
1036 zoneroot_ds
, sizeof (zoneroot_ds
)) != 0) {
1037 be_print_err(gettext("be_promote_zone_ds: "
1038 "Zone does not have an active root "
1039 "dataset, skipping this zone.\n"));
1043 if ((z_zhp
= zfs_open(g_zfs
, zoneroot_ds
,
1044 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
1045 be_print_err(gettext("be_promote_zone_ds: "
1046 "Failed to open dataset "
1047 "(%s): %s\n"), zoneroot_ds
,
1048 libzfs_error_description(g_zfs
));
1049 err
= zfs_err_to_be_err(g_zfs
);
1053 if (zfs_prop_get(z_zhp
, ZFS_PROP_ORIGIN
, origin
,
1054 sizeof (origin
), NULL
, NULL
, 0, B_FALSE
) != 0) {
1060 * We don't need to close the zfs handle at this
1061 * point because the callback funtion
1062 * be_promote_ds_callback() will close it for us.
1064 if (be_promote_ds_callback(z_zhp
, NULL
) != 0) {
1065 be_print_err(gettext("be_promote_zone_ds: "
1066 "failed to activate the "
1067 "datasets for %s: %s\n"),
1069 libzfs_error_description(g_zfs
));
1070 err
= BE_ERR_PROMOTE
;
1079 (void) _be_unmount(be_name
, 0);
1086 * Function: be_promote_ds_callback
1087 * Description: This function is used to promote the datasets for the BE
1088 * being activated as well as the datasets for the zones BE
1092 * zhp - the zfs handle for zone BE being activated.
1096 * be_errno_t - Failure
1103 be_promote_ds_callback(zfs_handle_t
*zhp
, void *data
)
1105 char origin
[MAXPATHLEN
];
1106 char *sub_dataset
= NULL
;
1110 sub_dataset
= strdup(zfs_get_name(zhp
));
1111 if (sub_dataset
== NULL
) {
1116 be_print_err(gettext("be_promote_ds_callback: "
1117 "Invalid zfs handle passed into function\n"));
1123 * This loop makes sure that we promote the dataset to the
1124 * top of the tree so that it is no longer a decendent of any
1125 * dataset. The ZFS close and then open is used to make sure that
1126 * the promotion is updated before we move on.
1128 while (zfs_prop_get(zhp
, ZFS_PROP_ORIGIN
, origin
,
1129 sizeof (origin
), NULL
, NULL
, 0, B_FALSE
) == 0) {
1130 if (zfs_promote(zhp
) != 0) {
1131 if (libzfs_errno(g_zfs
) != EZFS_EXISTS
) {
1132 be_print_err(gettext("be_promote_ds_callback: "
1133 "promote of %s failed: %s\n"),
1135 libzfs_error_description(g_zfs
));
1136 ret
= zfs_err_to_be_err(g_zfs
);
1140 * If the call to zfs_promote returns the
1141 * error EZFS_EXISTS we've hit a snapshot name
1142 * collision. This means we're probably
1143 * attemping to promote a zone dataset above a
1144 * parent dataset that belongs to another zone
1145 * which this zone was cloned from.
1147 * TODO: If this is a zone dataset at some
1148 * point we should skip this if the zone
1149 * paths for the dataset and the snapshot
1152 be_print_err(gettext("be_promote_ds_callback: "
1153 "promote of %s failed due to snapshot "
1154 "name collision: %s\n"), zfs_get_name(zhp
),
1155 libzfs_error_description(g_zfs
));
1156 ret
= zfs_err_to_be_err(g_zfs
);
1161 if ((zhp
= zfs_open(g_zfs
, sub_dataset
,
1162 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
1163 be_print_err(gettext("be_promote_ds_callback: "
1164 "Failed to open dataset (%s): %s\n"), sub_dataset
,
1165 libzfs_error_description(g_zfs
));
1166 ret
= zfs_err_to_be_err(g_zfs
);
1171 /* Iterate down this dataset's children and promote them */
1172 ret
= zfs_iter_filesystems(zhp
, be_promote_ds_callback
, NULL
);