From owner-svn-src-all@FreeBSD.ORG Mon Apr 14 01:18:04 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 53808C33; Mon, 14 Apr 2014 01:18:04 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 3E68E1B0F; Mon, 14 Apr 2014 01:18:04 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s3E1I46e045063; Mon, 14 Apr 2014 01:18:04 GMT (envelope-from dteske@svn.freebsd.org) Received: (from dteske@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s3E1I2WN045050; Mon, 14 Apr 2014 01:18:02 GMT (envelope-from dteske@svn.freebsd.org) Message-Id: <201404140118.s3E1I2WN045050@svn.freebsd.org> From: Devin Teske Date: Mon, 14 Apr 2014 01:18:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r264437 - in stable/9/usr.sbin/bsdinstall: . scripts X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 14 Apr 2014 01:18:04 -0000 Author: dteske Date: Mon Apr 14 01:18:02 2014 New Revision: 264437 URL: http://svnweb.freebsd.org/changeset/base/264437 Log: MFC r256343,256540-256541,256544,256549,256551,256553,257939,258021,258927, 259144,259148,259470,259472,259474,259476-259478,259480-259481,259570, 259597-259598, and 261960 (24 revisions; summarized below)... r256343: Add zfsboot module as an option for automatic configuration r256540: Add zpool_cache_* variables to loader.conf(5) r256541: Document BSDINSTALL_TMPBOOT in bsdinstall.8 r256544: Fix a typo when setting up loader.conf(5) GELI entries r256549: Document zfsboot in bsdinstall.8 r256551: Bump .Dd date in bsdinstall.8 r256553: Align ZFSBOOT_BEROOT_NAME with sysutils/beadm + Solaris beadm r257939: Validate scripted partition entry before acting on disks r258021: Switch default MBR bootcode from /boot/boot0 to /boot/mbr r258927: Fix early regression in enabling the Encryption feature r259144: Fix early regression in entering passphrase for Encryption r259148: Fix typo that broke booting from Encrypted setup r259470: Add default /var/mail with atime=on for mail apps r259472: Accept NULL input as also meaning zero swap r259474: Bug fixes and debugging improvements r259476: Improve default ZFS disk layout r259477: fletcher4 is currently the default r259478: De-uglify the geli(8)-setup infobox by adding a newline r259480: Fix ghosted zroot pool issue r259481: Auto-enable 4k alignment with Encryption r259570: Fix "[: -eq: argument expected" error r259597: Fix installation to 3-4+ disks r259598: Set the cachefile property so bootpools get imported r261960: Add zfsboot to scripted interface of bsdinstall Added: stable/9/usr.sbin/bsdinstall/scripts/zfsboot - copied, changed from r256343, head/usr.sbin/bsdinstall/scripts/zfsboot Modified: stable/9/usr.sbin/bsdinstall/bsdinstall stable/9/usr.sbin/bsdinstall/bsdinstall.8 stable/9/usr.sbin/bsdinstall/scripts/Makefile stable/9/usr.sbin/bsdinstall/scripts/auto stable/9/usr.sbin/bsdinstall/scripts/config stable/9/usr.sbin/bsdinstall/scripts/script Directory Properties: stable/9/ (props changed) stable/9/usr.sbin/ (props changed) stable/9/usr.sbin/bsdinstall/ (props changed) stable/9/usr.sbin/bsdinstall/scripts/ (props changed) Modified: stable/9/usr.sbin/bsdinstall/bsdinstall ============================================================================== --- stable/9/usr.sbin/bsdinstall/bsdinstall Mon Apr 14 00:24:04 2014 (r264436) +++ stable/9/usr.sbin/bsdinstall/bsdinstall Mon Apr 14 01:18:02 2014 (r264437) @@ -41,6 +41,7 @@ BSDCFG_SHARE="/usr/share/bsdconfig" ############################################################ GLOBALS : ${BSDINSTALL_TMPETC="/tmp/bsdinstall_etc"}; export BSDINSTALL_TMPETC +: ${BSDINSTALL_TMPBOOT="/tmp/bsdinstall_boot"}; export BSDINSTALL_TMPBOOT : ${PATH_FSTAB="$BSDINSTALL_TMPETC/fstab"}; export PATH_FSTAB : ${BSDINSTALL_DISTDIR="/usr/freebsd-dist"}; export BSDINSTALL_DISTDIR : ${BSDINSTALL_CHROOT="/mnt"}; export BSDINSTALL_CHROOT @@ -61,6 +62,7 @@ shift $(( $OPTIND - 1 )) VERB="${1:-auto}"; shift [ -d "$BSDINSTALL_TMPETC" ] || mkdir -p "$BSDINSTALL_TMPETC" +[ -d "$BSDINSTALL_TMPBOOT" ] || mkdir -p "$BSDINSTALL_TMPBOOT" # Only enable debugging if debugFile is non-NULL and can be initialized f_quietly f_debug_init Modified: stable/9/usr.sbin/bsdinstall/bsdinstall.8 ============================================================================== --- stable/9/usr.sbin/bsdinstall/bsdinstall.8 Mon Apr 14 00:24:04 2014 (r264436) +++ stable/9/usr.sbin/bsdinstall/bsdinstall.8 Mon Apr 14 01:18:02 2014 (r264437) @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 6, 2013 +.Dd October 15, 2013 .Dt BSDINSTALL 8 .Os .Sh NAME @@ -121,6 +121,21 @@ installations. Partitions disks, runs .Xr newfs 8 , and writes the new system's .Pa fstab . +.It Cm zfsboot +Provides the installer's +.Pq experimental +interactive/scriptable ZFS partitioner for multi-disk installations. +Creates a single +.Ic zpool +with datasets and writes to the new system's +.Pa rc.conf , +.Pa loader.conf , +and +.Pa fstab . +Supports +.Xr geli 8 , +.Xr gnop 8 , +and many other features. .It Cm partedit Provides the installer's interactive manual disk partitioner, with support for multi disk setups, non-UFS file systems, and manual selection of @@ -267,6 +282,14 @@ will be stored until the target is executed. If this directory does not already exist, it will be created. Default: .Pa /tmp/bsdinstall_etc +.It Ev BSDINSTALL_TMPBOOT +Directory where files destined for the new system's +.Pa /boot +will be stored until the +.Cm config +target is executed. If this directory does not already exist, it will be +created. Default: +.Pa /tmp/bsdinstall_boot .El .Sh SCRIPTING .Nm @@ -320,6 +343,15 @@ the preamble can contain a variable which is passed to the .Cm scriptedpart target to control disk setup. +Alternatively, +instead of +.Ev PARTITIONS , +the preamble can contain the variable +.Ev ZFSBOOT_DATASETS +which is parsed by the +.Pq experimental +.Cm zfsboot +target to control ZFS datasets/options of the boot pool setup. .Ss SETUP SCRIPT Following the preamble is an optional shell script, beginning with a #! declaration. This script will be run at the end of the installation process Modified: stable/9/usr.sbin/bsdinstall/scripts/Makefile ============================================================================== --- stable/9/usr.sbin/bsdinstall/scripts/Makefile Mon Apr 14 00:24:04 2014 (r264436) +++ stable/9/usr.sbin/bsdinstall/scripts/Makefile Mon Apr 14 01:18:02 2014 (r264437) @@ -2,7 +2,7 @@ SCRIPTS= auto adduser checksum config docsinstall entropy hostname jail \ keymap mirrorselect mount netconfig netconfig_ipv4 netconfig_ipv6 \ - rootpass script services time umount wlanconfig + rootpass script services time umount wlanconfig zfsboot BINDIR= /usr/libexec/bsdinstall NO_MAN= true Modified: stable/9/usr.sbin/bsdinstall/scripts/auto ============================================================================== --- stable/9/usr.sbin/bsdinstall/scripts/auto Mon Apr 14 00:24:04 2014 (r264436) +++ stable/9/usr.sbin/bsdinstall/scripts/auto Mon Apr 14 01:18:02 2014 (r264437) @@ -102,21 +102,38 @@ fi rm -f $PATH_FSTAB touch $PATH_FSTAB -dialog --backtitle "FreeBSD Installer" --title "Partitioning" --extra-button \ - --extra-label "Manual" --ok-label "Guided" --cancel-label "Shell" \ - --yesno "Would you like to use the guided partitioning tool (recommended for beginners) or to set up partitions manually (experts)? You can also open a shell and set up partitions entirely by hand." 0 0 +PMODES="\ +Guided \"Partitioning Tool (Recommended for Beginners)\" \ +Manual \"Manually Configure Partitions (Expert)\" \ +Shell \"Open a shell and partition by hand\"" + +CURARCH=$( uname -m ) +case $CURARCH in + amd64|i386) # Booting ZFS Supported + PMODES="$PMODES ZFS \"Automatic Root-on-ZFS (Experimental)\"" + ;; + *) # Booting ZFS Unspported + ;; +esac -case $? in -0) # Guided +exec 3>&1 +PARTMODE=`echo $PMODES | xargs dialog --backtitle "FreeBSD Installer" \ + --title "Partitioning" \ + --menu "How would you like to partition your disk?" \ + 0 0 0 2>&1 1>&3` || exit 1 +exec 3>&- + +case "$PARTMODE" in +"Guided") # Guided bsdinstall autopart || error bsdinstall mount || error ;; -1) # Shell +"Shell") # Shell clear echo "Use this shell to set up partitions for the new system. When finished, mount the system at $BSDINSTALL_CHROOT and place an fstab file for the new system at $PATH_FSTAB. Then type 'exit'. You can also enter the partition editor at any time by entering 'bsdinstall partedit'." sh 2>&1 ;; -3) # Manual +"Manual") # Manual if f_isset debugFile; then # Give partedit the path to our logfile so it can append BSDINSTALL_LOG="${debugFile#+}" bsdinstall partedit || error @@ -125,6 +142,10 @@ case $? in fi bsdinstall mount || error ;; +"ZFS") # ZFS + bsdinstall zfsboot || error + bsdinstall mount || error + ;; *) error ;; Modified: stable/9/usr.sbin/bsdinstall/scripts/config ============================================================================== --- stable/9/usr.sbin/bsdinstall/scripts/config Mon Apr 14 00:24:04 2014 (r264436) +++ stable/9/usr.sbin/bsdinstall/scripts/config Mon Apr 14 01:18:02 2014 (r264437) @@ -34,6 +34,11 @@ rm $BSDINSTALL_TMPETC/rc.conf.* cp $BSDINSTALL_TMPETC/* $BSDINSTALL_CHROOT/etc +cat $BSDINSTALL_TMPBOOT/loader.conf.* >> $BSDINSTALL_TMPBOOT/loader.conf +rm $BSDINSTALL_TMPBOOT/loader.conf.* + +cp $BSDINSTALL_TMPBOOT/* $BSDINSTALL_CHROOT/boot + [ "${debugFile#+}" ] && cp "${debugFile#+}" $BSDINSTALL_CHROOT/var/log/ # Set up other things from installed config Modified: stable/9/usr.sbin/bsdinstall/scripts/script ============================================================================== --- stable/9/usr.sbin/bsdinstall/scripts/script Mon Apr 14 00:24:04 2014 (r264436) +++ stable/9/usr.sbin/bsdinstall/scripts/script Mon Apr 14 01:18:02 2014 (r264437) @@ -95,7 +95,11 @@ fi # Make partitions rm -f $PATH_FSTAB touch $PATH_FSTAB -bsdinstall scriptedpart "$PARTITIONS" +if [ "$ZFSBOOT_DISKS" ]; then + bsdinstall zfsboot +else + bsdinstall scriptedpart "$PARTITIONS" +fi bsdinstall mount # Unpack distributions Copied and modified: stable/9/usr.sbin/bsdinstall/scripts/zfsboot (from r256343, head/usr.sbin/bsdinstall/scripts/zfsboot) ============================================================================== --- head/usr.sbin/bsdinstall/scripts/zfsboot Fri Oct 11 20:41:35 2013 (r256343, copy source) +++ stable/9/usr.sbin/bsdinstall/scripts/zfsboot Mon Apr 14 01:18:02 2014 (r264437) @@ -47,7 +47,7 @@ f_include $BSDCFG_SHARE/variable.subr # # Default name for the boot environment parent dataset # -: ${ZFSBOOT_BEROOT_NAME:=bootenv} +: ${ZFSBOOT_BEROOT_NAME:=ROOT} # # Default name for the primany boot environment @@ -66,23 +66,30 @@ f_include $BSDCFG_SHARE/variable.subr # # Should we use geli(8) to encrypt the drives? +# NB: Automatically enables ZFSBOOT_BOOT_POOL # -: ${ZFSBOOT_GELI_ENCRYPTION:=} +: ${ZFSBOOT_GELI_ENCRYPTION=} # -# Default name the unencrypted pool when using geli(8) to encrypt the drives +# Default path to the geli(8) keyfile used in drive encryption # -: ${ZFSBOOT_GELI_POOL_NAME:=bootpool} +: ${ZFSBOOT_GELI_KEY_FILE:=/boot/encryption.key} # -# Default size for the unencrypted boot pool when using geli(8) +# Create a separate boot pool? +# NB: Automatically set when using geli(8) or MBR # -: ${ZFSBOOT_GELI_BOOT_SIZE:=2g} +: ${ZFSBOOT_BOOT_POOL=} # -# Default path to the geli(8) keyfile used in drive encryption +# Default name for boot pool when enabled (e.g., geli(8) or MBR) # -: ${ZFSBOOT_GELI_KEY_FILE:=/boot/encryption.key} +: ${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) @@ -101,7 +108,7 @@ f_include $BSDCFG_SHARE/variable.subr : ${ZFSBOOT_SWAP_SIZE:=2g} # -# Default ZFS layout for root zpool +# 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. @@ -119,69 +126,117 @@ f_isset ZFSBOOT_DATASETS || ZFSBOOT_DATA # Don't mount /usr so that 'base' files go to the BEROOT /usr mountpoint=/usr,canmount=off - /usr/local # local files (i.e. from packages) separate from base system - # Home directories separated so they are common to all BEs - /usr/home setuid=off + /usr/home # NB: /home is a symlink to /usr/home # Ports tree /usr/ports compression=lz4,setuid=off - /usr/ports/distfiles compression=off,exec=off,setuid=off - /usr/ports/packages compression=off,exec=off,setuid=off # Source tree (compressed) /usr/src compression=lz4,exec=off,setuid=off - /usr/obj # Object files # Create /var and friends /var mountpoint=/var /var/crash compression=lz4,exec=off,setuid=off - /var/db exec=off,setuid=off - /var/db/pkg compression=lz4,exec=off,setuid=off - /var/empty exec=off,setuid=off /var/log compression=lz4,exec=off,setuid=off - /var/mail compression=lz4,exec=off,setuid=off - /var/run exec=off,setuid=off + /var/mail compression=lz4,atime=on /var/tmp compression=lz4,exec=on,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 +# +CHMOD_MODE='chmod %s "%s"' +DD_WITH_OPTIONS='dd if="%s" of="%s" %s' +ECHO_APPEND='echo "%s" >> "%s"' +GELI_ATTACH='geli attach -j - -k "%s" "%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"' +GNOP_CREATE='gnop create -S 4096 "%s"' +GNOP_DESTROY='gnop destroy "%s"' +GPART_ADD='gpart add -t %s "%s"' +GPART_ADD_INDEX='gpart add -i %s -t %s "%s"' +GPART_ADD_INDEX_WITH_SIZE='gpart add -i %s -t %s -s %s "%s"' +GPART_ADD_LABEL='gpart add -l %s -t %s "%s"' +GPART_ADD_LABEL_WITH_SIZE='gpart add -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_CREATE='gpart create -s %s "%s"' +GPART_DESTROY_F='gpart destroy -F "%s"' +GPART_SET_ACTIVE='gpart set -a active -i %s "%s"' +GRAID_DELETE='graid delete "%s"' +LN_SF='ln -sf "%s" "%s"' +MKDIR_P='mkdir -p "%s"' +MOUNT_TYPE='mount -t %s "%s" "%s"' +PRINTF_CONF="printf '%s=\"%%s\"\\\n' %s >> \"%s\"" +PRINTF_FSTAB='printf "$FSTAB_FMT" "%s" "%s" "%s" "%s" "%s" "%s" >> "%s"' +SHELL_TRUNCATE=':> "%s"' +UMOUNT='umount "%s"' +ZFS_CREATE_WITH_OPTIONS='zfs create %s "%s"' +ZFS_SET='zfs set "%s" "%s"' +ZFS_UNMOUNT='zfs unmount "%s"' +ZPOOL_CREATE_WITH_OPTIONS='zpool create %s "%s" %s %s' +ZPOOL_EXPORT='zpool export "%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="Change Selection" +msg_change_selection="Change Selection" msg_configure_options="Configure Options:" -msg_create="Install" -msg_create_desc="Proceed with Installation" -msg_create_help="Create ZFS boot pool with displayed 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_disks_to_use="Disks To Use" -msg_disks_to_use_help="Choose which disks to use for the Virtual Device (Required)" +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="Use gnop(8) to configure forced 4K sector alignment" msg_freebsd_installer="FreeBSD Installer" -msg_geli_encryption="Encrypt Disks?" -msg_geli_encryption_help="Use geli(8) to encrypt all data partitions" 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 the selected disks, this will take several seconds per disk" +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_invalid_virtual_device_type_help="Select another Virtual Device type or Cancel to\nreturn to the ZFS menu. From there you can select\nmore disks or rescan for additional devices." -msg_last_chance_are_you_sure="Last Chance! Are you sure you want to destroy the current contents of the following disks:\n%s" -msg_last_chance_are_you_sure_color="\\\\ZrLast Chance!\\\\ZR Are you \\\\Z1sure\\\\Zn you want to \\\\Zr\\\\Z1destroy\\\\Zn the current contents of the following disks:\n%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 wanted)" +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_ok="OK" msg_partition_scheme="Partition Scheme" msg_partition_scheme_help="Toggle between GPT and MBR partitioning schemes" @@ -191,6 +246,8 @@ msg_please_select_one_or_more_disks="Ple 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_raidz1_desc="RAID-Z1 - Single Redundant RAID" msg_raidz1_help="[3+ Disks] Withstand failure of 1 disk. Recommended for: 3, 5 or 9 disks" @@ -207,11 +264,12 @@ msg_stripe_desc="Stripe - No Redundancy" msg_stripe_help="[1+ Disks] Striping provides maximum storage but no redundancy" msg_swap_size="Swap Size" msg_swap_size_help="Customize how much swap space is allocated to each selected disk" -msg_these_disks_are_too_small="These disks are too small given the amount of requested\nswap (%s) and/or GELI (%s) partitions, which would take\n50%% or more (not recommended) of each of the following\nselected disk devices:\n\n %s\n\nRecommend changing partition size(s) and/or selecting a\ndifferent set of devices." +msg_these_disks_are_too_small="These disks are too small given the amount of requested\nswap (%s) and/or geli(8) (%s) partitions, which would\ntake 50%% or more of each of the following selected disk\ndevices (not recommended):\n\n %s\n\nRecommend changing partition size(s) and/or selecting a\ndifferent set of devices." +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" -msg_zfs_vdev_type="ZFS VDev Type" -msg_zfs_vdev_type_help="Select type of ZFS Virtual Device to create" ############################################################ FUNCTIONS @@ -228,26 +286,26 @@ dialog_menu_main() local usegeli="$msg_no" [ "$ZFSBOOT_GNOP_4K_FORCE_ALIGN" ] && force4k="$msg_yes" [ "$ZFSBOOT_GELI_ENCRYPTION" ] && usegeli="$msg_yes" + local disks n=$( set -- $ZFSBOOT_DISKS; echo $# ) + { [ $n -eq 1 ] && disks=disk; } || disks=disks # grammar local menu_list=" - '>>> $msg_create' '$msg_create_desc' - '$msg_create_help' + '>>> $msg_install' '$msg_install_desc' + '$msg_install_help' + 'T $msg_pool_type_disks' '$ZFSBOOT_VDEV_TYPE: $n $disks' + '$msg_pool_type_disks_help' '- $msg_rescan_devices' '*' '$msg_rescan_devices_help' '- $msg_disk_info' '*' '$msg_disk_info_help' - '1 $msg_pool_name' '$ZFSBOOT_POOL_NAME' + 'N $msg_pool_name' '$ZFSBOOT_POOL_NAME' '$msg_pool_name_help' - '2 $msg_disks_to_use' '$ZFSBOOT_DISKS' - '$msg_disks_to_use_help' - '3 $msg_zfs_vdev_type' '$ZFSBOOT_VDEV_TYPE' - '$msg_zfs_vdev_type_help' '4 $msg_force_4k_sectors' '$force4k' '$msg_force_4k_sectors_help' - '5 $msg_geli_encryption' '$usegeli' - '$msg_geli_encryption_help' - '6 $msg_partition_scheme' '$ZFSBOOT_PARTITION_SCHEME' + 'E $msg_encrypt_disks' '$usegeli' + '$msg_encrypt_disks_help' + 'P $msg_partition_scheme' '$ZFSBOOT_PARTITION_SCHEME' '$msg_partition_scheme_help' - '7 $msg_swap_size' '$ZFSBOOT_SWAP_SIZE' + 'S $msg_swap_size' '$ZFSBOOT_SWAP_SIZE' '$msg_swap_size_help' " # END-QUOTE local defaultitem= # Calculated below @@ -284,158 +342,279 @@ dialog_menu_main() return $retval } -# dialog_edit_disks +# dialog_last_chance $disks ... # -# Edit the list of disks to be used by the ZFS boot pool. +# 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_edit_disks() +dialog_last_chance() { local title="$DIALOG_TITLE" local btitle="$DIALOG_BACKTITLE" - local prompt="$msg_please_select_one_or_more_disks" - local check_list= # Calculated below - local hline="$hline_arrows_space_tab_enter" - local dev vardev disks= + local prompt # Calculated below + local hline="$hline_arrows_tab_enter" - # - # Get a [new] list of disk devices - # - f_device_find "" $DEVICE_TYPE_DISK disks - if [ ! "$disks" ]; then - f_show_msg "$msg_no_disks_present_to_configure" - return $FAILURE + 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 - # Lets sort the disks array to be more user friendly - disks=$( echo "$disks" | tr ' ' '\n' | sort | tr '\n' ' ' ) - - # - # Loop through the list of selected disks and create temporary local - # variables mapping their status onto an up-to-date list of disks. - # - for dev in $ZFSBOOT_DISKS; do - f_str2varname "$dev" vardev - local _${vardev}_status=on - done - - # - # Create the checklist menu of discovered disk devices - # - local on_off - for dev in $disks; do - local desc= - device_$dev get desc desc - f_shell_escape "$desc" desc - f_str2varname "$dev" vardev - f_getvar _${vardev}_status:-off on_off - check_list="$check_list '$dev' '$desc' $on_off" + 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 - # - # Prompt the user to check some disks - # - local height width rows - eval f_dialog_checklist_size height width rows \ - \"\$title\" \"\$btitle\" \"\$prompt\" \"\$hline\" $check_list - disks=$( eval $DIALOG \ - --title \"\$DIALOG_TITLE\" \ - --backtitle \"\$DIALOG_BACKTITLE\" \ - --hline \"\$hline\" \ - --ok-label \"\$msg_ok\" \ - --cancel-label \"\$msg_cancel\" \ - --checklist \"\$prompt\" \ - $height $width $rows \ - $check_list \ - 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD - ) || return $? - # Exit if user either pressed ESC or chose Cancel/No - f_dialog_data_sanitize disks - - ZFSBOOT_DISKS="$disks" + # Add height for Xdialog(1) + [ "$USE_XDIALOG" ] && height=$(( $height + $height / 5 + 3 )) - return $DIALOG_OK + 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_vdev +# dialog_menu_layout # -# Prompt the user to select a a Virtual Device type. +# 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_vdev() +dialog_menu_layout() { + local funcname=dialog_menu_layout local title="$DIALOG_TITLE" local btitle="$DIALOG_BACKTITLE" - local prompt="$msg_select_virtual_device_type" - - # Make sure [potentially scripted] selections are real - real_disks= - for disk in $ZFSBOOT_DISKS; do - f_struct device_$disk && real_disks="$real_disks $disk" - done - # Make sure we have at least one real disk selected - ndisks=$( set -- $real_disks; echo $# ) - - local menu_list=" + 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' '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|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 - local defaultitem="$ZFSBOOT_VDEV_TYPE" - local hline="$hline_arrows_tab_enter" - local error_msg revalidate_choice + # 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 - local mheight mwidth mrows - eval f_dialog_menu_size mheight mwidth mrows \ - \"\$title\" \"\$btitle\" \"\$prompt\" \"\$hline\" $menu_list - local iheight iwidth - f_dialog_infobox_size iheight iwidth \ - "$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$msg_processing_selection" + # Get a list of probed disk devices + local disks= + f_device_find "" $DEVICE_TYPE_DISK disks + f_dprintf "$funcname: disks=[%s]" "$disks" + if [ ! "$disks" ]; then + f_dprintf "No disk(s) present to configure" + f_show_err "$msg_no_disks_present_to_configure" + return $FAILURE + fi - local menu_choice - menu_choice=$( eval $DIALOG \ - --title \"\$title\" \ - --backtitle \"\$btitle\" \ - --hline \"\$hline\" \ - --ok-label \"\$msg_ok\" \ - --cancel-label \"\$msg_cancel\" \ - --item-help \ - --default-item \"\$defaultitem\" \ - --menu \"\$prompt\" \ - $mheight $mwidth $mrows \ - $menu_list \ - --and-widget \ - ${USE_XDIALOG:+--no-buttons} \ - --infobox \"\$msg_processing_selection\" \ - $iheight $iwidth \ - 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD - ) || return $FAILURE - f_dialog_data_sanitize menu_choice - sleep 0.5 # Give time to read `--and-widget --info-box' + # Lets sort the disks array to be more user friendly + disks=$( echo "$disks" | tr ' ' '\n' | sort | tr '\n' ' ' ) - # Make sure we have enough disks for the desired vdev type - case "$menu_choice" in - stripe) want_disks=1 ;; - mirror) want_disks=2 ;; - raidz1) want_disks=3 ;; - raidz2) want_disks=4 ;; - raidz3) want_disks=5 ;; - *) - f_show_msg "$msg_invalid_virtual_device_type" \ - "$menu_choice" - continue - esac - if [ $ndisks -lt $want_disks ]; then - msg_yes="$msg_change" msg_no="$msg_cancel" f_yesno \ - "%s: $msg_not_enough_disks_selected\n%s" \ - "$menu_choice" $ndisks $want_disks \ - "$msg_invalid_virtual_device_type_help" || - return $FAILURE - dialog_menu_vdev - else - ZFSBOOT_VDEV_TYPE="$menu_choice" - fi + # + # 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 + 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 + local want_disks=0 + case "$ZFSBOOT_VDEV_TYPE" in + stripe) want_disks=1 ;; + mirror) want_disks=2 ;; + raidz1) want_disks=3 ;; + raidz2) want_disks=4 ;; + raidz3) want_disks=5 ;; + esac + + # Warn the user if any scripted disks are invalid + local disk valid_disks= + local all_valid=${ZFSBOOT_DISKS:+1} # optimism + for disk in $ZFSBOOT_DISKS; do + if f_struct device_$disk; 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 + ndisks=$( set -- $ZFSBOOT_DISKS; echo $# ) + [ $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 + # + local breakout= + while :; do + # Loop over list of available disks, resetting state + for disk in $disks; do unset _${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 + local _${disk}_status=on + done + + # Create the checklist menu of discovered disk devices + disk_check_list= + for disk in $disks; do + local desc= + device_$disk get desc desc + f_shell_escape "$desc" desc + f_getvar _${disk}_status:-off onoff + disk_check_list="$disk_check_list + $disk '$desc' $onoff" + done + + local height width rows + eval f_dialog_checklist_size height width rows \ + \"\$title\" \"\$btitle\" \"\$prompt\" \ + \"\$hline\" $disk_check_list + + selections=$( eval $DIALOG \ + --title \"\$DIALOG_TITLE\" \ + --backtitle \"\$DIALOG_BACKTITLE\" \ + --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" + + ndisks=$( set -- $ZFSBOOT_DISKS; echo $# ) + [ $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 @@ -445,295 +624,446 @@ dialog_menu_vdev() # 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: The MBR layout is more complicated (GPT is preferred). +# NOTE: $swapsize and $bootsize should be defined by the calling function. +# NOTE: Sets $bootpart and $targetpart for the calling function. # zfs_create_diskpart() { - local disk="$1" index="$2" local funcname=zfs_create_diskpart - local disksize partsize + local disk="$1" index="$2" # Check arguments - [ "$disk" -a "$index" ] || return $FAILURE + 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_quietly gpart destroy -F $disk - f_quietly zpool labelclear -f /dev/$disk # Kill it with fire + 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_quietly gpart create -s gpt $disk || return $FAILURE - f_quietly gpart destroy -F $disk || return $FAILURE + f_eval_catch -d $funcname gpart "$GPART_CREATE" gpt $disk + f_eval_catch -d $funcname gpart "$GPART_DESTROY_F" $disk - # Calculate partition size given desired amount of swap - device_$disk get capacity disksize || return $FAILURE - partsize=$(( $disksize - $swapsize )) + # + # Enable boot pool if encryption is desired + # + [ "$ZFSBOOT_GELI_ENCRYPTION" ] && ZFSBOOT_BOOT_POOL=1 # # Lay down the desired type of partition scheme # local setsize mbrindex case "$ZFSBOOT_PARTITION_SCHEME" in - ""|GPT) + ""|GPT) f_dprintf "$funcname: Creating GPT layout..." # # 1. Create GPT layout using labels # - gpart create -s gpt $disk || return $FAILURE + f_eval_catch $funcname gpart "$GPART_CREATE" gpt $disk || + return $FAILURE # # 2. Add small freebsd-boot partition labeled `boot#' # - gpart add -l gptboot$index -t freebsd-boot -s 512k $disk || - return $FAILURE - gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 $disk || - return $FAILURE + f_eval_catch $funcname gpart "$GPART_ADD_LABEL_WITH_SIZE" \ + gptboot$index freebsd-boot 512k $disk || + return $FAILURE + f_eval_catch $funcname gpart "$GPART_BOOTCODE_PART" \ + /boot/pmbr /boot/gptzfsboot 1 $disk || + return $FAILURE - # zpool will use the `zfs#' GPT labels + # NB: zpool will use the `zfs#' GPT labels bootpart=p2 targetpart=p2 + [ ${swapsize:-0} -gt 0 ] && targetpart=p3 - # Change things around if we are using GELI - if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then + # + # Prepare boot pool if enabled (e.g., for geli(8)) + # + if [ "$ZFSBOOT_BOOT_POOL" ]; then bootpart=p2 targetpart=p3 - partsize=$(( $partsize - $gelisize )) - gpart add -l boot$index -t freebsd-zfs \ - -s ${gelisize}b -a 1m $disk || return $FAILURE - # Pedantically nuke any old labels, stop geli - f_quietly zpool labelclear -f /dev/$disk$bootpart - f_quietly geli detach -f /dev/$disk$targetpart + [ ${swapsize:-0} -gt 0 ] && targetpart=p4 + f_eval_catch $funcname gpart \ + "$GPART_ADD_LABEL_WITH_SIZE" 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-zfs partition labeled `zfs#' for zpool - # NOTE: Using above calculated partsize to leave room for swap. + # 3. Add freebsd-swap partition labeled `swap#' # - [ $swapsize -gt 0 ] && setsize="-s ${partsize}b" - gpart add -l zfs$index -t freebsd-zfs $setsize -a 1m $disk || - return $FAILURE - f_quietly zpool labelclear -f /dev/$disk$targetpart # Pedantic *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***