I’m not completely done with this script, but I decided to start a new thread and post the code now - since I did already mention it a couple times in other posts and in the findgrub thread. What’s still missing is a function to add chainload entries for other Legacy Grub and Grub2 bootloaders on legacy MBR and UEFI systems. updateGrub2 is primarily intended to install Grub2 on UEFI systems (with GUID partitioning scheme), in order to multiboot openSUSE on UEFI systems. I’m working on an explicit tutorial - targeted at UEFI systems.
Here the latest code (1.1 beta). Comments and bug reports are welcome.
#! /bin/bash
#
#: Title : updateGrub2
#: Date Created: Sat Jan 14 22:34:57 PST 2012
#: Last Edit : Thu Jan 19 04:29:31 PST 2012
#: Author : Agnelo de la Crotche (please_try_again)
#: Version : 1.1 - beta
#: Description : install grub2, grub2-efi and refresh Grub2 menu
#: Requires : os-prober
#: Usage : updategrub2
#
# -----------------------------------------------
# variables you may modify.
grub_timeout=60
# check the VESA resolutions available to your graphics card with hwinfo --framebuffer
# before changing this value. If you don't specify a video mode here, 'auto' will be used
# - it is often the the best choice.
#grub_gfx=800x600x16
#grub_gfx=1024x768x16
#grub_gfx=128x1024x16
# menu colors
COLOR_NORMAL="black"
COLOR_HIGHLIGHT="white"
# To use your own background image, put its path in the variable grub_bg
# and uncomment the line below
# grub_bg=/usr/local/share/images/stellarcart.png
# You shouldn't need to change these values
unifont_url=http://unifoundry.com
unifont=unifont-5.1.20080820.bdf.gz
# -----------------------------------------------
# Do not modify the variables below!!!
# current version
version="1.0"
prg=$(basename $0)
declare -l NOCONFIRM INSTALL DISPLAYONLY BLID USEBG noconfirm autoimport gdev distcode
GSIGN="020"
GRID="grubx64.efi"
USEBG=yes
G=$(tput setaf 2)
B=$(tput bold)
N=$(tput sgr0)
# Exit if we are not root
$(id -u) -gt 0 ] && exec echo "You need to run this script as root"
# This script only works in openSUSE and Fedora
which lsb_release &> /dev/null || exec cat << EOFLSB
Please install Linux Standard Base Release Tools
using this command:
- under openSUSE:
zypper in lsb_release
- under Fedora:
yum install redhat-lsb
EOFLSB
eval $(lsb_release -ircs | awk '{ sub(/SUSE LINUX/,"openSUSE", $0) ; printf "dist=%s;distver=%s;distcode=%s;", $1, $2, $3 }')
BLID=$dist
"$BLID" == "opensuse" -o "$BLID" == "fedora" ] || exec echo "This script only supports openSUSE and Fedora."
# Default distro background image
opensuse_bg=/usr/share/backgrounds/upwind/morning-1280x1024.jpg
fedora_bg=/usr/share/backgrounds/$distcode/default/standard/${distcode}.png
dist_bg=${BLID}_bg ; dist_bg=${!dist_bg}
"$grub_bg" ] && -f "$grub_bg" ] && dist_bg=$grub_bg
-f $dist_bg ] && grub_bg=$dist_bg || unset USEBG
rootdev=$(cat /etc/mtab | awk '/^\/dev/ { if ( $2 == "/" ) print $1 }')
eval $(udevadm info --query=all --name=$rootdev | awk '/UDISKS_PARTITION_SCHEME/ { print $2 }')
opensuse_noconfirm="--non-interactive"
fedora_noconfirm="--assumeyes"
dist_noconfirm=${BLID}_noconfirm ; dist_noconfirm=${!dist_noconfirm}
function install_osprober {
case $dist in
openSUSE)
PTA_repo="http://download.opensuse.org/repositories/home:/please_try_again/${dist}_${distver}/"
zypper lr -u | grep -q ${PTA_repo} || zypper ar $PTA_repo PTA
zypper -n $autoimport refresh -r PTA
zypper $noconfirm in -r PTA os-prober
;;
Fedora)
yum $noconfirm install os-prober
;;
esac
}
function install_pkg {
case $dist in
openSUSE)
zypper $noconfirm install $grub
;;
Fedora)
rpm -qa | grep -q "grub-efi" && yum $noconfirm remove grub-efi
yum $noconfirm install $grub $grub2
;;
esac
}
function install_grub {
if "$EFI" ] ; then
-f /boot/$ESP/$GRID ] || $ginstall --bootloader-id=$BLID --no-floppy
else
eval $(udevadm info --query=property --name=$gdev | awk '/DEVTYPE/ { print }')
case $DEVTYPE in
disk)
declare -l YESNO
read -n 1 -s -p "Are you sure that you want to install Grub2 in MBR of $gdev? [yn] " YESNO
"$YESNO" == "y" ] && $ginstall $gdev
;;
partition)
"$($gprobe -d $gdev)" == "ext2" ] || exec echo "Destination is not an ext4 or ext3 partition"
$ginstall --force $gdev
;;
esac
fi
}
function grub_font {
case $BLID in
opensuse)
zypper $noconfirm in gnu-unifont
grub2-mkfont -o $gdir/unicode.pf2 /usr/share/fonts/uni/unifont.pcf.gz
;;
fedora)
cd /tmp
-f $unifont ] || wget ${unifont_url}/${unifont}
-f $unifont ] || return
gunzip $unifont
grub2-mkfont -o $gdir/unicode.pf2 $(basename $unifont .gz)
;;
esac
}
function gfx_menu {
-f $gdir/unicode.pf2 ] || grub_font
if "$USEBG" == "yes" ] ; then
splashsrc=$grub_bg ; splash=splash.${splashsrc##*.}
-f $gdir/$splash ] || cp $grub_bg $gdir/$splash
fi
if ! -f /etc/default/grub.orig -a -f /etc/default/grub ] ; then
echo "- patching /etc/default/grub ..."
grub_timeout=${grub_timeout:-10}
cp /etc/default/grub{,.orig}
grub_gfx=${grub_gfx:-auto}
grep -q "GRUB_GFXMODE" /etc/default/grub || echo "#GRUB_GFXMODE=640x480" >> /etc/default/grub
cat << EOFGRUBDEFAULT | sed -i -f - /etc/default/grub
s|GRUB_TIMEOUT=.*|GRUB_TIMEOUT=$grub_timeout|
s|#GRUB_GFXMODE=640x480|GRUB_GFXMODE=$grub_gfx|
/GRUB_GFXMODE/ a\
GRUB_GFXPAYLOAD_LINUX=keep
EOFGRUBDEFAULT
if -f $gdir/$splash ] ; then
cat << EOFGRUBDEFAULT2 | sed -i -f - /etc/default/grub
/GRUB_GFXMODE/ a\
GRUB_BACKGROUND=$gdir/$splash
EOFGRUBDEFAULT2
fi
fi
if ! -f /etc/grub.d/05_menu_color ] ; then
cat > /etc/grub.d/05_menu_color << EOF05MENUCOLOR
#!/bin/sh -e
set -e
prefix=/usr
exec_prefix=/usr
libdir=/usr/lib
. \${libdir}/grub/grub-mkconfig_lib
COLOR_NORMAL="$COLOR_NORMAL/black"
COLOR_HIGHLIGHT="$COLOR_HIGHLIGHT/black"
if "\${GRUB_TERMINAL_OUTPUT}" = "gfxterm" ] ; then
cat <<EOF
set color_normal=\${COLOR_NORMAL}
set color_highlight=\${COLOR_HIGHLIGHT}
EOF
else
cat << EOF
set menu_color_normal=white/black
set menu_color_highlight=black/light-gray
EOF
fi
EOF05MENUCOLOR
chmod 0755 /etc/grub.d/05_menu_color
fi
}
function chainload_windows {
-f /boot/efi/EFI/Microsoft/Boot/bootmgfw.efi ] || return
WINID=$($gprobe --target=fs_uuid /boot/efi/EFI/Microsoft/Boot/bootmgfw.efi)
grep -q $WINID /etc/grub.d/40_custom && return
echo "chainloading Windows..."
cat >> /etc/grub.d/40_custom << EOFWINCHAINLOAD
menuentry "Microsoft Windows x86_64 UEFI-GPT" {
insmod part_gpt
insmod fat
insmod search_fs_uuid
insmod chain
search --fs-uuid --no-floppy --set=root $WINID
chainloader (\${root})/efi/Microsoft/Boot/bootmgfw.efi
}
EOFWINCHAINLOAD
}
function update_menu {
"$mkconfig" ] || exec echo "grub2 not found"
if "$DISPLAYONLY" ] ; then
echo "Scanning..."
$mkconfig
else
if -d $gdir ] ; then
-d /boot/$ESP ] && chainload_windows
$mkconfig -o $gmenu
-d /boot/$ESP ] && cp $gmenu /boot/${ESP}/
else
echo "Boot directory $gdir not found"
fi
fi
}
function restore_elilo {
$(efibootmgr | grep -c -i $BLID) -gt 1 ] && return
eliloPath=$(find /boot/efi -name "elilo.efi")
dev=$(grub2-probe -t device $eliloPath)
disk=${dev:0:8} ; part=${dev:8}
eliloBldr=$(echo $eliloPath | sed 's|/boot/efi||;s|/|\\\\|g')
efibootmgr --create --gpt --disk $disk --part $part --write-signature --label "$DIST (elilo)" --loader "$eliloBldr"
}
function syntax {
cat << EOFHELP
$prg $version - Grub2 install and boot menu update.
${G}Syntax:${N}
${B}updateGrub2 options ]${N}
${G}Options:${N}
${B}-n --noconfirm${N} Installs packages and imports keys without asking for confirmation.
${B}-i --install [device]${N} Installs Grub2 on UEFI systems.
On BIOS systems you have to specify a device. This option is ignored if
the root partition already contains Grub2 signature. Otherwise you will
be able to install Grub2 bootloader in any partition, including the MBR.
Use this option with care!
${B}-d --display${N} Refreshes and prints the boot menu to standard output.
${B}-h --help${N} Displays this help.
Without options, updateGrub2 scans for other OSes (provided os-prober is
installed) and refreshes the boot entries in grub.cfg. The first time it
is run, it also modifies default settings, adds a script to /etc/grub.d,
builds a missing font which prevents graphic mode from working, lets you
set a background image or uses the system default one.
EOFHELP
exit
}
# -------------------------------------------------
args=`getopt -q -u -o hndi:: -l help,noconfirm,display,install:: -- "$@"`
set -- $args
for i; do
case "$i" in
-n|--noconfirm) noconfirm="${dist_noconfirm}" ; autoimport="--gpg-auto-import-keys" ; shift ;;
-i|--install) INSTALL=yes ; shift ;;
-d|--display) DISPLAYONLY=yes ; shift ;;
-h|--help) syntax ; shift ;;
--) shift ; break ;;
esac
done
gdev=$1 ; shift
case $UDISKS_PARTITION_SCHEME in
mbr)
EFI=""
ESP=""
grub2=""
"$(hexdump -v -s 128 -n 2 -e '/1 "%x"' $rootdev)" == "$GSIGN" ] && unset INSTALL
if "$INSTALL" == "yes" ] ; then
"$gdev" ] || exec echo "Option --install requires an argument"
-b $gdev ] || exec echo "Destination is not a block device"
fi
;;
gpt)
EFI="-efi"
ESP="/efi/EFI/$BLID"
DIST="$dist $distver"
grub2="grub2"
;;
esac
grub="grub2$EFI"
mkconfig="${grub}-mkconfig"
ginstall="${grub}-install"
gprobe="${grub}-probe"
gdir="/boot/${grub}"
gmenu="$gdir/grub.cfg"
if "$INSTALL" == "yes" ] ; then
which os-prober &>/dev/null || install_osprober
rpm -qa | grep -q $grub || install_pkg
"$INSTALL" ] && install_grub
fi
gfx_menu
update_menu
This script is intended for openSUSE UEFI and MBR systems, as well as Fedora UEFI systems (Fedora 16 installs Grub2 by default on Legacy BIOS systems).
updateGrub2 will also build the missing pf2 font which prevents Grub2 from entering graphic mode. You can set your own backgound image in the variable grub_bg and uncomment this variable. updateGrub2 WON’T install the bootloader if it finds a Grub2 signature in the boot sector of your root partition. So the option “-i” will be ignored in this case. Otherwise you have to specify the partition where you want to install the bootloader. It can be any primary or logical (linux) partition but not the extended one!.
Examples:
updateGrub2 -i /dev/sda # install Grub2 in the MBR of the first HDD
updateGrub2 -i /dev/sda6 # install Grub2 in the bootsector of sda6
Installing grub2 in a partition boot sector has been discouraged since the beginning by Grub2 developers (read Grub2 documentation). It would require the use of the --force option (the script takes care ot that). Since version 1.99, Grub2 uses a compressed core - that made it tricky for findgrub to get the partition where it is installed on disk.
**
You’re using this script with option “-i” at your own risk! Don’t play with this script if you don’t have another way to boot your system, such as Legacy Grub installed in another partition and the possibility to boot from it if things go wrong.**