#!/bin/bash
# Steven Shiau <steven _at_ nchc org tw>
# License: GPL
# Description: prepare the pxelinux by using the files on the system or download and extract the required programs for DRBL.
DRBL_SCRIPT_PATH="${DRBL_SCRIPT_PATH:-/usr/share/drbl}"

. $DRBL_SCRIPT_PATH/sbin/drbl-conf-functions
[ -e /etc/drbl/drbl-ocs.conf ] && . /etc/drbl/drbl-ocs.conf
[ -e $DRBL_SCRIPT_PATH/sbin/ocs-functions ] && . $DRBL_SCRIPT_PATH/sbin/ocs-functions

# Local settings
# Not existing in ubuntu syslinux package: gpxelinux.0 sanboot.c32 README.menu hdt.c32
# The files are in /usr/lib/syslinux/ on Ubuntu 10.04 syslinux 3.63.
# Debian has syslinux-common, and the above files are in syslinux-common, but ubuntu 10.04 does not, and ubuntu 11.04 does.
# For Syslinux 5, new .c32 are required: ldlinux.c32, libcom32.c32, libutil.c32
DRBL_NEED_PXELINUX="isolinux.bin memdisk menu.c32 vesamenu.c32 pxelinux.0 gpxelinux.0 chain.c32 mboot.c32 sanboot.c32 README.menu mbr.bin hdt.c32 $sys_pxelinux_required_c32"
# By default we only copy the required files to $pxelinux_binsrc_dir. This option will allow us to copy files to dir $pxecfg_pd.
deploy_to_system_too="no"

# Functions
USAGE() {
  echo "Put the pxelinux files in DRBL package repository"
  echo "Usage: $0 [OPTION]"
  echo "OPTION:"
  echo "-u, --from-upstream   Use the binary from upstream ($syslinux_binsrc_url). If this option is not assigned, DRBL will try to use the pxelinux from your GNU/Linux distribution."
  echo "-pv, --pxelinux-version VERSION  The pxelinux version to be used with -u|--from-upstream. If not assigned, the version number specified in drbl.conf will be used."
  echo "-d, --deploy-to-system-too   Deploy the files to DRBL system ($pxecfg_pd), too."
  echo "Ex: To use the pxelinux 4.04 from $syslinux_binsrc_url, run '$0 -u -pv 4.04'"
}

#
put_pxelinux_bin_2_drbl_repo() {
  local pxelinux_extracted_bin_abs_path="$1"  # dir name
  [ -z "$pxelinux_extracted_bin_abs_path" ] && return 1
  echo "Putting required pxelinux files in DRBL package repository $pxelinux_binsrc_dir... "
  cp -a $pxelinux_extracted_bin_abs_path/* $pxelinux_binsrc_dir/
  pxelinux_v="$(LC_ALL=C strings $pxelinux_file | grep "^PXELINUX")"
  echo "PXELinux version: $pxelinux_v"
  echo $pxelinux_v > $pxelinux_binsrc_dir/VERSION
  echo "done!"
  if [ "$deploy_to_system_too" = "yes" ]; then
    echo -n "Putting required pxelinux files in DRBL system dir $pxecfg_pd... "
    cp -a $pxelinux_extracted_bin_abs_path/* $pxecfg_pd/
    echo $pxelinux_v > $pxecfg_pd/PXELINUX_VERSION
    echo "done!"
  fi
} # end of put_pxelinux_bin_2_drbl_repo

#
put_upstream_pxelinux(){
  # Function to use the upstream binary directly
  local ver="$1"
  local tmp_wd syslinux_tarball
  if [ -z "$ver" ]; then
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
    echo "No upstream syslinux/pxelinux version was assigned. Program terminated."
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    USAGE
    exit 1
  fi
  syslinux_tarball="syslinux-${ver}.tar.bz2"
  tmp_wd="$(LC_ALL=C mktemp -d /tmp/syslinux_tmp.XXXXXXX)"
  mkdir -p $tmp_wd/upstream
  echo -n "Downloading ${ver} syslinux/pxelinux files from $syslinux_binsrc_url... "
  LC_ALL=C wget $wget_opt -P $tmp_wd $syslinux_binsrc_url/$branch_path/$syslinux_tarball
  echo "done!"
  LC_ALL=C tar -xjf $tmp_wd/$syslinux_tarball -C $tmp_wd/upstream
  mkdir -p $tmp_wd/extracted/syslinux
  echo "Extracting the required files for DRBL..."
  for iprog in $DRBL_NEED_PXELINUX; do
    find $tmp_wd/upstream -name "$iprog" -type f -exec cp -af {} $tmp_wd/extracted/syslinux/ \;
  done
  # change the mode, no idea why main.c32 and chain.c32 is 755
  find $tmp_wd/extracted/syslinux/ -type f -exec chmod 644 {} \;
  put_pxelinux_bin_2_drbl_repo $tmp_wd/extracted/syslinux/
  if [ -d "$tmp_wd" -a -n "$(echo "$tmp_wd" | grep -i syslinux_tmp)" ]; then
    rm -rf $tmp_wd
  fi
} # end of put_upstream_pxelinux
#
put_distribution_pxelinux() {
  # Function to use the package from distribution.
  local possible_syslinux_pkgs req_syslinux_pkg_name syslinux_pkgs
  possible_syslinux_pkgs="syslinux-common syslinux"  # First we find syslinux-common, then syslinux. The order is important.
  # Package name:
  # Debian: syslinux-common
  # Ubuntu: 10.04: syslinux, > 10.10: syslinux-common
  # Fedora: syslinux
  # Suse: syslinux
  for i in $possible_syslinux_pkgs; do
    if $query_pkglist_exist_cmd $i &>/dev/null; then
       req_syslinux_pkg_name="$i"
       break
    fi
  done
  tmp_wd="$(LC_ALL=C mktemp -d /tmp/pxelinux_tmp.XXXXXXX)"
  if [ -n "$req_syslinux_pkg_name" ]; then
    # Found on the system
    # The syslinux-common version on Debian might be like: 2:4.02+dfsg-7, to compare the version, we'd better to strip the "2:"
    # syslinux_pkg_ver="$(LC_ALL=C dpkg-query -W -f='${Version}\n' $req_syslinux_pkg_name | sed -r -e "s/^[[:digit:]]*://g")"
    # echo "Syslinux package version: $syslinux_pkg_ver"
    # For Redhat-like system, there might return more than one file on a system, i.e. one file belongs to 2 rpm packages.
    pxelinux_bin="$(LC_ALL=C $query_pkglist_cmd $req_syslinux_pkg_name | grep -Ew "pxelinux.0$" | sort | head -n 1)"
    if [ -n "$pxelinux_bin" ]; then
      echo "Found $pxelinux_bin in this system, copying the PXELinux files to DRBL local repository..."
      pxelinux_bin_dir="$(LC_ALL=C dirname $pxelinux_bin)"
      for iprog in $DRBL_NEED_PXELINUX; do
        find $pxelinux_bin_dir -name "$iprog" -type f -exec cp -af {} $tmp_wd/ \;
      done
      put_pxelinux_bin_2_drbl_repo $tmp_wd
    else
      [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
      echo "Package of pxelinux was installed, but pxelinux boot file not found!"
      [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    fi
  else 
    # Download and extract it. The reason we do not install it is we do not want to bother the server's boot menu
    mkdir -p $tmp_wd/{extracted,upstream}
    echo "Trying to download syslinux from distribution repository..."
    if [ -e /etc/debian_version ]; then
      # Debian
      syslinux_pkgs=""
      for ipkg in $possible_syslinux_pkgs; do
        if [ -n "$(LC_ALL=C apt-cache show $ipkg 2>/dev/null)" ]; then
          syslinux_pkgs="$syslinux_pkgs $ipkg"
        fi
      done
      echo "Related syslinux package(s) on repository: $syslinux_pkgs"
       # Clean all stale deb files in the cache dir. Otherwise there might be some old version of debs exist in the cache dir.
      LC_ALL=C apt-get clean
      LC_ALL=C apt-get -d --reinstall install $syslinux_pkgs
      for i in $syslinux_pkgs; do
        LC_ALL=C dpkg --extract /var/cache/apt/archives/${i}_*.deb $tmp_wd/upstream
      done
      for iprog in $DRBL_NEED_PXELINUX; do
        find $tmp_wd/upstream -name "$iprog" -type f -exec cp -af {} $tmp_wd/extracted \;
      done
      put_pxelinux_bin_2_drbl_repo $tmp_wd/extracted
    elif [ -e /etc/SuSE-release ]; then
      # SuSE
      # The binary for syslinux-common in openSuse 11.3 is: /boot/pxelinux.bin
      # TODO: Clean cached files in /var/cache/zypp/packages/
      LC_ALL=C zypper install -d -f -y syslinux
      pxelinux_rpm="$(LC_ALL=C find /var/cache/zypp/packages/ -name "syslinux-*.rpm" -print)"
      (
       cd $tmp_wd/upstream
       LC_ALL=C rpm2cpio "$pxelinux_rpm" | cpio -idm
      )
      for iprog in $DRBL_NEED_PXELINUX; do
        find $tmp_wd/upstream -name "$iprog" -type f -exec cp -af {} $tmp_wd/extracted \;
      done
      put_pxelinux_bin_2_drbl_repo $tmp_wd/extracted
    else
      # RH-like
      LC_ALL=C yumdownloader --destdir $tmp_wd syslinux
      (
       cd $tmp_wd/upstream
       LC_ALL=C rpm2cpio $tmp_wd/syslinux*.rpm | cpio -idm
      )
      for iprog in $DRBL_NEED_PXELINUX; do
        find $tmp_wd/upstream -name "$iprog" -type f -exec cp -af {} $tmp_wd/extracted \;
      done
      put_pxelinux_bin_2_drbl_repo $tmp_wd/extracted
    fi
  fi
  if [ -d "$tmp_wd" -a -n "$(LC_ALL=C echo "$tmp_wd" | grep -i pxelinux_tmp)" ]; then
    rm -rf $tmp_wd
  fi
} # end of put_distribution_pxelinux

############
### MAIN ###
############

while [ $# -gt 0 ]; do
  case "$1" in
    -u|--from-upstream) shift; mode="from-upstream" ;;
    -pv|--pxelinux-version)
        shift;
        if [ -z "$(echo $1 |grep ^-.)" ]; then
          # skip the -xx option, in case 
          pxelinux_ver_requested="$1"
          [ -z "$pxelinux_ver_requested" ] && USAGE && exit 1
	  shift
        fi
	;;
    -d|--deploy-to-system-too) shift; deploy_to_system_too="yes" ;;
    *)  USAGE && exit 1 ;;
  esac
done
# mode is essential
[ -z "$mode" ] && mode="from-distribution"
[ -z "$pxelinux_ver_requested" ] && pxelinux_ver_requested="$SYS_PXELINUX_VER_DEF"

case "$mode" in
  from-distribution) put_distribution_pxelinux ;;
  from-upstream)     put_upstream_pxelinux $pxelinux_ver_requested ;;
esac

exit 0
