diff --git a/bin/nextboot b/bin/nextboot
index 9d81793..a400f22 100755
--- a/bin/nextboot
+++ b/bin/nextboot
@@ -1,25 +1,80 @@
#!/usr/bin/env bash
+# Pretty name for firmware interface
+biosname="Firmware Configuration"
+
+# Check if systemd-boot is available
+bootctl is-installed &> /dev/null && sdboot=1
+
+# Check if rebooting to the firmware interface is supported
+[[ "$(bootctl reboot-to-firmware)" == "supported" ]] && fwboot=1
+
+
+picksdboot() {
+ # Usage: picksdboot
+ local entry PS3 COLUMNS
+ PS3="$2 "
+ COLUMNS=1
+
+ # Print title to stderr
+ printf "\n%s\n\n" "$1" >&2
+
+ # Put all systemd-boot loder entry confs into an array
+ mapfile -t sdbootlist < <(systemctl --boot-loader-entry=help)
+
+ # Only add the firmware interface to the list if booting to it is supported
+ [[ -v fwboot ]] && sdbootlist+=("$biosname")
+
+ select entry in "${sdbootlist[@]}"; do
+ break
+ done
+
+ printf "%s" "$entry"
+}
+
+
+pickefi() {
+ # Usage: pickefi
+ local bootnext PS3 COLUMNS
+ PS3="$2 "
+ COLUMNS=1
+
+ # Print title to stderr
+ printf "\n%s\n\n" "$1" >&2
+
+ # This one is fun
+ # mapfile splits stdin on \n to an array
+ # The sed regex looks for an asterisk in the 8th position (0 indexed),
+ # which marks an efi boot entry as "active", so those are the only ones
+ # we care to add to the list.
+ # It *seems* like one could put mapfile at the end of the pipeline, but
+ # each command gets run in a subshell, so the array is lost. (ref: SC2031)
+ mapfile -t efientries < <(efibootmgr | sed -n '/.\{8\}\*/p')
+
+ # Rebooting to the firmware interface only works with systemd-boot, so only add
+ # it to the EFI mode list if systemd-boot is available and it's supported
+ [[ -v sdboot && -v fwboot ]] && efientries+=("$biosname")
+
+ select efiselection in "${efientries[@]}"; do
+
+ # If they chose the firmware interface
+ if [[ "$efiselection" == "$biosname" ]]; then
+ break
+ else
+ # Take only character 4-8 of the entry, which is the BOOTNUM
+ bootnext="${efiselection:4:4}"
+ break
+ fi
+ done
+
+ printf "%s" "$bootnext"
+}
-# The pretty name we want to give to the firmware entry
-biosname="Firmware Interface"
while getopts ":en" opt; do
case $opt in
e)
- # This one is fun
- # mapfile splits stdin on \n to an array
- # The sed regex looks for an asterisk in the 8th position (0 indexed)
- # It *seems* like one could put mapfile at the end of the pipeline, but
- # each command gets run in a subshell, so the array is lost. (ref: SC2031)
- mapfile -t efientries < <(efibootmgr | sed -n '/.\{8\}\*/p')
- PS3="EFI entry to BootNext: "
- COLUMNS=1
- select efiselection in "${efientries[@]}"; do
- bootnext="${efiselection:4:4}"
- break
- done
- sudo efibootmgr -q --bootnext "$bootnext"
+ efimode=1
;;
n)
noreboot=1
@@ -31,45 +86,66 @@ while getopts ":en" opt; do
esac
done
+# If -e wasn't set, and systemd-boot isn't installed, fail over to efimode anyways
+if [[ ! -v efimode && ! -v sdboot ]]; then
+ echo "W: systemd-boot not installed. Choosing EFI boot entries instead..."
+ efimode=1
+fi
-# If we are trying to set the EFI entry, this conditional isn't useful
-if [[ -v bootnext ]]; then
- :
-# If we aren't trying to set the EFI entry, and systemd-boot is installed
-elif [[ ! -v bootnext ]] && bootctl is-installed &> /dev/null; then
- # Select prompt options
- PS3="Select next boot entry: "
- COLUMNS=1
- select entry in $(systemctl --boot-loader-entry=help) "$biosname"; do
- if [[ "$entry" == "$biosname" ]]; then
- sudo bootctl reboot-to-firmware true
- break
- else
- sudo bootctl set-oneshot "$entry"
- break
- fi
- done
+# If we're in EFI mode
+if [[ -v efimode ]]; then
+ title="Pick EFI boot entry"
+ prompt="Entry"
+
+ if [[ -v noreboot ]]; then
+ prompt="$prompt for next boot:"
+ elif [[ ! -v noreboot ]]; then
+ prompt="$prompt to boot IMMEDIATELY:"
+ else
+ echo "E: idk how you got here..."
+ exit 1
+ fi
+
+ # Prompt for the user's choice
+ choice="$(pickefi "$title" "$prompt")"
+
+ # A special case to boot into firmware interface
+ if [[ "$choice" == "$biosname" ]]; then
+ sudo bootctl reboot-to-firmware true
+ elif [[ "$choice" != "$biosname" ]]; then
+ sudo efibootmgr -q --bootnext "$choice"
+ fi
+
+# If we're in systemd-boot mode
+elif [[ ! -v efimode ]]; then
+ title="Pick systemd-boot entry config"
+ prompt="Entry"
+
+ if [[ -v noreboot ]]; then
+ prompt="$prompt for next boot:"
+ elif [[ ! -v noreboot ]]; then
+ prompt="$prompt to boot IMMEDIATELY:"
+ else
+ echo "E: idk how you got here either..."
+ exit 1
+ fi
+
+ # Prompt for the user's choice
+ choice="$(picksdboot "$title" "$prompt")"
+
+ # A special case to boot into firmware interface
+ if [[ "$choice" == "$biosname" ]]; then
+ sudo bootctl reboot-to-firmware true
+ elif [[ "$choice" != "$biosname" ]]; then
+ sudo bootctl set-oneshot "$choice"
+ # Add an option to speed past the boot menu, since we've already
+ # chosen the desired entry.
+ rebootopts+=("--boot-loader-menu=1")
+ fi
else
- # If we've made it here, then we're not trying to set the EFI entry, and
- # systemd-boot is not installed in the ESP, so bail.
- echo "E: systemd-boot not installed. Exiting."
+ echo "E: you DEFINITELY don't belong here..."
exit 1
fi
-# If we do want to reboot now, and we aren't setting the EFI entry
-if [[ ! -v noreboot && ! -v bootnext ]]; then
- # Reboot, and set a low timeout on the systemd-boot menu for next boot only
- sudo systemctl reboot --boot-loader-menu=1
-# If we do want to reboot now, and we are setting the EFI entry
-elif [[ ! -v noreboot && -v bootnext ]]; then
- # Get on with it
- sudo systemctl reboot
-# If we don't want to reboot now
-elif [[ -v noreboot ]]; then
- echo "Next boot set."
- exit 0
-# If things are otherwise fucked
-else
- echo "E: You shouldn't be here..."
- exit 1
-fi
+
+[[ ! -v noreboot ]] && sudo systemctl reboot "${rebootopts[@]}"