#! /bin/bash

#: Title       : updateLegacyGrub
#: Date Created: Sat Apr 2 16:20:32 PDT 2011
#: Last Edit   : Mon Oct 15 13:57:13 PDT 2012
#: Author      : Agnelo de la Crotche (please_try_again)
#: Version     : 2.0
#: Description : add other Linux & Windows boot entries to Legacy Grub boot menu
#: Requires    : os-prober, dialog
#: Usage       : updategrub
#: Syntax      : There are a few options. Type updategrub -h for help.
#              : Read /usr/share/doc/packages/updategrub/README for details
#
# default timeout (in seconds)
timeout=120

# current version
version="2.0"
prg=$(basename $0)
devmap=/boot/grub/device.map
defaults=/etc/updategrub/defaults
custom=/etc/updategrub/custom
grubmenu=/boot/grub/menu.lst

# ~~~~~
# TESTS
# ~~~~~
# check if we are root
[ $UID -eq 0 ] || exec echo "You have to run this script as root or sudo"

# check for os-prober & linux-boot-prober
osprober=`which os-prober 2>/dev/null` || exec echo "os-prober not found"
linuxbootprober=`which linux-boot-prober 2>/dev/null` || exec echo "linux-boot-prober not found"
unlzma="xz --format=lzma --decompress"
which xz &>/dev/null && UNLZMA=yes
which blkid &>/dev/null || exec printf "blkid not found.\n"

# ~~~~~~~~~~~~~~~~
# DEFINE VARIABLES
# ~~~~~~~~~~~~~~~~
declare -l CHAINLOADGRUB CHECKROOT NOFAILSAFE MAKEACTIVE SETBOOTFLAG WINDOWSFIRST INTERACTIVE DISPLAYONLY EXCLUDE EXCLUDES BOOTCHART GRUB2 DIST
declare -a GRUBS HDDEV CHL
declare bootdev

# Chainload other Grubs by default
CHAINLOADGRUB=yes
# Ignore failsafe entries
NOFAILSAFE=yes
# Make Windows Partition active
MAKEACTIVE=no
# Windows Chainload entries before other Linux distros kernel entries
WINDOWSFIRST=no
# Set bootflag on Grub partition
SETBOOTFLAG=no
# Display changes but do not write boot menu
DISPLAYONLY=no
# Interactive menu
INTERACTIVE=no
# check if root device found in menu.lst matches devices scanned by linux-boot-prober (won't work for separate /boot)
CHECKROOT=yes
# if NOFAILSAFE is set, reject entries containing this words keywords
EXCLUDE='recovery|rescue|failsafe|fallback|single-user'
# add bootchart to grub menu
BOOTCHART=no

# import some defaults from (optional) configuration file
[ -f $defaults ] && source $defaults

for OPT in CHAINLOADGRUB CHECKROOT NOFAILSAFE MAKEACTIVE WINDOWSFIRST INTERACTIVE SETBOOTFLAG BOOTCHART DISPLAYONLY ; do
	[ "x${!OPT}" == "xyes" -o "x${!OPT}" == "xtrue" -o "x${!OPT}" == "x1" ] && eval $OPT=yes
	[ "x${!OPT}" == "xno" -o "x${!OPT}" == "xfalse" -o "x${!OPT}" == "x0" ] && eval unset $OPT
done

osprobedir="/usr/lib/os-probes/mounted"

[ "$NOFAILSAFE" ] || EXCLUDE="fkflsgjtriogserpfkawerpkfdlpw"
[ "$linux_ignore" ] && EXCLUDE="${EXCLUDE}$(echo $linux_ignore | tr " " "\n" | sed 's/^/|/' | tr -d "\n")"
EXCLUDES="$EXCLUDE"

# ~~~~~~~~~~~~~~~~
# DISTROS SPECIFIC
# ~~~~~~~~~~~~~~~~

which lsb_release &>/dev/null && DIST=`$(which lsb_release) -si | tr -d " "`
if [ "x$DIST" == "xn/a" ] ; then
	[ -f /etc/lsb-release ] && DIST=$(awk -F "=" '/DISTRIB/ { print $2 }' /etc/lsb-release | tr -d " \"")
elif [ "x$DIST" == "x" ] ; then
	if [ -f /etc/SuSE-release ] ; then
		DIST=suselinux
	elif [ -f /etc/fedora-release ] ; then
		DIST=fedora
	elif [ -f /etc/mandriva-release ] ; then
		DIST=mandrivalinux
	elif [ -f /etc/lsb-release ] ; then
		DIST=$(awk -F "=" '/DISTRIB/ { print $2 }' /etc/lsb-release | tr -d " \"")
	fi
fi

case $DIST in
suselinux) 
	CAP="###Don't change this comment - YaST2 identifier: Original name:"
	IN="zypper install"
;;
fedora)
	[ -f /boot/grub/grub.conf ] && grubmenu=/boot/grub/grub.conf
    [ -f /boot/efi/EFI/redhat/grub.conf ] && grubmenu=/boot/efi/EFI/redhat/grub.conf 
	IN="yum install"
;;
mandrivalinux)
	IN="urpmi"
;;
archlinux)
	IN="pacman -S"
;;
esac


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# some Bootsector ID at offset 0x80,81
# from bootinfo script by Ulrich Meierfrankenfeld
# http://sourceforge.net/projects/bootinfoscript/
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

BSaa75="Legacy Grub"
BS5272="Legacy Grub"
BS48b4="Grub2 (1.96)"
BS488="Grub2 s core.img"
BS7c3c="Grub2 (1.98)"
BS020="Grub2 (1.99)"
BS8053="Lilo"
BSbd0="MSWIN4.1 Fat 32"
BS7cc6="MSWIN4.1 Fat 32"
BS7cc6="Windows 98"
BS8cd="Windows XP"
BS8ec0="Windows XP"
BSfa33="Windows XP"
BSb6d1="Windows XP Fat32"
BS745="Vista Fat 32"
BS55aa="Windows Vista/7"
BSe9d8="Windows Vista/7"
BSb60="Dell Utility Fat16"
BSe00="Dell Utility Fat16"
BS4445="DEll Restore Fat32"
BS8ed0="DEll Recovery: Fat32"
BS3a5e="Recovery:Fat 32"
BS6974="BootIt: Fat16"
BS6f65="BootIt: Fat16"
BSe2f7="Fat32, Non Bootable"

# Grub signature offset
declare G377 G383 G385 G384 G392
G377="Fedora"
G383="Mandriva/ArchLinux/Debian"
G384="openSUSE"
G385="openSUSE"
G392="Ubuntu"

# Grub2 Core size
CS61520="Fedora"
CS53352="openSUSE"
CS64525="openSUSE"
CS41452="Ubuntu/Mint"
CS42508="Ubuntu"

# Grub2 lzma core sign
G2SIGN=""
Ld1e9dffeffff0000="Grub2 1.99"
Ld1e9dffeffff8db6="Grub2 2.00"
Ld1e9dffeffff6690="Grub2 2.00"

# labels
suse=openSUSE
archlinux=ArchLinux
debian=Debian
ubuntu=Ubuntu

# ~~~~~~~~~~~~~~~~~~~
# DEVICE/BIOS MAPPING
# ~~~~~~~~~~~~~~~~~~~
HDDEV=($(cat /proc/partitions | awk '!/major|dm/{ gsub(/[0-9]/,"",$4) ; print $4 }' | sort -u))

i=0
while [ $i -lt ${#HDDEV[*]} ] ; do eval ${HDDEV[$i]}=hd$i ; let i++ ; done

function invalidHD {
	str="[37;1m/grub/device.map contains an orphan link: [31;1m"$1"[37;1m. Maybe you removed a hard disk since you installed Grub. Either delete /boot/grup/device.map or edit the devices in this file to achieve a correct drive mapping. updategrub can not work with a corrupted device.map.[37;0m"
	printf "\n%s\n\n" "$str" | fmt
	exit
}

# map hard disk devices to BIOS drives according to /boot/grub/device.map (if this file exists)
if [ -f $devmap ] ; then
	devlinks=($(sed -n '/(hd/s|(\(.*\))[ 	][ 	]*\(.*\)|\2=\1|p' $devmap))
	if [ ${#devlinks[*]} -ge 1 ] ; then
		for dev in ${devlinks[*]} ; do
			sdx=${dev%=*} ; hdn=${dev#*=}
			if [ -b $sdx ] ; then
				[ -h $sdx ] && sdx=$(readlink $sdx)
			else
				invalidHD $sdx
			fi
			eval $(basename $sdx)=$hdn
		done
	fi
fi
DEVMAP=$(for d in ${HDDEV[*]} ; do printf "s|\\$\\$%s|%s|;" $d ${!d} ; done)

# ~~~~~~~~~
# FUNCTIONS
# ~~~~~~~~~

function grubname {
dev=$(basename $1 | tr -d "0-9")
part=$(($(basename $1 | tr -d "a-z") - 1))
if [ "${!dev}" ] ; then
	drv=${!dev}
else
	drv=$(echo $dev | sed 's|..|HD|' | tr "abcdefgh" "01234567" | sed 's|HD|hd|')
fi
if [ $part -ge 0 ] ; then
	echo "($drv,$part)"
else
	echo "($drv)"
fi
}

function checkroot {
 dev=$1	
 rootdevs=$($linuxbootprober $dev | sed '/\/boot\//s/.*root[^ ]*=\([^ ]*\).*/\1/')
 EXCLUDES="$EXCLUDE"
 for rootdev in $rootdevs ; do
	if [ "$rootdev" == "$dev" ] ; then
		continue
	elif [ "$(blkid -U $rootdev)" == "$dev" ] ; then
		continue
	elif [ "$(blkid -L $rootdev)" == "$dev" ] ; then
		continue
	elif [ "$(readlink $rootdev | sed 's|.*/|/dev/|')" == "$dev" ] ; then
		continue
	else
		EXCLUDES="$EXCLUDE|$rootdev"
	fi
 done		
}

function writeEntry {
M=$1 ; shift
for lin in $* ; do
	D=${lin##*:} ; LONG=${D//@/ }
	D=${lin%:*} ; SHORT=${D%:*} ; DEV=${D#*:}
	COM=${CAP:+$CAP $SHORT###}
	COM=${COM:-# $LONG on $DEV}
	HDP=$(grubname $DEV)
	OPT=${SHORT//[0-9]/}_options ; OPT="${!OPT}"
	O=$(printf "$OPT" | sed 's| *$|\\n|' | tr -d "\n")
	case $M in
	K)
	[ "$CHECKROOT" ] && checkroot $DEV
	T=${lin##*:} ; T=${T//@/ }
	UUID=$(blkid -o value -s UUID $DEV)
	UUID=${UUID:+UUID=$UUID} ; UUID=${UUID:-$DEV}
	UUIDMAP="s|root=$DEV|root=$UUID|"
	$linuxbootprober $DEV | sort -Vr | grep -E -i -v $EXCLUDES | awk -F ":" 'BEGIN { C="'"$COM"'" ; O="'"$O"'" } ; { P=$2 ; sub(/\/dev\//,"",P) ; MAJ=P ; MIN=P ; gsub(/[0-9]/,"",MAJ) ; gsub(/[a-zA-Z]/,"",MIN) ; MIN-- ; if ( $3 == "" ) { k = $4 ; sub(/.*vmlinuz-/, " - kernel ", k) ;  $3="'"$T"' "k  } ; printf "\n%s\ntitle %s\n%s    root ($$%s,%s)\n    kernel %s %s\n", C, $3, O, MAJ, MIN, $4, $6 ; if ($5 != "") printf "    initrd %s\n", $5 }' | sed -e "$DEVMAP" -e "$UUIDMAP"
	file -s $DEV | grep -i -q "Grand Unified Bootloader" && GRUBS=(${GRUBS[*]} "$DEV:$HDP:$SHORT") ;;
	C)
	printf "\n%s\ntitle %s - added by updategrub\n" "$COM" "$LONG"
	[ "$OPT" ] && printf "%s\n" "$OPT"
	HD=$(echo ${HDP%%,*} | tr -d "(")
	[ "$HD" == "hd0" ] || printf "    map (%s) (hd0)\n    map (hd0) (%s)\n" $HD $HD
	printf "    rootnoverify %s\n" "$HDP"
	[ "$MAKEACTIVE" ] && printf "    makeactive\n"
	printf "    chainloader +1\n" ;;
	esac
done
}

function grubver {
#	# part of this code was borrowed from Boot Info Script: http://bootinfoscript.sourceforge.net
	p=$1
	dev=${1:0:8}
	core=/tmp/core.img
	core_offset=$(hexdump -v -s 92 -n 4 -e '"%u"' $p)
	dd if=$dev of=$core skip=$core_offset count=1024 &>/dev/null
	magic=$(hexdump -v -n 4 -e '/1 "%02x"' $core)
	[ "${magic}" == '5256be1b' -o  "${magic}" == '52e82801' ] || { echo "Grub2 no core\n" ; return ; } 
	eval $(hexdump -v -n 10000 -e '1/1 "%02x"' $core | awk '{ lzp=match($0, "d1e9dffeffff" ); if (lzp == "0") { print "lzpos=0" } else { print "lzpos=" ((lzp - 1 ) / 2 ) + 8 "; lzsign=" substr($0,lzp,16) ";" } }')
	eval $(hexdump -v -s 520 -n 7 -e '1/4 "m=%u; " 1/4 "k=%u;"' $core)
	if [ $lzpos -gt 0 ] ; then
	 	[ $(hexdump -v -s ${lzpos} -n 8 -e '1/1 "%02x"' $core) = '0000000000000000' ] && lzpos=$(( $lzpos + 8 ))
  		lzusize=$(( $m + $k - $lzpos + 512 ))
		CS=CS$lzusize ; CS=${!CS} 		
	else
		CS="Unknown"
	fi
	grub2ver=L${lzsign} ; grub2ver=${!grub2ver}
	echo $CS $grub2ver
}

function writeGrubChainloadEntries {
SKIPDEV=$(df -hl / /boot | sed -n '/\/dev/s|/dev\([^ 	]*\).*|\1\$/d;|p' | sort -u)
[ ${#GRUBS[*]} -gt 0 ] && SKIPDEV="$SKIPDEV$(echo ${GRUBS[*]} | tr " " "\n" | sed 's|/dev/\([^:]*\).*|/\1$/d;|' | tr -d "\n")"
for dev in ${HDDEV[*]} ; do
 	dd if=/dev/$dev bs=512 count=1 2>/dev/null | grep -q GRUB && GRUBS=(${GRUBS[*]} "/dev/${dev}0:(${!dev}):MBR") 
done
for dev in $(/sbin/fdisk -l 2>/dev/null | awk '/ 83 | 5 | f / { print $1 }' | sed -e "$SKIPDEV") ; do
	dd if=$dev bs=512 count=1 2>/dev/null | grep -q GRUB &&	GRUBS=(${GRUBS[*]} "$dev:$(grubname $dev):Grub")
done
GRUBS=($(echo ${GRUBS[*]} | tr " " "\n" | sort -Vu))
for entry in ${GRUBS[*]} ; do
	eval $(echo $entry | awk -F ":" '{printf "DEV=%s ; HDP=%s ; LBL=%s ;", $1, $2, $3}')
	DEV=$(echo $DEV | sed 's/\([a-z]\)0/\1/') ; D=$DEV
	Grub="BS$(hexdump -v -s 128 -n 2 -e '/1 "%x"' $DEV)" ; Grub=${!Grub}
	if [ "$LBL" == "MBR" -o "$LBL" == "Grub" ] ; then
		MBR=$LBL
		BS=$(dd if=$DEV bs=512 count=1 2>/dev/null | tr -c "[:alnum:]" "0")
	 	POS=${BS%GRUB*} ; POS=${#POS}
		LBL=G$POS ; LBL=${!LBL}
		[ "${Grub}" == "Grub2 (1.99)" ] && TITLE="$(grubver $DEV)" || TITLE="$LBL $Grub"
	else
		TITLE="${LBL} $Grub"
	fi
	TITLE=${TITLE:-$Grub}
 	COM=${CAP:+$CAP $TITLE on $D###}
 	COM=${COM:-# $TITLE on $D}
	unset BS POS LBL
 	printf "\n%s\ntitle %s in %s\n    rootnoverify (%s)\n    chainloader +1\n" "$COM" "$TITLE" "$DEV" "$HDP"
done		
}

function setBootFlag {
devs=`LC_ALL=C /sbin/fdisk -l 2>/dev/null | awk '/^Disk/&&/dev/ { sub(/:/,"",$2) ; print $2 }'`
declare -a grubPt
for DEV in $devs ; do
	if [ "$(grubname $DEV)" == "(hd0)" ] ; then
		eval $(dd if=$DEV bs=1 skip=446 count=64 2>/dev/null | od -x | head -4 | cat -n | awk 'BEGIN { PART="'"$DEV"'"; I=-1 } ; { sub(/../,"", $3) ; sub(/../,"",$5) ; if ($5 == "0f" || $5 == "83") { I++ ; if ($3 == "00") P="i" ; else P="a" ; printf "%spart[%s]=%s ;", P, I, $1 }}')
		if [ ${#apart[*]} -eq 0 -a ${#ipart[*]} -ge 1 ] ; then
			for n in ${ipart[*]} ; do
				dd if=${DEV}$n bs=512 count=1 2>/dev/null | grep -q -i GRUB && grubPt=(${grubPt[*]} $n)
			done
			[ ${#grubPt[*]} -eq 1 -a -x /sbin/sfdisk ] && /sbin/sfdisk $DEV -A${grubPt[0]}
		fi
	fi
done
exit
}

function getBootchart {
case $DIST in
suselinux|fedora|mandrivalinux) 
rpm -qs bootchart &>/dev/null || $IN bootchart
;;
archlinux) 
pacman -Qi bootchart &>/dev/null || $IN bootchart
;;
esac
}


# ~~~~~~~~~~~~
# UPDATE GRUB2
# ~~~~~~~~~~~~
function updategrub2 {
if ( which updateGrub2 &> /dev/null ) ; then
	exec updateGrub2 -a
else
	grubmkconfig=$(find /usr/sbin/ -name "grub*-mkconfig")
	[ "$grubmkconfig" ] || exec echo "grub2 not found"
	
	if [ "$DISPLAYONLY" ] ; then
		echo "Scanning..."
		$grubmkconfig
	else
		[ -f /etc/default/grub ] || exec echo "/etc/default/grub not found"
		grubmenu=$(sed -n 's|.*\(/boot/grub.*/grub.cfg\).*|\1|p' /etc/default/grub | sort -u)
		[ "$grubmenu" ] || exec echo "could not find grub2 menu"
		[ -f $grubmenu ] && cp $grubmenu{,.updg}
		echo "Scanning..."
		$grubmkconfig -o $grubmenu
	fi	
fi
exit
}

# ~~~~
# HELP
# ~~~~
function syntax {
cat << EOFSYNTAX

$prg $version
______________
usage:
   $prg [options]

options:
   -d --display     : print grub menu to standard output, but do not write menu.lst.
   -i --interactive : launch interactive menu to enable/disable boot entries.
   -m --menu        : enable/disable boot entries in grubmenu (without scanning).
   -n --new         : rewrite Grub menu, including current system kernel entries.
   -a --activate    : activate Grub primary partition (if any) on 1st BIOS drive.
   -r --restore     : restore previous Grub menu.
   -h --help        : display this help.
   -2 --grub2       : update Grub2 menu.

EOFSYNTAX
[ -d $osprobedir ] && find $osprobedir -name "*linux-distro*" -exec awk -F "=" 'BEGIN { printf "linux distros short names:\n\n" } ; /short=/ { s=tolower($2) ; gsub(/"/,"",s) ; gsub(/ /,"",s) ; print s }' "{}" ";"
exit
}

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~
# BACK UP & RESTORE GRUB MENU
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~
function backupMenu {
# save original grub menu once
[ -f ${grubmenu}.dist ] || cp $grubmenu{,.dist}
# save current grub menu
[ -f ${grubmenu} ] && cp $grubmenu{,.updg}
}

function restoreMenu {
if [ -f ${grubmenu}.updg ] ; then
	declare -l yesno
	read -p "Do you want to restore previously saved grub menu? [y|n]" -n1 yesno
	printf "\n"
	[ "x$yesno" == "xy" ] && cp $grubmenu{.updg,}
fi
exit
}

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~
# REWRITE GRUB MENU
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~

function checkrootdev {
	eval $(cat /proc/cmdline | sed 's/.*root=\([^ ]*\).*/root="\1"/')
	if ( echo $root | grep -q -i uuid ); then
	  uuid=$(echo $root | sed 's|.*/||;s|UUID=||')
	  [ "$uuid" ] && bootdev=$(blkid -U $uuid)	
	elif ( echo $root | grep -q -i label ); then
	  label=$(echo $root | sed 's|.*/||;s|LABEL=||')
	  [ "$label" ] && bootdev=$(blkid -L $uuid)	
	elif ( echo $root | grep -q -i 'by-id' ); then
	   bootdev=`basename $(readlink $root)`
	elif ( echo $root | grep -q  '/dev/sd' ); then
		bootdev=$root  	
	fi
	if [ "x$bootdev" == "x" ]; then
		cat << EOF
Boot device not found. You might be using RAID and/or LVM. 	
This is not supported by updategrub.
EOF
		exit 1
	fi
}

function rewrite_menu {

eval $(cat /proc/cmdline | tr " " "\n" | sed 's|=|="|;/=/s|$|";|;s|BOOT_IMAGE|kernel|' | awk 'BEGIN {ORS=" "} ;  /^kernel|^root|^resume/ { print }')
eval $(cat /proc/cmdline | tr " " "\n" | awk ' BEGIN { ORS=" " ; printf "options=\"" } ; !/^BOOT_IMAGE|^root|^resume|^video/ { print }; END { print "\""}')

# get vendor, OS release and codename
if ( which lsb_release &>/dev/null ); then
	os_vendor=$(lsb_release -sd | sed 's|"||g;s|\([^ ]*\) .*|\1|')
	os_release=$(lsb_release -sr)
	os_codename=$(lsb_release -sc)
	os_title="$os_vendor $os_release ($os_codename)"
	os_comment="${os_vendor}$os_release"
elif [ -f /etc/SuSE-release ]; then 
	os_title=$(head -1 /etc/SuSE-release)
	os_comment=$(echo $os_title | sed 's| (.*||;s| ||g')
else
	os_title="${OSTYPE:-Linux}"
	os_comment="$os_title"
fi

FAILSAFE_APPEND_DEF="showopts apm=off noresume edd=off powersaved=off nohz=off highres=off processor.max_cstate=1 nomodeset x11failsafe"
[ -f /etc/sysconfig/bootloader ] && eval $(grep 'FAILSAFE_APPEND' /etc/sysconfig/bootloader)
FAILSAFE_APPEND=${FAILSAFE_APPEND:-$FAILSAFE_APPEND_DEF}


# find out if we are using a separate /boot

bootmnt=$(mount | awk '/on \/boot / { print $1 }')
rootmnt=$(mount | awk '/on \/ / { print $1 }')

if [ "${bootmnt}" ]; then
	[ "$kernel" ] || kernel=`find /boot -name "vmlinuz-$(uname -r)" | sed 's|/boot||'`
	[ "${bootdev}" == "${bootmnt}" ] || exec printf "boot and root devices conflict.\n"
	bootdir="/"
else
	[ "$kernel" ] || kernel=`find /boot -name "vmlinuz-$(uname -r)"`
	[ "${bootdev}" == "${rootmnt}" ] || exec printf "boot and root devices conflict.\n"
	bootdir="/boot/"
fi

[ -b  $bootdev ] || exec printf "Boot device not found.\n"

groot="$(grubname $bootdev)"

[ "$groot" ] || exec printf "Drive not found in device.map\n" 

cat  << EOF
# created by installLegacyGrub on $(date)
# (AFAIK) THIS FILE SHOULD NOT BE PARTIALLY OVERWRITTEN by perl-Bootloader :-D

default
timeout $timeout
EOF

[ -f /boot/message ] && cat << EOF
gfxmenu ${groot}${bootdir}message
EOF

for kernel in $(find /boot -type f -name "vmlinuz*" | sort -Vr) ; do
	initrd=${kernel/vmlinuz/initrd}
	[ -f $initrd ] || unset init
	kernel_ver=$(echo $kernel | sed 's/.*vmlinuz-\(.*\)-.*/\1/')
	kernel_typ=${kernel##*-}
	cat << EOF

###Don't change this comment - YaST2 idendifier: Original name: ${os_comment}_${kernel_ver}_${kernel_typ}###
title $os_title - kernel $kernel_ver ($kernel_typ)
	root $groot
	kernel $kernel root=$root resume=$resume $options
EOF
if [ "$initrd" ] ; then
	cat << EOF
	initrd $initrd
EOF
fi
	cat << EOF

###Don't change this comment - YaST2 idendifier: Original name: ${os_comment}_${kernel_ver}_failsafe###
title $os_title - kernel $kernel_ver (recovery mode)
	root $groot
	kernel $kernel root=$root resume=$resume $FAILSAFE_APPEND
EOF
if [ "$initrd" ] ; then
	cat << EOF
	initrd $initrd
EOF
fi
done
cat << EOF

EOF

if ( dd if=$bootdev bs=512 count=1 2>/dev/null | strings | grep -q -i grub) ; then
	Grubver="BS$(hexdump -v -s 128 -n 2 -e '/1 "%x"' $bootdev)"
	Grub=${!Grubver}
	[ "${Grub}" == "Grub2 (1.99)" ] && Grub="$(grubver $bootdev)"
	if [ "$groot" ]; then
	cat << EOF
###Don't change this comment - YaST2 idendifier: Original name: ${Grub// /_}###
title ${Grub} on $bootdev
	rootnoverify ${groot}
	chainloader +1

EOF
	fi
fi
}

# ~~~~~~~~~~~~~~~~
# interactive menu
# ~~~~~~~~~~~~~~~~
function grubmenu {

[ $(tail -1 $grubmenu | wc -L) -gt 0 ] && echo >> $grubmenu

# get checklist width and height
W=$(($(sed -n '/^#* *title/s/title *//p' $grubmenu | wc -L)+20))
h=$(sed -n '/^#* *title/s/title *//p' $grubmenu | wc -l)
H=$(($h + 7))
[ $W -eq 10 ] && W=80
[ $H -eq 6 ] && H=15

eval $(grep -E -n -e '^#* *title' -e '^ *$' $grubmenu | sed 's|:|@|;s|:|;|g;s|@|:|;s|\([0-9][0-9]*\):$|=:\1|' | sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D' | sed 's/\([0-9][0-9]*\):\(#*\)title *\([^:]*\) :\([0-9][0-9]*\).*/\1:\4:on\2:\3/;s/on#/off/;/^=/d' | awk -F ":" '{ $2-- ; printf "startpos[%s]=%s;endpos[%s]=%s;enable[%s]=%s;entry[%s]=\"%s\"\n" , NR, $1, NR, $2, NR, $3, NR, $4 }')
glist=$(sed -n '/^#* *title/s/title *//p' $grubmenu | sed 's/^/on /;s/on ##*/off /;s/^on \(.*\) *$/\"\1\" on/;s/^off \(.*\) *$/\"\1\" off/;s/  *"/"/' | awk '{ printf "%s %s ", NR, $0 }')

cat << EOFGLIST | sh -
dialog --clear --stdout --title "Grub Menu" --nocancel --output-separator "-" --checklist "Press spacebar to select/unselect boot menu entries" $H $W $h $glist | sed 's/"//g;s/$/-/' > /tmp/grubmenu.tmp
EOFGLIST

[ -f /tmp/grubmenu.tmp ] && enable=$(cat /tmp/grubmenu.tmp) || exec echo "can not get list of Menu entries"

# exit if user pressed escape
[ "x$enable" == "x" ] && return

i=1
while [ $i -le $h ] ; do
	[ "${enable%%-$i-*}" == "${enable}" ] && enable[$i]=off || enable[$i]=on
	let i++
done

i=1
cat << EOFSED | sed -f - -i $grubmenu
`while [ $i -le $h ] ; do
	[ "${enable[$i]}" == "on" ] && echo "${startpos[$i]},${endpos[$i]}s/^##*//" || echo "${startpos[$i]},${endpos[$i]}s/^\\\([^#]\\\)/#\\\1/"
	let i++
done`
EOFSED
}

# ~~~~~~~~~~~~~~~
# parsing options
# ~~~~~~~~~~~~~~~

ARGS=`getopt -q -o daminhrb2 --long display,activate,menu,interactive,new,help,restore,bootchart,grub2 -- "$@"`

[ "$?" == "0" ] || syntax

eval set -- "$ARGS"

while true ; do
case "$1" in
	-d|--display) DISPLAYONLY=yes ; shift ;;
	-a|--activate) setBootFlag ; shift ;;
	-b|--bootchart) BOOTCHART=yes ; shift ;;
	-i|--interactive) INTERACTIVE=yes ; shift ;;
	-m|--menu) GRUBMENU=yes ; shift ;;
    -n|--new) NEWMENU=yes ; shift ;;
	-h|--help) syntax ; shift ;;
	-r|--restore) restoreMenu ; shift ;;
	-2|--grub2) GRUB2=yes ; shift ;;
	--) shift ; break ;;
esac
done

[ "$prg" == "grubmenu" ] && GRUBMENU=yes

### ~~~ MAIN - BEGIN ~~~
# run grubmenu without scanning and exit
if [ "$GRUBMENU" ] ; then
	grubmenu
	exit
fi

# update Grub2 and exit
[ "$GRUB2" ] && updategrub2

echo "Scanning..."

if [ "$NEWMENU" ]; then
	if [ "$DISPLAYONLY" ] ; then
		rewrite_menu 
	else
		checkrootdev
		[ -f $grubmenu ] && cp $grubmenu{,.org}
		rewrite_menu > $grubmenu
	fi
fi

if [ "$DISPLAYONLY" ] ; then
	printf "###Don't change this comment - Added by updategrub %s\n" "$(date)###"
else
	backupMenu
	sed -i '/Added by updategrub/,$d' $grubmenu
	printf "###Don't change this comment - Added by updategrub %s\n" "$(date)###" >> $grubmenu
fi

if [ "$BOOTCHART" ] ; then
	getBootchart
	if [ -x /sbin/bootchartd ] ; then
		sed -n '/title/,$p' $grubmenu | sed -e '/initrd/G;/^$/,$d' -e '/title/s/$/ (bootchart)/;s/([^()]*) \((bootchart)\)/\1/;s/^[ 	]*kernel.*/& init=\/sbin\/bootchartd/' -e "1i\
$CAP # bootchart" | sed 's/: # bootchart/: bootchart/' >> $grubmenu
	else
		echo "bootchart not found."
	fi
fi

eval $($osprober 2>/dev/null | awk -F ":" 'BEGIN { OFS=":" ; i=-1 ; j=-1 }; { if ($4 == "linux") { i++ ; I=i } else { j++ ; I=j } ; S=tolower($3) ; s=tolower($2) ; sub(/ release/,"", $2) ; sub(/ .*/,"",s) ; if (S == "unknownlsb") S=s ; gsub(/ /, "@" , $2) ; printf "%s[%s]=\"%s:%s:%s\" ; ", $4, I, S, $1, $2 }')

if [ "$linux_order" ] ; then
	eval $(echo $linux_order | awk 'BEGIN { RS=" " ; printf "REPLACE=\"" } ; { printf "s|%s|%s%s|;", $1, NR, $1 } ; END { printf "\"" }')
	linux=($(echo ${linux[*]} | tr " " "\n" | sed "$REPLACE;s|\([a-zA-Z]\):|\10:|" | sort -n | sed 's|^[0-9]*||;s|0:/|:/|'))
fi

[ $((${#linux[*]} + ${#chain[*]})) -ge 1 ] || exec echo "No other operating systems found"

if [ "$WINDOWSFIRST" ] ; then
	if [ "$DISPLAYONLY" ] ; then
		writeEntry C ${chain[*]}
		writeEntry K ${linux[*]}
	else
		writeEntry C ${chain[*]} >> $grubmenu
		writeEntry K ${linux[*]} >> $grubmenu
	fi
else
	if [ "$DISPLAYONLY" ] ; then
		writeEntry K ${linux[*]}
		writeEntry C ${chain[*]}
	else
		writeEntry K ${linux[*]} >> $grubmenu
		writeEntry C ${chain[*]} >> $grubmenu
	fi
fi

if [ "$CHAINLOADGRUB" ] ; then
	if [ "$DISPLAYONLY" ] ; then
		writeGrubChainloadEntries
	else
		writeGrubChainloadEntries >> $grubmenu
	fi
fi

# append custom boot entries (like other OS chainload entries) from /etc/updategrub/custom
if [ -f $custom ] ; then
	if [ "$DISPLAYONLY" ] ; then
		printf "\n"
		cat $custom
	else
		printf "\n" >> $grubmenu
		cat $custom >> $grubmenu
 	fi
fi

[ "$DISPLAYONLY" ] && exit

# enabling/disabling boot entries.
[ "$INTERACTIVE" ] && grubmenu

# Set bootflag on Grub partition and exit
[ "$SETBOOTFLAG" ] && setBootFlag

### ~~~ MAIN - END ~~~
exit 0

