2023-02-08 21:01:48 +00:00
#!/bin/bash
2017-04-12 10:48:38 +00:00
# Shell functions for most initialization scripts
2023-03-07 15:10:32 +00:00
. /etc/ash_functions
2023-02-18 17:58:43 +00:00
2023-03-07 19:00:57 +00:00
# Print <hidden> or <empty> depending on whether $1 is empty. Useful to mask an
# optional password parameter.
mask_param() {
if [ -z "$1" ]; then
echo "<empty>"
else
echo "<hidden>"
fi
}
# Trace a command with DEBUG, then execute it.
# A password parameter can be masked by passing --mask-position N before the
# command to execute, the debug trace will just indicate whether the password
# was empty or nonempty (which is important when use of a password is optional).
# N=0 is the name of the command to be executed, N=1 is its first parameter,
# etc.
DO_WITH_DEBUG() {
if [ "$1" == "--mask-position" ]; then
mask_position="$2"
shift
shift
DEBUG_ARGS=("$@")
DEBUG_ARGS[$mask_position]="$(mask_param "${DEBUG_ARGS[$mask_position]}")"
DEBUG "${DEBUG_ARGS[@]}"
else
DEBUG "$@"
fi
"$@"
}
2017-04-12 10:48:38 +00:00
recovery() {
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:recovery"
2017-04-12 10:48:38 +00:00
echo >&2 "!!!!! $*"
# Remove any temporary secret files that might be hanging around
# but recreate the directory so that new tools can use it.
2023-01-12 23:04:27 +00:00
#safe to always be true. Otherwise "set -e" would make it exit here
shred -n 10 -z -u /tmp/secret/* 2> /dev/null || true
2017-04-12 10:48:38 +00:00
rm -rf /tmp/secret
mkdir -p /tmp/secret
2019-02-08 18:25:12 +00:00
# ensure /tmp/config exists for recovery scripts that depend on it
touch /tmp/config
tpm2-tools: Change sense of CONFIG_TPM to mean any TPM, not just TPM1.
Most logic throughout Heads doesn't need to know TPM1 versus TPM2 (and
shouldn't, the differences should be localized). Some checks were
incorrect and are fixed by this change. Most checks are now unchanged
relative to master.
There are not that many places outside of tpmr that need to
differentiate TPM1 and TPM2. Some of those are duplicate code that
should be consolidated (seal-hotpkey, unseal-totp, unseal-hotp), and
some more are probably good candidates for abstracting in tpmr so the
business logic doesn't have to know TPM1 vs. TPM2.
Previously, CONFIG_TPM could be variously 'y', 'n', or empty. Now it
is always 'y' or 'n', and 'y' means "any TPM". Board configs are
unchanged, setting CONFIG_TPM2_TOOLS=y implies CONFIG_TPM=y so this
doesn't have to be duplicated and can't be mistakenly mismatched.
There were a few checks for CONFIG_TPM = n that only coincidentally
worked for TPM2 because CONFIG_TPM was empty (not 'n'). This test is
now OK, but the checks were also cleaned up to '!= "y"' for robustness.
Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2023-02-22 21:30:07 +00:00
if [ "$CONFIG_TPM" = "y" ]; then
2022-08-25 18:43:31 +00:00
tpmr extend -ix 4 -ic recovery
2017-12-05 08:29:07 +00:00
fi
2018-04-10 19:39:05 +00:00
2020-09-16 21:46:22 +00:00
while [ true ]
do
echo >&2 "!!!!! Starting recovery shell"
sleep 1
if [ -x /bin/setsid ]; then
2023-02-28 20:35:44 +00:00
/bin/setsid -c /bin/sh
2020-09-16 21:46:22 +00:00
else
2023-02-28 20:35:44 +00:00
/bin/sh
2020-09-16 21:46:22 +00:00
fi
done
2017-04-12 10:48:38 +00:00
}
2018-03-10 23:40:07 +00:00
pause_recovery() {
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:pause_recovery"
2023-03-09 18:28:04 +00:00
read -p $'!!! Hit enter to proceed to recovery shell !!!\n'
2018-03-10 23:40:07 +00:00
recovery $*
}
2017-04-12 10:48:38 +00:00
pcrs() {
tpm2-tools: Change sense of CONFIG_TPM to mean any TPM, not just TPM1.
Most logic throughout Heads doesn't need to know TPM1 versus TPM2 (and
shouldn't, the differences should be localized). Some checks were
incorrect and are fixed by this change. Most checks are now unchanged
relative to master.
There are not that many places outside of tpmr that need to
differentiate TPM1 and TPM2. Some of those are duplicate code that
should be consolidated (seal-hotpkey, unseal-totp, unseal-hotp), and
some more are probably good candidates for abstracting in tpmr so the
business logic doesn't have to know TPM1 vs. TPM2.
Previously, CONFIG_TPM could be variously 'y', 'n', or empty. Now it
is always 'y' or 'n', and 'y' means "any TPM". Board configs are
unchanged, setting CONFIG_TPM2_TOOLS=y implies CONFIG_TPM=y so this
doesn't have to be duplicated and can't be mistakenly mismatched.
There were a few checks for CONFIG_TPM = n that only coincidentally
worked for TPM2 because CONFIG_TPM was empty (not 'n'). This test is
now OK, but the checks were also cleaned up to '!= "y"' for robustness.
Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2023-02-22 21:30:07 +00:00
if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then
2022-08-25 18:43:31 +00:00
tpm2 pcrread sha256
tpm2-tools: Change sense of CONFIG_TPM to mean any TPM, not just TPM1.
Most logic throughout Heads doesn't need to know TPM1 versus TPM2 (and
shouldn't, the differences should be localized). Some checks were
incorrect and are fixed by this change. Most checks are now unchanged
relative to master.
There are not that many places outside of tpmr that need to
differentiate TPM1 and TPM2. Some of those are duplicate code that
should be consolidated (seal-hotpkey, unseal-totp, unseal-hotp), and
some more are probably good candidates for abstracting in tpmr so the
business logic doesn't have to know TPM1 vs. TPM2.
Previously, CONFIG_TPM could be variously 'y', 'n', or empty. Now it
is always 'y' or 'n', and 'y' means "any TPM". Board configs are
unchanged, setting CONFIG_TPM2_TOOLS=y implies CONFIG_TPM=y so this
doesn't have to be duplicated and can't be mistakenly mismatched.
There were a few checks for CONFIG_TPM = n that only coincidentally
worked for TPM2 because CONFIG_TPM was empty (not 'n'). This test is
now OK, but the checks were also cleaned up to '!= "y"' for robustness.
Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2023-02-22 21:30:07 +00:00
elif [ "$CONFIG_TPM" = "y" ]; then
head -8 /sys/class/tpm/tpm0/pcrs
2022-08-25 18:43:31 +00:00
fi
2017-04-12 10:48:38 +00:00
}
2017-04-29 17:40:34 +00:00
confirm_totp()
{
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:confirm_totp"
2017-07-18 17:44:02 +00:00
prompt="$1"
2017-04-29 17:40:34 +00:00
last_half=X
2017-07-18 17:44:02 +00:00
unset totp_confirm
2017-04-29 17:40:34 +00:00
while true; do
# update the TOTP code every thirty seconds
date=`date "+%Y-%m-%d %H:%M:%S"`
seconds=`date "+%s"`
half=`expr \( $seconds % 60 \) / 30`
tpm2-tools: Change sense of CONFIG_TPM to mean any TPM, not just TPM1.
Most logic throughout Heads doesn't need to know TPM1 versus TPM2 (and
shouldn't, the differences should be localized). Some checks were
incorrect and are fixed by this change. Most checks are now unchanged
relative to master.
There are not that many places outside of tpmr that need to
differentiate TPM1 and TPM2. Some of those are duplicate code that
should be consolidated (seal-hotpkey, unseal-totp, unseal-hotp), and
some more are probably good candidates for abstracting in tpmr so the
business logic doesn't have to know TPM1 vs. TPM2.
Previously, CONFIG_TPM could be variously 'y', 'n', or empty. Now it
is always 'y' or 'n', and 'y' means "any TPM". Board configs are
unchanged, setting CONFIG_TPM2_TOOLS=y implies CONFIG_TPM=y so this
doesn't have to be duplicated and can't be mistakenly mismatched.
There were a few checks for CONFIG_TPM = n that only coincidentally
worked for TPM2 because CONFIG_TPM was empty (not 'n'). This test is
now OK, but the checks were also cleaned up to '!= "y"' for robustness.
Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2023-02-22 21:30:07 +00:00
if [ "$CONFIG_TPM" != "y" ]; then
2017-07-18 17:44:02 +00:00
TOTP="NO TPM"
elif [ "$half" != "$last_half" ]; then
2017-04-29 17:40:34 +00:00
last_half=$half;
TOTP=`unseal-totp` \
|| recovery "TOTP code generation failed"
fi
echo -n "$date $TOTP: "
# read the first character, non-blocking
read \
-t 1 \
-n 1 \
-s \
2017-07-18 17:44:02 +00:00
-p "$prompt" \
2017-04-29 17:40:34 +00:00
totp_confirm \
&& break
# nothing typed, redraw the line
echo -ne '\r'
done
# clean up with a newline
echo
}
2017-07-04 23:49:14 +00:00
2017-12-06 08:04:27 +00:00
enable_usb()
2017-07-04 23:49:14 +00:00
{
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:enable_usb"
2023-01-16 20:18:05 +00:00
#insmod ehci_hcd prior of uhdc_hcd and ohci_hcd to suppress dmesg warning
if ! lsmod | grep -q ehci_hcd; then
insmod /lib/modules/ehci-hcd.ko \
|| die "ehci_hcd: module load failed"
fi
2017-12-06 08:04:27 +00:00
if [ "$CONFIG_LINUX_USB_COMPANION_CONTROLLER" = y ]; then
if ! lsmod | grep -q uhci_hcd; then
insmod /lib/modules/uhci-hcd.ko \
|| die "uhci_hcd: module load failed"
fi
if ! lsmod | grep -q ohci_hcd; then
insmod /lib/modules/ohci-hcd.ko \
|| die "ohci_hcd: module load failed"
fi
if ! lsmod | grep -q ohci_pci; then
insmod /lib/modules/ohci-pci.ko \
|| die "ohci_pci: module load failed"
fi
2017-07-22 20:32:10 +00:00
fi
2017-07-04 23:49:14 +00:00
if ! lsmod | grep -q ehci_pci; then
insmod /lib/modules/ehci-pci.ko \
|| die "ehci_pci: module load failed"
fi
if ! lsmod | grep -q xhci_hcd; then
insmod /lib/modules/xhci-hcd.ko \
2017-12-06 08:04:27 +00:00
|| die "xhci_hcd: module load failed"
2017-07-04 23:49:14 +00:00
fi
if ! lsmod | grep -q xhci_pci; then
insmod /lib/modules/xhci-pci.ko \
2017-12-06 08:04:27 +00:00
|| die "xhci_pci: module load failed"
2017-07-04 23:49:14 +00:00
sleep 2
fi
2022-04-05 17:53:09 +00:00
if [ "$CONFIG_USB_KEYBOARD" = y ]; then
if ! lsmod | grep -q usbhid; then
insmod /lib/modules/usbhid.ko \
|| die "usbhid: module load failed"
fi
fi
2017-12-06 08:04:27 +00:00
}
2022-11-02 15:03:30 +00:00
list_usb_storage()
{
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:list_usb_storage"
2022-11-02 15:03:30 +00:00
stat -c %N /sys/block/sd* 2>/dev/null | grep usb |
cut -f1 -d ' ' |
sed "s/[']//g" |
while read b; do
# Ignore devices of size 0, such as empty SD card
# readers on laptops attached via USB.
if [ "$(cat "$b/size")" -gt 0 ]; then
echo "$b"
fi
done |
sed "s|/sys/block|/dev|" |
while read b; do
# If the device has a partition table, ignore it and
# include the partitions instead - even if the kernel
# hasn't detected the partitions yet. Such a device is
# never usable directly, and this allows the "wait for
# disks" loop in mount-usb to correctly wait for the
# partitions.
2023-01-17 20:24:11 +00:00
# This check: [ $(fdisk -l "$b" | wc -l) -eq 5 ]
# covers the case of a device without partition table but
# formatted as fat32, which contains a sortof partition table.
# this causes fdisk to not print the invalid partition table
# message and instead it'll print an empty table with header.
# In both cases the output is 5 lines: 3 about device info,
# 1 empty line and the 5th will be the table header or the
# unvalid message.
DISK_DATA=$(fdisk -l "$b")
if echo "$DISK_DATA" | grep -q "doesn't contain a valid partition table" || [ $(echo "$DISK_DATA" | wc -l) -eq 5 ]; then
2022-11-02 15:03:30 +00:00
# No partition table, include this device
echo "$b"
else
# Has a partition table, include partitions
ls -1 "$b"* | awk 'NR!=1 {print $0}'
fi
done
}
2017-12-06 08:04:27 +00:00
confirm_gpg_card()
{
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:confirm_gpg_card"
2017-12-06 08:04:27 +00:00
read \
-n 1 \
-p "Please confirm that your GPG card is inserted [Y/n]: " \
card_confirm
echo
if [ "$card_confirm" != "y" \
-a "$card_confirm" != "Y" \
-a -n "$card_confirm" ] \
; then
die "gpg card not confirmed"
fi
# setup the USB so we can reach the GPG card
enable_usb
2017-07-04 23:49:14 +00:00
2019-07-09 21:46:14 +00:00
echo -e "\nVerifying presence of GPG card...\n"
# ensure we don't exit without retrying
errexit=$(set -o | grep errexit | awk '{print $2}')
set +e
gpg --card-status > /dev/null
if [ $? -ne 0 ]; then
# prompt for reinsertion and try a second time
read -n1 -r -p \
"Can't access GPG key; remove and reinsert, then press Enter to retry. " \
ignored
# restore prev errexit state
if [ "$errexit" = "on" ]; then
set -e
fi
# retry card status
gpg --card-status > /dev/null \
|| die "gpg card read failed"
fi
# restore prev errexit state
if [ "$errexit" = "on" ]; then
set -e
fi
2017-07-04 23:49:14 +00:00
}
2017-07-08 20:59:37 +00:00
check_tpm_counter()
{
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:check_tpm_counter"
2018-06-19 19:27:27 +00:00
LABEL=${2:-3135106223}
2017-07-08 20:59:37 +00:00
# if the /boot.hashes file already exists, read the TPM counter ID
# from it.
if [ -r "$1" ]; then
TPM_COUNTER=`grep counter- "$1" | cut -d- -f2`
else
2018-06-19 19:27:27 +00:00
warn "$1 does not exist; creating new TPM counter"
2017-07-08 20:59:37 +00:00
read -s -p "TPM Owner password: " tpm_password
echo
2022-08-25 18:43:31 +00:00
tpmr counter_create \
2017-07-08 20:59:37 +00:00
-pwdo "$tpm_password" \
-pwdc '' \
2018-05-09 21:25:43 +00:00
-la $LABEL \
2017-07-08 20:59:37 +00:00
| tee /tmp/counter \
|| die "Unable to create TPM counter"
TPM_COUNTER=`cut -d: -f1 < /tmp/counter`
fi
if [ -z "$TPM_COUNTER" ]; then
die "$1: TPM Counter not found?"
fi
}
read_tpm_counter()
{
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:read_tpm_counter"
2022-08-25 18:43:31 +00:00
tpmr counter_read -ix "$1" | tee "/tmp/counter-$1" \
2017-07-08 20:59:37 +00:00
|| die "Counter read failed"
}
increment_tpm_counter()
{
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:increment_tpm_counter"
2022-08-25 18:43:31 +00:00
tpmr counter_increment -ix "$1" -pwdc '' \
2017-07-08 20:59:37 +00:00
| tee /tmp/counter-$1 \
|| die "Counter increment failed"
}
check_config() {
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:check_config"
2017-07-08 20:59:37 +00:00
if [ ! -d /tmp/kexec ]; then
mkdir /tmp/kexec \
|| die 'Failed to make kexec tmp dir'
else
rm -rf /tmp/kexec/* \
|| die 'Failed to empty kexec tmp dir'
fi
if [ ! -r $1/kexec.sig ]; then
return
fi
if [ `find $1/kexec*.txt | wc -l` -eq 0 ]; then
return
fi
2018-03-14 17:24:14 +00:00
if [ "$2" != "force" ]; then
if ! sha256sum `find $1/kexec*.txt` | gpgv $1/kexec.sig - ; then
die 'Invalid signature on kexec boot params'
fi
2017-07-08 20:59:37 +00:00
fi
echo "+++ Found verified kexec boot params"
cp $1/kexec*.txt /tmp/kexec \
|| die "Failed to copy kexec boot params to tmp"
}
2018-04-22 00:21:37 +00:00
2018-12-06 23:24:28 +00:00
replace_config() {
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:replace_config"
2018-12-06 23:41:20 +00:00
CONFIG_FILE=$1
CONFIG_OPTION=$2
NEW_SETTING=$3
2018-12-06 23:24:28 +00:00
2018-12-06 23:41:20 +00:00
touch $CONFIG_FILE
2018-12-06 23:24:28 +00:00
# first pull out the existing option from the global config and place in a tmp file
2018-12-06 23:41:20 +00:00
awk "gsub(\"^export ${CONFIG_OPTION}=.*\",\"export ${CONFIG_OPTION}=\\\"${NEW_SETTING}\\\"\")" /tmp/config > ${CONFIG_FILE}.tmp
awk "gsub(\"^${CONFIG_OPTION}=.*\",\"${CONFIG_OPTION}=\\\"${NEW_SETTING}\\\"\")" /tmp/config >> ${CONFIG_FILE}.tmp
2018-12-06 23:24:28 +00:00
# then copy any remaining settings from the existing config file, minus the option you changed
2018-12-07 00:10:10 +00:00
grep -v "^export ${CONFIG_OPTION}=" ${CONFIG_FILE} | grep -v "^${CONFIG_OPTION}=" >> ${CONFIG_FILE}.tmp || true
2018-12-07 00:51:43 +00:00
sort ${CONFIG_FILE}.tmp | uniq > ${CONFIG_FILE}
2019-02-22 01:17:16 +00:00
rm -f ${CONFIG_FILE}.tmp
2018-12-06 23:24:28 +00:00
}
combine_configs() {
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:combine_configs"
2018-12-07 00:29:09 +00:00
cat /etc/config* > /tmp/config
2018-12-06 23:24:28 +00:00
}
2019-07-05 22:04:00 +00:00
update_checksums()
{
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:update_checksums"
2019-07-05 22:04:00 +00:00
# ensure /boot mounted
if ! grep -q /boot /proc/mounts ; then
mount -o ro /boot \
|| recovery "Unable to mount /boot"
fi
2020-10-08 13:16:08 +00:00
2019-07-05 22:04:00 +00:00
# remount RW
2020-07-13 22:22:40 +00:00
mount -o rw,remount /boot
2019-07-05 22:04:00 +00:00
# sign and auto-roll config counter
extparam=
tpm2-tools: Change sense of CONFIG_TPM to mean any TPM, not just TPM1.
Most logic throughout Heads doesn't need to know TPM1 versus TPM2 (and
shouldn't, the differences should be localized). Some checks were
incorrect and are fixed by this change. Most checks are now unchanged
relative to master.
There are not that many places outside of tpmr that need to
differentiate TPM1 and TPM2. Some of those are duplicate code that
should be consolidated (seal-hotpkey, unseal-totp, unseal-hotp), and
some more are probably good candidates for abstracting in tpmr so the
business logic doesn't have to know TPM1 vs. TPM2.
Previously, CONFIG_TPM could be variously 'y', 'n', or empty. Now it
is always 'y' or 'n', and 'y' means "any TPM". Board configs are
unchanged, setting CONFIG_TPM2_TOOLS=y implies CONFIG_TPM=y so this
doesn't have to be duplicated and can't be mistakenly mismatched.
There were a few checks for CONFIG_TPM = n that only coincidentally
worked for TPM2 because CONFIG_TPM was empty (not 'n'). This test is
now OK, but the checks were also cleaned up to '!= "y"' for robustness.
Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2023-02-22 21:30:07 +00:00
if [ "$CONFIG_TPM" = "y" ];then
2022-08-25 18:43:31 +00:00
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
extparam=-r
fi
2019-07-05 22:04:00 +00:00
fi
2020-10-08 13:16:08 +00:00
if ! kexec-sign-config -p /boot -u $extparam ; then
2021-09-24 20:05:14 +00:00
rv=1
else
rv=0
2019-11-13 23:28:12 +00:00
fi
2019-07-05 22:04:00 +00:00
# switch back to ro mode
mount -o ro,remount /boot
2021-09-24 20:05:14 +00:00
return $rv
2019-07-05 22:04:00 +00:00
}
2019-08-19 22:07:22 +00:00
2022-12-31 17:41:24 +00:00
print_tree() {
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:print_tree"
2023-01-08 13:02:13 +00:00
find ./ ! -path './kexec*' -print0 | sort -z
}
2023-01-14 12:14:09 +00:00
# Escape zero-delimited standard input to safely display it to the user in e.g.
# `whiptail`, `less`, `echo`, `cat`. Doesn't produce shell-escaped output.
# Most printable characters are passed verbatim (exception: \).
# These escapes are used to replace their corresponding characters: #n#r#t#v#b
# Other characters are rendered as hexadecimal escapes.
2023-01-08 13:02:13 +00:00
# escape_zero [prefix] [escape character]
# prefix: \0 in the input will result in \n[prefix]
# escape character: character to use for escapes (default: #); \ may be interpreted by `whiptail`
escape_zero() {
local prefix="$1"
local echar="${2:-#}"
local todo=""
2023-01-14 12:14:09 +00:00
local echar_hex="$(echo -n "$echar" | xxd -p -c1)"
[ ${#echar_hex} -eq 2 ] || die "Invalid escape character $echar passed to escape_zero(). Programming error?!"
2023-01-08 13:02:13 +00:00
echo -e -n "$prefix"
2023-01-14 12:14:09 +00:00
xxd -p -c1 | tr -d '\n' |
2023-01-08 13:02:13 +00:00
{
while IFS= read -r -n2 -d '' ; do
if [ -n "$todo" ] ; then
#REPLY == " " is EOF
[[ "$REPLY" == " " ]] && echo '' || echo -e -n "$todo"
todo=""
fi
case "$REPLY" in
00)
todo="\n$prefix"
;;
08)
echo -n "${echar}b"
;;
09)
echo -n "${echar}t"
;;
0a)
echo -n "${echar}n"
;;
0b)
echo -n "${echar}v"
;;
0d)
echo -n "${echar}r"
;;
2023-01-14 12:14:09 +00:00
"$echar_hex")
echo -n "$echar$echar"
2023-01-08 13:02:13 +00:00
;;
2023-01-14 12:14:09 +00:00
#interpreted characters:
2[0-9a-f]|3[0-9a-f]|4[0-9a-f]|5[0-9abd-f]|6[0-9a-f]|7[0-9a-e])
2023-01-08 13:02:13 +00:00
echo -e -n '\x'"$REPLY"
;;
# All others are escaped
2023-01-14 12:14:09 +00:00
*)
2023-01-08 13:02:13 +00:00
echo -n "${echar}x$REPLY"
;;
esac
done
}
2022-12-31 17:41:24 +00:00
}
2023-01-12 16:31:31 +00:00
# Currently heads doesn't support signing file names with certain characters
# due to https://bugs.busybox.net/show_bug.cgi?id=14226. Also, certain characters
# may be intepreted by `whiptail`, `less` et al (e.g. \n, \b, ...).
assert_signable() {
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:assert_signable"
2023-01-12 16:31:31 +00:00
# ensure /boot mounted
if ! grep -q /boot /proc/mounts ; then
mount -o ro /boot || die "Unable to mount /boot"
fi
find /boot -print0 > /tmp/signable.ref
local del='\001-\037\134\177-\377'
LC_ALL=C tr -d "$del" < /tmp/signable.ref > /tmp/signable.del || die "Failed to execute tr."
if ! cmp -s "/tmp/signable.ref" "/tmp/signable.del" &> /dev/null ; then
2023-01-14 09:27:42 +00:00
local user_out="/tmp/hash_output_mismatches"
local add="Please investigate!"
[ -f "$user_out" ] && add="Please investigate the following relative paths to /boot (where # are sanitized invalid characters):"$'\n'"$(cat "$user_out")"
recovery "Some /boot file names contain characters that are currently not supported by heads: $del"$'\n'"$add"
2023-01-12 16:31:31 +00:00
fi
rm -f /tmp/signable.*
}
2022-12-31 17:41:24 +00:00
verify_checksums()
{
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:verify_checksums"
2022-12-31 17:41:24 +00:00
local boot_dir="$1"
2023-01-12 16:18:52 +00:00
local gui="${2:-y}"
2022-12-31 17:41:24 +00:00
(
set +e -o pipefail
local ret=0
cd "$boot_dir" || ret=1
sha256sum -c "$TMP_HASH_FILE" > /tmp/hash_output || ret=1
# also make sure that the file & directory structure didn't change
# (sha256sum won't detect added files)
print_tree > /tmp/tree_output || ret=1
2023-01-08 13:02:13 +00:00
if ! cmp -s "$TMP_TREE_FILE" /tmp/tree_output &> /dev/null ; then
ret=1
2023-01-12 16:18:52 +00:00
[[ "$gui" != "y" ]] && exit "$ret"
2023-01-08 13:02:13 +00:00
# produce a diff that can safely be presented to the user
# this is relatively hard as file names may e.g. contain backslashes etc.,
# which are interpreted by whiptail, less, ...
escape_zero "(new) " < "$TMP_TREE_FILE" > "${TMP_TREE_FILE}.user"
escape_zero "(new) " < /tmp/tree_output > /tmp/tree_output.user
diff "${TMP_TREE_FILE}.user" /tmp/tree_output.user | grep -E '^\+\(new\).*$' | sed -r 's/^\+\(new\)/(new)/g' >> /tmp/hash_output
rm -f "${TMP_TREE_FILE}.user"
rm -f /tmp/tree_output.user
fi
2022-12-31 17:41:24 +00:00
exit $ret
)
return $?
}
2019-08-19 22:07:22 +00:00
# detect and set /boot device
# mount /boot if successful
detect_boot_device()
{
2023-02-20 16:01:17 +00:00
TRACE "Under /etc/functions:detect_boot_device"
2019-08-19 22:07:22 +00:00
# unmount /boot to be safe
2020-07-13 22:22:40 +00:00
cd / && umount /boot 2>/dev/null
2019-08-19 22:07:22 +00:00
# check $CONFIG_BOOT_DEV if set/valid
if [ -e "$CONFIG_BOOT_DEV" ]; then
2019-11-13 23:36:29 +00:00
if mount -o ro $CONFIG_BOOT_DEV /boot >/dev/null 2>&1; then
if ls -d /boot/grub* >/dev/null 2>&1; then
# CONFIG_BOOT_DEV is valid device and contains an installed OS
return 0
fi
2019-08-19 22:07:22 +00:00
fi
fi
# generate list of possible boot devices
2021-01-05 22:13:41 +00:00
fdisk -l | grep "Disk /dev/" | cut -f2 -d " " | cut -f1 -d ":" > /tmp/disklist
2020-10-18 18:46:57 +00:00
2019-08-19 22:07:22 +00:00
# filter out extraneous options
> /tmp/boot_device_list
for i in `cat /tmp/disklist`; do
# remove block device from list if numeric partitions exist, since not bootable
2020-02-27 20:39:13 +00:00
DEV_NUM_PARTITIONS=$((`ls -1 $i* | wc -l`-1))
2019-08-19 22:07:22 +00:00
if [ ${DEV_NUM_PARTITIONS} -eq 0 ]; then
echo $i >> /tmp/boot_device_list
else
ls $i* | tail -${DEV_NUM_PARTITIONS} >> /tmp/boot_device_list
fi
done
2020-10-18 18:46:57 +00:00
2019-08-19 22:07:22 +00:00
# iterate thru possible options and check for grub dir
for i in `cat /tmp/boot_device_list`; do
umount /boot 2>/dev/null
2019-11-13 23:36:29 +00:00
if mount -o ro $i /boot >/dev/null 2>&1; then
if ls -d /boot/grub* >/dev/null 2>&1; then
CONFIG_BOOT_DEV="$i"
return 0
fi
2019-08-19 22:07:22 +00:00
fi
done
# no valid boot device found
echo "Unable to locate /boot files on any mounted disk"
umount /boot 2>/dev/null
return 1
}
2021-10-19 18:48:03 +00:00
calc()
{
awk "BEGIN { print "$*" }";
}
print_battery_health()
{
2021-10-26 20:26:11 +00:00
if [ -d /sys/class/power_supply/BAT* ]; then
battery_health=$(calc $(cat /sys/class/power_supply/BAT*/charge_full)/$(cat /sys/class/power_supply/BAT*/charge_full_design)*100 | awk -F "." {'print $1'})
2021-10-19 18:48:03 +00:00
echo "$battery_health"
fi
}
print_battery_charge()
{
2021-10-26 20:26:11 +00:00
if [ -d /sys/class/power_supply/BAT* ]; then
battery_charge=$(calc $(cat /sys/class/power_supply/BAT*/charge_now)/$(cat /sys/class/power_supply/BAT*/charge_full)*100 | awk -F "." {'print $1'})
2021-10-19 18:48:03 +00:00
echo "$battery_charge"
fi
}
2022-04-29 14:24:02 +00:00
generate_random_mac_address()
{
#Borrowed from https://stackoverflow.com/questions/42660218/bash-generate-random-mac-address-unicast
hexdump -n 6 -ve '1/1 "%.2x "' /dev/urandom | awk -v a="2,6,a,e" -v r="$RANDOM" 'BEGIN{srand(r);}NR==1{split(a,b,",");r=int(rand()*4+1);printf "%s%s:%s:%s:%s:%s:%s\n",substr($1,0,1),b[r],$2,$3,$4,$5,$6}'
}