Refactor to set up checks for systemd-boot and the firmware interface
This commit is contained in:
		
							parent
							
								
									4d346881df
								
							
						
					
					
						commit
						7abb171389
					
				
							
								
								
									
										180
									
								
								bin/nextboot
									
									
									
									
									
								
							
							
						
						
									
										180
									
								
								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 <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 | ||||
| 	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[@]}" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user