#!/bin/bash

#
# This is a little helper script that tries to convert linux-style device
# names to grub-style.  It's not very smart, so it
# probably won't work for more complicated setups.
#
# If it doesn't work for you, try installing grub manually:
#
#    # mkdir -p /boot/grub
#    # cp /usr/lib/grub/i386-pc/* /boot/grub/
#
# Then start up the 'grub' shell and run something like the following:
#
#    grub> root (hd0,0)
#    grub> setup (hd0)
#
# The "root" line should point to the partition your kernel is located on,
# /boot if you have a separate boot partition, otherwise your root (/).
#
# The "setup" line tells grub which disc/partition to install the
# bootloader to.  In the example above, it will install to the MBR of the
# primary master hard drive.
#

usage() {
  echo "usage: install-grub <install_device> [boot_device]"
  echo
  echo "where <install_device> is the device where Grub will be installed"
  echo "and [boot_device] is the partition that contains the /boot"
  echo "directory (auto-detected if omitted)"
  echo
  echo "examples: install-grub /dev/hda"
  echo "          install-grub /dev/hda /dev/hda1"
  echo
  exit 0
}

## new install-grub, code was taken from setup script
ROOTDEV=${1}
PART_ROOT=${2}

if [ "${ROOTDEV}" = "" ]; then
  usage
fi
if [ "${PART_ROOT}" = "" ]; then
  PART_ROOT=$(mount | grep "on /boot type" | cut -d' ' -f 1)
fi
if [ "$PART_ROOT" = "" ]; then
  PART_ROOT=$(mount | grep "on / type" | cut -d' ' -f 1)
fi
if [ "${PART_ROOT}" = "" ]; then
  echo "error: could not determine BOOT_DEVICE, please specify manually" >&2
  exit 1
fi


get_grub_map() {
  [ -e /tmp/dev.map ]  && rm /tmp/dev.map	
  /sbin/grub --no-floppy --device-map /tmp/dev.map >/tmp/grub.log 2>&1 <<EOF
quit
EOF
}

mapdev() {
  partition_flag=0
  device_found=0
  devs=$(cat /tmp/dev.map | grep -v fd | sed 's/ *\t/ /' | sed ':a;$!N;$!ba;s/\n/ /g')
  linuxdevice=$(echo $1 | cut -b1-8)
  if [ "$(echo ${1} | egrep '[0-9]$')" ]; then
    # /dev/hdXY
    pnum=$(echo ${1} | cut -b9-)
    pnum=$((${pnum}-1))
    partition_flag=1
  fi
  for  dev in ${devs}; do
    if [ "(" = $(echo ${dev} | cut -b1) ]; then
      grubdevice="${dev}"
    else
      if [ "${dev}" = "${linuxdevice}" ]; then
	device_found=1
	break   
      fi
    fi
  done	
  if [ "${device_found}" = "1" ]; then
    if [ "${partition_flag}" = "0" ]; then
      echo "${grubdevice}"
    else
      grubdevice_stringlen=${#grubdevice}
      let grubdevice_stringlen--
      grubdevice=$(echo $grubdevice | cut -b1-$grubdevice_stringlen)
      echo "${grubdevice},${pnum})"
    fi
  else
    echo " DEVICE NOT FOUND"
  fi
}

dogrub() {
  get_grub_map	
  if [ ! -f /boot/grub/menu.lst ]; then
    echo "Error: Couldn't find /boot/grub/menu.lst.  Is GRUB installed?"
    exit 1
  fi
  # try to auto-configure GRUB...
  if [ "${PART_ROOT}" != "" -a "$S_GRUB" != "1" ]; then
    grubdev=$(mapdev ${PART_ROOT})
    # look for a separately-mounted /boot partition
    bootdev=$(mount | grep /boot | cut -d' ' -f 1)
    if [ "${grubdev}" != "" -o "${bootdev}" != "" ]; then
      cp /boot/grub/menu.lst /tmp/.menu.lst
      # remove the default entries by truncating the file at our little tag (#-*)
      head -n $(cat /tmp/.menu.lst | grep -n '#-\*' | cut -d: -f 1) /tmp/.menu.lst >/boot/grub/menu.lst
      rm -f /tmp/.menu.lst

      for kernel in /boot/vmlinuz-linux* /boot/vmlinuz26-*; do
	if [ ${kernel} == "/boot/vmlinuz-linux*" ] || [ ${kernel} == "/boot/vmlinuz26-*" ] ; then
	  echo > /dev/null
	else
	  VMLINUZ=$( echo ${kernel} | cut -c 7- )

	  if [ "$( echo ${VMLINUZ} | cut -c -13 )" = "vmlinuz-linux" ]; then # new naming scheme for linux > 3.0
	    extension=$( echo ${VMLINUZ} | cut -c 14- )
	    INITRAMFS_BASENAME=initramfs-linux${extension}
	  else # old naming scheme for lts kernel
	    extension=$( echo ${VMLINUZ} | cut -c 10- ) 
	    INITRAMFS_BASENAME=kernel26${extension}
	  fi

	  echo "" >>/boot/grub/menu.lst
	  echo "# (0) Arch Linux" >>/boot/grub/menu.lst
	  echo "title  Arch Linux - ${VMLINUZ}" >>/boot/grub/menu.lst
	  subdir=
	  if [ "${bootdev}" != "" ]; then
	    grubdev=$(mapdev ${bootdev})
	  else
	    subdir="/boot"
	  fi
	  echo "root   ${grubdev}" >>/boot/grub/menu.lst
	  echo "kernel ${subdir}/${VMLINUZ} root=${PART_ROOT} ro" >>/boot/grub/menu.lst
	  echo "initrd ${subdir}/${INITRAMFS_BASENAME}.img" >>/boot/grub/menu.lst
	  echo "" >>/boot/grub/menu.lst
		
	  # adding fallback/full image
	  echo "# (1) Arch Linux" >>/boot/grub/menu.lst
	  echo "title  Arch Linux Fallback - ${VMLINUZ}" >>/boot/grub/menu.lst
	  echo "root   ${grubdev}" >>/boot/grub/menu.lst
	  echo "kernel ${subdir}/${VMLINUZ} root=${PART_ROOT} ro" >>/boot/grub/menu.lst
	  echo "initrd ${subdir}/${INITRAMFS_BASENAME}-fallback.img" >>/boot/grub/menu.lst
	  echo "" >>/boot/grub/menu.lst
	fi
      done
    fi
  fi

  echo "Installing the GRUB bootloader..."
  cp -a /usr/lib/grub/i386-pc/* /boot/grub/
  sync

  # freeze xfs filesystems to enable grub installation on xfs filesystems
  if [ -x /usr/sbin/xfs_freeze ]; then
    [ "$(stat -fLc %T /boot)" == "xfs" ] && /usr/sbin/xfs_freeze -f /boot > /dev/null 2>&1
    [ "$(stat -fLc %T /)" == "xfs" ] && /usr/sbin/xfs_freeze -f / > /dev/null 2>&1
  fi

  # look for a separately-mounted /boot partition
  bootpart=$(mount | grep /boot | cut -d' ' -f 1)
  if [ "${bootpart}" = "" ]; then
    bootpart=${PART_ROOT}
  fi
  bootpart=$(mapdev ${bootpart})
  bootdev=$(mapdev ${ROOTDEV})
  if [ "${bootpart}" = "" ]; then
    echo "Error: Missing/Invalid root device: ${bootpart}"
    exit 1
  fi

  echo ${bootpart}
  echo ${bootdev}
  /sbin/grub --no-floppy --batch >/tmp/grub.log 2>&1 <<EOF
root ${bootpart}
setup ${bootdev}
quit
EOF
  cat /tmp/grub.log

  # unfreeze xfs filesystems
  if [ -x /usr/sbin/xfs_freeze ]; then
    [ "$(stat -fLc %T /boot)" == "xfs" ] && /usr/sbin/xfs_freeze -u /boot > /dev/null 2>&1
    [ "$(stat -fLc %T /)" == "xfs" ] && /usr/sbin/xfs_freeze -u / > /dev/null 2>&1
  fi
  if grep "Error [0-9]*: " /tmp/grub.log >/dev/null; then
    echo "Error installing GRUB. (see /tmp/grub.log for output)"
    exit 1
  fi
  echo "GRUB was successfully installed."

  rm -f /tmp/grub.log

  exit 0
}

dogrub
