#!/bin/bash
#
# by robert Plestenjak, robert.plestenjak@xlab.si
#
# depends on: cloud-utils

function deps () {
  for file in ${@}; do
    # check if is a valid file
    [ -f ${file} ] &&
      # is this file new?
      if [ ! -f /tmp/initrd${file} ]; then
        cp -v ${file} /tmp/initrd${file}
        if [ $? != 0 ]; then
          # error, bug out
          echo "Can't copy \"${file}\""
          exit 1
        fi
      fi
  done
}

function copy-tools() {
  # install files listed in deps.lst
  while read tool; do
    IN=0
    for bin_path in "${initrd_path}"; do
      [[ -f ${bin_path}/${tool} ]] && IN=1
    done
    if [ ${IN} -eq 0 ]; then
      # get tools path
      toolpath=$(command -v ${tool})
      if [ $? != 0 ]; then
        # tool not installed, bug out
        echo "\"${tool}\" not found! Please install"
        exit 1
      fi
      # copy tool into initrd
      cp -v ${toolpath} bin/${tool}
      # install needed libraries
      deps "($(ldd ${toolpath}))"
    else
      echo "${tool} present"
    fi
  done <${inst_dir}/distro/${distro}/deps
}

initrd() {
  # clean up
  [ -d /tmp/initrd ] && rm -rf /tmp/initrd
  # create temp directory and move there
  mkdir /tmp/initrd && cd /tmp/initrd
  # extract current initrd
  gunzip -c ${initrd} | cpio -i --make-directories
  # modify
  copy-tools
  touch etc/mtab
  [ "${mod_type}" == "mod_lvm" ] && \
    sed -i "s/locking_type = 4/locking_type = 1/" etc/lvm/lvm.conf
  mod_file=${inst_dir}/distro/${distro}/${mod_type}
  sed -i -e "/${proc_insert_point}/r ${mod_file}" -e "//N" ${init_script}
  sed -i "/${call_insert_point}/i ${proc_name}" ${init_script}
  # create new
  find ./ | cpio -H newc -o > /tmp/initrd.cpio
  gzip -c /tmp/initrd.cpio > ${initrd}-mod
  # clean up
  cd ${inst_dir}
  rm -rf /tmp/initrd.cpio /tmp/initrd
}

grub-mod() {
  case ${1} in
    "grub1")
      # clean existing mod
      grubby -o ${grub_config} --grub --remove-kernel=${kernel}-mod
      # create new mod
      # copy kernel
      [ ! -f ${kernel}-mod ] && cp ${kernel} ${kernel}-mod
      # grub title
      grub_title="$(cat /etc/redhat-release) $(uname -r) mod"
      # grub kernel (softlink)
      grub_kernel=${kernel}-mod
      # modified initrd
      grub_initrd=${initrd}-mod
      # modify grub config
      grubby -o ${grub_config} --grub --copy-default --add-kernel="${grub_kernel}" \
        --title="${grub_title}" --initrd="${grub_initrd}" --make-default
    ;;
    "grub2")
      # copy kernel
      [ ! -f ${kernel}-mod ] && cp ${kernel} ${kernel}-mod
      # generate new grub2 config
      grub-mkconfig -o ${grub_config}
    ;;
  esac
}

function partition-type() {
  LVM=0
  # check if LVM tool lvs is present
  which lvs 2>&1 >/dev/null
  if [ $? -eq 0 ]; then
    # check for logical volumes
    if [[ "$(lvs --noheadings -o +lv_path)" != *No\ volume\ groups\ found* ]]; then
      # get rootfs mount device
      rootfs_device=$(mount |grep -o "^.* / " |awk '{print $1}')
      # look for match, set LVM true if found
      for lv_name in $(lvs --noheading |awk '{print $1}'); do
        [[ "${rootfs_device}" == *${lv_name}* ]] && LVM=1
      done
    fi
  fi
  return ${LVM}
}

# store directory from where we run install
inst_dir=$(pwd)

# set common variables
partition-type
[ $? -eq 1 ] && mod_type="mod_lvm" || mod_type="mod"

# check distro and set distro specific variables
distro=""

# RedHat derivate
[ -f /etc/redhat-release ] &&
  if [[ "$(cat /etc/redhat-release)" == *CentOS\ release\ 6* ]]; then
    distro="centos-6"
    initrd_path="bin sbin usr/bin usr/sbin"
    kernel_version=$(uname -r)
    if [ -f /boot/initramfs-${kernel_version}.img ]
    then
      initrd="/boot/initramfs-$(uname -r).img"
      kernel="/boot/vmlinuz-$(uname -r)"
    else
      # this assumes that a box has just been built and there is only a single
      # kernel and initramfs, which kinda sucks, but not sure how to handle
      # multiple initramfs or kernels that might be present - which one is the
      # 'real' one?
      initrd=$(ls /boot/initramfs*)
      kernel=$(ls /boot/vmlinuz-*)
    fi
    init_script="init"
    proc_insert_point="^export PATH=.*"
    proc_name="growroot"
    call_insert_point="^source_all pre-mount"
    grub_config="/boot/grub/grub.conf"
    grub="grub1"
  fi
# Debian derivate
[ -f /etc/issue ] &&
  if [[ "$(cat /etc/issue)" == *Debian\ GNU\/Linux\ 7* ]]; then
    distro="debian-7"
    initrd_path="bin sbin"
    initrd="/boot/initrd.img-$(uname -r)"
    kernel="/boot/vmlinuz-$(uname -r)"
    init_script="scripts/local"
    proc_insert_point="^mountroot()"
    proc_name="\        growroot"
    call_insert_point="^.*pre_mountroot$"
    grub_config="/boot/grub/grub.cfg"
    grub="grub2"
  elif [[ "$(cat /etc/issue)" == *Debian\ GNU\/Linux\ 6* ]]; then
    distro="debian-6"
    initrd_path="bin sbin"
    initrd="/boot/initrd.img-$(uname -r)"
    kernel="/boot/vmlinuz-$(uname -r)"
    init_script="scripts/local"
    proc_insert_point="^mountroot()"
    proc_name="\        growroot"
    call_insert_point="^.*pre_mountroot$"
    grub_config="/boot/grub/grub.cfg"
    grub="grub2"
  fi

# exit if distro is not supported
if [ "${distro}" == "" ]; then
  echo "Distribution NOT supported!"
  exit 1
fi

initrd
grub-mod ${grub}

exit 0
