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 | #!/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 | 	else | ||||||
| 			sudo bootctl reboot-to-firmware true | 		echo "E: idk how you got here..." | ||||||
| 			break | 		exit 1 | ||||||
| 		else | 	fi | ||||||
| 			sudo bootctl set-oneshot "$entry" | 
 | ||||||
| 			break | 	# Prompt for the user's choice | ||||||
| 		fi | 	choice="$(pickefi "$title" "$prompt")" | ||||||
| 	done | 	 | ||||||
|  | 	# 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 | 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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user