#! /bin/bash
# set COLOR to 0 to copy/paste or redirect debug output to a file
COLOR=1
# default mointpoint
mnt=/mnt
function help {
cat << EOFHELP
findgrub - description and help
options:
[37;1m-h --help[37;0m : show this help
[37;1m-w --writemenu[37;0m : add boot entries to /boot/grub/men.lst
[37;1m-d --debug [-n --nocolor] [37;0m : print Win bootsectors to standard output
EOFHELP
exit
}
function Linux2LegacyGrub {
eval `echo ${1:2} | sed 's|\(.\)|maj=\1;min=|;s|$|;|'`
let min--
echo "(hd$(($(printf "%d
" \'$maj) - 97)),$min)"
}
function chainloadEntry {
if [ "${WRITEMENU}" ] ; then
printf " - append boot entry to chainload Windows bootmanager on [31;1m%s[37;0m to [37;1m/boot/grub/menu.lst[37;0m
" $1
cp /boot/grub/menu.lst{,.findgrub}
cat << EOFWriteGrubEntry | sed '/^[ ][ ]*$/d' >> /boot/grub/menu.lst
###Don't change this comment - YaST2 identifier: Original name: WindowsBootLoader###
title Windows on $1
rootnoverify $(Linux2LegacyGrub ${1#/dev/*})
$makeactive
chainloader +1
EOFWriteGrubEntry
else
printf "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can add the following entry to [37;1m/boot/grub/menu.lst[37;0m :
"
cat << EOFDisplayGrubEntry | sed '/^[ ]*$/d'
[32;1m
###Don't change this comment - YaST2 identifier: Original name: WindowsBootLoader###
title Windows on $1
rootnoverify $(Linux2LegacyGrub ${1#/dev/*})
$makeactive
chainloader +1
[37;0m
EOFDisplayGrubEntry
printf "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"
fi
}
function printbs {
if [ $COLOR -eq 1 ] ; then
printf "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[37;1m%s [37;0mBootsector
---------------------------------------------------------------------------
[36;1m" $1
dd if=$1 bs=512 count=1 2>/dev/null | tr -cd "[:alnum:] [:space:]"
printf " [37;0m
----------------------------------------------------------------------------
"
dd if=/dev/sda1 bs=512 count=1 2>/dev/null | od -x | awk '{ if ( NF == 9 ) { printf "[35m%s|[33;1m %s %s %s %s %s %s %s", $1, $2, $3, $4, $5, $6, $7, $8 ; if ( $9 == "aa55" ) printf " [31;1m%s[35;0m
", $9 ; else printf " %s[35;0m
", $9 }}'
printf " [37;0m
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"
else
printf "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%s Bootsector
---------------------------------------------------------------------------
" $1
dd if=$1 bs=512 count=1 2>/dev/null | tr -cd "[:alnum:] [:space:]"
printf "
----------------------------------------------------------------------------
"
dd if=/dev/sda1 bs=512 count=1 2>/dev/null | od -x
printf "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"
fi
}
function printptbl {
if [ $COLOR -eq 1 ] ; then
printf "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[37;1m%s[37;0m Partition table
---------------------------------------------------------------
" $1
dd if=$1 bs=1 skip=446 count=64 2>/dev/null | od -x | head -4 | awk '{HD=substr($2,1,2) ; BF=substr($2,3,2); FE=substr($4,1,2) ; ID=substr($4,3,2); if ( BF == "80" ) BF="[31;1m"BF ; printf "[35m%s|[32;1m %s%s [32;1m%s %s[37;1m%s [32;1m%s %s %s %s %s[35;0m
", $1, HD, BF, $3, FE, ID, $5, $6, $7, $8 , $9}'
printf "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"
else
printf "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%s Partition table
---------------------------------------------------------------
" $1
dd if=$1 bs=1 skip=446 count=64 2>/dev/null | od -x | head -4
printf "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"
fi
}
function findbootmgr {
case $3 in
6|b|c|e) fs=vfat ;;
7) fs=ntfs;;
esac
mp=`mount | grep $1 | awk '{ print $3 }'`
if [ "x$mp" == "x" ] ; then
mp=$mnt
mount | grep -q "$p " && mp=/findgrub
[ -d $mp ] || mkdir $mp
mount -t $fs $1 $mp
UNMOUNT=1
else
unset UNMOUNT
fi
case $2 in
bootmgr)
find $mp -maxdepth 1 -iname "bootmgr" | grep -q -i "bootmgr" && {
printf " --> [37;1mWindows7/Vista Loader found in [31;1m%s[37;0m
" $pt
chainloadEntry $pt
}
;;
ntldr)
find $mp -maxdepth 1 -iname "ntldr" | grep -q -i "ntldr" && {
printf " --> [37;1mWindows NT/2K/XP Loader found in [31;1m%s[37;0m
" $pt
chainloadEntry $pt
}
;;
esac
if [ "$UNMOUNT" ] ; then
umount $mp
fi
[ -d /findgrub ] && rmdir /findgrub
}
# some partition types with color
x6=FAT16 ; c6='33;1m'
xb=FAT32 ; cb='32;1m'
xc=FAT32 ; cc='32;1m'
xe=FAT32 ; ce='32;1m'
x5=Extended ; c5='32;1m'
xf=Extended ; cf='32;1m'
x7=NTFS ; c7='34;1m'
x27="Win Recovery" ; c27='31m'
x82=swap ; c82='33m'
x83=LINUX ; c83='36;1m'
xee=EFI ; cee='31m'
xaf=HFS ; caf='35m'
xa5=FreeBSD ; ca5='35m'
xa6=OpenBSD ; ca6='35m'
xa9=NetBSD ; ca9='35m'
# Main - BEGIN --------------------------
devs=(`fdisk -l 2>/dev/null | sed -n 's|^Disk \(/dev/[hs]d[a-z]\):.*|\1|p'`)
case "$1" in
-w|--writemenu) WRITEMENU=1 ; shift ;;
-d|--debug)
DEBUG=1
shift
case "$1" in
-n|--nocolor) COLOR=0 ;;
esac
;;
-h|--help) help ;;
esac
# look for GRUB signature in MBR, Linux(0x83) and Extended(0x05, 0x0f) partitions
# skip EFI (0xee), swap (0x82) and BSD (0xa5, 0xa6, 0xa9) partitions
# !!! deliberately skip Windows Recovery (0x27) partition
# look for strings 'BOOTMGR' or 'NTLDR' in all other partitions bootsector and
# if found mount the partition and search for files bootmgr or ntldr
# in debug mode, output bootsector of NTFS and FAT partitons in ASCII and HEX
# output partition table
# get all partitions ids
eval `fdisk -l 2>/dev/null | awk '/^\/dev/ { if ($2 == "*") ID = $6 ; else ID = $5 ; print $1"="ID";" }' | sed s'|/dev/||'`
for dev in ${devs[li]} ; do[/li] if [ -b $dev ] ; then
printf "
[31;1m - reading MBR on disk %-27s [37;0m..." "$dev"
dd if=$dev bs=512 count=1 2> /dev/null | grep -q GRUB && {
printf " --> [37;1mGrub found in [31;1mMBR[37;0m"
[ "$dev" == "/dev/sda" ] && makeactive=makeactive
}
for pt in `fdisk -l $dev 2>/dev/null | awk '/^\/dev/ { print $1 }'` ; do
PT=$(basename $pt) fs=${!PT}
f=x${fs} ; FS=${!f} ; c=c${fs} ; CL=${!c}
if [ "$DEBUG" ] ; then
case $fs in
6|b|c|e|7) printbs $pt ;;
esac
else
case $fs in
ee|af|a5|a6|a9|82|27)
printf "
- skiping partition [%s%-11s %-15s[37;0m" $CL "$pt" "($FS)"
;;
83|5|f)
printf "
- reading bootsector [%s%-11s %-15s [37;0m..." $CL "$pt" "($FS)"
dd if=$pt bs=512 count=1 2> /dev/null | grep -q GRUB && printf " --> [37;1mGrub found in [31;1m%s[37;0m" $pt
;;
*)
printf "
- searching partition [%s%-11s %-15s [37;0m..." $CL "$pt" "($FS)"
dd if=$pt bs=512 count=1 2> /dev/null | grep -q NTLDR && findbootmgr $pt ntldr $fs
dd if=$pt bs=512 count=1 2> /dev/null | grep -q BOOTMGR && findbootmgr $pt bootmgr $fs
;;
esac
fi
done
[ "$DEBUG" ] && printptbl $dev
fi
done
printf "
"
[ -d /findgrub ] && rmdir /findgrub
# Main - END ---------------------------
I hope this script is not going to get longer or people will be afraid of using it.
So far, I tested it on an Aspire revo with Windows 7 preinstalled (3 partitions), on an iMac ( redirecting all the GPT related warnings) and on one of my computers full of Linux and Unix partitions. It seems to work but … I’m sure there are bugs.
I add a ‘makeactive’ to the Windows partition only if Grub is found in MBR. (so it won’t infringe openSUSE policies)
usage :
[ul]
[li]findgrub[/li][li]findgrub -h | --help[/li][li]findgrub -w | – writemenu[/li][li]findgrub -d | --debug [ -n | --nocolor ][/li][/ul]
the option --debug is used to display bootsectors (like in that example
Help: I borked my WindowsXP boot when installing OpenSUSE 11.3
), so we can tell if they are garbaged (or encrypted like in the example) and not bootable with Grub.
Use --debug --nocolor ( or -d -n ) if you want to post the output (otherwise it will be full of escape sequences).
What else ? … I don’t know. Just enjoy.