#!/bin/bash
# Simple script to download a Grml ISO image to use with grml-rescueboot
# Needs the Debian keyring, sopv + wget
# Licensed under GPL v2+

set -eu -o pipefail

# defaults
grmlflavor=full
force=0
retrieved_iso=0

declare -A bin_to_pkg=( [update-grub]=grub2-common [wget]=wget [sopv]=sqopv )
declare -a missing_packages=()
for binary in "${!bin_to_pkg[@]}" ; do
  if ! command -v "${binary}" &>/dev/null ; then
    echo "ERROR: Binary $binary not found." >&2
    missing_packages+=( ${bin_to_pkg[$binary]} )
  fi
done

keyringname="/usr/share/keyrings/debian-keyring"
keyring=""
for pgpext in pgp gpg; do
  keyring="${keyringname}.${pgpext}"
  if [ -r "${keyring}" ] ; then
    break
  fi
  keyring=""
done
if [ -z "${keyring}" ] ; then
  echo "ERROR: File ${keyringname}.{pgp,gpg} not found." >&2
  missing_packages+=( debian-keyring )
fi

if [ ${#missing_packages[@]} -ne 0 ] ; then
  echo "TIP: Try running \`apt install ${missing_packages[*]}\` to fix this." >&2
  exit 1
fi

usage() {
  echo "Usage: $(basename "$0") [-f] [-t <small|full>]"
}

while getopts ":a:t:fh" opt ; do
  case ${opt} in
    t)
      if [ "${OPTARG}" = "full" ] || [ "${OPTARG}" = "small" ] ; then
	grmlflavor="${OPTARG}"
      else
	echo "ERROR: Invalid value '${OPTARG}'. Supported values: small, full" >&2
	usage >&2 ; exit 1
      fi
      ;;
    f)
      force=1
      ;;
    h)
      usage ; exit 0
      ;;
    \?)
      echo "ERROR: Invalid Option: -${OPTARG}" >&2
      usage >&2 ; exit 1
      ;;
    :)
      echo "ERROR: Option -${OPTARG} requires an argument." >&2
      ;;
  esac
done

arch="$(uname -m)"
case ${arch} in
  aarch64)
    grmlarch=arm64
    ;;
  x86_64)
    grmlarch=amd64
    ;;
  *)
    echo "ERROR: Unsupported architecture '${arch}'." >&2
    usage >&2
    exit 1
    ;;
esac

echo "Finding out latest ISO image..."
date=$(wget --quiet -O- https://download.grml.org/ | sed --regex -n 's/.*grml-('"$grmlflavor"')-([0-9]{4}\.[0-9]{2})-('"$grmlarch"')\.iso.*/\2/p' | sort | tail -1)

if [ -z "${date}" ] ; then
  echo "ERROR: Could not find out latest ISO." >&2
  exit 1
fi

output_directory="/boot/grml"
mkdir -p "${output_directory}"

diskfree=$(df --output=avail "${output_directory}" | tail -1)
if [ -z "${diskfree}" ] ; then
  echo "ERROR: couldn't calculate free disk space in /boot." >&2
  exit 1
fi

if [ "${grmlflavor}" = "full" ] && [ "${diskfree}" -lt 1048576 ] ; then
  if [ "${force}" = "1" ] ; then
    echo "WARN: There might not be enough free disk space in /boot, continuing anyway as requested via -f."
  else
    echo "ERROR: there doesn't seem to be enough free disk space in /boot." >&2
    echo "Note: >=1GB for grml-full recommended (use -f to force download anyway)."
    exit 1
  fi
elif [ "${grmlflavor}" = "small" ] && [ "${diskfree}" -lt 524288 ] ; then
  if [ "${force}" = "1" ] ; then
    echo "WARN: There might not be enough free disk space in /boot, continuing anyway as requested via -f."
  else
    echo "ERROR: there doesn't seem to be enough free disk space in /boot." >&2
    echo "Note: >=512MB for grml-small recommended (use -f to force download anyway)."
    exit 1
  fi
fi

isoname="grml-${grmlflavor}-${date}-${grmlarch}.iso"
isofile="${output_directory}/${isoname}"
isofiletmp="${isofile}.tmp"

if [ "${force}" = "1" ] || ! [ -f "${isofile}" ] ; then
  echo "Downloading Grml ISO to '${isofile}'."
  wget -O "${isofiletmp}" "https://download.grml.org/${isoname}"
  retrieved_iso=1
elif [ -f "${isofile}" ] ; then
  echo "Found local ${isofile}, skipping download (use -f to force download)."
fi

if [ "${retrieved_iso}" = "1" ] ; then
  sig="$(mktemp)"
  echo "Verifying ISO..."
  wget --quiet -O "${sig}" "https://download.grml.org/${isoname}.asc"

  if ! sopv verify "${sig}" "${keyring}" <"${isofiletmp}" ; then
    echo "ERROR: ISO file will be left in '${isofiletmp}'." >&2
    rm "${sig}"
    exit 1
  fi

  rm "${sig}"
  mv "${isofiletmp}" "${isofile}"

  echo "ISO file is OK."
fi

echo "Invoking 'update-grub' now."
update-grub

echo "Successfully finished grml-rescueboot integration."
