diff --git a/release/tools/arm.subr b/release/tools/arm.subr
index 343d9f3a7034..2f91490c0859 100644
--- a/release/tools/arm.subr
+++ b/release/tools/arm.subr
@@ -1,279 +1,280 @@
 #!/bin/sh
 #-
 # Copyright (c) 2015-2017 The FreeBSD Foundation
 # All rights reserved.
 #
 # Portions of this software were developed by Glen Barber
 # under sponsorship from the FreeBSD Foundation.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
 # are met:
 # 1. Redistributions of source code must retain the above copyright
 #    notice, this list of conditions and the following disclaimer.
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
 #
 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
 # Common subroutines used to build arm, arm64, or RISC-V SD card images.
 #
 # $FreeBSD$
 #
 
 cleanup() {
 	if [ -c "${DESTDIR}/dev/null" ]; then
 		umount_loop ${DESTDIR}/dev 2>/dev/null
 	fi
 	umount_loop ${DESTDIR}
 	if [ ! -z "${mddev}" ]; then
 		mdconfig -d -u ${mddev}
 	fi
 
 	return 0
 }
 
 umount_loop() {
 	DIR=$1
 	i=0
 	sync
 	while ! umount ${DIR}; do
 		i=$(( $i + 1 ))
 		if [ $i -ge 10 ]; then
 			# This should never happen.  But, it has happened.
 			echo "Cannot umount(8) ${DIR}"
 			echo "Something has gone horribly wrong."
 			return 1
 		fi
 		sleep 1
 	done
 
 	return 0
 }
 
 arm_create_disk() {
 	# Create the target raw file and temporary work directory.
 	chroot ${CHROOTDIR} gpart create -s ${PART_SCHEME} ${mddev}
 	if [ "${PART_SCHEME}" == "GPT" ]; then
 		chroot ${CHROOTDIR} gpart add -t efi -l efi -a 512k -s ${FAT_SIZE} ${mddev}
 		chroot ${CHROOTDIR} newfs_msdos -L efi -F ${FAT_TYPE} /dev/${mddev}p1
 		chroot ${CHROOTDIR} gpart add -t freebsd-ufs -l rootfs -a 64k ${mddev}
 		chroot ${CHROOTDIR} newfs -U -L rootfs /dev/${mddev}p2
 	fi
 	if [ "${PART_SCHEME}" == "MBR" ]; then
 		chroot ${CHROOTDIR} gpart add -t '!12' -a 512k -s ${FAT_SIZE} ${mddev}
 		chroot ${CHROOTDIR} gpart set -a active -i 1 ${mddev}
 		chroot ${CHROOTDIR} newfs_msdos -L msdosboot -F ${FAT_TYPE} /dev/${mddev}s1
 		chroot ${CHROOTDIR} gpart add -t freebsd ${mddev}
 		chroot ${CHROOTDIR} gpart create -s bsd ${mddev}s2
 		chroot ${CHROOTDIR} gpart add -t freebsd-ufs -a 64k /dev/${mddev}s2
 		chroot ${CHROOTDIR} newfs -U -L rootfs /dev/${mddev}s2a
 	fi
 
 	return 0
 }
 
 arm_create_user() {
 	# Create a default user account 'freebsd' with the password 'freebsd',
 	# and set the default password for the 'root' user to 'root'.
 	chroot ${CHROOTDIR} /usr/sbin/pw -R ${DESTDIR} \
 		groupadd freebsd -g 1001
 	chroot ${CHROOTDIR} mkdir -p ${DESTDIR}/home/freebsd
 	chroot ${CHROOTDIR} /usr/sbin/pw -R ${DESTDIR} \
 		useradd freebsd \
 		-m -M 0755 -w yes -n freebsd -u 1001 -g 1001 -G 0 \
 		-c 'FreeBSD User' -d '/home/freebsd' -s '/bin/csh'
 	chroot ${CHROOTDIR} /usr/sbin/pw -R ${DESTDIR} \
 		usermod root -w yes
 
 	return 0
 }
 
 arm_setup_usb_otg() {
 	# Set up virtual serial port over USB OTG / device mode.
 	echo >> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf
 	echo '# Required for USB OTG virtual serial port.' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf
 	echo 'notify 100 {' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf
 	echo '	match "system"		"DEVFS";' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf
 	echo '	match "subsystem"	"CDEV";' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf
 	echo '	match "type"		"CREATE";' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf
 	echo '	match "cdev"		"ttyU[0-9]+";' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf
 	echo '	action "/sbin/init q";' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf
 	echo '};' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf
 
 	echo '# USB OTG virtual serial port' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/ttys
 	echo 'ttyU0	"/usr/libexec/getty 3wire"	vt100	onifconsole  secure' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/ttys
 	echo 'ttyU1	"/usr/libexec/getty 3wire"	vt100	onifconsole  secure' \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/ttys
 
 	echo '# Configure USB OTG; see usb_template(4).' \
 		>> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 	echo 'hw.usb.template=3' \
 		>> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 	echo 'umodem_load="YES"' \
 	     >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 }
 
 arm64_setup_multicons() {
 	if [ "${EMBEDDED_TARGET_ARCH}" != "aarch64" ]; then
 		return
 	fi
 
 	echo '# Multiple console (serial+efi gop) enabled.' \
 		>> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 	echo 'boot_multicons="YES"' \
 	     >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 	echo 'boot_serial="YES"' \
 	     >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 }
 
 arm_setup_fdt_overlays() {
 	if [ -z "${FDT_OVERLAYS}" ]; then
 		return
 	fi
 
 	echo '# DTB OVERLAYS' \
 		>> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 	echo "fdt_overlays=\"${FDT_OVERLAYS}\"" \
 	     >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 }
 
 arm_setup_minimal_loader() {
 	echo '# Disable the beastie menu and color' \
 		>> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 	echo 'beastie_disable="YES"' \
 		>> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 	echo 'loader_color="NO"' \
 		>> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf
 }
 
 arm_install_base() {
 	if [ "${PART_SCHEME}" == "GPT" ]; then
 		chroot ${CHROOTDIR} mount /dev/${mddev}p2 ${DESTDIR}
 	fi
 	if [ "${PART_SCHEME}" == "MBR" ]; then
 		chroot ${CHROOTDIR} mount /dev/${mddev}s2a ${DESTDIR}
 	fi
 	_OSVERSION=$(chroot ${CHROOTDIR} /usr/bin/uname -U)
 	REVISION=$(chroot ${CHROOTDIR} make -C /usr/src/release -V REVISION)
 	BRANCH=$(chroot ${CHROOTDIR} make -C /usr/src/release -V BRANCH)
 	export UNAME_r=${REVISION}-${BRANCH}
 	eval chroot ${CHROOTDIR} make -C ${WORLDDIR} \
 		TARGET=${EMBEDDED_TARGET} \
 		TARGET_ARCH=${EMBEDDED_TARGET_ARCH} \
 		DESTDIR=${DESTDIR} KERNCONF=${KERNEL} \
 		${CONF_FILES} installworld installkernel distribution
+	chroot ${CHROOTDIR} mkdir -p ${DESTDIR}/boot/efi
 	chroot ${CHROOTDIR} mkdir -p ${DESTDIR}/boot/msdos
 
 	arm_create_user
 	arm_setup_usb_otg
 	arm64_setup_multicons
 	arm_setup_fdt_overlays
 	arm_setup_minimal_loader
 	arm_do_quirk
 
 	echo '# Custom /etc/fstab for FreeBSD embedded images' \
 		> ${CHROOTDIR}/${DESTDIR}/etc/fstab
 	if [ "${PART_SCHEME}" == "GPT" ]; then
 		echo "/dev/ufs/rootfs   /       ufs     rw      1       1" \
 			>> ${CHROOTDIR}/${DESTDIR}/etc/fstab
 		echo "/dev/msdosfs/EFI /boot/efi msdosfs rw,noatime 0 0" \
 			>> ${CHROOTDIR}/${DESTDIR}/etc/fstab
 	fi
 	if [ "${PART_SCHEME}" == "MBR" ]; then
 		echo "/dev/ufs/rootfs   /       ufs     rw      1       1" \
 			>> ${CHROOTDIR}/${DESTDIR}/etc/fstab
 		echo "/dev/msdosfs/MSDOSBOOT /boot/msdos msdosfs rw,noatime 0 0" \
 			>> ${CHROOTDIR}/${DESTDIR}/etc/fstab
 	fi
 	echo "tmpfs /tmp tmpfs rw,mode=1777,size=50m 0 0" \
 		>> ${CHROOTDIR}/${DESTDIR}/etc/fstab
 
 	local hostname
 	hostname="$(echo ${KERNEL} | tr '[:upper:]' '[:lower:]')"
 	echo "hostname=\"${hostname}\"" > ${CHROOTDIR}/${DESTDIR}/etc/rc.conf
 	echo 'ifconfig_DEFAULT="DHCP"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf
 	echo 'sshd_enable="YES"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf
 	echo 'sendmail_enable="NONE"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf
 	echo 'sendmail_submit_enable="NO"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf
 	echo 'sendmail_outbound_enable="NO"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf
 	echo 'sendmail_msp_queue_enable="NO"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf
 	echo 'growfs_enable="YES"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf
 
 	sync
 	umount_loop ${CHROOTDIR}/${DESTDIR}
 
 	return 0
 }
 
 arm_install_boot() {
 	FATMOUNT="${DESTDIR%${KERNEL}}/fat"
 	UFSMOUNT="${DESTDIR%${KERNEL}}/ufs"
 	chroot ${CHROOTDIR} mkdir -p "${FATMOUNT}" "${UFSMOUNT}"
 	if [ "${PART_SCHEME}" == "GPT" ]; then
 		dospart="/dev/${mddev}p1"
 		ufspart="/dev/${mddev}p2"
 	fi
 	if [ "${PART_SCHEME}" == "MBR" ]; then
 		dospart="/dev/${mddev}s1"
 		ufspart="/dev/${mddev}s2a"
 	fi
 
 	chroot ${CHROOTDIR} mount_msdosfs ${dospart} ${FATMOUNT}
 	chroot ${CHROOTDIR} mount ${ufspart} ${UFSMOUNT}
 
 	if [ "${EMBEDDED_TARGET}" == "arm" ]; then
 	chroot ${CHROOTDIR} cp -p ${UFSMOUNT}/boot/ubldr.bin \
 		${FATMOUNT}/ubldr.bin
 	fi
 
 	BOOTFILES="$(chroot ${CHROOTDIR} \
 		env TARGET=${EMBEDDED_TARGET} TARGET_ARCH=${EMBEDDED_TARGET_ARCH} \
 		WITH_UNIFIED_OBJDIR=yes \
 		make -C ${WORLDDIR}/stand -V .OBJDIR)"
 	BOOTFILES="$(chroot ${CHROOTDIR} realpath ${BOOTFILES})"
 
 	chroot ${CHROOTDIR} mkdir -p ${FATMOUNT}/EFI/BOOT
 	chroot ${CHROOTDIR} cp -p ${BOOTFILES}/efi/loader_lua/loader_lua.efi \
 		${FATMOUNT}/EFI/BOOT/$(efi_boot_name ${EMBEDDED_TARGET})
 
 	chroot ${CHROOTDIR} cp -R ${UFSMOUNT}/boot/dtb ${FATMOUNT}
 
 	chroot ${CHROOTDIR} touch ${UFSMOUNT}/firstboot
 	sync
 	umount_loop ${CHROOTDIR}/${FATMOUNT}
 	umount_loop ${CHROOTDIR}/${UFSMOUNT}
 	chroot ${CHROOTDIR} rmdir ${FATMOUNT}
 	chroot ${CHROOTDIR} rmdir ${UFSMOUNT}
 }
 
 arm_install_uboot() {
 	# Override in the ${EMBEDDED_TARGET}/${BOARDNAME}.conf file.
 
 	return 0
 }
 
 arm_do_quirk() {
 	# Override in the ${EMBEDDED_TARGET}/${BOARDNAME}.conf file.
 }
diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr
index 7bad725c9870..7bd971013656 100644
--- a/release/tools/vmimage.subr
+++ b/release/tools/vmimage.subr
@@ -1,279 +1,288 @@
 #!/bin/sh
 #
 # $FreeBSD$
 #
 #
 # Common functions for virtual machine image build scripts.
 #
 
 scriptdir=$(dirname $(realpath $0))
 . ${scriptdir}/../../tools/boot/install-boot.sh
 
 export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
 trap "cleanup" INT QUIT TRAP ABRT TERM
 
 write_partition_layout() {
 	if [ -z "${NOSWAP}" ]; then
 		SWAPOPT="-p freebsd-swap/swapfs::${SWAPSIZE}"
 	fi
 
 	BOOTFILES="$(env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \
 		WITH_UNIFIED_OBJDIR=yes \
 		make -C ${WORLDDIR}/stand -V .OBJDIR)"
 	BOOTFILES="$(realpath ${BOOTFILES})"
 
 	case "${TARGET}:${TARGET_ARCH}" in
 		amd64:amd64 | i386:i386)
 			ESP=yes
 			SCHEME=gpt
 			BOOTPARTS="-b ${BOOTFILES}/i386/pmbr/pmbr \
 				   -p freebsd-boot/bootfs:=${BOOTFILES}/i386/gptboot/gptboot"
 			ROOTFSPART="-p freebsd-ufs/rootfs:=${VMBASE}"
 			;;
 		arm64:aarch64 | riscv:riscv64*)
 			ESP=yes
 			SCHEME=gpt
 			BOOTPARTS=
 			ROOTFSPART="-p freebsd-ufs/rootfs:=${VMBASE}"
 			;;
 		powerpc:powerpc*)
 			ESP=no
 			SCHEME=apm
 			BOOTPARTS="-p apple-boot/bootfs:=${BOOTFILES}/powerpc/boot1.chrp/boot1.hfs"
 			ROOTFSPART="-p freebsd-ufs/rootfs:=${VMBASE}"
 			;;
 		*)
 			echo "vmimage.subr: unsupported target '${TARGET}:${TARGET_ARCH}'" >&2
 			exit 1
 			;;
 	esac
 
 	if [ ${ESP} = "yes" ]; then
 		# Create an ESP
 		espfilename=$(mktemp /tmp/efiboot.XXXXXX)
 		make_esp_file ${espfilename} ${fat32min} ${BOOTFILES}/efi/loader_lua/loader_lua.efi
-		BOOTPARTS="${BOOTPARTS} -p efi:=${espfilename}"
+		BOOTPARTS="${BOOTPARTS} -p efi/efiesp:=${espfilename}"
+
+		# Add this to fstab, requires temporarily remounting the fs
+		mddev=$(mdconfig -f ${VMBASE})
+		mount /dev/${mddev} ${DESTDIR}
+		mkdir -p ${DESTDIR}/boot/efi
+		echo "/dev/${ROOTLABEL}/efiesp	/boot/efi       msdosfs     rw      2       2" \
+			>> ${DESTDIR}/etc/fstab
+		umount ${DESTDIR}
+		mdconfig -d -u ${mddev}
 	fi
 
 	mkimg -s ${SCHEME} -f ${VMFORMAT} \
 		${BOOTPARTS} \
 		${SWAPOPT} \
 		${ROOTFSPART} \
 		-o ${VMIMAGE}
 
 	if [ ${ESP} = "yes" ]; then
 		rm ${espfilename}
 	fi
 
 	return 0
 }
 
 err() {
 	printf "${@}\n"
 	cleanup
 	return 1
 }
 
 cleanup() {
 	if [ -c "${DESTDIR}/dev/null" ]; then
 		umount_loop ${DESTDIR}/dev 2>/dev/null
 	fi
 	umount_loop ${DESTDIR}
 	if [ ! -z "${mddev}" ]; then
 		mdconfig -d -u ${mddev}
 	fi
 
 	return 0
 }
 
 vm_create_base() {
 	# Creates the UFS root filesystem for the virtual machine disk,
 	# written to the formatted disk image with mkimg(1).
 
 	mkdir -p ${DESTDIR}
 	truncate -s ${VMSIZE} ${VMBASE}
 	mddev=$(mdconfig -f ${VMBASE})
 	newfs -L rootfs /dev/${mddev}
 	mount /dev/${mddev} ${DESTDIR}
 
 	return 0
 }
 
 vm_copy_base() {
 	# Creates a new UFS root filesystem and copies the contents of the
 	# current root filesystem into it.  This produces a "clean" disk
 	# image without any remnants of files which were created temporarily
 	# during image-creation and have since been deleted (e.g., downloaded
 	# package archives).
 
 	mkdir -p ${DESTDIR}/old
 	mdold=$(mdconfig -f ${VMBASE})
 	mount /dev/${mdold} ${DESTDIR}/old
 
 	truncate -s ${VMSIZE} ${VMBASE}.tmp
 	mkdir -p ${DESTDIR}/new
 	mdnew=$(mdconfig -f ${VMBASE}.tmp)
 	newfs -L rootfs /dev/${mdnew}
 	mount /dev/${mdnew} ${DESTDIR}/new
 
 	tar -cf- -C ${DESTDIR}/old . | tar -xUf- -C ${DESTDIR}/new
 
 	umount_loop /dev/${mdold}
 	rmdir ${DESTDIR}/old
 	mdconfig -d -u ${mdold}
 
 	umount_loop /dev/${mdnew}
 	rmdir ${DESTDIR}/new
 	tunefs -n enable /dev/${mdnew}
 	mdconfig -d -u ${mdnew}
 	mv ${VMBASE}.tmp ${VMBASE}
 }
 
 vm_install_base() {
 	# Installs the FreeBSD userland/kernel to the virtual machine disk.
 
 	cd ${WORLDDIR} && \
 		make DESTDIR=${DESTDIR} \
 		installworld installkernel distribution || \
 		err "\n\nCannot install the base system to ${DESTDIR}."
 
 	# Bootstrap etcupdate(8) and mergemaster(8) databases.
 	mkdir -p ${DESTDIR}/var/db/etcupdate
 	etcupdate extract -B \
 		-M "TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}" \
 		-s ${WORLDDIR} -d ${DESTDIR}/var/db/etcupdate
 	sh ${WORLDDIR}/release/scripts/mm-mtree.sh -m ${WORLDDIR} \
 		-F "TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}" \
 		-D ${DESTDIR}
 
 	echo '# Custom /etc/fstab for FreeBSD VM images' \
 		> ${DESTDIR}/etc/fstab
 	echo "/dev/${ROOTLABEL}/rootfs   /       ufs     rw      1       1" \
 		>> ${DESTDIR}/etc/fstab
 	if [ -z "${NOSWAP}" ]; then
 		echo '/dev/gpt/swapfs  none    swap    sw      0       0' \
 			>> ${DESTDIR}/etc/fstab
 	fi
 
 	local hostname
 	hostname="$(echo $(uname -o) | tr '[:upper:]' '[:lower:]')"
 	echo "hostname=\"${hostname}\"" >> ${DESTDIR}/etc/rc.conf
 
 	if ! [ -z "${QEMUSTATIC}" ]; then
 		export EMULATOR=/qemu
 		cp ${QEMUSTATIC} ${DESTDIR}/${EMULATOR}
 	fi
 
 	mkdir -p ${DESTDIR}/dev
 	mount -t devfs devfs ${DESTDIR}/dev
 	chroot ${DESTDIR} ${EMULATOR} /usr/bin/newaliases
 	chroot ${DESTDIR} ${EMULATOR} /bin/sh /etc/rc.d/ldconfig forcestart
 	umount_loop ${DESTDIR}/dev
 
 	cp /etc/resolv.conf ${DESTDIR}/etc/resolv.conf
 
 	return 0
 }
 
 vm_extra_install_base() {
 	# Prototype.  When overridden, runs extra post-installworld commands
 	# as needed, based on the target virtual machine image or cloud
 	# provider image target.
 
 	return 0
 }
 
 vm_extra_enable_services() {
 	if [ ! -z "${VM_RC_LIST}" ]; then
 		for _rcvar in ${VM_RC_LIST}; do
 			echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf
 		done
 	fi
 
 	if [ -z "${VMCONFIG}" -o -c "${VMCONFIG}" ]; then
 		echo 'ifconfig_DEFAULT="DHCP inet6 accept_rtadv"' >> \
 			${DESTDIR}/etc/rc.conf
 		# Expand the filesystem to fill the disk.
 		echo 'growfs_enable="YES"' >> ${DESTDIR}/etc/rc.conf
 		touch ${DESTDIR}/firstboot
 	fi
 
 	return 0
 }
 
 vm_extra_install_packages() {
 	if [ -z "${VM_EXTRA_PACKAGES}" ]; then
 		return 0
 	fi
 	mkdir -p ${DESTDIR}/dev
 	mount -t devfs devfs ${DESTDIR}/dev
 	chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \
 		/usr/sbin/pkg bootstrap -y
 	chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \
 		/usr/sbin/pkg install -y ${VM_EXTRA_PACKAGES}
 	umount_loop ${DESTDIR}/dev
 
 	return 0
 }
 
 vm_extra_install_ports() {
 	# Prototype.  When overridden, installs additional ports within the
 	# virtual machine environment.
 
 	return 0
 }
 
 vm_extra_pre_umount() {
 	# Prototype.  When overridden, performs additional tasks within the
 	# virtual machine environment prior to unmounting the filesystem.
 	# Note: When overriding this function, removing resolv.conf in the
 	# disk image must be included.
 
 	if ! [ -z "${QEMUSTATIC}" ]; then
 		rm -f ${DESTDIR}/${EMULATOR}
 	fi
 	rm -f ${DESTDIR}/etc/resolv.conf
 	return 0
 }
 
 vm_extra_pkg_rmcache() {
 	if [ -e ${DESTDIR}/usr/local/sbin/pkg ]; then
 		chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \
 			/usr/local/sbin/pkg clean -y -a
 	fi
 
 	return 0
 }
 
 umount_loop() {
 	DIR=$1
 	i=0
 	sync
 	while ! umount ${DIR}; do
 		i=$(( $i + 1 ))
 		if [ $i -ge 10 ]; then
 			# This should never happen.  But, it has happened.
 			echo "Cannot umount(8) ${DIR}"
 			echo "Something has gone horribly wrong."
 			return 1
 		fi
 		sleep 1
 	done
 
 	return 0
 }
 
 vm_create_disk() {
 	echo "Creating image...  Please wait."
 	echo
 
 	write_partition_layout || return 1
 
 	return 0
 }
 
 vm_extra_create_disk() {
 
 	return 0
 }
 
diff --git a/usr.sbin/bsdinstall/partedit/gpart_ops.c b/usr.sbin/bsdinstall/partedit/gpart_ops.c
index e68a02b4264c..b49ff1c9fd42 100644
--- a/usr.sbin/bsdinstall/partedit/gpart_ops.c
+++ b/usr.sbin/bsdinstall/partedit/gpart_ops.c
@@ -1,1470 +1,1460 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2011 Nathan Whitehorn
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libutil.h>
 #include <inttypes.h>
 
 #include <libgeom.h>
 #include <dialog.h>
 #include <dlg_keys.h>
 
 #include "partedit.h"
 
 #define GPART_FLAGS "x" /* Do not commit changes by default */
 
 static void
 gpart_show_error(const char *title, const char *explanation, const char *errstr)
 {
 	char *errmsg;
 	char message[512];
 	int error;
 
 	if (explanation == NULL)
 		explanation = "";
 
 	error = strtol(errstr, &errmsg, 0);
 	if (errmsg != errstr) {
 		while (errmsg[0] == ' ')
 			errmsg++;
 		if (errmsg[0] != '\0')
 			sprintf(message, "%s%s. %s", explanation,
 			    strerror(error), errmsg);
 		else
 			sprintf(message, "%s%s", explanation, strerror(error));
 	} else {
 		sprintf(message, "%s%s", explanation, errmsg);
 	}
 
 	dialog_msgbox(title, message, 0, 0, TRUE);
 }
 
 static int
 scheme_supports_labels(const char *scheme)
 {
 	if (strcmp(scheme, "APM") == 0)
 		return (1);
 	if (strcmp(scheme, "GPT") == 0)
 		return (1);
 
 	return (0);
 }
 
 static void
 newfs_command(const char *fstype, char *command, int use_default)
 {
 	if (strcmp(fstype, "freebsd-ufs") == 0) {
 		int i;
 		DIALOG_LISTITEM items[] = {
 			{"UFS1", "UFS Version 1",
 			    "Use version 1 of the UFS file system instead "
 			    "of version 2 (not recommended)", 0 },
 			{"SU", "Softupdates",
 			    "Enable softupdates (default)", 1 },
 			{"SUJ", "Softupdates journaling",
 			    "Enable file system journaling (default - "
 			    "turn off for SSDs)", 1 },
 			{"TRIM", "Enable SSD TRIM support",
 			    "Enable TRIM support, useful on solid-state drives",
 			    0 },
 		};
 
 		if (!use_default) {
 			int choice;
 			choice = dlg_checklist("UFS Options", "", 0, 0, 0,
 			    nitems(items), items, NULL,
 			    FLAG_CHECK, &i);
 			if (choice == 1) /* Cancel */
 				return;
 		}
 
 		strcpy(command, "newfs ");
 		for (i = 0; i < (int)nitems(items); i++) {
 			if (items[i].state == 0)
 				continue;
 			if (strcmp(items[i].name, "UFS1") == 0)
 				strcat(command, "-O1 ");
 			else if (strcmp(items[i].name, "SU") == 0)
 				strcat(command, "-U ");
 			else if (strcmp(items[i].name, "SUJ") == 0)
 				strcat(command, "-j ");
 			else if (strcmp(items[i].name, "TRIM") == 0)
 				strcat(command, "-t ");
 		}
 	} else if (strcmp(fstype, "freebsd-zfs") == 0) {
 		int i;
 		DIALOG_LISTITEM items[] = {
 			{"fletcher4", "checksum algorithm: fletcher4",
 			    "Use fletcher4 for data integrity checking. "
 			    "(default)", 1 },
 			{"fletcher2", "checksum algorithm: fletcher2",
 			    "Use fletcher2 for data integrity checking. "
 			    "(not recommended)", 0 },
 			{"sha256", "checksum algorithm: sha256",
 			    "Use sha256 for data integrity checking. "
 			    "(not recommended)", 0 },
 			{"atime", "Update atimes for files",
 			    "Disable atime update", 0 },
 		};
 
 		if (!use_default) {
 			int choice;
 			choice = dlg_checklist("ZFS Options", "", 0, 0, 0,
 			    nitems(items), items, NULL,
 			    FLAG_CHECK, &i);
 			if (choice == 1) /* Cancel */
 				return;
 		}
 
 		strcpy(command, "zpool create -f -m none ");
 		if (getenv("BSDINSTALL_TMPBOOT") != NULL) {
 			char zfsboot_path[MAXPATHLEN];
 			snprintf(zfsboot_path, sizeof(zfsboot_path), "%s/zfs",
 			    getenv("BSDINSTALL_TMPBOOT"));
 			mkdir(zfsboot_path, S_IRWXU | S_IRGRP | S_IXGRP |
 			    S_IROTH | S_IXOTH);
 			sprintf(command, "%s -o cachefile=%s/zpool.cache ",
 			    command, zfsboot_path);
 		}
 		for (i = 0; i < (int)nitems(items); i++) {
 			if (items[i].state == 0)
 				continue;
 			if (strcmp(items[i].name, "fletcher4") == 0)
 				strcat(command, "-O checksum=fletcher4 ");
 			else if (strcmp(items[i].name, "fletcher2") == 0)
 				strcat(command, "-O checksum=fletcher2 ");
 			else if (strcmp(items[i].name, "sha256") == 0)
 				strcat(command, "-O checksum=sha256 ");
 			else if (strcmp(items[i].name, "atime") == 0)
 				strcat(command, "-O atime=off ");
 		}
 	} else if (strcmp(fstype, "fat32") == 0 || strcmp(fstype, "efi") == 0 ||
 	     strcmp(fstype, "ms-basic-data") == 0) {
 		int i;
 		DIALOG_LISTITEM items[] = {
 			{"FAT32", "FAT Type 32",
 			    "Create a FAT32 filesystem (default)", 1 },
 			{"FAT16", "FAT Type 16",
 			    "Create a FAT16 filesystem", 0 },
 			{"FAT12", "FAT Type 12",
 			    "Create a FAT12 filesystem", 0 },
 		};
 
 		if (!use_default) {
 			int choice;
 			choice = dlg_checklist("FAT Options", "", 0, 0, 0,
 			    nitems(items), items, NULL,
 			    FLAG_RADIO, &i);
 			if (choice == 1) /* Cancel */
 				return;
 		}
 
 		strcpy(command, "newfs_msdos ");
 		for (i = 0; i < (int)nitems(items); i++) {
 			if (items[i].state == 0)
 				continue;
 			if (strcmp(items[i].name, "FAT32") == 0)
 				strcat(command, "-F 32 -c 1");
 			else if (strcmp(items[i].name, "FAT16") == 0)
 				strcat(command, "-F 16 ");
 			else if (strcmp(items[i].name, "FAT12") == 0)
 				strcat(command, "-F 12 ");
 		}
 	} else {
 		if (!use_default)
 			dialog_msgbox("Error", "No configurable options exist "
 			    "for this filesystem.", 0, 0, TRUE);
 		command[0] = '\0';
 	}
 }
 
 const char *
 choose_part_type(const char *def_scheme)
 {
 	int cancel, choice;
 	const char *scheme = NULL;
 
 	DIALOG_LISTITEM items[] = {
 		{"APM", "Apple Partition Map",
 		    "Bootable on PowerPC Apple Hardware", 0 },
 		{"BSD", "BSD Labels",
 		    "Bootable on most x86 systems", 0 },
 		{"GPT", "GUID Partition Table",
 		    "Bootable on most x86 systems and EFI aware ARM64", 0 },
 		{"MBR", "DOS Partitions",
 		    "Bootable on most x86 systems", 0 },
 	};
 
 parttypemenu:
 	dialog_vars.default_item = __DECONST(char *, def_scheme);
 	cancel = dlg_menu("Partition Scheme",
 	    "Select a partition scheme for this volume:", 0, 0, 0,
 	    nitems(items), items, &choice, NULL);
 	dialog_vars.default_item = NULL;
 
 	if (cancel)
 		return NULL;
 
 	if (!is_scheme_bootable(items[choice].name)) {
 		char message[512];
 		sprintf(message, "This partition scheme (%s) is not "
 		    "bootable on this platform. Are you sure you want "
 		    "to proceed?", items[choice].name);
 		dialog_vars.defaultno = TRUE;
 		cancel = dialog_yesno("Warning", message, 0, 0);
 		dialog_vars.defaultno = FALSE;
 		if (cancel) /* cancel */
 			goto parttypemenu;
 	}
 
 	scheme = items[choice].name;
 
 	return scheme;
 }
 
 int
 gpart_partition(const char *lg_name, const char *scheme)
 {
 	int cancel;
 	struct gctl_req *r;
 	const char *errstr;
 
 schememenu:
 	if (scheme == NULL) {
 		scheme = choose_part_type(default_scheme());
 
 		if (scheme == NULL)
 			return (-1);
 
 		if (!is_scheme_bootable(scheme)) {
 			char message[512];
 			sprintf(message, "This partition scheme (%s) is not "
 			    "bootable on this platform. Are you sure you want "
 			    "to proceed?", scheme);
 			dialog_vars.defaultno = TRUE;
 			cancel = dialog_yesno("Warning", message, 0, 0);
 			dialog_vars.defaultno = FALSE;
 			if (cancel) { /* cancel */
 				/* Reset scheme so user can choose another */
 				scheme = NULL;
 				goto schememenu;
 			}
 		}
 	}
 
 	r = gctl_get_handle();
 	gctl_ro_param(r, "class", -1, "PART");
 	gctl_ro_param(r, "arg0", -1, lg_name);
 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
 	gctl_ro_param(r, "scheme", -1, scheme);
 	gctl_ro_param(r, "verb", -1, "create");
 
 	errstr = gctl_issue(r);
 	if (errstr != NULL && errstr[0] != '\0') {
 		gpart_show_error("Error", NULL, errstr);
 		gctl_free(r);
 		scheme = NULL;
 		goto schememenu;
 	}
 	gctl_free(r);
 
 	if (bootcode_path(scheme) != NULL)
 		get_part_metadata(lg_name, 1)->bootcode = 1;
 	return (0);
 }
 
 static void
 gpart_activate(struct gprovider *pp)
 {
 	struct gconfig *gc;
 	struct gctl_req *r;
 	const char *errstr, *scheme;
 	const char *attribute = NULL;
 	intmax_t idx;
 
 	/*
 	 * Some partition schemes need this partition to be marked 'active'
 	 * for it to be bootable.
 	 */
 	LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) {
 		if (strcmp(gc->lg_name, "scheme") == 0) {
 			scheme = gc->lg_val;
 			break;
 		}
 	}
 
 	if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "EBR") == 0)
 		attribute = "active";
 	else
 		return;
 
 	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
 		if (strcmp(gc->lg_name, "index") == 0) {
 			idx = atoi(gc->lg_val);
 			break;
 		}
 	}
 
 	r = gctl_get_handle();
 	gctl_ro_param(r, "class", -1, "PART");
 	gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name);
 	gctl_ro_param(r, "verb", -1, "set");
 	gctl_ro_param(r, "attrib", -1, attribute);
 	gctl_ro_param(r, "index", sizeof(idx), &idx);
 
 	errstr = gctl_issue(r);
 	if (errstr != NULL && errstr[0] != '\0') 
 		gpart_show_error("Error", "Error marking partition active:",
 		    errstr);
 	gctl_free(r);
 }
 
 void
 gpart_set_root(const char *lg_name, const char *attribute)
 {
 	struct gctl_req *r;
 	const char *errstr;
 
 	r = gctl_get_handle();
 	gctl_ro_param(r, "class", -1, "PART");
 	gctl_ro_param(r, "arg0", -1, lg_name);
 	gctl_ro_param(r, "flags", -1, "C");
 	gctl_ro_param(r, "verb", -1, "set");
 	gctl_ro_param(r, "attrib", -1, attribute);
 
 	errstr = gctl_issue(r);
 	if (errstr != NULL && errstr[0] != '\0') 
 		gpart_show_error("Error", "Error setting parameter on disk:",
 		    errstr);
 	gctl_free(r);
 }
 
 static void
 gpart_bootcode(struct ggeom *gp)
 {
 	const char *bootcode;
 	struct gconfig *gc;
 	struct gctl_req *r;
 	const char *errstr, *scheme;
 	uint8_t *boot;
 	size_t bootsize, bytes;
 	int bootfd;
 
 	/*
 	 * Write default bootcode to the newly partitioned disk, if that
 	 * applies on this platform.
 	 */
 	LIST_FOREACH(gc, &gp->lg_config, lg_config) {
 		if (strcmp(gc->lg_name, "scheme") == 0) {
 			scheme = gc->lg_val;
 			break;
 		}
 	}
 
 	bootcode = bootcode_path(scheme);
 	if (bootcode == NULL) 
 		return;
 
 	bootfd = open(bootcode, O_RDONLY);
 	if (bootfd < 0) {
 		dialog_msgbox("Bootcode Error", strerror(errno), 0, 0,
 		    TRUE);
 		return;
 	}
 
 	bootsize = lseek(bootfd, 0, SEEK_END);
 	boot = malloc(bootsize);
 	lseek(bootfd, 0, SEEK_SET);
 	bytes = 0;
 	while (bytes < bootsize)
 		bytes += read(bootfd, boot + bytes, bootsize - bytes);
 	close(bootfd);
 
 	r = gctl_get_handle();
 	gctl_ro_param(r, "class", -1, "PART");
 	gctl_ro_param(r, "arg0", -1, gp->lg_name);
 	gctl_ro_param(r, "verb", -1, "bootcode");
 	gctl_ro_param(r, "bootcode", bootsize, boot);
 
 	errstr = gctl_issue(r);
 	if (errstr != NULL && errstr[0] != '\0') 
 		gpart_show_error("Bootcode Error", NULL, errstr);
 	gctl_free(r);
 	free(boot);
 }
 
 static void
 gpart_partcode(struct gprovider *pp, const char *fstype)
 {
 	struct gconfig *gc;
 	const char *scheme;
 	const char *indexstr;
 	char message[255], command[255];
 
 	LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) {
 		if (strcmp(gc->lg_name, "scheme") == 0) {
 			scheme = gc->lg_val;
 			break;
 		}
 	}
 
 	/* Make sure this partition scheme needs partcode on this platform */
 	if (partcode_path(scheme, fstype) == NULL)
 		return;
 
 	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
 		if (strcmp(gc->lg_name, "index") == 0) {
 			indexstr = gc->lg_val;
 			break;
 		}
 	}
 
 	/* Shell out to gpart for partcode for now */
 	sprintf(command, "gpart bootcode -p %s -i %s %s",
 	    partcode_path(scheme, fstype), indexstr, pp->lg_geom->lg_name);
 	if (system(command) != 0) {
 		sprintf(message, "Error installing partcode on partition %s",
 		    pp->lg_name);
 		dialog_msgbox("Error", message, 0, 0, TRUE);
 	}
 }
 
 void
 gpart_destroy(struct ggeom *lg_geom)
 {
 	struct gctl_req *r;
 	struct gprovider *pp;
 	const char *errstr;
 	int force = 1;
 
 	/* Delete all child metadata */
 	LIST_FOREACH(pp, &lg_geom->lg_provider, lg_provider)
 		gpart_delete(pp);
 
 	/* Revert any local changes to get this geom into a pristine state */
 	r = gctl_get_handle();
 	gctl_ro_param(r, "class", -1, "PART");
 	gctl_ro_param(r, "arg0", -1, lg_geom->lg_name);
 	gctl_ro_param(r, "verb", -1, "undo");
 	gctl_issue(r); /* Ignore errors -- these are non-fatal */
 	gctl_free(r);
 
 	/* Now destroy the geom itself */
 	r = gctl_get_handle();
 	gctl_ro_param(r, "class", -1, "PART");
 	gctl_ro_param(r, "arg0", -1, lg_geom->lg_name);
 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
 	gctl_ro_param(r, "force", sizeof(force), &force);
 	gctl_ro_param(r, "verb", -1, "destroy");
 	errstr = gctl_issue(r);
 	if (errstr != NULL && errstr[0] != '\0') {
 		/*
 		 * Check if we reverted away the existence of the geom
 		 * altogether. Show all other errors to the user.
 		 */
 		if (strtol(errstr, NULL, 0) != EINVAL)
 			gpart_show_error("Error", NULL, errstr);
 	}
 	gctl_free(r);
 
 	/* And any metadata associated with the partition scheme itself */
 	delete_part_metadata(lg_geom->lg_name);
 }
 
 void
 gpart_edit(struct gprovider *pp)
 {
 	struct gctl_req *r;
 	struct gconfig *gc;
 	struct gconsumer *cp;
 	struct ggeom *geom;
 	const char *errstr, *oldtype, *scheme;
 	struct partition_metadata *md;
 	char sizestr[32];
 	char newfs[255];
 	intmax_t idx;
 	int hadlabel, choice, junk, nitems;
 	unsigned i;
 
 	DIALOG_FORMITEM items[] = {
 		{0, "Type:", 5, 0, 0, FALSE, "", 11, 0, 12, 15, 0,
 		    FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, "
 		    "freebsd-swap)", FALSE},
 		{0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 0, 0,
 		    FALSE, "Partition size. Append K, M, G for kilobytes, "
 		    "megabytes or gigabytes.", FALSE},
 		{0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0,
 		    FALSE, "Path at which to mount this partition (leave blank "
 		    "for swap, set to / for root filesystem)", FALSE},
 		{0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE,
 		    "Partition name. Not all partition schemes support this.",
 		    FALSE},
 	};
 
 	/*
 	 * Find the PART geom we are manipulating. This may be a consumer of
 	 * this provider, or its parent. Check the consumer case first.
 	 */
 	geom = NULL;
 	LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
 		if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
 			/* Check for zombie geoms, treating them as blank */
 			scheme = NULL;
 			LIST_FOREACH(gc, &cp->lg_geom->lg_config, lg_config) {
 				if (strcmp(gc->lg_name, "scheme") == 0) {
 					scheme = gc->lg_val;
 					break;
 				}
 			}
 			if (scheme == NULL || strcmp(scheme, "(none)") == 0) {
 				gpart_partition(cp->lg_geom->lg_name, NULL);
 				return;
 			}
 
 			/* If this is a nested partition, edit as usual */
 			if (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0)
 				break;
 
 			/* Destroy the geom and all sub-partitions */
 			gpart_destroy(cp->lg_geom);
 
 			/* Now re-partition and return */
 			gpart_partition(cp->lg_geom->lg_name, NULL);
 			return;
 		}
 
 	if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0)
 		geom = pp->lg_geom;
 
 	if (geom == NULL) {
 		/* Disk not partitioned, so partition it */
 		gpart_partition(pp->lg_name, NULL);
 		return;
 	}
 
 	LIST_FOREACH(gc, &geom->lg_config, lg_config) {
 		if (strcmp(gc->lg_name, "scheme") == 0) {
 			scheme = gc->lg_val;
 			break;
 		}
 	}
 
 	nitems = scheme_supports_labels(scheme) ? 4 : 3;
 
 	/* Edit editable parameters of a partition */
 	hadlabel = 0;
 	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
 		if (strcmp(gc->lg_name, "type") == 0) {
 			oldtype = gc->lg_val;
 			items[0].text = gc->lg_val;
 		}
 		if (strcmp(gc->lg_name, "label") == 0 && gc->lg_val != NULL) {
 			hadlabel = 1;
 			items[3].text = gc->lg_val;
 		}
 		if (strcmp(gc->lg_name, "index") == 0)
 			idx = atoi(gc->lg_val);
 	}
 
 	TAILQ_FOREACH(md, &part_metadata, metadata) {
 		if (md->name != NULL && strcmp(md->name, pp->lg_name) == 0) {
 			if (md->fstab != NULL)
 				items[2].text = md->fstab->fs_file;
 			break;
 		}
 	}
 
 	humanize_number(sizestr, 7, pp->lg_mediasize, "B", HN_AUTOSCALE,
 	    HN_NOSPACE | HN_DECIMAL);
 	items[1].text = sizestr;
 
 editpart:
 	choice = dlg_form("Edit Partition", "", 0, 0, 0, nitems, items, &junk);
 
 	if (choice) /* Cancel pressed */
 		goto endedit;
 
 	/* If this is the root partition, check that this fs is bootable */
 	if (strcmp(items[2].text, "/") == 0 && !is_fs_bootable(scheme,
 	    items[0].text)) {
 		char message[512];
 		sprintf(message, "This file system (%s) is not bootable "
 		    "on this system. Are you sure you want to proceed?",
 		    items[0].text);
 		dialog_vars.defaultno = TRUE;
 		choice = dialog_yesno("Warning", message, 0, 0);
 		dialog_vars.defaultno = FALSE;
 		if (choice == 1) /* cancel */
 			goto editpart;
 	}
 
 	/* Check if the label has a / in it */
 	if (strchr(items[3].text, '/') != NULL) {
 		dialog_msgbox("Error", "Label contains a /, which is not an "
 		    "allowed character.", 0, 0, TRUE);
 		goto editpart;
 	}
 
 	r = gctl_get_handle();
 	gctl_ro_param(r, "class", -1, "PART");
 	gctl_ro_param(r, "arg0", -1, geom->lg_name);
 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
 	gctl_ro_param(r, "verb", -1, "modify");
 	gctl_ro_param(r, "index", sizeof(idx), &idx);
 	if (hadlabel || items[3].text[0] != '\0')
 		gctl_ro_param(r, "label", -1, items[3].text);
 	gctl_ro_param(r, "type", -1, items[0].text);
 	errstr = gctl_issue(r);
 	if (errstr != NULL && errstr[0] != '\0') {
 		gpart_show_error("Error", NULL, errstr);
 		gctl_free(r);
 		goto editpart;
 	}
 	gctl_free(r);
 
 	newfs_command(items[0].text, newfs, 1);
 	set_default_part_metadata(pp->lg_name, scheme, items[0].text,
 	    items[2].text, (strcmp(oldtype, items[0].text) != 0) ?
 	    newfs : NULL);
 
 endedit:
 	if (strcmp(oldtype, items[0].text) != 0 && cp != NULL)
 		gpart_destroy(cp->lg_geom);
 	if (strcmp(oldtype, items[0].text) != 0 && strcmp(items[0].text,
 	    "freebsd") == 0)
 		gpart_partition(pp->lg_name, "BSD");
 
 	for (i = 0; i < nitems(items); i++)
 		if (items[i].text_free)
 			free(items[i].text);
 }
 
 void
 set_default_part_metadata(const char *name, const char *scheme,
     const char *type, const char *mountpoint, const char *newfs)
 {
 	struct partition_metadata *md;
 	char *zpool_name = NULL;
 	const char *default_bootmount = NULL;
 	int i;
 
 	/* Set part metadata */
 	md = get_part_metadata(name, 1);
 
 	if (newfs) {
 		if (md->newfs != NULL) {
 			free(md->newfs);
 			md->newfs = NULL;
 		}
 
 		if (newfs != NULL && newfs[0] != '\0') {
 			md->newfs = malloc(strlen(newfs) + strlen(" /dev/") +
 			    strlen(mountpoint) + 5 + strlen(name) + 1);
 			if (strcmp("freebsd-zfs", type) == 0) {
 				zpool_name = strdup((strlen(mountpoint) == 1) ?
 				    "root" : &mountpoint[1]);
 				for (i = 0; zpool_name[i] != 0; i++)
 					if (!isalnum(zpool_name[i]))
 						zpool_name[i] = '_';
 				sprintf(md->newfs, "%s %s /dev/%s", newfs,
 				    zpool_name, name);
 			} else {
 				sprintf(md->newfs, "%s /dev/%s", newfs, name);
 			}
 		}
 	}
 
 	if (strcmp(type, "freebsd-swap") == 0)
 		mountpoint = "none";
 	if (strcmp(type, bootpart_type(scheme, &default_bootmount)) == 0) {
-		if (default_bootmount == NULL) {
-
-			int fd = openat(tmpdfd, "bsdinstall-esps",
-			    O_CREAT | O_WRONLY | O_APPEND, 0600);
-			if (fd > 0) {
-				write(fd, md->name, strlen(md->name));
-				write(fd, "\n", 1);
-				close(fd);
-			}
-
+		if (default_bootmount == NULL)
 			md->bootcode = 1;
-		}
 		else if (mountpoint == NULL || strlen(mountpoint) == 0)
 			mountpoint = default_bootmount;
 	}
 
 	if (mountpoint == NULL || mountpoint[0] == '\0') {
 		if (md->fstab != NULL) {
 			free(md->fstab->fs_spec);
 			free(md->fstab->fs_file);
 			free(md->fstab->fs_vfstype);
 			free(md->fstab->fs_mntops);
 			free(md->fstab->fs_type);
 			free(md->fstab);
 			md->fstab = NULL;
 		}
 	} else {
 		if (md->fstab == NULL) {
 			md->fstab = malloc(sizeof(struct fstab));
 		} else {
 			free(md->fstab->fs_spec);
 			free(md->fstab->fs_file);
 			free(md->fstab->fs_vfstype);
 			free(md->fstab->fs_mntops);
 			free(md->fstab->fs_type);
 		}
 		if (strcmp("freebsd-zfs", type) == 0) {
 			md->fstab->fs_spec = strdup(zpool_name);
 		} else {
 			md->fstab->fs_spec = malloc(strlen(name) +
 			    strlen("/dev/") + 1);
 			sprintf(md->fstab->fs_spec, "/dev/%s", name);
 		}
 		md->fstab->fs_file = strdup(mountpoint);
 		/* Get VFS from text after freebsd-, if possible */
 		if (strncmp("freebsd-", type, 8) == 0)
 			md->fstab->fs_vfstype = strdup(&type[8]);
 		else if (strcmp("fat32", type) == 0 || strcmp("efi", type) == 0
 	     	    || strcmp("ms-basic-data", type) == 0)
 			md->fstab->fs_vfstype = strdup("msdosfs");
 		else
 			md->fstab->fs_vfstype = strdup(type); /* Guess */
 		if (strcmp(type, "freebsd-swap") == 0) {
 			md->fstab->fs_type = strdup(FSTAB_SW);
 			md->fstab->fs_freq = 0;
 			md->fstab->fs_passno = 0;
 		} else if (strcmp(type, "freebsd-zfs") == 0) {
 			md->fstab->fs_type = strdup(FSTAB_RW);
 			md->fstab->fs_freq = 0;
 			md->fstab->fs_passno = 0;
 		} else {
 			md->fstab->fs_type = strdup(FSTAB_RW);
 			if (strcmp(mountpoint, "/") == 0) {
 				md->fstab->fs_freq = 1;
 				md->fstab->fs_passno = 1;
 			} else {
 				md->fstab->fs_freq = 2;
 				md->fstab->fs_passno = 2;
 			}
 		}
 		md->fstab->fs_mntops = strdup(md->fstab->fs_type);
 	}
 
 	if (zpool_name != NULL)
 		free(zpool_name);
 }
 
 static
 int part_compare(const void *xa, const void *xb)
 {
 	struct gprovider **a = (struct gprovider **)xa;
 	struct gprovider **b = (struct gprovider **)xb;
 	intmax_t astart, bstart;
 	struct gconfig *gc;
 	
 	astart = bstart = 0;
 	LIST_FOREACH(gc, &(*a)->lg_config, lg_config)
 		if (strcmp(gc->lg_name, "start") == 0) {
 			astart = strtoimax(gc->lg_val, NULL, 0);
 			break;
 		}
 	LIST_FOREACH(gc, &(*b)->lg_config, lg_config)
 		if (strcmp(gc->lg_name, "start") == 0) {
 			bstart = strtoimax(gc->lg_val, NULL, 0);
 			break;
 		}
 
 	if (astart < bstart)
 		return -1;
 	else if (astart > bstart)
 		return 1;
 	else
 		return 0;
 }
 
 intmax_t
 gpart_max_free(struct ggeom *geom, intmax_t *npartstart)
 {
 	struct gconfig *gc;
 	struct gprovider *pp, **providers;
 	intmax_t sectorsize, stripesize, offset;
 	intmax_t lastend;
 	intmax_t start, end;
 	intmax_t maxsize, maxstart;
 	intmax_t partstart, partend;
 	int i, nparts;
 
 	/* Now get the maximum free size and free start */
 	start = end = 0;
 	LIST_FOREACH(gc, &geom->lg_config, lg_config) {
 		if (strcmp(gc->lg_name, "first") == 0)
 			start = strtoimax(gc->lg_val, NULL, 0);
 		if (strcmp(gc->lg_name, "last") == 0)
 			end = strtoimax(gc->lg_val, NULL, 0);
 	}
 
 	i = nparts = 0;
 	LIST_FOREACH(pp, &geom->lg_provider, lg_provider)
 		nparts++;
 	providers = calloc(nparts, sizeof(providers[0]));
 	LIST_FOREACH(pp, &geom->lg_provider, lg_provider)
 		providers[i++] = pp;
 	qsort(providers, nparts, sizeof(providers[0]), part_compare);
 
 	lastend = start - 1;
 	maxsize = 0;
 	for (i = 0; i < nparts; i++) {
 		pp = providers[i];
 
 		LIST_FOREACH(gc, &pp->lg_config, lg_config) {
 			if (strcmp(gc->lg_name, "start") == 0)
 				partstart = strtoimax(gc->lg_val, NULL, 0);
 			if (strcmp(gc->lg_name, "end") == 0)
 				partend = strtoimax(gc->lg_val, NULL, 0);
 		}
 
 		if (partstart - lastend > maxsize) {
 			maxsize = partstart - lastend - 1;
 			maxstart = lastend + 1;
 		}
 
 		lastend = partend;
 	}
 
 	if (end - lastend > maxsize) {
 		maxsize = end - lastend;
 		maxstart = lastend + 1;
 	}
 
 	pp = LIST_FIRST(&geom->lg_consumer)->lg_provider;
 
 	/*
 	 * Round the start and size of the largest available space up to
 	 * the nearest multiple of the adjusted stripe size.
 	 *
 	 * The adjusted stripe size is the least common multiple of the
 	 * actual stripe size, or the sector size if no stripe size was
 	 * reported, and 4096.  The reason for this is that contemporary
 	 * disks often have 4096-byte physical sectors but report 512
 	 * bytes instead for compatibility with older / broken operating
 	 * systems and BIOSes.  For the same reasons, virtualized storage
 	 * may also report a 512-byte stripe size, or none at all.
 	 */
 	sectorsize = pp->lg_sectorsize;
 	if ((stripesize = pp->lg_stripesize) == 0)
 		stripesize = sectorsize;
 	while (stripesize % 4096 != 0)
 		stripesize *= 2;
 	if ((offset = maxstart * sectorsize % stripesize) != 0) {
 		offset = (stripesize - offset) / sectorsize;
 		maxstart += offset;
 		maxsize -= offset;
 	}
 
 	if (npartstart != NULL)
 		*npartstart = maxstart;
 
 	return (maxsize);
 }
 
 static size_t
 add_boot_partition(struct ggeom *geom, struct gprovider *pp,
     const char *scheme, int interactive)
 {
 	struct gconfig *gc;
 	struct gprovider *ppi;
 	int choice;
 
 	/* Check for existing freebsd-boot partition */
 	LIST_FOREACH(ppi, &geom->lg_provider, lg_provider) {
 		struct partition_metadata *md;
 		const char *bootmount = NULL;
 
 		LIST_FOREACH(gc, &ppi->lg_config, lg_config)
 			if (strcmp(gc->lg_name, "type") == 0)
 				break;
 		if (gc == NULL)
 			continue;
 		if (strcmp(gc->lg_val, bootpart_type(scheme, &bootmount)) != 0)
 			continue;
 
 		/*
 		 * If the boot partition is not mountable and needs partcode,
 		 * but doesn't have it, it doesn't satisfy our requirements.
 		 */
 		md = get_part_metadata(ppi->lg_name, 0);
 		if (bootmount == NULL && (md == NULL || !md->bootcode))
 			continue;
 
 		/* If it is mountable, but mounted somewhere else, remount */
 		if (bootmount != NULL && md != NULL && md->fstab != NULL
 		    && strlen(md->fstab->fs_file) > 0
 		    && strcmp(md->fstab->fs_file, bootmount) != 0)
 			continue;
 
 		/* If it is mountable, but mountpoint is not set, mount it */
 		if (bootmount != NULL && md == NULL)
 			set_default_part_metadata(ppi->lg_name, scheme,
 			    gc->lg_val, bootmount, NULL);
 		
 		/* Looks good at this point, no added data needed */
 		return (0);
 	}
 
 	if (interactive)
 		choice = dialog_yesno("Boot Partition",
 		    "This partition scheme requires a boot partition "
 		    "for the disk to be bootable. Would you like to "
 		    "make one now?", 0, 0);
 	else
 		choice = 0;
 
 	if (choice == 0) { /* yes */
 		struct partition_metadata *md;
 		const char *bootmount = NULL;
 		char *bootpartname = NULL;
 		char sizestr[7];
 
 		humanize_number(sizestr, 7,
 		    bootpart_size(scheme), "B", HN_AUTOSCALE,
 		    HN_NOSPACE | HN_DECIMAL);
 
 		gpart_create(pp, bootpart_type(scheme, &bootmount),
 		    sizestr, bootmount, &bootpartname, 0);
 
 		if (bootpartname == NULL) /* Error reported to user already */
 			return 0;
 
 		/* If the part is not mountable, make sure newfs isn't set */
 		if (bootmount == NULL) {
 			md = get_part_metadata(bootpartname, 0);
 			if (md != NULL && md->newfs != NULL) {
 				free(md->newfs);
 				md->newfs = NULL;
 			}
 		}
 
 		free(bootpartname);
 
 		return (bootpart_size(scheme));
 	}
 	
 	return (0);
 }
 
 void
 gpart_create(struct gprovider *pp, const char *default_type,
     const char *default_size, const char *default_mountpoint,
     char **partname, int interactive)
 {
 	struct gctl_req *r;
 	struct gconfig *gc;
 	struct gconsumer *cp;
 	struct ggeom *geom;
 	const char *errstr, *scheme;
 	char sizestr[32], startstr[32], output[64], *newpartname;
 	char newfs[255], options_fstype[64];
 	intmax_t maxsize, size, sector, firstfree, stripe;
 	uint64_t bytes;
 	int nitems, choice, junk;
 	unsigned i;
 
 	DIALOG_FORMITEM items[] = {
 		{0, "Type:", 5, 0, 0, FALSE, "freebsd-ufs", 11, 0, 12, 15, 0,
 		    FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, "
 		    "freebsd-swap)", FALSE},
 		{0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 15, 0,
 		    FALSE, "Partition size. Append K, M, G for kilobytes, "
 		    "megabytes or gigabytes.", FALSE},
 		{0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0,
 		    FALSE, "Path at which to mount partition (blank for "
 		    "swap, / for root filesystem)", FALSE},
 		{0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE,
 		    "Partition name. Not all partition schemes support this.",
 		    FALSE},
 	};
 
 	if (partname != NULL)
 		*partname = NULL;
 
 	/* Record sector and stripe sizes */
 	sector = pp->lg_sectorsize;
 	stripe = pp->lg_stripesize;
 
 	/*
 	 * Find the PART geom we are manipulating. This may be a consumer of
 	 * this provider, or its parent. Check the consumer case first.
 	 */
 	geom = NULL;
 	LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
 		if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
 			geom = cp->lg_geom;
 			break;
 		}
 
 	if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0)
 		geom = pp->lg_geom;
 
 	/* Now get the partition scheme */
 	scheme = NULL;
 	if (geom != NULL) {
 		LIST_FOREACH(gc, &geom->lg_config, lg_config) 
 			if (strcmp(gc->lg_name, "scheme") == 0)
 				scheme = gc->lg_val;
 	}
 
 	if (geom == NULL || scheme == NULL || strcmp(scheme, "(none)") == 0) {
 		if (gpart_partition(pp->lg_name, NULL) == 0)
 			dialog_msgbox("",
 			    "The partition table has been successfully created."
 			    " Please press Create again to create partitions.",
 			    0, 0, TRUE);
 
 		return;
 	}
 
 	/*
 	 * If we still don't have a geom, either the user has
 	 * canceled partitioning or there has been an error which has already
 	 * been displayed, so bail.
 	 */
 	if (geom == NULL)
 		return;
 
 	maxsize = size = gpart_max_free(geom, &firstfree);
 	if (size <= 0) {
 		dialog_msgbox("Error", "No free space left on device.", 0, 0,
 		    TRUE);
 		return;
 	}
 
 	humanize_number(sizestr, 7, size*sector, "B", HN_AUTOSCALE,
 	    HN_NOSPACE | HN_DECIMAL);
 	items[1].text = sizestr;
 
 	/* Special-case the MBR default type for nested partitions */
 	if (strcmp(scheme, "MBR") == 0) {
 		items[0].text = "freebsd";
 		items[0].help = "Filesystem type (e.g. freebsd, fat32)";
 	}
 
 	nitems = scheme_supports_labels(scheme) ? 4 : 3;
 
 	if (default_type != NULL)
 		items[0].text = (char *)default_type;
 	if (default_size != NULL)
 		items[1].text = (char *)default_size;
 	if (default_mountpoint != NULL)
 		items[2].text = (char *)default_mountpoint;
 
 	/* Default options */
 	strncpy(options_fstype, items[0].text,
 	    sizeof(options_fstype));
 	newfs_command(options_fstype, newfs, 1);
 addpartform:
 	if (interactive) {
 		dialog_vars.extra_label = "Options";
 		dialog_vars.extra_button = TRUE;
 		choice = dlg_form("Add Partition", "", 0, 0, 0, nitems,
 		    items, &junk);
 		dialog_vars.extra_button = FALSE;
 		switch (choice) {
 		case 0: /* OK */
 			break;
 		case 1: /* Cancel */
 			return;
 		case 3: /* Options */
 			strncpy(options_fstype, items[0].text,
 			    sizeof(options_fstype));
 			newfs_command(options_fstype, newfs, 0);
 			goto addpartform;
 		}
 	}
 
 	/*
 	 * If the user changed the fs type after specifying options, undo
 	 * their choices in favor of the new filesystem's defaults.
 	 */
 	if (strcmp(options_fstype, items[0].text) != 0) {
 		strncpy(options_fstype, items[0].text, sizeof(options_fstype));
 		newfs_command(options_fstype, newfs, 1);
 	}
 
 	size = maxsize;
 	if (strlen(items[1].text) > 0) {
 		if (expand_number(items[1].text, &bytes) != 0) {
 			char error[512];
 
 			sprintf(error, "Invalid size: %s\n", strerror(errno));
 			dialog_msgbox("Error", error, 0, 0, TRUE);
 			goto addpartform;
 		}
 		size = MIN((intmax_t)(bytes/sector), maxsize);
 	}
 
 	/* Check if the label has a / in it */
 	if (strchr(items[3].text, '/') != NULL) {
 		dialog_msgbox("Error", "Label contains a /, which is not an "
 		    "allowed character.", 0, 0, TRUE);
 		goto addpartform;
 	}
 
 	/* Warn if no mountpoint set */
 	if (strcmp(items[0].text, "freebsd-ufs") == 0 &&
 	    items[2].text[0] != '/') {
 		choice = 0;
 		if (interactive) {
 			dialog_vars.defaultno = TRUE;
 			choice = dialog_yesno("Warning",
 			    "This partition does not have a valid mountpoint "
 			    "(for the partition from which you intend to boot the "
 			    "operating system, the mountpoint should be /). Are you "
 			    "sure you want to continue?"
 			, 0, 0);
 			dialog_vars.defaultno = FALSE;
 		}
 		if (choice == 1) /* cancel */
 			goto addpartform;
 	}
 
 	/*
 	 * Error if this scheme needs nested partitions, this is one, and
 	 * a mountpoint was set.
 	 */
 	if (strcmp(items[0].text, "freebsd") == 0 &&
 	    strlen(items[2].text) > 0) {
 		dialog_msgbox("Error", "Partitions of type \"freebsd\" are "
 		    "nested BSD-type partition schemes and cannot have "
 		    "mountpoints. After creating one, select it and press "
 		    "Create again to add the actual file systems.", 0, 0, TRUE);
 		goto addpartform;
 	}
 
 	/* If this is the root partition, check that this scheme is bootable */
 	if (strcmp(items[2].text, "/") == 0 && !is_scheme_bootable(scheme)) {
 		char message[512];
 		sprintf(message, "This partition scheme (%s) is not bootable "
 		    "on this platform. Are you sure you want to proceed?",
 		    scheme);
 		dialog_vars.defaultno = TRUE;
 		choice = dialog_yesno("Warning", message, 0, 0);
 		dialog_vars.defaultno = FALSE;
 		if (choice == 1) /* cancel */
 			goto addpartform;
 	}
 
 	/* If this is the root partition, check that this fs is bootable */
 	if (strcmp(items[2].text, "/") == 0 && !is_fs_bootable(scheme,
 	    items[0].text)) {
 		char message[512];
 		sprintf(message, "This file system (%s) is not bootable "
 		    "on this system. Are you sure you want to proceed?",
 		    items[0].text);
 		dialog_vars.defaultno = TRUE;
 		choice = dialog_yesno("Warning", message, 0, 0);
 		dialog_vars.defaultno = FALSE;
 		if (choice == 1) /* cancel */
 			goto addpartform;
 	}
 
 	/*
 	 * If this is the root partition, and we need a boot partition, ask
 	 * the user to add one.
 	 */
 
 	if ((strcmp(items[0].text, "freebsd") == 0 ||
 	    strcmp(items[2].text, "/") == 0) && bootpart_size(scheme) > 0) {
 		size_t bytes = add_boot_partition(geom, pp, scheme,
 		    interactive);
 
 		/* Now adjust the part we are really adding forward */
 		if (bytes > 0) {
 			firstfree += bytes / sector;
 			size -= (bytes + stripe)/sector;
 			if (stripe > 0 && (firstfree*sector % stripe) != 0) 
 				firstfree += (stripe - ((firstfree*sector) %
 				    stripe)) / sector;
 		}
 	}
 
 	r = gctl_get_handle();
 	gctl_ro_param(r, "class", -1, "PART");
 	gctl_ro_param(r, "arg0", -1, geom->lg_name);
 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
 	gctl_ro_param(r, "verb", -1, "add");
 
 	gctl_ro_param(r, "type", -1, items[0].text);
 	snprintf(sizestr, sizeof(sizestr), "%jd", size);
 	gctl_ro_param(r, "size", -1, sizestr);
 	snprintf(startstr, sizeof(startstr), "%jd", firstfree);
 	gctl_ro_param(r, "start", -1, startstr);
 	if (items[3].text[0] != '\0')
 		gctl_ro_param(r, "label", -1, items[3].text);
 	gctl_rw_param(r, "output", sizeof(output), output);
 	errstr = gctl_issue(r);
 	if (errstr != NULL && errstr[0] != '\0') {
 		gpart_show_error("Error", NULL, errstr);
 		gctl_free(r);
 		goto addpartform;
 	}
 	newpartname = strtok(output, " ");
 	gctl_free(r);
 
 	/*
 	 * Try to destroy any geom that gpart picked up already here from
 	 * dirty blocks.
 	 */
 	r = gctl_get_handle();
 	gctl_ro_param(r, "class", -1, "PART");
 	gctl_ro_param(r, "arg0", -1, newpartname);
 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
 	junk = 1;
 	gctl_ro_param(r, "force", sizeof(junk), &junk);
 	gctl_ro_param(r, "verb", -1, "destroy");
 	gctl_issue(r); /* Error usually expected and non-fatal */
 	gctl_free(r);
 
 
 	if (strcmp(items[0].text, "freebsd") == 0)
 		gpart_partition(newpartname, "BSD");
 	else
 		set_default_part_metadata(newpartname, scheme,
 		    items[0].text, items[2].text, newfs);
 
 	for (i = 0; i < nitems(items); i++)
 		if (items[i].text_free)
 			free(items[i].text);
 
 	if (partname != NULL)
 		*partname = strdup(newpartname);
 }
 	
 void
 gpart_delete(struct gprovider *pp)
 {
 	struct gconfig *gc;
 	struct ggeom *geom;
 	struct gconsumer *cp;
 	struct gctl_req *r;
 	const char *errstr;
 	intmax_t idx;
 	int is_partition;
 
 	/* Is it a partition? */
 	is_partition = (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0);
 
 	/* Find out if this is the root of a gpart geom */
 	geom = NULL;
 	LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
 		if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
 			geom = cp->lg_geom;
 			break;
 		}
 
 	/* If so, destroy all children */
 	if (geom != NULL) {
 		gpart_destroy(geom);
 
 		/* If this is a partition, revert it, so it can be deleted */
 		if (is_partition) {
 			r = gctl_get_handle();
 			gctl_ro_param(r, "class", -1, "PART");
 			gctl_ro_param(r, "arg0", -1, geom->lg_name);
 			gctl_ro_param(r, "verb", -1, "undo");
 			gctl_issue(r); /* Ignore non-fatal errors */
 			gctl_free(r);
 		}
 	}
 
 	/*
 	 * If this is not a partition, see if that is a problem, complain if
 	 * necessary, and return always, since we need not do anything further,
 	 * error or no.
 	 */
 	if (!is_partition) {
 		if (geom == NULL)
 			dialog_msgbox("Error",
 			    "Only partitions can be deleted.", 0, 0, TRUE);
 		return;
 	}
 
 	r = gctl_get_handle();
 	gctl_ro_param(r, "class", -1, pp->lg_geom->lg_class->lg_name);
 	gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name);
 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
 	gctl_ro_param(r, "verb", -1, "delete");
 
 	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
 		if (strcmp(gc->lg_name, "index") == 0) {
 			idx = atoi(gc->lg_val);
 			gctl_ro_param(r, "index", sizeof(idx), &idx);
 			break;
 		}
 	}
 
 	errstr = gctl_issue(r);
 	if (errstr != NULL && errstr[0] != '\0') {
 		gpart_show_error("Error", NULL, errstr);
 		gctl_free(r);
 		return;
 	}
 
 	gctl_free(r);
 
 	delete_part_metadata(pp->lg_name);
 }
 
 void
 gpart_revert_all(struct gmesh *mesh)
 {
 	struct gclass *classp;
 	struct gconfig *gc;
 	struct ggeom *gp;
 	struct gctl_req *r;
 	const char *modified;
 
 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
 		if (strcmp(classp->lg_name, "PART") == 0)
 			break;
 	}
 
 	if (strcmp(classp->lg_name, "PART") != 0) {
 		dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE);
 		return;
 	}
 
 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
 		modified = "true"; /* XXX: If we don't know (kernel too old),
 				    * assume there are modifications. */
 		LIST_FOREACH(gc, &gp->lg_config, lg_config) {
 			if (strcmp(gc->lg_name, "modified") == 0) {
 				modified = gc->lg_val;
 				break;
 			}
 		}
 
 		if (strcmp(modified, "false") == 0)
 			continue;
 
 		r = gctl_get_handle();
 		gctl_ro_param(r, "class", -1, "PART");
 		gctl_ro_param(r, "arg0", -1, gp->lg_name);
 		gctl_ro_param(r, "verb", -1, "undo");
 
 		gctl_issue(r);
 		gctl_free(r);
 	}
 }
 
 void
 gpart_commit(struct gmesh *mesh)
 {
 	struct partition_metadata *md;
 	struct gclass *classp;
 	struct ggeom *gp;
 	struct gconfig *gc;
 	struct gconsumer *cp;
 	struct gprovider *pp;
 	struct gctl_req *r;
 	const char *errstr;
 	const char *modified;
 	const char *rootfs;
 
 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
 		if (strcmp(classp->lg_name, "PART") == 0)
 			break;
 	}
 
 	/* Figure out what filesystem / uses */
 	rootfs = "ufs"; /* Assume ufs if nothing else present */
 	TAILQ_FOREACH(md, &part_metadata, metadata) {
 		if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0) {
 			rootfs = md->fstab->fs_vfstype;
 			break;
 		}
 	}
 
 	if (strcmp(classp->lg_name, "PART") != 0) {
 		dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE);
 		return;
 	}
 
 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
 		modified = "true"; /* XXX: If we don't know (kernel too old),
 				    * assume there are modifications. */
 		LIST_FOREACH(gc, &gp->lg_config, lg_config) {
 			if (strcmp(gc->lg_name, "modified") == 0) {
 				modified = gc->lg_val;
 				break;
 			}
 		}
 
 		if (strcmp(modified, "false") == 0)
 			continue;
 
 		/* Add bootcode if necessary, before the commit */
 		md = get_part_metadata(gp->lg_name, 0);
 		if (md != NULL && md->bootcode)
 			gpart_bootcode(gp);
 
 		/* Now install partcode on its partitions, if necessary */
 		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
 			md = get_part_metadata(pp->lg_name, 0);
 			if (md == NULL || !md->bootcode)
 				continue;
 		
 			/* Mark this partition active if that's required */
 			gpart_activate(pp);
 
 			/* Check if the partition has sub-partitions */
 			LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
 				if (strcmp(cp->lg_geom->lg_class->lg_name,
 				    "PART") == 0)
 					break;
 
 			if (cp == NULL) /* No sub-partitions */
 				gpart_partcode(pp, rootfs);
 		}
 
 		r = gctl_get_handle();
 		gctl_ro_param(r, "class", -1, "PART");
 		gctl_ro_param(r, "arg0", -1, gp->lg_name);
 		gctl_ro_param(r, "verb", -1, "commit");
 
 		errstr = gctl_issue(r);
 		if (errstr != NULL && errstr[0] != '\0') 
 			gpart_show_error("Error", NULL, errstr);
 		gctl_free(r);
 	}
 }
 
diff --git a/usr.sbin/bsdinstall/partedit/partedit_efi.c b/usr.sbin/bsdinstall/partedit/partedit_efi.c
index 85b3b15d1853..074475e07152 100644
--- a/usr.sbin/bsdinstall/partedit/partedit_efi.c
+++ b/usr.sbin/bsdinstall/partedit/partedit_efi.c
@@ -1,105 +1,106 @@
 /*
  * Copyright (C) 2016 Cavium Inc.
  * All rights reserved.
  *
  * Developed by Semihalf.
  * Based on work by Nathan Whitehorn.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #include <sys/types.h>
 #include <string.h>
 
 #include "partedit.h"
 
 /*
  * partedit implementation for platforms on which the installer only offers
  * UEFI-based boot. Currently, this includes arm64 and RISC-V.
  */
 
 /* EFI partition size in bytes */
 #define	EFI_BOOTPART_SIZE	(260 * 1024 * 1024)
 
 const char *
 default_scheme(void)
 {
 
 	return ("GPT");
 }
 
 int
 is_scheme_bootable(const char *part_type)
 {
 
 	if (strcmp(part_type, "GPT") == 0)
 		return (1);
 
 	return (0);
 }
 
 int
 is_fs_bootable(const char *part_type, const char *fs)
 {
 
 	if (strcmp(fs, "freebsd-ufs") == 0)
 		return (1);
 
 	return (0);
 }
 
 size_t
 bootpart_size(const char *scheme)
 {
 
 	/* We only support GPT with EFI */
 	if (strcmp(scheme, "GPT") != 0)
 		return (0);
 
 	return (EFI_BOOTPART_SIZE);
 }
 
 const char *
 bootpart_type(const char *scheme, const char **mountpoint)
 {
 
 	/* Only EFI is supported as boot partition */
+	*mountpoint = "/boot/efi";
 	return ("efi");
 }
 
 const char *
 bootcode_path(const char *part_type)
 {
 
 	return (NULL);
 }
 
 const char *
 partcode_path(const char *part_type, const char *fs_type)
 {
 
 	/* No boot partition data. */
 	return (NULL);
 }
 
diff --git a/usr.sbin/bsdinstall/partedit/partedit_x86.c b/usr.sbin/bsdinstall/partedit/partedit_x86.c
index e81adcad5f6b..6983188ba34f 100644
--- a/usr.sbin/bsdinstall/partedit/partedit_x86.c
+++ b/usr.sbin/bsdinstall/partedit/partedit_x86.c
@@ -1,153 +1,155 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2011 Nathan Whitehorn
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #include <sys/types.h>
 #include <sys/sysctl.h>
 #include <string.h>
 
 #include "partedit.h"
 
 /* EFI partition size in bytes */
 #define	EFI_BOOTPART_SIZE	(260 * 1024 * 1024)
 
 static const char *
 x86_bootmethod(void)
 {
 	static char fw[255] = "";
 	size_t len = sizeof(fw);
 	int error;
 	
 	if (strlen(fw) == 0) {
 		error = sysctlbyname("machdep.bootmethod", fw, &len, NULL, -1);
 		if (error != 0)
 			return ("BIOS");
 	}
 
 	return (fw);
 }
 
 const char *
 default_scheme(void)
 {
 	if (strcmp(x86_bootmethod(), "UEFI") == 0)
 		return ("GPT");
 	else
 		return ("MBR");
 }
 
 int
 is_scheme_bootable(const char *part_type)
 {
 
 	if (strcmp(part_type, "GPT") == 0)
 		return (1);
 	if (strcmp(x86_bootmethod(), "BIOS") == 0) {
 		if (strcmp(part_type, "BSD") == 0)
 			return (1);
 		if (strcmp(part_type, "MBR") == 0)
 			return (1);
 	}
 
 	return (0);
 }
 
 int
 is_fs_bootable(const char *part_type, const char *fs)
 {
 
 	if (strcmp(fs, "freebsd-ufs") == 0)
 		return (1);
 
 	if (strcmp(fs, "freebsd-zfs") == 0 &&
 	    strcmp(part_type, "GPT") == 0 &&
 	    strcmp(x86_bootmethod(), "BIOS") == 0)
 		return (1);
 
 	return (0);
 }
 
 size_t
 bootpart_size(const char *scheme)
 {
 
 	/* No partcode except for GPT */
 	if (strcmp(scheme, "GPT") != 0)
 		return (0);
 
 	if (strcmp(x86_bootmethod(), "BIOS") == 0)
 		return (512*1024);
 	else 
 		return (EFI_BOOTPART_SIZE);
 
 	return (0);
 }
 
 const char *
 bootpart_type(const char *scheme, const char **mountpoint)
 {
 
-	if (strcmp(x86_bootmethod(), "UEFI") == 0)
+	if (strcmp(x86_bootmethod(), "UEFI") == 0) {
+		*mountpoint = "/boot/efi";
 		return ("efi");
+	}
 
 	return ("freebsd-boot");
 }
 
 const char *
 bootcode_path(const char *part_type)
 {
 
 	if (strcmp(x86_bootmethod(), "UEFI") == 0)
 		return (NULL);
 
 	if (strcmp(part_type, "GPT") == 0)
 		return ("/boot/pmbr");
 	if (strcmp(part_type, "MBR") == 0)
 		return ("/boot/mbr");
 	if (strcmp(part_type, "BSD") == 0)
 		return ("/boot/boot");
 
 	return (NULL);
 }
 	
 const char *
 partcode_path(const char *part_type, const char *fs_type)
 {
 
 	if (strcmp(part_type, "GPT") == 0 && strcmp(x86_bootmethod(), "UEFI") != 0) {
 		if (strcmp(fs_type, "zfs") == 0)
 			return ("/boot/gptzfsboot");
 		else
 			return ("/boot/gptboot");
 	}
 	
 	/* No partcode except for non-UEFI GPT */
 	return (NULL);
 }
 
diff --git a/usr.sbin/bsdinstall/scripts/bootconfig b/usr.sbin/bsdinstall/scripts/bootconfig
index f07fb3065c23..a592142d87a2 100755
--- a/usr.sbin/bsdinstall/scripts/bootconfig
+++ b/usr.sbin/bsdinstall/scripts/bootconfig
@@ -1,190 +1,92 @@
 #!/bin/sh
 #-
 # Copyright (c) 2018 Rebecca Cran
 # Copyright (c) 2017 Nathan Whitehorn
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
 # are met:
 # 1. Redistributions of source code must retain the above copyright
 #    notice, this list of conditions and the following disclaimer.
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
 #
 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
 # $FreeBSD$
 
 BSDCFG_SHARE="/usr/share/bsdconfig"
 . $BSDCFG_SHARE/common.subr || exit 1
 
 : ${TMPDIR:="/tmp"}
 
 die() {
 	echo $*
 	exit 1
 }
 
 if [ `uname -m` == powerpc ]; then
 	platform=`sysctl -n hw.platform`
 	if [ "$platform" == ps3 -o "$platform" == powernv ]; then
 		rootpart=$(awk '{ if($2 == "/") printf("%s:%s\n", $3, $1); }' $PATH_FSTAB)
 		mkdir -p $BSDINSTALL_CHROOT/boot/etc/
 		echo FreeBSD=\'/kernel/kernel kernelname=/boot/kernel/kernel vfs.root.mountfrom=${rootpart}\' > $BSDINSTALL_CHROOT/boot/etc/kboot.conf
 	fi
 fi
 
-# Update the ESP (EFI System Partition) with the new bootloader
-if [ "$(uname -m)" = "amd64" ] || [ "$(uname -m)" = "i386" ]; then
-	X86_BOOTMETHOD=$(sysctl -n machdep.bootmethod)
-fi
-
-if [ "$(uname -m)" = "arm64" ] || [ "$(uname -m)" = "riscv" ] || [ "$X86_BOOTMETHOD" = "UEFI" ]; then
-	UFSBOOT_ESPS=$(cat $TMPDIR/bsdinstall-esps 2>/dev/null)
-	ZFSBOOT_DISKS=$(cat $TMPDIR/bsdinstall-zfsboot 2>/dev/null)
-	num_esps=0
-
-	if [ -n "$ZFSBOOT_DISKS" ]; then
-		# We're in a ZFS install environment
-		for disk in $ZFSBOOT_DISKS; do
-			index=$(gpart show "$disk" | cut -w -f 4,5 | grep "efi" | cut -w -f 1)
-			# Check that $index is an integer
-			[ -n "$index" ] && [ "$index" -eq "$index" ] && [ "$index" -ge 0 ] 2> /dev/null
-			if [ $? -ne 0 ]; then
-				continue
-			fi
-
-			if [ -e "/dev/${disk}p${index}" ]; then
-				ESPS="$ESPS ${disk}p${index}"
-			elif [ -e "/dev/${disk}s${index}" ]; then
-				ESPS="$ESPS ${disk}s${index}"
-			else
-				continue
-			fi
-
-			num_esps=$((num_esps + 1))
-		done
-	fi
-
-	if [ -n "$UFSBOOT_ESPS" ]; then
-		# We're in a UFS install environment
-		for partition in $UFSBOOT_ESPS; do
-			ESPS="$ESPS $partition"
-			num_esps=$((num_esps + 1))
-		done
-	fi
-
-	if [ -z "$ESPS" ]; then
-		# The installer hasn't given us any ESPs to use.
-		# Try and figure out which to use by looking for an
-		# unformatted efi partition
-
-		for geom in $(gpart status -sg | awk '{print $1}'); do
-			hasfreebsd=$(gpart show "${geom}" | cut -w -f 4,5 | grep "freebsd")
-			if [ -n "$hasfreebsd" ]; then
-				index=$(gpart show "${geom}" | cut -w -f 4,5 | grep "efi" | cut -w -f 1)
-				# Check that $index is a valid integer
-				[ -n "$index" ] && [ "$index" -eq "$index" ] && [ "$index" -ge 0 ] 2> /dev/null 
-				if [ $? -ne 0 ]; then
-					continue
-				fi
-
-				mntpt=$(mktemp -d $TMPDIR/stand-test.XXXXXX)
-				if [ -e "/dev/${geom}p${index}" ]; then
-					dev=${geom}p${index}
-				elif [ -e "/dev/${geom}s${index}" ]; then
-					dev=/${geom}s${index}
-				else
-					continue
-				fi
-
-				# Try and mount it. If it fails, assume it's
-				# unformatted and should be used.
-				mount -t msdosfs -o ro "/dev/${dev}" "${mntpt}"
-				if [ $? -ne 0 ]; then
-					ESPS="$ESPS ${dev}"
-					num_esps=$((num_esps + 1))
-				else
-					umount "${mntpt}"
-				fi
-				rmdir "${mntpt}"
-			fi
-		done
-	fi
-
+# Update the ESP (EFI System Partition) with the new bootloader if we have an ESP
+if [ -n "$(awk '{if ($2=="/boot/efi") printf("%s\n",$1);}' $PATH_FSTAB)" ]; then
 	case $(uname -m) in
 	    arm64)	ARCHBOOTNAME=aa64 ;;
 	    amd64)	ARCHBOOTNAME=x64 ;;
 	    riscv)	ARCHBOOTNAME=riscv64 ;;
     #	    arm)	ARCHBOOTNAME=arm ;; # No other support for arm install
     #	    i386)	ARCHBOOTNAME=ia32 ;; # no support for this in i386 kernels, rare machines
 	    *)		die "Unsupported arch $(uname -m) for UEFI install"
 	esac
 	BOOTDIR="/efi/boot"
 	BOOTNAME="${BOOTDIR}/boot${ARCHBOOTNAME}.efi"
 	FREEBSD_BOOTDIR="/efi/freebsd"
 	FREEBSD_BOOTNAME="${FREEBSD_BOOTDIR}/loader.efi"
+	mntpt="$BSDINSTALL_CHROOT/boot/efi"
+
+	f_dprintf "Installing loader.efi onto ESP"
+	mkdir -p "${mntpt}/${FREEBSD_BOOTDIR}" "${mntpt}/${BOOTDIR}"
+	cp "$BSDINSTALL_CHROOT/boot/loader.efi" "${mntpt}/${FREEBSD_BOOTNAME}"
+
+	#
+	# The following shouldn't be necessary. UEFI defines a way to
+	# specifically select what to boot (which we do via
+	# efibootmgr). However, virtual environments often times lack
+	# support for the NV variables efibootmgr sets. In addition,
+	# some UEFI implementations have features that interfere with
+	# the setting of these variables. To combat that, we install the
+	# default removable media boot file as a fallback if it doesn't
+	# exist. We don't install it all the time since that can
+	# interfere with other installations on the drive (like rEFInd).
+	#
+	if [ ! -f "${mntpt}/${BOOTNAME}" ]; then
+		cp "$BSDINSTALL_CHROOT/boot/loader.efi" "${mntpt}/${BOOTNAME}"
+	fi
 
-	for esp in $ESPS; do
-		f_dprintf "Formatting /dev/${esp} as FAT32"
-		newfs_msdos -F 32 -c 1 -L EFISYS "/dev/$esp" > /dev/null 2>&1
-		if [ $? -ne 0 ]; then
-			die "Failed to format ESP $esp as FAT32"
-		fi
-
-		mntpt=$(mktemp -d $TMPDIR/stand-test.XXXXXX)
-		f_dprintf "Mounting ESP /dev/${esp}"
-		mount -t msdosfs "/dev/${esp}" "${mntpt}"
-		if [ $? -ne 0 ]; then
-			die "Failed to mount ESP ${dev} on ${mntpt}"
-		fi
-
-		f_dprintf "Installing loader.efi onto ESP"
-		mkdir -p "${mntpt}/${FREEBSD_BOOTDIR}" "${mntpt}/${BOOTDIR}"
-		cp "$BSDINSTALL_CHROOT/boot/loader.efi" "${mntpt}/${FREEBSD_BOOTNAME}"
-
-		#
-		# The following shouldn't be necessary. UEFI defines a way to
-		# specifically select what to boot (which we do via
-		# efibootmgr). However, virtual environments often times lack
-		# support for the NV variables efibootmgr sets. In addition,
-		# some UEFI implementations have features that interfere with
-		# the setting of these variables. To combat that, we install the
-		# default removable media boot file as a fallback if it doesn't
-		# exist. We don't install it all the time since that can
-		# interfere with other installations on the drive (like rEFInd).
-		#
-		if [ ! -f "${mntpt}/${BOOTNAME}" ]; then
-			cp "$BSDINSTALL_CHROOT/boot/loader.efi" "${mntpt}/${BOOTNAME}"
-		fi
-
-		if [ "$num_esps" -gt 1 ]; then
-			bootlabel="FreeBSD (${esp})"
-		else
-			bootlabel="FreeBSD"
-		fi
-
-		f_dprintf "Creating UEFI boot entry"
-		efibootmgr --create --activate --label "$bootlabel" --loader "${mntpt}/${FREEBSD_BOOTNAME}" > /dev/null
+	bootlabel="FreeBSD"
 
-		f_dprintf "Unmounting ESP"
-		umount "${mntpt}"
-		rmdir "${mntpt}"
+	f_dprintf "Creating UEFI boot entry"
+	efibootmgr --create --activate --label "$bootlabel" --loader "${mntpt}/${FREEBSD_BOOTNAME}" > /dev/null
 
-		f_dprintf "Finished configuring /dev/${esp} as ESP"
-	done
+	f_dprintf "Finished configuring ESP"
 fi
 
 # Add boot0cfg for MBR BIOS booting?
diff --git a/usr.sbin/bsdinstall/scripts/zfsboot b/usr.sbin/bsdinstall/scripts/zfsboot
index 33cec0ef9ae9..3b673addb10a 100755
--- a/usr.sbin/bsdinstall/scripts/zfsboot
+++ b/usr.sbin/bsdinstall/scripts/zfsboot
@@ -1,1769 +1,1784 @@
 #!/bin/sh
 #-
 # Copyright (c) 2013-2016 Allan Jude
 # Copyright (c) 2013-2018 Devin Teske
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
 # are met:
 # 1. Redistributions of source code must retain the above copyright
 #    notice, this list of conditions and the following disclaimer.
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
 #
 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
 # $FreeBSD$
 #
 ############################################################ INCLUDES
 
 BSDCFG_SHARE="/usr/share/bsdconfig"
 . $BSDCFG_SHARE/common.subr || exit 1
 f_dprintf "%s: loading includes..." "$0"
 f_include $BSDCFG_SHARE/device.subr
 f_include $BSDCFG_SHARE/dialog.subr
 f_include $BSDCFG_SHARE/password/password.subr
 f_include $BSDCFG_SHARE/variable.subr
 
 ############################################################ CONFIGURATION
 
 #
 # Default name of the boot-pool
 #
 : ${ZFSBOOT_POOL_NAME:=zroot}
 
 #
 # Default options to use when creating zroot pool
 #
 : ${ZFSBOOT_POOL_CREATE_OPTIONS:=-O compress=lz4 -O atime=off}
 
 #
 # Default name for the boot environment parent dataset
 #
 : ${ZFSBOOT_BEROOT_NAME:=ROOT}
 
 #
 # Default name for the primary boot environment
 #
 : ${ZFSBOOT_BOOTFS_NAME:=default}
 
 #
 # Default Virtual Device (vdev) type to create
 #
 : ${ZFSBOOT_VDEV_TYPE:=stripe}
 
 #
 # Should we use sysctl(8) vfs.zfs.min_auto_ashift=12 to force 4K sectors?
 #
 : ${ZFSBOOT_FORCE_4K_SECTORS:=1}
 
 #
 # Should we use geli(8) to encrypt the drives?
 # NB: Automatically enables ZFSBOOT_BOOT_POOL
 #
 : ${ZFSBOOT_GELI_ENCRYPTION=}
 
 #
 # Default path to the geli(8) keyfile used in drive encryption
 #
 : ${ZFSBOOT_GELI_KEY_FILE:=/boot/encryption.key}
 
 #
 # Create a separate boot pool?
 # NB: Automatically set when using geli(8) or MBR
 #
 : ${ZFSBOOT_BOOT_POOL=}
 
 #
 # Options to use when creating separate boot pool (if any)
 #
 : ${ZFSBOOT_BOOT_POOL_CREATE_OPTIONS:=}
 
 #
 # Default name for boot pool when enabled (e.g., geli(8) or MBR)
 #
 : ${ZFSBOOT_BOOT_POOL_NAME:=bootpool}
 
 #
 # Default size for boot pool when enabled (e.g., geli(8) or MBR)
 #
 : ${ZFSBOOT_BOOT_POOL_SIZE:=2g}
 
 #
 # Default disks to use (always empty unless being scripted)
 #
 : ${ZFSBOOT_DISKS:=}
 
 #
 # Default partitioning scheme to use on disks
 #
 : ${ZFSBOOT_PARTITION_SCHEME:=}
 
 #
 # Default boot type to use on disks
 #
 : ${ZFSBOOT_BOOT_TYPE:=}
 
 #
 # How much swap to put on each block device in the boot zpool
 # NOTE: Value passed to gpart(8); which supports SI unit suffixes.
 #
 : ${ZFSBOOT_SWAP_SIZE:=2g}
 
 #
 # Should we use geli(8) to encrypt the swap?
 #
 : ${ZFSBOOT_SWAP_ENCRYPTION=}
 
 #
 # Should we use gmirror(8) to mirror the swap?
 #
 : ${ZFSBOOT_SWAP_MIRROR=}
 
 #
 # Default ZFS datasets for root zpool
 #
 # NOTE: Requires /tmp, /var/tmp, /$ZFSBOOT_BOOTFS_NAME/$ZFSBOOT_BOOTFS_NAME
 # NOTE: Anything after pound/hash character [#] is ignored as a comment.
 #
 f_isset ZFSBOOT_DATASETS || ZFSBOOT_DATASETS="
 	# DATASET	OPTIONS (comma or space separated; or both)
 
 	# Boot Environment [BE] root and default boot dataset
 	/$ZFSBOOT_BEROOT_NAME				mountpoint=none
 	/$ZFSBOOT_BEROOT_NAME/$ZFSBOOT_BOOTFS_NAME	mountpoint=/
 
 	# Compress /tmp, allow exec but not setuid
 	/tmp		mountpoint=/tmp,exec=on,setuid=off
 
 	# Don't mount /usr so that 'base' files go to the BEROOT
 	/usr		mountpoint=/usr,canmount=off
 
 	# Home directories separated so they are common to all BEs
 	/usr/home	# NB: /home is a symlink to /usr/home
 
 	# Ports tree
 	/usr/ports	setuid=off
 
 	# Source tree (compressed)
 	/usr/src
 
 	# Create /var and friends
 	/var		mountpoint=/var,canmount=off
 	/var/audit	exec=off,setuid=off
 	/var/crash	exec=off,setuid=off
 	/var/log	exec=off,setuid=off
 	/var/mail	atime=on
 	/var/tmp	setuid=off
 " # END-QUOTE
 
 #
 # If interactive and the user has not explicitly chosen a vdev type or disks,
 # make the user confirm scripted/default choices when proceeding to install.
 #
 : ${ZFSBOOT_CONFIRM_LAYOUT:=1}
 
 ############################################################ GLOBALS
 
 #
 # Format of a line in printf(1) syntax to add to fstab(5)
 #
 FSTAB_FMT="%s\t\t%s\t%s\t%s\t\t%s\t%s\n"
 
 #
 # Command strings for various tasks
 #
 COPY='cp "%s" "%s"'
 CHMOD_MODE='chmod %s "%s"'
 DD_WITH_OPTIONS='dd if="%s" of="%s" %s'
 ECHO_APPEND='echo "%s" >> "%s"'
 ECHO_OVERWRITE='echo "%s" > "%s"'
 GELI_ATTACH='geli attach -j - -k "%s" "%s"'
 GELI_ATTACH_NOKEY='geli attach -j - "%s"'
 GELI_DETACH_F='geli detach -f "%s"'
 GELI_PASSWORD_INIT='geli init -b -B "%s" -e %s -J - -K "%s" -l 256 -s 4096 "%s"'
 GELI_PASSWORD_GELIBOOT_INIT='geli init -bg -e %s -J - -l 256 -s 4096 "%s"'
 GPART_ADD_ALIGN='gpart add %s -t %s "%s"'
 GPART_ADD_ALIGN_INDEX='gpart add %s -i %s -t %s "%s"'
 GPART_ADD_ALIGN_INDEX_WITH_SIZE='gpart add %s -i %s -t %s -s %s "%s"'
 GPART_ADD_ALIGN_LABEL='gpart add %s -l %s -t %s "%s"'
 GPART_ADD_ALIGN_LABEL_WITH_SIZE='gpart add %s -l %s -t %s -s %s "%s"'
 GPART_BOOTCODE='gpart bootcode -b "%s" "%s"'
 GPART_BOOTCODE_PART='gpart bootcode -b "%s" -p "%s" -i %s "%s"'
 GPART_BOOTCODE_PARTONLY='gpart bootcode -p "%s" -i %s "%s"'
 GPART_CREATE='gpart create -s %s "%s"'
 GPART_DESTROY_F='gpart destroy -F "%s"'
 GPART_SET_ACTIVE='gpart set -a active -i %s "%s"'
 GPART_SET_LENOVOFIX='gpart set -a lenovofix "%s"'
 GPART_SET_PMBR_ACTIVE='gpart set -a active "%s"'
 GRAID_DELETE='graid delete "%s"'
 KLDLOAD='kldload %s'
 LN_SF='ln -sf "%s" "%s"'
 MKDIR_P='mkdir -p "%s"'
 MOUNT_TYPE='mount -t %s "%s" "%s"'
+NEWFS_ESP='newfs_msdos "%s"'
 PRINTF_CONF="printf '%s=\"%%s\"\\\n' %s >> \"%s\""
 PRINTF_FSTAB='printf "$FSTAB_FMT" "%s" "%s" "%s" "%s" "%s" "%s" >> "%s"'
 SHELL_TRUNCATE=':> "%s"'
 SWAP_GMIRROR_LABEL='gmirror label swap %s'
 SYSCTL_ZFS_MIN_ASHIFT_12='sysctl vfs.zfs.min_auto_ashift=12'
 UMOUNT='umount "%s"'
 ZFS_CREATE_WITH_OPTIONS='zfs create %s "%s"'
 ZFS_MOUNT='zfs mount "%s"'
 ZFS_SET='zfs set "%s" "%s"'
 ZFS_UNMOUNT='zfs unmount "%s"'
 ZPOOL_CREATE_WITH_OPTIONS='zpool create %s "%s" %s %s'
 ZPOOL_DESTROY='zpool destroy "%s"'
 ZPOOL_EXPORT='zpool export "%s"'
 ZPOOL_EXPORT_F='zpool export -f "%s"'
 ZPOOL_IMPORT_WITH_OPTIONS='zpool import %s "%s"'
 ZPOOL_LABELCLEAR_F='zpool labelclear -f "%s"'
 ZPOOL_SET='zpool set %s "%s"'
 
 #
 # Strings that should be moved to an i18n file and loaded with f_include_lang()
 #
 hline_alnum_arrows_punc_tab_enter="Use alnum, arrows, punctuation, TAB or ENTER"
 hline_arrows_space_tab_enter="Use arrows, SPACE, TAB or ENTER"
 hline_arrows_tab_enter="Press arrows, TAB or ENTER"
 msg_an_unknown_error_occurred="An unknown error occurred"
 msg_back="Back"
 msg_cancel="Cancel"
 msg_change_selection="Change Selection"
 msg_configure_options="Configure Options:"
 msg_detailed_disk_info="gpart(8) show %s:\n%s\n\ncamcontrol(8) inquiry %s:\n%s\n\n\ncamcontrol(8) identify %s:\n%s\n"
 msg_disk_info="Disk Info"
 msg_disk_info_help="Get detailed information on disk device(s)"
 msg_disk_plural="disks"
 msg_disk_singular="disk"
 msg_encrypt_disks="Encrypt Disks?"
 msg_encrypt_disks_help="Use geli(8) to encrypt all data partitions"
 msg_error="Error"
 msg_force_4k_sectors="Force 4K Sectors?"
 msg_force_4k_sectors_help="Align partitions to 4K sector boundries and set vfs.zfs.min_auto_ashift=12"
 msg_freebsd_installer="FreeBSD Installer"
 msg_geli_password="Enter a strong passphrase, used to protect your encryption keys. You will be required to enter this passphrase each time the system is booted"
 msg_geli_setup="Initializing encryption on selected disks,\n this will take several seconds per disk"
 msg_install="Install"
 msg_install_desc="Proceed with Installation"
 msg_install_help="Create ZFS boot pool with displayed options"
 msg_invalid_boot_pool_size="Invalid boot pool size \`%s'"
 msg_invalid_disk_argument="Invalid disk argument \`%s'"
 msg_invalid_index_argument="Invalid index argument \`%s'"
 msg_invalid_swap_size="Invalid swap size \`%s'"
 msg_invalid_virtual_device_type="Invalid Virtual Device type \`%s'"
 msg_last_chance_are_you_sure="Last Chance! Are you sure you want to destroy\nthe current contents of the following disks:\n\n   %s"
 msg_last_chance_are_you_sure_color='\\ZrLast Chance!\\ZR Are you \\Z1sure\\Zn you want to \\Zr\\Z1destroy\\Zn\nthe current contents of the following disks:\n\n   %s'
 msg_mirror_desc="Mirror - n-Way Mirroring"
 msg_mirror_help="[2+ Disks] Mirroring provides the best performance, but the least storage"
 msg_missing_disk_arguments="missing disk arguments"
 msg_missing_one_or_more_scripted_disks="Missing one or more scripted disks!"
 msg_no="NO"
 msg_no_disks_present_to_configure="No disk(s) present to configure"
 msg_no_disks_selected="No disks selected."
 msg_not_enough_disks_selected="Not enough disks selected. (%u < %u minimum)"
 msg_null_disk_argument="NULL disk argument"
 msg_null_index_argument="NULL index argument"
 msg_null_poolname="NULL poolname"
 msg_odd_disk_selected="An even number of disks must be selected to create a RAID 1+0. (%u selected)"
 msg_ok="OK"
 msg_partition_scheme="Partition Scheme"
 msg_partition_scheme_help="Select partitioning scheme. GPT is recommended."
 msg_please_enter_a_name_for_your_zpool="Please enter a name for your zpool:"
 msg_please_enter_amount_of_swap_space="Please enter amount of swap space (SI-Unit suffixes\nrecommended; e.g., \`2g' for 2 Gigabytes):"
 msg_please_select_one_or_more_disks="Please select one or more disks to create a zpool:"
 msg_pool_name="Pool Name"
 msg_pool_name_cannot_be_empty="Pool name cannot be empty."
 msg_pool_name_help="Customize the name of the zpool to be created (Required)"
 msg_pool_type_disks="Pool Type/Disks:"
 msg_pool_type_disks_help="Choose type of ZFS Virtual Device and disks to use (Required)"
 msg_processing_selection="Processing selection..."
 msg_raid10_desc="RAID 1+0 - n x 2-Way Mirrors"
 msg_raid10_help="[4+ Disks] Striped Mirrors provides the best performance, but the least storage"
 msg_raidz1_desc="RAID-Z1 - Single Redundant RAID"
 msg_raidz1_help="[3+ Disks] Withstand failure of 1 disk. Recommended for: 3, 5 or 9 disks"
 msg_raidz2_desc="RAID-Z2 - Double Redundant RAID"
 msg_raidz2_help="[4+ Disks] Withstand failure of 2 disks. Recommended for: 4, 6 or 10 disks"
 msg_raidz3_desc="RAID-Z3 - Triple Redundant RAID"
 msg_raidz3_help="[5+ Disks] Withstand failure of 3 disks. Recommended for: 5, 7 or 11 disks"
 msg_rescan_devices="Rescan Devices"
 msg_rescan_devices_help="Scan for device changes"
 msg_select="Select"
 msg_select_a_disk_device="Select a disk device"
 msg_select_virtual_device_type="Select Virtual Device type:"
 msg_stripe_desc="Stripe - No Redundancy"
 msg_stripe_help="[1+ Disks] Striping provides maximum storage but no redundancy"
 msg_swap_encrypt="Encrypt Swap?"
 msg_swap_encrypt_help="Encrypt swap partitions with temporary keys, discarded on reboot"
 msg_swap_invalid="The selected swap size (%s) is invalid. Enter a number optionally followed by units. Example: 2G"
 msg_swap_mirror="Mirror Swap?"
 msg_swap_mirror_help="Mirror swap partitions for redundancy, breaks crash dumps"
 msg_swap_size="Swap Size"
 msg_swap_size_help="Customize how much swap space is allocated to each selected disk"
 msg_swap_toosmall="The selected swap size (%s) is to small. Please enter a value greater than 100MB or enter 0 for no swap"
 msg_these_disks_are_too_small="These disks are smaller than the amount of requested\nswap (%s) and/or geli(8) (%s) partitions, which would\ntake 100%% or more of each of the following selected disks:\n\n  %s\n\nRecommend changing partition size(s) and/or selecting a\ndifferent set of disks."
 msg_unable_to_get_disk_capacity="Unable to get disk capacity of \`%s'"
 msg_unsupported_partition_scheme="%s is an unsupported partition scheme"
 msg_user_cancelled="User Cancelled."
 msg_yes="YES"
 msg_zfs_configuration="ZFS Configuration"
 
 ############################################################ FUNCTIONS
 
 # dialog_menu_main
 #
 # Display the dialog(1)-based application main menu.
 #
 dialog_menu_main()
 {
 	local title="$DIALOG_TITLE"
 	local btitle="$DIALOG_BACKTITLE"
 	local prompt="$msg_configure_options"
 	local force4k="$msg_no"
 	local usegeli="$msg_no"
 	local swapgeli="$msg_no"
 	local swapmirror="$msg_no"
 	[ "$ZFSBOOT_FORCE_4K_SECTORS" ] && force4k="$msg_yes"
 	[ "$ZFSBOOT_GELI_ENCRYPTION" ] && usegeli="$msg_yes"
 	[ "$ZFSBOOT_SWAP_ENCRYPTION" ] && swapgeli="$msg_yes"
 	[ "$ZFSBOOT_SWAP_MIRROR" ] && swapmirror="$msg_yes"
 	local disks n disks_grammar
 	f_count n $ZFSBOOT_DISKS
 	{ [ $n -eq 1 ] && disks_grammar=$msg_disk_singular; } ||
 		disks_grammar=$msg_disk_plural # grammar
 	local menu_list="
 		'>>> $msg_install'      '$msg_install_desc'
 		                        '$msg_install_help'
 		'T $msg_pool_type_disks'
 		               '$ZFSBOOT_VDEV_TYPE: $n $disks_grammar'
 		               '$msg_pool_type_disks_help'
 		'- $msg_rescan_devices' '*'
 		                        '$msg_rescan_devices_help'
 		'- $msg_disk_info'      '*'
 		                        '$msg_disk_info_help'
 		'N $msg_pool_name'      '$ZFSBOOT_POOL_NAME'
 		                        '$msg_pool_name_help'
 		'4 $msg_force_4k_sectors'
 		                        '$force4k'
 		                        '$msg_force_4k_sectors_help'
 		'E $msg_encrypt_disks'  '$usegeli'
 		                        '$msg_encrypt_disks_help'
 		'P $msg_partition_scheme'
 		               '$ZFSBOOT_PARTITION_SCHEME ($ZFSBOOT_BOOT_TYPE)'
 		               '$msg_partition_scheme_help'
 		'S $msg_swap_size'      '$ZFSBOOT_SWAP_SIZE'
 		                        '$msg_swap_size_help'
 		'M $msg_swap_mirror'    '$swapmirror'
 		                        '$msg_swap_mirror_help'
 		'W $msg_swap_encrypt'   '$swapgeli'
 		                        '$msg_swap_encrypt_help'
 	" # END-QUOTE
 	local defaultitem= # Calculated below
 	local hline="$hline_alnum_arrows_punc_tab_enter"
 
 	local height width rows
 	eval f_dialog_menu_with_help_size height width rows \
 		\"\$title\" \"\$btitle\" \"\$prompt\" \"\$hline\" $menu_list
 
 	# Obtain default-item from previously stored selection
 	f_dialog_default_fetch defaultitem
 
 	local menu_choice
 	menu_choice=$( eval $DIALOG \
 		--title \"\$title\"              \
 		--backtitle \"\$btitle\"         \
 		--hline \"\$hline\"              \
 		--item-help                      \
 		--ok-label \"\$msg_select\"      \
 		--cancel-label \"\$msg_cancel\"  \
 		--default-item \"\$defaultitem\" \
 		--menu \"\$prompt\"              \
 		$height $width $rows             \
 		$menu_list                       \
 		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
 	)
 	local retval=$?
 	f_dialog_data_sanitize menu_choice
 	f_dialog_menutag_store "$menu_choice"
 
 	# Only update default-item on success
 	[ $retval -eq $DIALOG_OK ] && f_dialog_default_store "$menu_choice"
 
 	return $retval
 }
 
 # dialog_last_chance $disks ...
 #
 # Display a list of the disks that the user is about to destroy. The default
 # action is to return error status unless the user explicitly (non-default)
 # selects "Yes" from the noyes dialog.
 #
 dialog_last_chance()
 {
 	local title="$DIALOG_TITLE"
 	local btitle="$DIALOG_BACKTITLE"
 	local prompt # Calculated below
 	local hline="$hline_arrows_tab_enter"
 
 	local height=8 width=50 prefix="   "
 	local plen=${#prefix} list= line=
 	local max_width=$(( $width - 3 - $plen ))
 
 	local yes no defaultno extra_args format
 	if [ "$USE_XDIALOG" ]; then
 		yes=ok no=cancel defaultno=default-no
 		extra_args="--wrap --left"
 		format="$msg_last_chance_are_you_sure"
 	else
 		yes=yes no=no defaultno=defaultno
 		extra_args="--colors --cr-wrap"
 		format="$msg_last_chance_are_you_sure_color"
 	fi
 
 	local disk line_width
 	for disk in $*; do
 		if [ "$line" ]; then
 			line_width=${#line}
 		else
 			line_width=$plen
 		fi
 		line_width=$(( $line_width + 1 + ${#disk} ))
 		# Add newline before disk if it would exceed max_width
 		if [ $line_width -gt $max_width ]; then
 			list="$list$line\n"
 			line="$prefix"
 			height=$(( $height + 1 ))
 		fi
 		# Add the disk to the list
 		line="$line $disk"
 	done
 	# Append the left-overs
 	if [ "${line#$prefix}" ]; then
 		list="$list$line"
 		height=$(( $height + 1 ))
 	fi
 
 	# Add height for Xdialog(1)
 	[ "$USE_XDIALOG" ] && height=$(( $height + $height / 5 + 3 ))
 
 	prompt=$( printf "$format" "$list" )
 	f_dprintf "%s: Last Chance!" "$0"
 	$DIALOG \
 		--title "$title"        \
 		--backtitle "$btitle"   \
 		--hline "$hline"        \
 		--$defaultno            \
 		--$yes-label "$msg_yes" \
 		--$no-label "$msg_no"   \
 		$extra_args             \
 		--yesno "$prompt" $height $width
 }
 
 # dialog_menu_layout
 #
 # Configure Virtual Device type and disks to use for the ZFS boot pool. User
 # must select enough disks to satisfy the chosen vdev type.
 #
 dialog_menu_layout()
 {
 	local funcname=dialog_menu_layout
 	local title="$DIALOG_TITLE"
 	local btitle="$DIALOG_BACKTITLE"
 	local vdev_prompt="$msg_select_virtual_device_type"
 	local disk_prompt="$msg_please_select_one_or_more_disks"
 	local vdev_menu_list="
 		'stripe' '$msg_stripe_desc' '$msg_stripe_help'
 		'mirror' '$msg_mirror_desc' '$msg_mirror_help'
 		'raid10' '$msg_raid10_desc' '$msg_raid10_help'
 		'raidz1' '$msg_raidz1_desc' '$msg_raidz1_help'
 		'raidz2' '$msg_raidz2_desc' '$msg_raidz2_help'
 		'raidz3' '$msg_raidz3_desc' '$msg_raidz3_help'
 	" # END-QUOTE
 	local disk_check_list= # Calculated below
 	local vdev_hline="$hline_arrows_tab_enter"
 	local disk_hline="$hline_arrows_space_tab_enter"
 
 	# Warn the user if vdev type is not valid
 	case "$ZFSBOOT_VDEV_TYPE" in
 	stripe|mirror|raid10|raidz1|raidz2|raidz3) : known good ;;
 	*)
 		f_dprintf "%s: Invalid virtual device type \`%s'" \
 			  $funcname "$ZFSBOOT_VDEV_TYPE"
 		f_show_err "$msg_invalid_virtual_device_type" \
 			   "$ZFSBOOT_VDEV_TYPE"
 		f_interactive || return $FAILURE
 	esac
 
 	# Calculate size of vdev menu once only
 	local vheight vwidth vrows
 	eval f_dialog_menu_with_help_size vheight vwidth vrows \
 		\"\$title\" \"\$btitle\" \"\$vdev_prompt\" \"\$vdev_hline\" \
 		$vdev_menu_list
 
 	# Get a list of probed disk devices
 	local disks=
 	debug= f_device_find "" $DEVICE_TYPE_DISK disks
 
 	# Prune out mounted md(4) devices that may be part of the boot process
 	local disk name new_list=
 	for disk in $disks; do
 		debug= $disk get name name
 		case "$name" in
 		md[0-9]*) f_mounted -b "/dev/$name" && continue ;;
 		esac
 		new_list="$new_list $disk"
 	done
 	disks="${new_list# }"
 
 	# Debugging
 	if [ "$debug" ]; then
 		local disk_names=
 		for disk in $disks; do
 			debug= $disk get name name
 			disk_names="$disk_names $name"
 		done
 		f_dprintf "$funcname: disks=[%s]" "${disk_names# }"
 	fi
 
 	if [ ! "$disks" ]; then
 		f_dprintf "No disk(s) present to configure"
 		f_show_err "$msg_no_disks_present_to_configure"
 		return $FAILURE
 	fi
 
 	# Lets sort the disks array to be more user friendly
 	f_device_sort_by name disks disks
 
 	#
 	# Operate in a loop so we can (if interactive) repeat if not enough
 	# disks are selected to satisfy the chosen vdev type or user wants to
 	# back-up to the previous menu.
 	#
 	local vardisk ndisks onoff selections vdev_choice breakout device
 	local valid_disks all_valid want_disks desc height width rows
 	while :; do
 		#
 		# Confirm the vdev type that was selected
 		#
 		if f_interactive && [ "$ZFSBOOT_CONFIRM_LAYOUT" ]; then
 			vdev_choice=$( eval $DIALOG \
 				--title \"\$title\"              \
 				--backtitle \"\$btitle\"         \
 				--hline \"\$vdev_hline\"         \
 				--ok-label \"\$msg_ok\"          \
 				--cancel-label \"\$msg_cancel\"  \
 				--item-help                      \
 				--default-item \"\$ZFSBOOT_VDEV_TYPE\" \
 				--menu \"\$vdev_prompt\"         \
 				$vheight $vwidth $vrows          \
 				$vdev_menu_list                  \
 				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
 			) || return $?
 				# Exit if user pressed ESC or chose Cancel/No
 			f_dialog_data_sanitize vdev_choice
 
 			ZFSBOOT_VDEV_TYPE="$vdev_choice"
 			f_dprintf "$funcname: ZFSBOOT_VDEV_TYPE=[%s]" \
 			          "$ZFSBOOT_VDEV_TYPE"
 		fi
 
 		# Determine the number of disks needed for this vdev type
 		want_disks=0
 		case "$ZFSBOOT_VDEV_TYPE" in
 		stripe) want_disks=1 ;;
 		mirror) want_disks=2 ;;
 		raid10) want_disks=4 ;;
 		raidz1) want_disks=3 ;;
 		raidz2) want_disks=4 ;;
 		raidz3) want_disks=5 ;;
 		esac
 
 		#
 		# Warn the user if any scripted disks are invalid
 		#
 		valid_disks= all_valid=${ZFSBOOT_DISKS:+1} # optimism
 		for disk in $ZFSBOOT_DISKS; do
 			if debug= f_device_find -1 \
 				$disk $DEVICE_TYPE_DISK device
 			then
 				valid_disks="$valid_disks $disk"
 				continue
 			fi
 			f_dprintf "$funcname: \`%s' is not a real disk" "$disk"
 			all_valid=
 		done
 		if [ ! "$all_valid" ]; then
 			if [ "$ZFSBOOT_DISKS" ]; then
 				f_show_err \
 				    "$msg_missing_one_or_more_scripted_disks"
 			else
 				f_dprintf "No disks selected."
 				f_interactive ||
 					f_show_err "$msg_no_disks_selected"
 			fi
 			f_interactive || return $FAILURE
 		fi
 		ZFSBOOT_DISKS="${valid_disks# }"
 
 		#
 		# Short-circuit if we're running non-interactively
 		#
 		if ! f_interactive || [ ! "$ZFSBOOT_CONFIRM_LAYOUT" ]; then
 			f_count ndisks $ZFSBOOT_DISKS
 			[ $ndisks -ge $want_disks ] && break # to success
 
 			# Not enough disks selected
 			f_dprintf "$funcname: %s: %s (%u < %u minimum)" \
 				  "$ZFSBOOT_VDEV_TYPE" \
 				  "Not enough disks selected." \
 				  $ndisks $want_disks
 			f_interactive || return $FAILURE
 			msg_yes="$msg_change_selection" msg_no="$msg_cancel" \
 				f_yesno "%s: $msg_not_enough_disks_selected" \
 				"$ZFSBOOT_VDEV_TYPE" $ndisks $want_disks ||
 				return $FAILURE
 		fi
 
 		#
 		# Confirm the disks that were selected
 		# Loop until the user cancels or selects enough disks
 		#
 		breakout=
 		while :; do
 			# Loop over list of available disks, resetting state
 			for disk in $disks; do
 				f_isset _${disk}_status && _${disk}_status=
 			done
 
 			# Loop over list of selected disks and create temporary
 			# locals to map statuses onto up-to-date list of disks
 			for disk in $ZFSBOOT_DISKS; do
 				debug= f_device_find -1 \
 					$disk $DEVICE_TYPE_DISK disk
 				f_isset _${disk}_status ||
 					local _${disk}_status
 				_${disk}_status=on
 			done
 
 			# Create the checklist menu of discovered disk devices
 			disk_check_list=
 			for disk in $disks; do
 				desc=
 				$disk get name name
 				$disk get desc desc
 				f_shell_escape "$desc" desc
 				f_getvar _${disk}_status:-off onoff
 				disk_check_list="$disk_check_list
 					$name '$desc' $onoff"
 			done
 
 			eval f_dialog_checklist_size height width rows \
 				\"\$title\" \"\$btitle\" \"\$prompt\" \
 				\"\$hline\" $disk_check_list
 
 			selections=$( eval $DIALOG \
 				--title \"\$DIALOG_TITLE\"         \
 				--backtitle \"\$DIALOG_BACKTITLE\" \
 				--separate-output                  \
 				--hline \"\$hline\"                \
 				--ok-label \"\$msg_ok\"            \
 				--cancel-label \"\$msg_back\"      \
 				--checklist \"\$prompt\"           \
 				$height $width $rows               \
 				$disk_check_list                   \
 				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
 			) || break
 				# Loop if user pressed ESC or chose Cancel/No
 			f_dialog_data_sanitize selections
 
 			ZFSBOOT_DISKS="$selections"
 			f_dprintf "$funcname: ZFSBOOT_DISKS=[%s]" \
 			          "$ZFSBOOT_DISKS"
 
 			f_count ndisks $ZFSBOOT_DISKS
 
 			if [ "$ZFSBOOT_VDEV_TYPE" == "raid10" ] &&
 			    [ $(( $ndisks % 2 )) -ne 0 ]; then
 				f_dprintf "$funcname: %s: %s (%u %% 2 = %u)" \
 					  "$ZFSBOOT_VDEV_TYPE" \
 					  "Number of disks not even:" \
 					  $ndisks $(( $ndisks % 2 ))
 				msg_yes="$msg_change_selection" \
 					msg_no="$msg_cancel" \
 					f_yesno "%s: $msg_odd_disk_selected" \
 						"$ZFSBOOT_VDEV_TYPE" $ndisks ||
 						break
 				continue
 			fi
 
 			[ $ndisks -ge $want_disks ] &&
 				breakout=break && break
 
 			# Not enough disks selected
 			f_dprintf "$funcname: %s: %s (%u < %u minimum)" \
 				  "$ZFSBOOT_VDEV_TYPE" \
 			          "Not enough disks selected." \
 			          $ndisks $want_disks
 			msg_yes="$msg_change_selection" msg_no="$msg_cancel" \
 				f_yesno "%s: $msg_not_enough_disks_selected" \
 				"$ZFSBOOT_VDEV_TYPE" $ndisks $want_disks ||
 				break
 		done
 		[ "$breakout" = "break" ] && break
 		[ "$ZFSBOOT_CONFIRM_LAYOUT" ] || return $FAILURE
 	done
 
 	return $DIALOG_OK
 }
 
 # zfs_create_diskpart $disk $index
 #
 # For each block device to be used in the zpool, rather than just create the
 # zpool with the raw block devices (e.g., da0, da1, etc.) we create partitions
 # so we can have some real swap. This also provides wiggle room incase your
 # replacement drivers do not have the exact same sector counts.
 #
 # NOTE: $swapsize and $bootsize should be defined by the calling function.
 # NOTE: Sets $bootpart and $targetpart for the calling function.
 #
 zfs_create_diskpart()
 {
 	local funcname=zfs_create_diskpart
 	local disk="$1" index="$2"
 
 	# Check arguments
 	if [ ! "$disk" ]; then
 		f_dprintf "$funcname: NULL disk argument"
 		msg_error="$msg_error: $funcname" \
 			f_show_err "$msg_null_disk_argument"
 		return $FAILURE
 	fi
 	if [ "${disk#*[$IFS]}" != "$disk" ]; then
 		f_dprintf "$funcname: Invalid disk argument \`%s'" "$disk"
 		msg_error="$msg_error: $funcname" \
 			f_show_err "$msg_invalid_disk_argument" "$disk"
 		return $FAILURE
 	fi
 	if [ ! "$index" ]; then
 		f_dprintf "$funcname: NULL index argument"
 		msg_error="$msg_error: $funcname" \
 			f_show_err "$msg_null_index_argument"
 		return $FAILURE
 	fi
 	if ! f_isinteger "$index"; then
 		f_dprintf "$funcname: Invalid index argument \`%s'" "$index"
 		msg_error="$msg_error: $funcname" \
 			f_show_err "$msg_invalid_index_argument" "$index"
 		return $FAILURE
 	fi
 	f_dprintf "$funcname: disk=[%s] index=[%s]" "$disk" "$index"
 
 	# Check for unknown partition scheme before proceeding further
 	case "$ZFSBOOT_PARTITION_SCHEME" in
 	""|MBR|GPT*) : known good ;;
 	*)
 		f_dprintf "$funcname: %s is an unsupported partition scheme" \
 		          "$ZFSBOOT_PARTITION_SCHEME"
 		msg_error="$msg_error: $funcname" f_show_err \
 			"$msg_unsupported_partition_scheme" \
 			"$ZFSBOOT_PARTITION_SCHEME"
 		return $FAILURE
 	esac
 
 	#
 	# Destroy whatever partition layout is currently on disk.
 	# NOTE: `-F' required to destroy if partitions still exist.
 	# NOTE: Failure is ok here, blank disk will have nothing to destroy.
 	#
 	f_dprintf "$funcname: Exporting ZFS pools..."
 	zpool list -Ho name | while read z_name; do
 		f_eval_catch -d $funcname zpool "$ZPOOL_EXPORT_F" $z_name
 	done
 	f_dprintf "$funcname: Detaching all GELI providers..."
 	geli status | tail -n +2 | while read g_name g_status g_component; do
 		f_eval_catch -d $funcname geli "$GELI_DETACH_F" $g_name
 	done
 	f_dprintf "$funcname: Destroying all data/layouts on \`%s'..." "$disk"
 	f_eval_catch -d $funcname gpart "$GPART_DESTROY_F" $disk
 	f_eval_catch -d $funcname graid "$GRAID_DELETE" $disk
 	f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" /dev/$disk
 
 	# Make doubly-sure backup GPT is destroyed
 	f_eval_catch -d $funcname gpart "$GPART_CREATE" gpt $disk
 	f_eval_catch -d $funcname gpart "$GPART_DESTROY_F" $disk
 
 	#
 	# Lay down the desired type of partition scheme
 	#
 	local setsize mbrindex align_small align_big
 	#
 	# If user has requested 4 K alignment, add these params to the
 	# gpart add calls. With GPT, we align large partitions to 1 M for
 	# improved performance on SSDs. MBR does not always play well with gaps
 	# between partitions, so all alignment is only 4k for that case.
 	# With MBR, we align the BSD partition that contains the MBR, otherwise
 	# the system fails to boot.
 	#
 	if [ "$ZFSBOOT_FORCE_4K_SECTORS" ]; then
 		align_small="-a 4k"
 		align_big="-a 1m"
 	fi
 
 	case "$ZFSBOOT_PARTITION_SCHEME" in
 	""|GPT*) f_dprintf "$funcname: Creating GPT layout..."
 		#
 		# 1. Create GPT layout using labels
 		#
 		f_eval_catch $funcname gpart "$GPART_CREATE" gpt $disk ||
 		             return $FAILURE
 
 		#
 		# Apply workarounds if requested by the user
 		#
 		if [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT + Lenovo Fix" ]; then
 			f_eval_catch $funcname gpart "$GPART_SET_LENOVOFIX" \
 			             $disk || return $FAILURE
 		elif [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT + Active" ]; then
 			f_eval_catch $funcname gpart "$GPART_SET_PMBR_ACTIVE" \
 			             $disk || return $FAILURE
 		fi
 
 		#
 		# 2. Add small freebsd-boot and/or efi partition
 		#
 		if [ "$ZFSBOOT_BOOT_TYPE" = "UEFI" -o \
 		     "$ZFSBOOT_BOOT_TYPE" = "BIOS+UEFI" ]
 		then
-			f_eval_catch $funcname gpart \
+			f_eval_catch -k justaddedpart $funcname gpart \
 			             "$GPART_ADD_ALIGN_LABEL_WITH_SIZE" \
-			             "$align_small" efiboot$index efi 200M \
+			             "$align_small" efiboot$index efi 260M \
 			             $disk || return $FAILURE
 
 			# We'll configure the ESP in bootconfig
+			if [ -z "$efibootpart" ]; then
+				efibootpart="/dev/$(echo $justaddedpart | cut -f 1 -d ' ')"
+				f_dprintf "$funcname: configuring ESP at [%s]" \
+				          "${efibootpart}"
+
+				f_eval_catch $funcname newfs_msdos "$NEWFS_ESP"\
+				             "$efibootpart" \
+				             || return $FAILURE
+				f_eval_catch $funcname printf "$PRINTF_FSTAB" \
+					     $efibootpart /boot/efi msdosfs \
+				             rw 2 2 "$BSDINSTALL_TMPETC/fstab" \
+				             || return $FAILURE
+			fi
 		fi
 
 		if [ "$ZFSBOOT_BOOT_TYPE" = "BIOS" -o \
 		     "$ZFSBOOT_BOOT_TYPE" = "BIOS+UEFI" ]
 		then
 			f_eval_catch $funcname gpart \
 			             "$GPART_ADD_ALIGN_LABEL_WITH_SIZE" \
 			             "$align_small" gptboot$index \
 			             freebsd-boot 512k $disk || return $FAILURE
 			if [ "$ZFSBOOT_BOOT_TYPE" = "BIOS" ]; then
 				f_eval_catch $funcname gpart \
 				             "$GPART_BOOTCODE_PART" \
 				             /boot/pmbr /boot/gptzfsboot 1 \
 				             $disk || return $FAILURE
 			else
 				f_eval_catch $funcname gpart \
 				             "$GPART_BOOTCODE_PART" \
 				             /boot/pmbr /boot/gptzfsboot 2 \
 				             $disk || return $FAILURE
 			fi
 		fi
 
 		# NB: zpool will use the `zfs#' GPT labels
 		if [ "$ZFSBOOT_BOOT_TYPE" = "BIOS+UEFI" ]; then
 			if [ "$ZFSBOOT_BOOT_POOL" ]; then
 				bootpart=p3 swappart=p4 targetpart=p4
 				[ ${swapsize:-0} -gt 0 ] && targetpart=p5
 			else
 				# Bootpart unused
 				bootpart=p3 swappart=p3 targetpart=p3
 				[ ${swapsize:-0} -gt 0 ] && targetpart=p4
 			fi
 		else
 			if [ "$ZFSBOOT_BOOT_POOL" ]; then
 				bootpart=p2 swappart=p3 targetpart=p3
 				[ ${swapsize:-0} -gt 0 ] && targetpart=p4
 			else
 				# Bootpart unused
 				bootpart=p2 swappart=p2 targetpart=p2
 				[ ${swapsize:-0} -gt 0 ] && targetpart=p3
 			fi
 		fi
 
 		#
 		# Prepare boot pool if enabled (e.g., for geli(8))
 		#
 		if [ "$ZFSBOOT_BOOT_POOL" ]; then
 			f_eval_catch $funcname gpart \
 			             "$GPART_ADD_ALIGN_LABEL_WITH_SIZE" \
 			             "$align_big" boot$index freebsd-zfs \
 			             ${bootsize}b $disk || return $FAILURE
 			# Pedantically nuke any old labels
 			f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
 			                /dev/$disk$bootpart
 			if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then
 				# Pedantically detach targetpart for later
 				f_eval_catch -d $funcname geli \
 				                "$GELI_DETACH_F" \
 				                /dev/$disk$targetpart
 			fi
 		fi
 
 		#
 		# 3. Add freebsd-swap partition labeled `swap#'
 		#
 		if [ ${swapsize:-0} -gt 0 ]; then
 			f_eval_catch $funcname gpart \
 			             "$GPART_ADD_ALIGN_LABEL_WITH_SIZE" \
 			             "$align_big" swap$index freebsd-swap \
 			             ${swapsize}b $disk || return $FAILURE
 			# Pedantically nuke any old labels on the swap
 			f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
 			                /dev/$disk$swappart
 		fi
 
 		#
 		# 4. Add freebsd-zfs partition labeled `zfs#' for zroot
 		#
 		f_eval_catch $funcname gpart "$GPART_ADD_ALIGN_LABEL" \
 		             "$align_big" zfs$index freebsd-zfs $disk ||
 		             return $FAILURE
 		f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
 		                /dev/$disk$targetpart
 		;;
 
 	MBR) f_dprintf "$funcname: Creating MBR layout..."
 		#
 		# Enable boot pool if encryption is desired
 		#
 		[ "$ZFSBOOT_GELI_ENCRYPTION" ] && ZFSBOOT_BOOT_POOL=1
 		#
 		# 1. Create MBR layout (no labels)
 		#
 		f_eval_catch $funcname gpart "$GPART_CREATE" mbr $disk ||
 		             return $FAILURE
 		f_eval_catch $funcname gpart "$GPART_BOOTCODE" /boot/mbr \
 		             $disk || return $FAILURE
 
 		#
 		# 2. Add freebsd slice with all available space
 		#
 		f_eval_catch $funcname gpart "$GPART_ADD_ALIGN" \
 		             "$align_small" freebsd $disk || return $FAILURE
 		f_eval_catch $funcname gpart "$GPART_SET_ACTIVE" 1 $disk ||
 		             return $FAILURE
 		# Pedantically nuke any old labels
 		f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
 		                /dev/${disk}s1
 		# Pedantically nuke any old scheme
 		f_eval_catch -d $funcname gpart "$GPART_DESTROY_F" ${disk}s1
 
 		#
 		# 3. Write BSD scheme to the freebsd slice
 		#
 		f_eval_catch $funcname gpart "$GPART_CREATE" BSD ${disk}s1 ||
 		             return $FAILURE
 
 		# NB: zpool will use s1a (no labels)
 		bootpart=s1a swappart=s1b targetpart=s1d mbrindex=4
 
 		#
 		# Always prepare a boot pool on MBR
 		# Do not align this partition, there must not be a gap
 		#
 		ZFSBOOT_BOOT_POOL=1
 		f_eval_catch $funcname gpart \
 		             "$GPART_ADD_ALIGN_INDEX_WITH_SIZE" \
 		             "" 1 freebsd-zfs ${bootsize}b ${disk}s1 ||
 		             return $FAILURE
 		# Pedantically nuke any old labels
 		f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
 		                /dev/$disk$bootpart
 		if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then
 			# Pedantically detach targetpart for later
 			f_eval_catch -d $funcname geli \
 			                "$GELI_DETACH_F" \
 					/dev/$disk$targetpart
 		fi
 
 		#
 		# 4. Add freebsd-swap partition
 		#
 		if [ ${swapsize:-0} -gt 0 ]; then
 			f_eval_catch $funcname gpart \
 			             "$GPART_ADD_ALIGN_INDEX_WITH_SIZE" \
 			             "$align_small" 2 freebsd-swap \
 			             ${swapsize}b ${disk}s1 || return $FAILURE
 			# Pedantically nuke any old labels on the swap
 			f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
 			                /dev/${disk}s1b
 		fi
 
 		#
 		# 5. Add freebsd-zfs partition for zroot
 		#
 		f_eval_catch $funcname gpart "$GPART_ADD_ALIGN_INDEX" \
 		             "$align_small" $mbrindex freebsd-zfs ${disk}s1 ||
 		             return $FAILURE
 		f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
 		                /dev/$disk$targetpart # Pedantic
 		f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
 		             /boot/zfsboot /dev/${disk}s1 count=1 ||
 		             return $FAILURE
 		;;
 
 	esac # $ZFSBOOT_PARTITION_SCHEME
 
 	# Update fstab(5)
 	local swapsize
 	f_expand_number "$ZFSBOOT_SWAP_SIZE" swapsize
 	if [ "$isswapmirror" ]; then
 		# This is not the first disk in the mirror, do nothing
 	elif [ ${swapsize:-0} -eq 0 ]; then
 		# If swap is 0 sized, don't add it to fstab
 	elif [ "$ZFSBOOT_SWAP_ENCRYPTION" -a "$ZFSBOOT_SWAP_MIRROR" ]; then
 		f_eval_catch $funcname printf "$PRINTF_FSTAB" \
 		             /dev/mirror/swap.eli none swap sw 0 0 \
 		             $BSDINSTALL_TMPETC/fstab || return $FAILURE
 		isswapmirror=1
 	elif [ "$ZFSBOOT_SWAP_MIRROR" ]; then
 		f_eval_catch $funcname printf "$PRINTF_FSTAB" \
 		             /dev/mirror/swap none swap sw 0 0 \
 		             $BSDINSTALL_TMPETC/fstab || return $FAILURE
 		isswapmirror=1
 	elif [ "$ZFSBOOT_SWAP_ENCRYPTION" ]; then
 		f_eval_catch $funcname printf "$PRINTF_FSTAB" \
 		             /dev/$disk${swappart}.eli none swap sw 0 0 \
 		             $BSDINSTALL_TMPETC/fstab || return $FAILURE
 	else
 		f_eval_catch $funcname printf "$PRINTF_FSTAB" \
 		             /dev/$disk$swappart none swap sw 0 0 \
 		             $BSDINSTALL_TMPETC/fstab || return $FAILURE
 	fi
 
 	return $SUCCESS
 }
 
 # zfs_create_boot $poolname $vdev_type $disks ...
 #
 # Creates boot pool and dataset layout. Returns error if something goes wrong.
 # Errors are printed to stderr for collection and display.
 #
 zfs_create_boot()
 {
 	local funcname=zfs_create_boot
 	local zroot_name="$1"
 	local zroot_vdevtype="$2"
 	local zroot_vdevs= # Calculated below
 	local swap_devs= # Calculated below
 	local boot_vdevs= # Used for geli(8) and/or MBR layouts
 	shift 2 # poolname vdev_type
 	local disks="$*" disk
 	local isswapmirror
 	local bootpart targetpart swappart # Set by zfs_create_diskpart() below
 	local create_options
+	local efibootpart
 
 	#
 	# Pedantic checks; should never be seen
 	#
 	if [ ! "$zroot_name" ]; then
 		f_dprintf "$funcname: NULL poolname"
 		msg_error="$msg_error: $funcname" \
 			f_show_err "$msg_null_poolname"
 		return $FAILURE
 	fi
 	if [ $# -lt 1 ]; then
 		f_dprintf "$funcname: missing disk arguments"
 		msg_error="$msg_error: $funcname" \
 			f_show_err "$msg_missing_disk_arguments"
 		return $FAILURE
 	fi
 	f_dprintf "$funcname: poolname=[%s] vdev_type=[%s]" \
 	          "$zroot_name" "$zroot_vdevtype"
 
 	#
 	# Initialize fstab(5)
 	#
 	f_dprintf "$funcname: Initializing temporary fstab(5) file..."
 	f_eval_catch $funcname sh "$SHELL_TRUNCATE" $BSDINSTALL_TMPETC/fstab ||
 	             return $FAILURE
 	f_eval_catch $funcname printf "$PRINTF_FSTAB" \
 	             "# Device" Mountpoint FStype Options Dump "Pass#" \
 	             $BSDINSTALL_TMPETC/fstab || return $FAILURE
 
 	#
 	# Expand SI units in desired sizes
 	#
 	f_dprintf "$funcname: Expanding supplied size values..."
 	local swapsize bootsize
 	if ! f_expand_number "$ZFSBOOT_SWAP_SIZE" swapsize; then
 		f_dprintf "$funcname: Invalid swap size \`%s'" \
 		          "$ZFSBOOT_SWAP_SIZE"
 		f_show_err "$msg_invalid_swap_size" "$ZFSBOOT_SWAP_SIZE"
 		return $FAILURE
 	fi
 	if ! f_expand_number "$ZFSBOOT_BOOT_POOL_SIZE" bootsize; then
 		f_dprintf "$funcname: Invalid boot pool size \`%s'" \
 		          "$ZFSBOOT_BOOT_POOL_SIZE"
 		f_show_err "$msg_invalid_boot_pool_size" \
 		           "$ZFSBOOT_BOOT_POOL_SIZE"
 		return $FAILURE
 	fi
 	f_dprintf "$funcname: ZFSBOOT_SWAP_SIZE=[%s] swapsize=[%s]" \
 	          "$ZFSBOOT_SWAP_SIZE" "$swapsize"
 	f_dprintf "$funcname: ZFSBOOT_BOOT_POOL_SIZE=[%s] bootsize=[%s]" \
 	          "$ZFSBOOT_BOOT_POOL_SIZE" "$bootsize"
 
 	#
 	# Destroy the pool in-case this is our second time 'round (case of
 	# failure and installer presented ``Retry'' option to come back).
 	#
 	# NB: If we don't destroy the pool, later gpart(8) destroy commands
 	# that try to clear existing partitions (see zfs_create_diskpart())
 	# will fail with a `Device Busy' error, leading to `GEOM exists'.
 	#
 	f_eval_catch -d $funcname zpool "$ZPOOL_DESTROY" "$zroot_name"
 
 	#
 	# Prepare the disks and build pool device list(s)
 	#
 	f_dprintf "$funcname: Preparing disk partitions for ZFS pool..."
 
 	# Force 4K sectors using vfs.zfs.min_auto_ashift=12
 	if [ "$ZFSBOOT_FORCE_4K_SECTORS" ]; then
 		f_dprintf "$funcname: With 4K sectors..."
 		f_eval_catch $funcname sysctl "$SYSCTL_ZFS_MIN_ASHIFT_12" \
 		    || return $FAILURE
 		sysctl kern.geom.part.mbr.enforce_chs=0
 	fi
 	local n=0
 	for disk in $disks; do
 		zfs_create_diskpart $disk $n || return $FAILURE
 		# Now $bootpart, $targetpart, and $swappart are set (suffix
 		# for $disk)
 		if [ "$ZFSBOOT_BOOT_POOL" ]; then
 			boot_vdevs="$boot_vdevs $disk$bootpart"
 		fi
 		zroot_vdevs="$zroot_vdevs $disk$targetpart"
 		if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then
 			zroot_vdevs="$zroot_vdevs.eli"
 		fi
 
 		n=$(( $n + 1 ))
 	done # disks
 
 	#
 	# If we need/want a boot pool, create it
 	#
 	if [ "$ZFSBOOT_BOOT_POOL" ]; then
 		local bootpool_vdevtype= # Calculated below
 		local bootpool_options= # Calculated below
 		local bootpool_name="$ZFSBOOT_BOOT_POOL_NAME"
 		local bootpool="$BSDINSTALL_CHROOT/$bootpool_name"
 		local zroot_key="${ZFSBOOT_GELI_KEY_FILE#/}"
 
 		f_dprintf "$funcname: Setting up boot pool..."
 		[ "$ZFSBOOT_GELI_ENCRYPTION" ] &&
 			f_dprintf "$funcname: For encrypted root disk..."
 
 		# Create parent directory for boot pool
 		f_eval_catch -d $funcname umount "$UMOUNT" "$BSDINSTALL_CHROOT"
 		f_eval_catch $funcname mount "$MOUNT_TYPE" tmpfs none \
 		             $BSDINSTALL_CHROOT || return $FAILURE
 
 		# Create mirror across the boot partition on all disks
 		local nvdevs
 		f_count nvdevs $boot_vdevs
 		[ $nvdevs -gt 1 ] && bootpool_vdevtype=mirror
 
 		create_options="$ZFSBOOT_BOOT_POOL_CREATE_OPTIONS"
 		bootpool_options="-o altroot=$BSDINSTALL_CHROOT"
 		bootpool_options="$bootpool_options $create_options"
 		bootpool_options="$bootpool_options -m \"/$bootpool_name\" -f"
 		f_eval_catch $funcname zpool "$ZPOOL_CREATE_WITH_OPTIONS" \
 		             "$bootpool_options" "$bootpool_name" \
 		             "$bootpool_vdevtype" "$boot_vdevs" ||
 		             return $FAILURE
 
 		f_eval_catch $funcname mkdir "$MKDIR_P" "$bootpool/boot" ||
 		             return $FAILURE
 
 		if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then
 			# Generate an encryption key using random(4)
 			f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
 			             /dev/random "$bootpool/$zroot_key" \
 			             "bs=4096 count=1" || return $FAILURE
 			f_eval_catch $funcname chmod "$CHMOD_MODE" \
 			             go-wrx "$bootpool/$zroot_key" ||
 			             return $FAILURE
 		fi
 
 	fi
 
 	#
 	# Create the geli(8) GEOMS
 	#
 	if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then
 		#
 		# Load the AES-NI kernel module to accelerate encryption
 		#
 		f_eval_catch -d $funcname kldload "$KLDLOAD" "aesni"
 		# Prompt user for password (twice)
 		if ! msg_enter_new_password="$msg_geli_password" \
 			f_dialog_input_password
 		then
 			f_dprintf "$funcname: User cancelled"
 			f_show_err "$msg_user_cancelled"
 			return $FAILURE
 		fi
 
 		# Initialize geli(8) on each of the target partitions
 		for disk in $disks; do
 			f_dialog_info "$msg_geli_setup" \
 				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
 			if [ "$ZFSBOOT_BOOT_POOL" ]; then
 				if ! echo "$pw_password" | f_eval_catch \
 					$funcname geli "$GELI_PASSWORD_INIT" \
 					"$bootpool/boot/$disk$targetpart.eli" \
 					AES-XTS "$bootpool/$zroot_key" \
 					$disk$targetpart
 				then
 					f_interactive || f_die
 					unset pw_password # Sensitive info
 					return $FAILURE
 				fi
 				if ! echo "$pw_password" | f_eval_catch \
 					$funcname geli "$GELI_ATTACH" \
 					"$bootpool/$zroot_key" $disk$targetpart
 				then
 					f_interactive || f_die
 					unset pw_password # Sensitive info
 					return $FAILURE
 				fi
 			else
 				# With no bootpool, there is no place to store
 				# the key files, use only a password
 				if ! echo "$pw_password" | f_eval_catch \
 					$funcname geli \
 					"$GELI_PASSWORD_GELIBOOT_INIT" \
 					AES-XTS $disk$targetpart
 				then
 					f_interactive || f_die
 					unset pw_password # Sensitive info
 					return $FAILURE
 				fi
 				if ! echo "$pw_password" | f_eval_catch \
 					$funcname geli "$GELI_ATTACH_NOKEY" \
 					$disk$targetpart
 				then
 					f_interactive || f_die
 					unset pw_password # Sensitive info
 					return $FAILURE
 				fi
 			fi
 		done
 		unset pw_password # Sensitive info
 	fi
 
 	if [ "$ZFSBOOT_BOOT_POOL" ]; then
 		# Clean up
 		f_eval_catch $funcname zfs "$ZFS_UNMOUNT" "$bootpool_name" ||
 			return $FAILURE
 		# tmpfs
 		f_eval_catch -d $funcname umount "$UMOUNT" "$BSDINSTALL_CHROOT"
 	fi
 
 	#
 	# Create the gmirror(8) GEOMS for swap
 	#
 	if [ ${swapsize:-0} -gt 0 -a "$ZFSBOOT_SWAP_MIRROR" ]; then
 		for disk in $disks; do
 			swap_devs="$swap_devs $disk$swappart"
 		done
 		f_eval_catch $funcname gmirror "$SWAP_GMIRROR_LABEL" \
 			"$swap_devs" || return $FAILURE
 	fi
 
 	#
 	# Create the ZFS root pool with desired type and disk devices
 	#
 	f_dprintf "$funcname: Creating root pool..."
 	create_options="$ZFSBOOT_POOL_CREATE_OPTIONS"
 	if [ "$zroot_vdevtype" == "raid10" ]; then
 		raid10_vdevs=""
 		for vdev in $zroot_vdevs; do
 			f_count nvdev $raid10_vdevs
 			if [ $(( $nvdev % 3 )) -eq 0 ]; then
 				raid10_vdevs="$raid10_vdevs mirror"
 			fi
 			raid10_vdevs="$raid10_vdevs $vdev"
 		done
 		f_eval_catch $funcname zpool "$ZPOOL_CREATE_WITH_OPTIONS" \
 			"-o altroot=$BSDINSTALL_CHROOT $create_options -m none -f" \
 			"$zroot_name" "" "$raid10_vdevs" || return $FAILURE
 	else
 		f_eval_catch $funcname zpool "$ZPOOL_CREATE_WITH_OPTIONS" \
 			"-o altroot=$BSDINSTALL_CHROOT $create_options -m none -f" \
 			"$zroot_name" "$zroot_vdevtype" "$zroot_vdevs" ||
 			return $FAILURE
 	fi
 
 	#
 	# Create ZFS dataset layout within the new root pool
 	#
 	f_dprintf "$funcname: Creating ZFS datasets..."
 	echo "$ZFSBOOT_DATASETS" | while read dataset options; do
 		# Skip blank lines and comments
 		case "$dataset" in "#"*|"") continue; esac
 		# Remove potential inline comments in options
 		options="${options%%#*}"
 		# Replace tabs with spaces
 		f_replaceall "$options" "	" " " options
 		# Reduce contiguous runs of space to one single space
 		oldoptions=
 		while [ "$oldoptions" != "$options" ]; do
 			oldoptions="$options"
 			f_replaceall "$options" "  " " " options
 		done
 		# Replace both commas and spaces with ` -o '
 		f_replaceall "$options" "[ ,]" " -o " options
 		# Create the dataset with desired options
 		f_eval_catch $funcname zfs "$ZFS_CREATE_WITH_OPTIONS" \
 		             "${options:+-o $options}" "$zroot_name$dataset" ||
 		             return $FAILURE
 	done
 
 	#
 	# Set a mountpoint for the root of the pool so newly created datasets
 	# have a mountpoint to inherit
 	#
 	f_dprintf "$funcname: Setting mountpoint for root of the pool..."
 	f_eval_catch $funcname zfs "$ZFS_SET" \
 		"mountpoint=/$zroot_name" "$zroot_name" || return $FAILURE
 
 	# Touch up permissions on the tmp directories
 	f_dprintf "$funcname: Modifying directory permissions..."
 	local dir
 	for dir in /tmp /var/tmp; do
 		f_eval_catch $funcname mkdir "$MKDIR_P" \
 		             $BSDINSTALL_CHROOT$dir || return $FAILURE
 		f_eval_catch $funcname chmod "$CHMOD_MODE" 1777 \
 		             $BSDINSTALL_CHROOT$dir || return $FAILURE
 	done
 
 	# Set bootfs property
 	local zroot_bootfs="$ZFSBOOT_BEROOT_NAME/$ZFSBOOT_BOOTFS_NAME"
 	f_dprintf "$funcname: Setting bootfs property..."
 	f_eval_catch $funcname zpool "$ZPOOL_SET" \
 		"bootfs=\"$zroot_name/$zroot_bootfs\"" "$zroot_name" ||
 		return $FAILURE
 
 	# MBR boot loader touch-up
 	if [ "$ZFSBOOT_PARTITION_SCHEME" = "MBR" ]; then
 		# Export the pool(s)
 		f_dprintf "$funcname: Temporarily exporting ZFS pool(s)..."
 		f_eval_catch $funcname zpool "$ZPOOL_EXPORT" "$zroot_name" ||
 			     return $FAILURE
 		if [ "$ZFSBOOT_BOOT_POOL" ]; then
 			f_eval_catch $funcname zpool "$ZPOOL_EXPORT" \
 				     "$bootpool_name" || return $FAILURE
 		fi
 
 		f_dprintf "$funcname: Updating MBR boot loader on disks..."
 		# Stick the ZFS boot loader in the "convenient hole" after
 		# the ZFS internal metadata
 		for disk in $disks; do
 			f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
 			             /boot/zfsboot /dev/$disk$bootpart \
 			             "skip=1 seek=1024" || return $FAILURE
 		done
 
 		# Re-import the ZFS pool(s)
 		f_dprintf "$funcname: Re-importing ZFS pool(s)..."
 		f_eval_catch $funcname zpool "$ZPOOL_IMPORT_WITH_OPTIONS" \
 			     "-o altroot=\"$BSDINSTALL_CHROOT\"" \
 			     "$zroot_name" || return $FAILURE
 		if [ "$ZFSBOOT_BOOT_POOL" ]; then
 			# Import the bootpool, but do not mount it yet
 			f_eval_catch $funcname zpool \
 				     "$ZPOOL_IMPORT_WITH_OPTIONS" \
 				     "-o altroot=\"$BSDINSTALL_CHROOT\" -N" \
 				     "$bootpool_name" || return $FAILURE
 		fi
 	fi
 
 	# Remount bootpool and create symlink(s)
 	if [ "$ZFSBOOT_BOOT_POOL" ]; then
 		f_eval_catch $funcname zfs "$ZFS_MOUNT" "$bootpool_name" ||
 			return $FAILURE
 		f_dprintf "$funcname: Creating /boot symlink for boot pool..."
 		f_eval_catch $funcname ln "$LN_SF" "$bootpool_name/boot" \
 		             $BSDINSTALL_CHROOT/boot || return $FAILURE
 	fi
 
 	# zpool.cache is required to mount more than one pool at boot time
 	f_dprintf "$funcname: Configuring zpool.cache for zroot..."
 	f_eval_catch $funcname mkdir "$MKDIR_P" $BSDINSTALL_CHROOT/boot/zfs ||
 	             return $FAILURE
 	f_eval_catch $funcname zpool "$ZPOOL_SET" \
 	             "cachefile=\"$BSDINSTALL_CHROOT/boot/zfs/zpool.cache\"" \
 	             "$zroot_name" || return $FAILURE
 
 	if [ "$ZFSBOOT_BOOT_POOL" ]; then
 		f_eval_catch $funcname printf "$PRINTF_CONF" \
 			vfs.root.mountfrom \
 			"\"zfs:$zroot_name/$zroot_bootfs\"" \
 			$BSDINSTALL_TMPBOOT/loader.conf.root || return $FAILURE
 	fi
 	#
 	# Set canmount=noauto so that the default Boot Environment (BE) does
 	# not get mounted if a different BE is selected from the beastie menu
 	#
 	f_dprintf "$funcname: Set canmount=noauto for the root of the pool..."
 	f_eval_catch $funcname zfs "$ZFS_SET" "canmount=noauto" \
 		"$zroot_name/$ZFSBOOT_BEROOT_NAME/$ZFSBOOT_BOOTFS_NAME"
 
 	# Last, but not least... required lines for rc.conf(5)/loader.conf(5)
 	# NOTE: We later concatenate these into their destination
 	f_dprintf "%s: Configuring rc.conf(5)/loader.conf(5) additions..." \
 	          "$funcname"
 	f_eval_catch $funcname echo "$ECHO_APPEND" 'zfs_enable=\"YES\"' \
 	             $BSDINSTALL_TMPETC/rc.conf.zfs || return $FAILURE
 	f_eval_catch $funcname echo "$ECHO_APPEND" \
 	             'kern.geom.label.disk_ident.enable=\"0\"' \
 	             $BSDINSTALL_TMPBOOT/loader.conf.zfs || return $FAILURE
 	f_eval_catch $funcname echo "$ECHO_APPEND" \
 	             'kern.geom.label.gptid.enable=\"0\"' \
 	             $BSDINSTALL_TMPBOOT/loader.conf.zfs || return $FAILURE
 
 	if [ "$ZFSBOOT_FORCE_4K_SECTORS" ]; then
 		f_eval_catch $funcname echo "$ECHO_APPEND" \
 	             'vfs.zfs.min_auto_ashift=12' \
 	             $BSDINSTALL_TMPETC/sysctl.conf.zfs || return $FAILURE
 	fi
 
 	if [ "$ZFSBOOT_SWAP_MIRROR" ]; then
 		f_eval_catch $funcname echo "$ECHO_APPEND" \
 		             'geom_mirror_load=\"YES\"' \
 		             $BSDINSTALL_TMPBOOT/loader.conf.gmirror ||
 		             return $FAILURE
 	fi
 
 	# We're all done unless we should go on to do encryption
 	[ "$ZFSBOOT_GELI_ENCRYPTION" ] || return $SUCCESS
 
 	#
 	# Configure geli(8)-based encryption
 	#
 	f_dprintf "$funcname: Configuring disk encryption..."
 	f_eval_catch $funcname echo "$ECHO_APPEND" 'aesni_load=\"YES\"' \
 		$BSDINSTALL_TMPBOOT/loader.conf.aesni || return $FAILURE
 	f_eval_catch $funcname echo "$ECHO_APPEND" 'geom_eli_load=\"YES\"' \
 		$BSDINSTALL_TMPBOOT/loader.conf.geli || return $FAILURE
 
 	# We're all done unless we should go on for boot pool
 	[ "$ZFSBOOT_BOOT_POOL" ] || return $SUCCESS
 
 	for disk in $disks; do
 		f_eval_catch $funcname printf "$PRINTF_CONF" \
 			geli_%s_keyfile0_load "$disk$targetpart YES" \
 			$BSDINSTALL_TMPBOOT/loader.conf.$disk$targetpart ||
 			return $FAILURE
 		f_eval_catch $funcname printf "$PRINTF_CONF" \
 			geli_%s_keyfile0_type \
 			"$disk$targetpart $disk$targetpart:geli_keyfile0" \
 			$BSDINSTALL_TMPBOOT/loader.conf.$disk$targetpart ||
 			return $FAILURE
 		f_eval_catch $funcname printf "$PRINTF_CONF" \
 			geli_%s_keyfile0_name \
 			"$disk$targetpart \"$ZFSBOOT_GELI_KEY_FILE\"" \
 			$BSDINSTALL_TMPBOOT/loader.conf.$disk$targetpart ||
 			return $FAILURE
 	done
 
 	# Set cachefile for boot pool so it auto-imports at system start
 	f_dprintf "$funcname: Configuring zpool.cache for boot pool..."
 	f_eval_catch $funcname zpool "$ZPOOL_SET" \
 	             "cachefile=\"$BSDINSTALL_CHROOT/boot/zfs/zpool.cache\"" \
 	             "$bootpool_name" || return $FAILURE
 
 	# Some additional geli(8) requirements for loader.conf(5)
 	for option in \
 		'zpool_cache_load=\"YES\"' \
 		'zpool_cache_type=\"/boot/zfs/zpool.cache\"' \
 		'zpool_cache_name=\"/boot/zfs/zpool.cache\"' \
 		'geom_eli_passphrase_prompt=\"YES\"' \
 	; do
 		f_eval_catch $funcname echo "$ECHO_APPEND" "$option" \
 		             $BSDINSTALL_TMPBOOT/loader.conf.zfs ||
 		             return $FAILURE
 	done
 	return $SUCCESS
 }
 
 # dialog_menu_diskinfo
 #
 # Prompt the user to select a disk and then provide detailed info on it.
 #
 dialog_menu_diskinfo()
 {
 	local device disk
 
 	#
 	# Break from loop when user cancels disk selection
 	#
 	while :; do
 		device=$( msg_cancel="$msg_back" f_device_menu \
 			"$DIALOG_TITLE" "$msg_select_a_disk_device" "" \
 			$DEVICE_TYPE_DISK 2>&1 ) || break
 		$device get name disk
 
 		# Show gpart(8) `show' and camcontrol(8) `inquiry' data
 		f_show_msg "$msg_detailed_disk_info" \
 			"$disk" "$( gpart show $disk 2> /dev/null )" \
 			"$disk" "$( camcontrol inquiry $disk 2> /dev/null )" \
 			"$disk" "$( camcontrol identify $disk 2> /dev/null )"
 	done
 
 	return $SUCCESS
 }
 
 ############################################################ MAIN
 
 #
 # Initialize
 #
 f_dialog_title "$msg_zfs_configuration"
 f_dialog_backtitle "$msg_freebsd_installer"
 
 # User may have specifically requested ZFS-related operations be interactive
 ! f_interactive && f_zfsinteractive && unset $VAR_NONINTERACTIVE
 
 #
 # Debugging
 #
 f_dprintf "BSDINSTALL_CHROOT=[%s]" "$BSDINSTALL_CHROOT"
 f_dprintf "BSDINSTALL_TMPETC=[%s]" "$BSDINSTALL_TMPETC"
 f_dprintf "FSTAB_FMT=[%s]" "$FSTAB_FMT"
 
 #
 # Determine default boot type
 #
 case $(uname -m) in
 arm64|riscv)
 	# We support only UEFI boot for arm64 and riscv.
 	: ${ZFSBOOT_BOOT_TYPE:=UEFI}
 	: ${ZFSBOOT_PARTITION_SCHEME:=GPT}
 	;;
 *)
 	# If the system was booted with UEFI, set the default boot type to UEFI
 	bootmethod=$( sysctl -n machdep.bootmethod )
 	f_dprintf "machdep.bootmethod=[%s]" "$bootmethod"
 	if [ "$bootmethod" = "UEFI" ]; then
 		: ${ZFSBOOT_BOOT_TYPE:=BIOS+UEFI}
 		: ${ZFSBOOT_PARTITION_SCHEME:=GPT}
 	else
 		: ${ZFSBOOT_BOOT_TYPE:=BIOS}
 		: ${ZFSBOOT_PARTITION_SCHEME:=GPT}
 	fi
 	;;
 esac
 
 #
 # Loop over the main menu until we've accomplished what we came here to do
 #
 while :; do
 	if ! f_interactive; then
 		retval=$DIALOG_OK
 		mtag=">>> $msg_install"
 	else
 		dialog_menu_main
 		retval=$?
 		f_dialog_menutag_fetch mtag
 	fi
 
 	f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
 	[ $retval -eq $DIALOG_OK ] || f_die
 
 	case "$mtag" in
 	">>> $msg_install")
 		#
 		# First, validate the user's selections
 		#
 
 		# Make sure they gave us a name for the pool
 		if [ ! "$ZFSBOOT_POOL_NAME" ]; then
 			f_dprintf "Pool name cannot be empty."
 			f_show_err "$msg_pool_name_cannot_be_empty"
 			continue
 		fi
 
 		# Validate vdev type against number of disks selected/scripted
 		# (also validates that ZFSBOOT_DISKS are real [probed] disks)
 		# NB: dialog_menu_layout supports running non-interactively
 		dialog_menu_layout || continue
 
 		# Make sure each disk will have room for ZFS
 		if f_expand_number "$ZFSBOOT_SWAP_SIZE" swapsize &&
 		   f_expand_number "$ZFSBOOT_BOOT_POOL_SIZE" bootsize &&
 		   f_expand_number "1g" zpoolmin
 		then
 			minsize=$(( $swapsize + $zpoolmin )) teeny_disks=
 			[ "$ZFSBOOT_BOOT_POOL" ] &&
 				minsize=$(( $minsize + $bootsize ))
 			for disk in $ZFSBOOT_DISKS; do
 				debug= f_device_find -1 \
 					$disk $DEVICE_TYPE_DISK device
 				$device get capacity disksize || continue
 				[ ${disksize:-0} -ge 0 ] || disksize=0
 				[ $disksize -lt $minsize ] &&
 					teeny_disks="$teeny_disks $disk"
 			done
 			if [ "$teeny_disks" ]; then
 				f_dprintf "swapsize=[%s] bootsize[%s] %s" \
 				          "$ZFSBOOT_SWAP_SIZE" \
 				          "$ZFSBOOT_BOOT_POOL_SIZE" \
 				          "minsize=[$minsize]"
 				f_dprintf "These disks are too small: %s" \
 				          "$teeny_disks"
 				f_show_err "$msg_these_disks_are_too_small" \
 				           "$ZFSBOOT_SWAP_SIZE" \
 				           "$ZFSBOOT_BOOT_POOL_SIZE" \
 				           "$teeny_disks"
 				continue
 			fi
 		fi
 
 		#
 		# Last Chance!
 		#
 		if f_interactive; then
 			dialog_last_chance $ZFSBOOT_DISKS || continue
 		fi
 
 		#
 		# Let's do this
 		#
 
 		vdev_type="$ZFSBOOT_VDEV_TYPE"
 
 		# Blank the vdev type for the default layout
 		[ "$vdev_type" = "stripe" ] && vdev_type=
 
 		zfs_create_boot "$ZFSBOOT_POOL_NAME" \
 		                "$vdev_type" $ZFSBOOT_DISKS || continue
 
 		# To be reused by bootconfig
 		echo "$ZFSBOOT_DISKS" > ${TMPDIR:-"/tmp"}/bsdinstall-zfsboot
 
 		break # to success
 		;;
 	?" $msg_pool_type_disks")
 		ZFSBOOT_CONFIRM_LAYOUT=1
 		dialog_menu_layout
 		# User has poked settings, disable later confirmation
 		ZFSBOOT_CONFIRM_LAYOUT=
 		;;
 	"- $msg_rescan_devices") f_device_rescan ;;
 	"- $msg_disk_info") dialog_menu_diskinfo ;;
 	?" $msg_pool_name")
 		# Prompt the user to input/change the name for the new pool
 		f_dialog_input input \
 			"$msg_please_enter_a_name_for_your_zpool" \
 			"$ZFSBOOT_POOL_NAME" &&
 			ZFSBOOT_POOL_NAME="$input"
 		;;
 	?" $msg_force_4k_sectors")
 		# Toggle the variable referenced both by the menu and later
 		if [ "$ZFSBOOT_FORCE_4K_SECTORS" ]; then
 			ZFSBOOT_FORCE_4K_SECTORS=
 		else
 			ZFSBOOT_FORCE_4K_SECTORS=1
 		fi
 		;;
 	?" $msg_encrypt_disks")
 		# Toggle the variable referenced both by the menu and later
 		if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then
 			ZFSBOOT_GELI_ENCRYPTION=
 		else
 			ZFSBOOT_FORCE_4K_SECTORS=1
 			ZFSBOOT_GELI_ENCRYPTION=1
 		fi
 		;;
 	?" $msg_partition_scheme")
 		# Toggle between GPT (BIOS), GPT (UEFI) and MBR
 		if [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT" -a \
 		     "$ZFSBOOT_BOOT_TYPE" = "BIOS" ]
 		then
 			ZFSBOOT_PARTITION_SCHEME="GPT"
 			ZFSBOOT_BOOT_TYPE="UEFI"
 		elif [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT" -a \
 		       "$ZFSBOOT_BOOT_TYPE" = "UEFI" ]
 		then
 			ZFSBOOT_PARTITION_SCHEME="GPT"
 			ZFSBOOT_BOOT_TYPE="BIOS+UEFI"
 		elif [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT" ]; then
 			ZFSBOOT_PARTITION_SCHEME="MBR"
 			ZFSBOOT_BOOT_TYPE="BIOS"
 		elif [ "$ZFSBOOT_PARTITION_SCHEME" = "MBR" ]; then
 			ZFSBOOT_PARTITION_SCHEME="GPT + Active"
 			ZFSBOOT_BOOT_TYPE="BIOS"
 		elif [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT + Active" ]; then
 			ZFSBOOT_PARTITION_SCHEME="GPT + Lenovo Fix"
 			ZFSBOOT_BOOT_TYPE="BIOS"
 		else
 			ZFSBOOT_PARTITION_SCHEME="GPT"
 			ZFSBOOT_BOOT_TYPE="BIOS"
 		fi
 		;;
 	?" $msg_swap_size")
 		# Prompt the user to input/change the swap size for each disk
 		while :; do
 		    f_dialog_input input \
 			    "$msg_please_enter_amount_of_swap_space" \
 			    "$ZFSBOOT_SWAP_SIZE" &&
 			    ZFSBOOT_SWAP_SIZE="${input:-0}"
 		    if f_expand_number "$ZFSBOOT_SWAP_SIZE" swapsize
 		    then
 			if [ $swapsize -ne 0 -a $swapsize -lt 104857600 ]; then
 			    f_show_err "$msg_swap_toosmall" \
 				       "$ZFSBOOT_SWAP_SIZE"
 			    continue;
 			else
 			    break;
 			fi
 		    else
 			f_show_err "$msg_swap_invalid" \
 				   "$ZFSBOOT_SWAP_SIZE"
 			continue;
 		    fi
 		done
 		;;
 	?" $msg_swap_mirror")
 		# Toggle the variable referenced both by the menu and later
 		if [ "$ZFSBOOT_SWAP_MIRROR" ]; then
 			ZFSBOOT_SWAP_MIRROR=
 		else
 			ZFSBOOT_SWAP_MIRROR=1
 		fi
 		;;
 	?" $msg_swap_encrypt")
 		# Toggle the variable referenced both by the menu and later
 		if [ "$ZFSBOOT_SWAP_ENCRYPTION" ]; then
 			ZFSBOOT_SWAP_ENCRYPTION=
 		else
 			ZFSBOOT_SWAP_ENCRYPTION=1
 		fi
 		;;
 	esac
 done
 
 exit $SUCCESS
 
 ################################################################################
 # END
 ################################################################################