#!/usr/bin/env bash

set -x #comment it out if you don't want debug
grub_write_chain() {
	cat >> $tmpfile <<EOF

# This entry automatically added by the PCLinuxOS redo-mbr for a bootable-linux/non-linux OS
# on $partition
title		$title
root		$grubdrive
savedefault
EOF
	# Only set makeactive if grub is installed in the mbr
	if [ "$bootdev" = "(hd0)" ]; then
		cat >> $tmpfile <<EOF
makeactive
EOF
	fi
	# DOS/Windows can't deal with booting from a non-first hard drive
	case $shortname in
	    MS*|Win*)
		grubdisk="$(echo "$grubdrive" | sed 's/^(//; s/)$//; s/,.*//')"
		case $grubdisk in
		    hd0)	;;
		    hd*)
			cat >> $tmpfile <<EOF
map		(hd0) ($grubdisk)
map		($grubdisk) (hd0)
EOF
			;;
		esac
		;;
	esac
	cat >> $tmpfile <<EOF
chainloader	+1

EOF
} # grub_write_chain end

grub_write_linux() {
	cat >> $tmpfile <<EOF

# This entry automatically added by the PCLinuxOS redo-mbr for an existing
# linux installation on $mappedpartition.
title		$label (on $mappedpartition)
root		$grubdrive
kernel		$kernel $params
EOF
	if [ -n "$initrd" ]; then
		cat >> $tmpfile <<EOF
initrd		$initrd
EOF
	fi
	cat >> $tmpfile <<EOF
savedefault
boot

EOF
} # grub_write_linux end

grub_write_divider() {
	cat > $tmpfile << EOF

# This is a divider, added to separate the menu items below from the PCLINUXOS standard grub entries
title		Other operating systems:

EOF
} # grub_write_divider end

## test for bootable partition bootflag (from lilo QuickInst) to avoid
## Fatal: First sector of /dev/hda10 doesn't have a valid boot signature
bootflag() {
    [ "XY" = "`(dd of=/dev/null bs=510 count=1; dd bs=2 count=1 |
      tr -c '\125\252' . | tr '\125\252' XY) <$1 2>/dev/null`" ]
      return
} # bootflag end

newline="
"

log() {
	logger -t grub-installer "$@"
}

error() {
	log "error: $@"
}

info() {
	log "info: $@"
}

# shim to make it easier to use os-prober outside d-i
if ! type mapdevfs >/dev/null 2>&1; then
  mapdevfs () {
    readlink -f "$1"
  }
fi

convert () {
	host_os=$(uname -s | tr 'A-Z' 'a-z')
	tmp_disk=$(echo "$1" | sed -e 's%\([sh]d[a-z]\)[0-9]*$%\1%' \
	  -e 's%\(fd[0-9]*\)$%\1%' \
	  -e 's%/part[0-9]*$%/disc%' \
	  -e 's%\(c[0-7]d[0-9]*\).*$%\1%')
	tmp_part=$(echo "$1" | sed -e 's%.*/[sh]d[a-z]\([0-9]*\)$%\1%' \
	  -e 's%.*/fd[0-9]*$%%' \
	  -e 's%.*/floppy/[0-9]*$%%' \
	  -e 's%.*/\(disc\|part\([0-9]*\)\)$%\2%' \
	  -e 's%.*c[0-7]d[0-9]*p*%%')
	# Get the drive name
	tmp_drive=$(grep -v '^#' $device_map | grep "$tmp_disk *$" | \
	 sed 's%.*\(([hf]d[0-9][a-g0-9,]*)\).*%\1%')

	# If not found, print an error message and exit
	if [ -z "$tmp_drive" ]; then
		echo "$1 does not have any corresponding BIOS drive." 1>&2
		exit 1
	fi

	if [ -n "$tmp_part" ]; then
		# If a partition is specified, we need to translate it into the
		# GRUB's syntax
	    	echo "$tmp_drive" | sed "s%)$%,`expr $tmp_part - 1`)%"
	else
		# If no partition is specified, just print the drive name
		echo "$tmp_drive"
	fi
}

create_extras() {
# Generate menu.lst additions for other OSes
device_map=/boot/grub/device.map
tmpfile=/tmp/menu.lst.extras
rm -f /tmp/os-probed
os-prober|grep -v $dev|grep -v MS|grep -v Win > /tmp/os-probed
grub_write_divider
OLDIFS="$IFS"
IFS="$newline"
for os in $(cat /tmp/os-probed); do
	IFS="$OLDIFS"
	partition=$(echo "$os" | cut -d: -f1)
	title=$(echo "$os" | cut -d: -f2)
	shortname=$(echo "$os" | cut -d: -f3)
	type=$(echo "$os" | cut -d: -f4)
	if bootflag $partition; then
		type="chain"
	fi
	case "$type" in
	    chain)
		partition=$(mapdevfs $(echo "$os" | cut -d: -f1))
		grubdrive=$(convert "$partition") || true
		grub_write_chain
		;;
	    linux)
		partition=$(echo "$os" | cut -d: -f1)
		mappedpartition=$(mapdevfs "$partition")
		#IFS="$newline"
		#for entry in $(linux-boot-prober "$partition"); do
		entry=$(linux-boot-prober "$partition" | grep "$partition" | head -1)
			IFS="$OLDIFS"
			bootpart=$(echo "$entry" | cut -d: -f2)
			mappedbootpart=$(mapdevfs "$bootpart") || true
			if [ -z "$mappedbootpart" ]; then
				mappedbootpart="$bootpart"
			fi
			label=$(echo "$entry" | cut -d : -f3)
			if [ -z "$label" ]; then
				label="$title"
			fi
			kernel=$(echo "$entry" | cut -d : -f4)
			initrd=$(echo "$entry" | cut -d : -f5)
			if echo "$kernel" | grep -q '^/boot/' && \
			   [ "$mappedbootpart" != "$mappedpartition" ]; then
			   	# separate /boot partition
				kernel=$(echo "$kernel" | sed 's!^/boot!!')
				initrd=$(echo "$initrd" | sed 's!^/boot!!')
				grubdrive=$(convert "$mappedbootpart") || true
			else
				grubdrive=$(convert "$mappedpartition") || true
			fi
			params="$(echo "$entry" | cut -d : -f6-) $serial"
			grub_write_linux
			#IFS="$newline"
		#done
		IFS="$OLDIFS"
		;;
	    *)
		info "unhandled: $os"
		;;
	esac
	IFS="$newline"
done
IFS="$OLDIFS"
rm -f /tmp/os-probed
}

if [ $UID != 0 ] ; then
  echo "This script requires root privileges."
  exit 0
fi

DIA=gdialog

TMP=/tmp/redo-mbr.$$
mkdir -p /mnt/loop

fdisk -l|grep "^/dev.*Linux$"|tr -d '*'|
while read dev x x size x 
do
	mount $dev /mnt/loop
	distro=`cat /mnt/loop/etc/mandrake-release 2>/dev/null|awk '{print \$1 }'|tr [:upper:] [:lower:]`
	if [ "$distro" =  "pclinuxos" ] ; then
		size=${size%+}
		echo  $dev  $dev  off>> $TMP
	fi
	umount /mnt/loop
done

NUMPCLOS="`wc -l <$TMP`"
PCLOSPART="`cat $TMP`"

T1="PCLinuxOS partition selection"
M1="No PCLinuxOS installation could be found on your hard disks. The script will be terminated."

if [ $NUMPCLOS -eq 0 ]; then
	$DIA --title "$T1" --msgbox "$M1" 15 40
	rm -f $TMP
	exit 0
fi

if [ $NUMPCLOS -gt 1 ]; then
	#more than one PCLOS partition
	M1="More than one PCLinuxOS installation found, Please select the one you want to reinstall mbr from"
	$DIA --title "$T1" --radiolist "$M1" \
  		$PCLOSPART 2> $TMP
	FSCHOICE="`cat $TMP`"

	M1="No partition chosen. The script will be terminated."

	if [ -z "$FSCHOICE" ] ; then
		$DIA --title "$T1" --msgbox "$M1" 15 80
		rm -f $TMP
		exit 0
	fi
	dev=$FSCHOICE
	NUMPCLOS=1
else
	dev="`echo $PCLOSPART|awk '{print $1}'`"
fi

TR="/mnt/loop"
grub-install --recheck --no-floppy /dev/null &>/dev/null
GRUB_MBR=$(grep "(hd0)" /boot/grub/device.map | awk '{print $2}')
dd if=$GRUB_MBR count=1 bs=512|grep -iw "grub" 2>/dev/null
x=$?
if [ $x != 0 ]; then 
	dd if=$GRUB_MBR count=1 bs=512|grep -iw "lilo"
	x=$?
	if [ $x != 0  ]; then
		BOOTLOADER="WINDOWS"
	else
		BOOTLOADER="LILO"
	fi
else
	BOOTLOADER="GRUB"
fi	

M1="The bootloader configuration of the chosen partition will displayed\n\n\
You can edit the the configuration and save your changes\n\n\
You will be asked if you want to recreate your bootloader"
if [ $NUMPCLOS -eq 1 ]; then
	mount $dev $TR
	if [ "$BOOTLOADER" = "WINDOWS" ]; then
		if [ -e $TR/etc/lilo.conf ]; then
			if [ -e $TR/boot/grub/menu.lst ]; then
				print "Huston we have problem, both bootloader exists"
			else
				BOOTLOADER="LILO"
			fi
		else 
			BOOTLOADER="GRUB"
		fi
	fi
	$DIA --title "Edit" --msgbox  "$M1" 15 80
	if [ "$BOOTLOADER" = "LILO" ]; then
		leafpad $TR/etc/lilo.conf
	else
		NUMLINUX=$(os-prober|grep -v $dev|grep -v MS|grep -v Win|wc -l)
		if [ $NUMLINUX != 0 ]; then
			M1="You seems to have other linux distroes installed. Do you want to add those to your existing GRUB?"
			$DIA --title "$T1" --yesno "$M1" 15 80
			x=$?
			if [ $x = 0 ] ; then
				create_extras
				cat  $tmpfile >> $TR/boot/grub/menu.lst
				rm -f $tmpfile
			fi
		fi
		leafpad $TR/boot/grub/menu.lst
	fi
	M1="Do you want to reset your bootloader?"
	$DIA --title "$T1" --yesno "$M1" 15 80
	x=$?
	if [ $x != 0 ] ; then
		M1="Cancelled. The script will be terminated."
		$DIA --title "$T1" --msgbox "$M1" 15 40
		rm -f $TMP
		exit 0
	fi
	# the actual reset is commented out for debugging
	mount -t proc none $TR/proc
	mount -t none /dev $TR/dev -o bind
	if [ "$BOOTLOADER" = "LILO" ]; then
		/sbin/lilo -v -r $TR
	else
		chroot $TR boot/grub/install.sh
	fi
	umount $TR/dev
	umount $TR/proc
fi
rm -f $TMP
