#!/bin/bash
# Author: Steven Shiau <steven _at_ nchc org tw>
# License: GPL
# Program to put the signed EFI boot loader from Ubuntu
# Ref: 1. /usr/sbin/grub-install from package grub2-common (verson 2.00-13ubuntu3) on Ubuntu 13.04 (Raring)
#      2. https://wiki.edubuntu.org/SecurityTeam/SecureBoot
# Required files from packages on Ubuntu: 
# shim-signed: /usr/lib/shim/shim.efi.signed
# grub-efi-amd64-signed: /usr/lib/grub/x86_64-efi-signed/gcdx64.efi.signed
# //NOTE// The signed packages only exist on AMD64 arch, not IA32 arch. That's why here we only create AMD64 arch files (bootx64.efi and grubx64.efi).

# Settings
# Load DRBL setting and functions
DRBL_SCRIPT_PATH="${DRBL_SCRIPT_PATH:-/usr/share/drbl}"

. $DRBL_SCRIPT_PATH/sbin/drbl-conf-functions

grub_required_files="/usr/share/grub/unicode.pf2"
required_packages="shim-signed grub-efi-amd64-signed grub-efi-amd64-bin"
# Signed file with full path inside the deb.
shim_signed=/usr/lib/shim/shim.efi.signed
shimx64_signed=/usr/lib/shim/shimx64.efi.signed
# gcdx64.efi was grub-cd.efi, which is the boot loader for removable device, like CD or USB flash drive.
# while grubx64.efi is for hard drive.
efi_signed=/usr/lib/grub/x86_64-efi-signed/gcdx64.efi.signed
# Path to grub x86-64 efi modules. Do not put "/" in the end
x86_64_mod_path=/usr/lib/grub/x86_64-efi
# Default nameserver for chroot environment
dns_default="8.8.8.8"

# Functions
USAGE() {
  echo "To create an EFI boot loader from grub2."
  echo "Usage: $ocs [OPTION] OUTPUT_DIR"
  echo "Options:"
  echo "-c, --chroot DIR chroot to DIR for running apt. This allows to use a debootstrap environment for different distributions. E.g. running OS is debian, while Ubuntu environment is required for packages shim-signed and grub-efi-amd64-signed which do not exist on Debian."
  echo "OUTPUT_DIR is the where the created boot loader will be placed."
  echo "   E.g.  $ocs /tmp/efi/"
}
#
#############
###  MAIN ###
#############
ocs=`basename $0`
#
check_if_root

#
while [ $# -gt 0 ]; do
 case "$1" in
   -c|--chroot)
           # Use the chroot dir
           shift; 
           if [ -z "$(echo $1 |grep ^-.)" ]; then
             # skip the -xx option, in case 
             chroot="$1"
             shift;
           fi
           [ -z "$chroot" ] && USAGE && exit 1
           ;;
   -*)     echo "${0}: ${1}: invalid option" >&2
           USAGE >& 2
           exit 2 ;;
   *)      break ;;
 esac
done

output_dir="$1"

# Checking
if [ ! -e /etc/debian_version ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo "This is not a Debian/Ubuntu Linux system. This program only works on Debian/Ubuntu Linux system."
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo "Program terminated!"
  exit 1
fi
if [ -z "$output_dir" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo "No output dir! Program terminated!"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  USAGE
  exit 1
fi
if [ ! -d "$output_dir" ]; then
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo "The output dir \"$output_dir\" does not exist, or it's not a directory."
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo "Program terminated!"
  exit 1
fi

grub_efi_dir="$(mktemp -d /tmp/grub-efi.XXXXXX)"
if [ -n "$chroot" ]; then
  if [ ! -d "$chroot" ]; then
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
    echo "Chroot dir $chroot not found!"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo "Program terminated!"
    exit 1
  fi
  # Run in chroot environment
  grub_efi_tmp_exe="$chroot/tmp/grub-efi-exe.sh"
  dns_chroot="$(drbl-get-dnsserver | awk -F"," '{print $1}')"
  [ -z "$dns_chroot" ] && dns_chroot="$dns_default"
  echo "dns_chroot: $dns_chroot"
  # create a script to be run in chroot
cat <<-EFI_END > $grub_efi_tmp_exe
#!/bin/bash
echo "nameserver $dns_chroot" > /etc/resolv.conf
for i in $required_packages; do
  echo "Download \$i from deb packages repository..."
  LC_ALL=C apt-get -d --reinstall -y install \$i
done
EFI_END
  chmod 755 $grub_efi_tmp_exe
  echo "The content of $grub_efi_tmp_exe:"
  echo "========================================"
  cat $grub_efi_tmp_exe
  echo "========================================"
  chroot $chroot /tmp/grub-efi-exe.sh
  rm -f $grub_efi_tmp_exe
else
  # Run in running OS environment, not chroot.
  # Check if it's Ubuntu environment
  [ -e /etc/lsb-release ] && . /etc/lsb-release
  if [ "$DISTRIB_ID" != "Ubuntu" ] ;then
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
    echo "This GNU/Linux distribution is not Ubuntu Linux."
    echo "Packages $required_packages exist only on Ubuntu Linux!"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo "Program terminated!"
    exit 1
  fi
  for i in $required_packages; do
    echo "Download $i from deb packages repository..."
    LC_ALL=C apt-get -d --reinstall -y install $i &>/dev/null
  done
fi
for i in $chroot/var/cache/apt/archives/shim-signed_*.deb \
	 $chroot/var/cache/apt/archives/grub-efi-amd64-signed_* \
	 $chroot//var/cache/apt/archives/grub-efi-amd64-bin_*
do
  dpkg --extract $i $grub_efi_dir
done

if [ -e "$grub_efi_dir/$shim_signed" ]; then
  cp -av "$grub_efi_dir/$shim_signed" "${output_dir}/bootx64.efi"
elif [ -e "$grub_efi_dir/$shimx64_signed" ]; then
  cp -av "$grub_efi_dir/$shimx64_signed" "${output_dir}/bootx64.efi"
fi
cp -av "$grub_efi_dir/$efi_signed" "${output_dir}/grubx64.efi"
cp -a  "$grub_efi_dir/$x86_64_mod_path" "${output_dir}/"

# Copy the required files, e.g. fonts to the output dir.
cp -a $grub_required_files $output_dir

# Clean the temp dir
if [ -e "$grub_efi_dir" -a -n "$(echo $grub_efi_dir | grep -E "grub-efi")" ]; then
  rm -rf $grub_efi_dir
fi
