#!/bin/sh

set -e

script_dir="$(cd "$(dirname "$0")" && pwd)"
die() {
   echo "ERROR"
   echo "$@" >&2
   exit 1
}

TMP_CONFIG=""
TMP_EEPROM=""
TMP_EEPROM2=""
cleanup() {
   rm -f "${TMP_CONFIG}" -f "${TMP_EEPROM}" "${TMP_EEPROM2}"
   TMP_CONFIG=""
   TMP_EEPROM=""
   TMP_EEPROM2=""
}
trap cleanup EXIT

check_reduce_size()
{
   # Verify that unused bytes are set to 0xff if the size of the config file is reduced.
   echo "check_reduce_size $1 $2"

   image="${script_dir}/$1"
   conf="${script_dir}/$2"

   # Check that the production config file can be read correctly
   image_md5="$(md5sum "${image}" | awk '{print $1}')"
   TMP_CONFIG="$(mktemp)"

   # Generate a new EEPROM with larger config file
   cp -f "${conf}" "${TMP_CONFIG}"
   echo "Add some random text to the config file" >> "${TMP_CONFIG}"

   TMP_EEPROM="$(mktemp)"
   "${script_dir}/../rpi-eeprom-config" \
      "${image}" \
      --config "${TMP_CONFIG}" \
      --out "${TMP_EEPROM}"

   # Check that the new image is different
   actual_md5="$(md5sum "${TMP_EEPROM}" | awk '{print $1}')"
   [ "${image_md5}" != "${actual_md5}" ] || die "EEPROM images should be different"

   # Re-apply the original configuration and make sure the image is the same
   TMP_EEPROM2="$(mktemp)"
   "${script_dir}/../rpi-eeprom-config" \
      "${TMP_EEPROM}" \
      --config "${conf}" \
      --out "${TMP_EEPROM2}"

   # Check that applying the EEPROM config file again gets back to the original image
   actual_md5="$(md5sum "${TMP_EEPROM2}" | awk '{print $1}')"
   [ "${image_md5}" = "${actual_md5}" ] || die "Image should be the same as original"

}

check_signed_loopback()
{
   echo "check_signed $1 $2"

   image="${script_dir}/$1"
   conf="${script_dir}/$2"
   digest="${script_dir}/$3"
   pubkey="${script_dir}/$4"

   # Replace the config, config.sig and pubkey and verify that the output is the same
   TMP_EEPROM="$(mktemp)"
   "${script_dir}/../rpi-eeprom-config" \
      "${image}" \
      --config "${conf}" \
      --digest "${digest}" \
      --pubkey "${pubkey}" \
      --out "${TMP_EEPROM}"

   expected_md5="$(md5sum "${image}" | awk '{print $1}')"
   actual_md5="$(md5sum "${TMP_EEPROM}" | awk '{print $1}')"
   [ "${actual_md5}" = "${expected_md5}" ] || die "EEPROM signed-loopback: checksum mismatch"
}

check_loopback()
{
   echo "check_loopback $1 $2"

   image="${script_dir}/$1"
   conf="${script_dir}/$2"

   # Check that the production config file can be read correctly
   expected_md5="$(md5sum "${conf}" | awk '{print $1}')"
   actual_md5="$("${script_dir}/../rpi-eeprom-config" "${image}" | md5sum | awk '{print $1}')"
   [ "${actual_md5}" = "${expected_md5}" ] || die "Config-read: checksum mismatch"

   # Check that overwriting the config section produces an identical binary
   TMP_EEPROM="$(mktemp)"
   "${script_dir}/../rpi-eeprom-config" \
      "${image}" \
      --config "${conf}" \
      --out "${TMP_EEPROM}"

   expected_md5="$(md5sum "${image}" | awk '{print $1}')"
   actual_md5="$(md5sum "${TMP_EEPROM}" | awk '{print $1}')"
   [ "${actual_md5}" = "${expected_md5}" ] || die "EEPROM loopback: checksum mismatch"
}

# Update the EEPROM with a new config and check the expected image is produced
check_update()
{
   echo "check_update $1 $2 $3"

   image="${script_dir}/$1"
   ref_image="${script_dir}/$2"
   conf="${script_dir}/$3"

   expected_md5="$(md5sum "${ref_image}" | awk '{print $1}')"

   TMP_EEPROM="$(mktemp)"
   "${script_dir}/../rpi-eeprom-config" \
      "${image}" \
      --config "${conf}" \
      --out "${TMP_EEPROM}"

   actual_md5="$(md5sum "${TMP_EEPROM}" | awk '{print $1}')"
   if [ "${actual_md5}" != "${expected_md5}" ]; then
      hexdump -C "${TMP_EEPROM}" > "tmp.hex"
      die "EEPROM update: checksum mismatch"
   fi
}

# Verify that rpi-eeprom-config will apply and 2024 byte configuration file correctly.
check_conf_size_large()
{
   echo "check maximum config file size"
   image="${script_dir}/$1"
   conf="bootconf-2024.txt"

   expected_md5="$(md5sum "${conf}" | awk '{print $1}')"

   TMP_EEPROM="$(mktemp)"
   "${script_dir}/../rpi-eeprom-config" \
      "${image}" \
      --config "${conf}" \
      --out "${TMP_EEPROM}"

   actual_md5="$("${script_dir}/../rpi-eeprom-config" "${TMP_EEPROM}" | md5sum | awk '{print $1}')"
   [ "${actual_md5}" = "${expected_md5}" ] || die "EEPROM check large config: checksum mismatch"
}

# Verify that rpi-eeprom-config will reject files exceeding 2024 bytes
check_conf_size_too_large()
{
   echo "check config file which exceeds the maximum size"
   image="${script_dir}/$1"
   conf="bootconf-2025.txt"

   expected_md5="$(md5sum "${conf}" | awk '{print $1}')"

   TMP_EEPROM="$(mktemp)"
   if "${script_dir}/../rpi-eeprom-config" "${image}" --config "${conf}" --out "${TMP_EEPROM}" > /dev/null 2>&1; then
      die "$config should have been rejected"
   fi
}

echo "Check config read and loopback read/write against reference config files"
versions="$(cd configs; ls *.txt | sed 's/bootconf-//g' | sed 's/.txt//g')"
for ver in ${versions}; do
   check_loopback "../firmware/old/beta/pieeprom-${ver}.bin" "configs/bootconf-${ver}.txt"
   cleanup
done

echo "Test lookback with a signed EEPROM image"
check_loopback pieeprom-signed.bin bootconf.txt
check_signed_loopback pieeprom-signed.bin bootconf.txt bootconf.sig public.pem
cleanup

check_update "../firmware/old/beta/pieeprom-2019-07-15.bin" "pieeprom-2019-07-15-freeze.bin" "bootconf-2019-07-15-freeze.txt"
cleanup

check_reduce_size "../firmware/old/beta/pieeprom-2019-07-15.bin" "bootconf-2019-07-15.txt"
cleanup

check_conf_size_large "../firmware/old/beta/pieeprom-2019-07-15.bin"
cleanup

check_conf_size_too_large "../firmware/old/beta/pieeprom-2019-07-15.bin"
cleanup
