Refactor to set up checks for systemd-boot and the firmware interface
This commit is contained in:
parent
4d346881df
commit
7abb171389
176
bin/nextboot
176
bin/nextboot
|
@ -1,25 +1,80 @@
|
||||||
#!/usr/bin/env bash
|
#!/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 <title> <prompt>
|
||||||
|
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 <title> <prompt>
|
||||||
|
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
|
while getopts ":en" opt; do
|
||||||
case $opt in
|
case $opt in
|
||||||
e)
|
e)
|
||||||
# This one is fun
|
efimode=1
|
||||||
# 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"
|
|
||||||
;;
|
;;
|
||||||
n)
|
n)
|
||||||
noreboot=1
|
noreboot=1
|
||||||
|
@ -31,45 +86,66 @@ while getopts ":en" opt; do
|
||||||
esac
|
esac
|
||||||
done
|
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 we're in EFI mode
|
||||||
if [[ -v bootnext ]]; then
|
if [[ -v efimode ]]; then
|
||||||
:
|
title="Pick EFI boot entry"
|
||||||
# If we aren't trying to set the EFI entry, and systemd-boot is installed
|
prompt="Entry"
|
||||||
elif [[ ! -v bootnext ]] && bootctl is-installed &> /dev/null; then
|
|
||||||
# Select prompt options
|
if [[ -v noreboot ]]; then
|
||||||
PS3="Select next boot entry: "
|
prompt="$prompt for next boot:"
|
||||||
COLUMNS=1
|
elif [[ ! -v noreboot ]]; then
|
||||||
select entry in $(systemctl --boot-loader-entry=help) "$biosname"; do
|
prompt="$prompt to boot IMMEDIATELY:"
|
||||||
if [[ "$entry" == "$biosname" ]]; then
|
|
||||||
sudo bootctl reboot-to-firmware true
|
|
||||||
break
|
|
||||||
else
|
else
|
||||||
sudo bootctl set-oneshot "$entry"
|
echo "E: idk how you got here..."
|
||||||
break
|
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
|
fi
|
||||||
done
|
|
||||||
else
|
else
|
||||||
# If we've made it here, then we're not trying to set the EFI entry, and
|
echo "E: you DEFINITELY don't belong here..."
|
||||||
# systemd-boot is not installed in the ESP, so bail.
|
|
||||||
echo "E: systemd-boot not installed. Exiting."
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If we do want to reboot now, and we aren't setting the EFI entry
|
|
||||||
if [[ ! -v noreboot && ! -v bootnext ]]; then
|
[[ ! -v noreboot ]] && sudo systemctl reboot "${rebootopts[@]}"
|
||||||
# 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
|
|
||||||
|
|
Loading…
Reference in New Issue