#!/bin/bash
#set -x
set -e

# create the new files for
# /boot/extlinux/extlinux.conf and
# /boot/grub/menu.lst
# when a kernel is upgraded.
#
# 1. latest kernel
# 2. previous kernel
# 3. (current running kernel [if different])
#
# logic stolen blatently from /etc/kernel/postinst.d/apt-auto-removal
# (version_test_gt & get_kernel_versions)
#
# grub menu.lst only gets the version being installed now

DPKG=/usr/bin/dpkg
declare -A WG_kernels
WG_kernels={}
LINUX_PFX=$(ls /boot/ |grep ".*linu.*-.*" |sed -e "s|-.*$||" |head -1)

[ -r /etc/default/wg_system ] && source /etc/default/wg_system
WG_PRODUCT_NAME=${WG_PRODUCT_NAME:-WatchGuard Dimension}
WG_PRODUCT_VERSION=${WG_PRODUCT_VERSION:-}

#####################
#
check_for_menu32() {
  if [ -f /boot/extlinux/menu.c32 ]; then
     return 
  fi
  if [ -f /usr/lib/syslinux/menu.c32 ]; then
    cp -f /usr/lib/syslinux/menu.c32 /boot/extlinux/
  fi

  if [ ! -f /boot/extlinux/menu.c32 ]; then
    # No menu, abort with error
    echo >&2 "$0 Error: can not find /boot/extlinux/menu.c32 for extlinux (/usr/lib/syslinux/menu.c32)"
    exit 1
  fi
}

#####################
#
update_file() {
  local orig_file=$1
  local new_file=$2

  if  diff -q "${orig_file}" "${new_file}" >/dev/null ; then
    # nothing to do
    return
  fi
  
  if [ -f "${orig_file}.bak" ]; then rm -f "${orig_file}.bak"; fi
  cp -f "${orig_file}" "${orig_file}.bak"
  mv -f "${new_file}"  "${orig_file}"
  chmod 0644 "${orig_file}"
}

#####################
#
one_extlinux_entry() {
  local tlabel=$1
  local tversion=$2
  [ "$tversion" = "" ] && return

  local tlabel_str="$WG_PRODUCT_NAME $WG_PRODUCT_VERSION ($tversion)"
  
  cat <<EOM

LABEL   $tlabel
  MENU LABEL $tlabel_str
  SAY     $tlabel_str
  LINUX   /boot/${LINUX_PFX}-${tversion}
  APPEND  root=/dev/disk/by-label/wgrd.root ro
  INITRD  /boot/initrd.img-$tversion
$([ "$tlabel" = "newest" ] && echo "  MENU DEFAULT")
EOM
}

#####################
#
make_extlinux_conf() {
  local EXTLINUX_CONF=/boot/extlinux/extlinux.conf
  local WG_EXT_tfile=temp_extlinux.txt
  if [ ! -f "$EXTLINUX_CONF" ] ; then
    return
  fi
  if [ -f "$WG_EXT_tfile" ]; then
    rm -f "$WG_EXT_tfile"
  fi
  cat > ${WG_EXT_tfile} <<EOF
DEFAULT newest
UI menu.c32
TIMEOUT 100
$(
for ktype in newest previous running ; do
  one_extlinux_entry $ktype ${WG_kernels[$ktype]}
done
)
EOF
  update_file "$EXTLINUX_CONF" "$WG_EXT_tfile"
}

#####################
#
make_grub_menu_lst() {
  # grub menu.lst only gets the installed kernel
  local MENU_LST=/boot/grub/menu.lst
  local WG_GRUB_tfile=temp_grub_menu.txt
  if [ ! -f "$MENU_LST" ]; then
    : return
  fi
  if [ -f "$WG_GRUB_tfile" ]; then
    rm -f "$WG_GRUB_tfile"
  fi
  local tversion=$NEW_LINUX_VERSION
  cat $MENU_LST |
    sed -e "
    /^title/  s|kernel [^[:space:]]\+|kernel $tversion|;
    /^kernel/ s|/boot/[^[:space:]]\+|/boot/${LINUX_PFX}-$tversion|;
    /^initrd/ s|/boot/init[^[:space:]]\+|/boot/initrd.img-$tversion|;
    "  > ${WG_GRUB_tfile}

  update_file "$MENU_LST" "$WG_GRUB_tfile"
}

#####################
#
version_test_gt () {
  local version_test_gt_sedexp="s/[._-]\(pre\|rc\|test\|git\|old\|trunk\)/~\1/g"
  local version_a="`echo "$1" | sed -e "$version_test_gt_sedexp"`"
  local version_b="`echo "$2" | sed -e "$version_test_gt_sedexp"`"
  $DPKG --compare-versions "$version_a" gt "$version_b"
  return "$?"
}

#####################
#
get_kernel_versions () {
  local installed_version=$1
  local running_version="$(uname -r)"
  list=$(${DPKG} -l 'linux-image-[0-9]*'|awk '/^ii/ { print $2 }' | sed -e's/linux-image-//')
  list="${list} $installed_version"

  latest_version=""
  previous_version=""
  for i in $list; do
    if version_test_gt "$i" "$latest_version"; then
       previous_version="$latest_version"
       latest_version="$i"
    elif version_test_gt "$i" "$previous_version"; then
       previous_version="$i"
    fi
  done

  if [ "$latest_version" = "$running_version" ] \
     || [ "$previous_version" = "$running_version" ]
  then
    # running version is not different, no need to preserve it.
    running_version=
  fi

  if [ "$latest_version" = "$previous_version" ]; then
    # only one kernel
    previous_version=
  fi

  WG_kernels[newest]=$latest_version
  [ -z "$previous_version" ] || WG_kernels[previous]=$previous_version
  [ -z "$running_version" ]  || WG_kernels[running]=$running_version
}

#####################
#
# main

# passed newest version on the command-line
NEW_LINUX_VERSION=$1

check_for_menu32
get_kernel_versions $NEW_LINUX_VERSION
make_extlinux_conf
make_grub_menu_lst
