heads/initrd/bin/kexec-select-boot
Kyle Rankin 22a8d6f603
Colorize warning and error messages in fbwhiptail
Since fbwhiptail allows us to customize the background colors, we should
colorize warnings and error messages to provide a user with an
additional subtle cue that there might be a problem. I have added two
additional configuration options:

CONFIG_WARNING_BG_COLOR
CONFIG_ERROR_BG_COLOR

and in the librem13v2.config file you can see an example for how to set
them to be yellow and red gradients, respectively. I've also updated the
main two scripts that use whiptail to include those background colors.

If you decide to use regular whiptail, just don't set these config
options and it should behave as expected.
2018-04-25 13:21:56 -07:00

363 lines
8.7 KiB
Bash
Executable File

#!/bin/sh
# Generic configurable boot script via kexec
set -e -o pipefail
. /etc/config
. /etc/functions
add=""
remove=""
config="*.cfg"
unique="n"
valid_hash="n"
valid_global_hash="n"
valid_rollback="n"
force_menu="n"
gui_menu="n"
force_boot="n"
while getopts "b:d:p:a:r:c:uimgf" arg; do
case $arg in
b) bootdir="$OPTARG" ;;
d) paramsdev="$OPTARG" ;;
p) paramsdir="$OPTARG" ;;
a) add="$OPTARG" ;;
r) remove="$OPTARG" ;;
c) config="$OPTARG" ;;
u) unique="y" ;;
m) force_menu="y" ;;
i) valid_hash="y"; valid_rollback="y" ;;
g) gui_menu="y" ;;
f) force_boot="y"; valid_hash="y"; valid_rollback="y" ;;
esac
done
if [ -z "$bootdir" ]; then
die "Usage: $0 -b /boot"
fi
if [ -z "$paramsdev" ]; then
paramsdev="$bootdir"
fi
if [ -z "$paramsdir" ]; then
paramsdir="$bootdir"
fi
bootdir="${bootdir%%/}"
paramsdev="${paramsdev%%/}"
paramsdir="${paramsdir%%/}"
verify_global_hashes()
{
echo "+++ Checking verified boot hash file "
# Check the hashes of all the files
if cd $bootdir && sha256sum -c "$TMP_HASH_FILE" > /tmp/hash_output ; then
echo "+++ Verified boot hashes "
valid_hash='y'
valid_global_hash='y'
else
if [ "$gui_menu" = "y" ]; then
CHANGED_FILES=$(grep -v 'OK$' /tmp/hash_output | cut -f1 -d ':')
whiptail $CONFIG_ERROR_BG_COLOR --title 'ERROR: Boot Hash Mismatch' \
--msgbox "The following files failed the verification process:\n${CHANGED_FILES}\nExiting to a recovery shell" 16 60
fi
die "$TMP_HASH_FILE: boot hash mismatch"
fi
}
verify_rollback_counter()
{
TPM_COUNTER=`grep counter $TMP_ROLLBACK_FILE | cut -d- -f2`
if [ -z "$TPM_COUNTER" ]; then
die "$TMP_ROLLBACK_FILE: TPM counter not found?"
fi
read_tpm_counter $TPM_COUNTER \
|| die "Failed to read TPM counter"
sha256sum -c $TMP_ROLLBACK_FILE \
|| die "Invalid TPM counter state"
valid_rollback="y"
}
first_menu="y"
get_menu_option() {
num_options=`cat $TMP_MENU_FILE | wc -l`
if [ $num_options -eq 0 ]; then
die "No boot options"
fi
if [ $num_options -eq 1 -a $first_menu = "y" ]; then
option_index=1
elif [ "$gui_menu" = "y" ]; then
MENU_OPTIONS=""
n=0
while read option
do
parse_option
n=`expr $n + 1`
name=$(echo $name | tr " " "_")
kernel=$(echo $kernel | cut -f2 -d " ")
MENU_OPTIONS="$MENU_OPTIONS $n ${name}_[$kernel]"
done < $TMP_MENU_FILE
whiptail --clear --title "Select your boot option" \
--menu "Choose the boot option [1-$n, a to abort]:" 20 120 8 \
-- $MENU_OPTIONS \
2>/tmp/whiptail || die "Aborting boot attempt"
option_index=$(cat /tmp/whiptail)
else
echo "+++ Select your boot option:"
n=0
while read option
do
parse_option
n=`expr $n + 1`
echo "$n. $name [$kernel]"
done < $TMP_MENU_FILE
read \
-p "Choose the boot option [1-$n, a to abort]: " \
option_index
if [ "$option_index" = "a" ]; then
die "Aborting boot attempt"
fi
fi
first_menu="n"
option=`head -n $option_index $TMP_MENU_FILE | tail -1`
parse_option
}
confirm_menu_option() {
if [ "$gui_menu" = "y" ]; then
whiptail --clear --title "Confirm boot details" \
--menu "Confirm the boot details for $name:\n\n$option\n\n" 20 120 8 \
-- 'y' "Boot $name" 'd' "Make $name the default" \
2>/tmp/whiptail || die "Aborting boot attempt"
option_confirm=$(cat /tmp/whiptail)
else
echo "+++ Please confirm the boot details for $name:"
echo $option
read \
-n 1 \
-p "Confirm selection by pressing 'y', make default with 'd': " \
option_confirm
echo
fi
}
parse_option() {
name=`echo $option | cut -d\| -f1`
kernel=`echo $option | cut -d\| -f3`
}
scan_options() {
echo "+++ Scanning for unsigned boot options"
option_file="/tmp/kexec_options.txt"
if [ -r $option_file ]; then rm $option_file; fi
for i in `find $bootdir -name "$config"`; do
kexec-parse-boot "$bootdir" "$i" >> $option_file
done
if [ ! -r $option_file ]; then
die "Failed to parse any boot options"
fi
if [ "$unique" = 'y' ]; then
sort $option_file | uniq > $TMP_MENU_FILE
else
cp $option_file $TMP_MENU_FILE
fi
}
save_default_option() {
read \
-n 1 \
-p "Saving a default will modify the disk. Proceed? (y/n): " \
default_confirm
echo
if [ "$default_confirm" = "y" ]; then
if kexec-save-default \
-b "$bootdir" \
-d "$paramsdev" \
-p "$paramsdir" \
-i "$option_index" \
; then
echo "+++ Saved defaults to device"
sleep 2
default_failed="n"
force_menu="n"
return
else
echo "Failed to save defaults"
fi
fi
option_confirm="n"
}
default_select() {
# Attempt boot with expected parameters
# Check that entry matches that which is expected from menu
default_index=`basename "$TMP_DEFAULT_FILE" | cut -d. -f 2`
# Check to see if entries have changed - useful for detecting grub update
expectedoption=`cat $TMP_DEFAULT_FILE`
option=`head -n $default_index $TMP_MENU_FILE | tail -1`
if [ "$option" != "$expectedoption" ]; then
if [ "$gui_menu" = "y" ]; then
whiptail $CONFIG_ERROR_BG_COLOR --title 'ERROR: Boot Entry Has Changed' \
--msgbox "The list of boot entries has changed\n\nPlease set a new default" 16 60
fi
warn "!!! Boot entry has changed - please set a new default"
return
fi
parse_option
# Enforce that default option hashes are valid
echo "+++ Checking verified default boot hash file "
# Check the hashes of all the files
if cd $bootdir && sha256sum -c "$TMP_DEFAULT_HASH_FILE" > /tmp/hash_output ; then
echo "+++ Verified default boot hashes "
valid_hash='y'
else
if [ "$gui_menu" = "y" ]; then
CHANGED_FILES=$(grep -v 'OK$' /tmp/hash_output | cut -f1 -d ':')
whiptail $CONFIG_ERROR_BG_COLOR --title 'ERROR: Default Boot Hash Mismatch' \
--msgbox "The following files failed the verification process:\n${CHANGED_FILES}\nExiting to a recovery shell" 16 60
fi
die "!!! $TMP_DEFAULT_HASH_FILE: default boot hash mismatch"
fi
echo "+++ Executing default boot for $name:"
do_boot
warn "Failed to boot default option"
}
user_select() {
# No default expected boot parameters, ask user
option_confirm=""
while [ "$option_confirm" != "y" -a "$option_confirm" != "d" ]
do
get_menu_option
confirm_menu_option
if [ "$option_confirm" = 'd' ]; then
save_default_option
fi
done
if [ "$option_confirm" = "d" ]; then
if [ ! -r "$TMP_KEY_DEVICES" ]; then
# rerun primary boot loop to boot the new default option
continue
else
echo "+++ Rebooting to start the new default option"
sleep 2
reboot \
|| die "!!! Failed to reboot system"
fi
fi
do_boot
}
do_boot()
{
if [ "$CONFIG_BOOT_REQ_ROLLBACK" = "y" -a "$valid_rollback" = "n" ]; then
die "!!! Missing required rollback counter state"
fi
if [ "$CONFIG_BOOT_REQ_HASH" = "y" -a "$valid_hash" = "n" ]; then
die "!!! Missing required boot hashes"
fi
if [ "$CONFIG_TPM" = "y" \
-a -r "$TMP_KEY_DEVICES" ]; then
INITRD=`kexec-boot -b "$bootdir" -e "$option" -i` \
|| die "!!! Failed to extract the initrd from boot option"
if [ -z "$INITRD" ]; then
die "!!! No initrd file found in boot option"
fi
kexec-insert-key $INITRD \
|| die "!!! Failed to insert disk key into a new initrd"
kexec-boot -b "$bootdir" -e "$option" \
-a "$add" -r "$remove" -o "/tmp/secret/initrd.cpio" \
|| die "!!! Failed to boot w/ options: $option"
else
kexec-boot -b "$bootdir" -e "$option" -a "$add" -r "$remove" \
|| die "!!! Failed to boot w/ options: $option"
fi
}
while true; do
check_config $paramsdir
TMP_DEFAULT_FILE=`find /tmp/kexec/kexec_default.*.txt 2>/dev/null | head -1` || true
TMP_MENU_FILE="/tmp/kexec/kexec_menu.txt"
TMP_HASH_FILE="/tmp/kexec/kexec_hashes.txt"
TMP_DEFAULT_HASH_FILE="/tmp/kexec/kexec_default_hashes.txt"
TMP_ROLLBACK_FILE="/tmp/kexec/kexec_rollback.txt"
TMP_KEY_DEVICES="/tmp/kexec/kexec_key_devices.txt"
TMP_KEY_LVM="/tmp/kexec/kexec_key_lvm.txt"
# Allow a way for users to ignore warnings and boot into their systems
# even if hashes don't match
if [ "$force_boot" = "y" ]; then
scan_options
user_select
fi
if [ "$CONFIG_TPM" = "y" \
-a ! -r "$TMP_KEY_DEVICES" ]; then
# Extend PCR4 as soon as possible
tpm extend -ix 4 -ic generic \
|| die "Failed to extend PCR 4"
fi
# if no saved options, scan the boot directory and generate
if [ ! -r "$TMP_MENU_FILE" ]; then
scan_options
fi
if [ "$CONFIG_TPM" = "y" ]; then
# Optionally enforce device file hashes
if [ -r "$TMP_HASH_FILE" ]; then
valid_global_hash="n"
verify_global_hashes
if [ "$valid_global_hash" = "n" ]; then
die "Failed to verify global hashes"
fi
fi
if [ -r "$TMP_ROLLBACK_FILE" ]; then
# in the case of iso boot with a rollback file, do not assume valid
valid_rollback="n"
verify_rollback_counter
fi
fi
if [ "$default_failed" != "y" \
-a "$force_menu" = "n" \
-a -r "$TMP_DEFAULT_FILE" \
-a -r "$TMP_DEFAULT_HASH_FILE" ] \
; then
default_select
default_failed="y"
else
user_select
fi
done
die "!!! Shouldn't get here""