Monday, 9 April 2012

Installing grub2 without Linux

Old Win XP PC + a new HDD + Win 7 = ?
? = a need to toggle between Win XP and Win 7
at least for a while

I'd like to tell you how to set this up with Grub2

Plenty of tutorials are available online which teach you how to rescue Grub after Windows has been installed. They commonly assume you've already got a Linux installation on your machine. So they instruct you to mount that installation as /mnt then chroot /mnt and fix Grub from the chroot environment.

I don't have a Linux installation. All I have is

- Win XP on an /dev/sdb1
- a new HDD to install Win 7 on /dev/sda
- Win 7 installation media
- Ubuntu 11.10 Live CD

I heard about grub4dos. Maybe it's good for the task. However I already have the Ubuntu Live CD and I would like to learn a bit about Grub2.

So what do I do?

- boot into Ubuntu Live CD, click "Try Ubuntu"
- create a 128Mb ext3 partition /dev/sda1 for Grub with gparted
- boot from Win 7 installation DVD
- allow Win 7 to create it's usual 2 new ntfs partitions (/dev/sda2 and /dev/sda3)
- allow Win 7 to install completely (a few reboots.., update..., reboot..)

It's time to implement toggling between Win 7 and Win XP

- boot into Ubuntu Live CD, click "Try Ubuntu"
- Ctrl+Alt+T to launch terminal
- sudo bash (okay now I have a root shell)
- run gparted
- make sure the 128Mb partition I had created for Grub is /dev/sda1
- execute
mkfs.ext3 /dev/sda1
mount /dev/sda1 /mnt
mkdir /mnt/boot
grub-install --boot-directory=/mnt/boot /dev/sda1
Only this does not work.
grub-install --boot-directory=/mnt/boot /dev/sda1
yields
/usr/sbin/grub-setup: warn: Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea..
/usr/sbin/grub-setup: warn: Embedding is not possible. GRUB can only be installed in this setup by using blocklists. However, blocklists are UNRELIABLE and their use is discouraged..
/usr/sbin/grub-setup: error: will not proceed with blocklists.
Two solutions are available: --force or install Grub2 to MBR, e.g. one of
grub-install --force --boot-directory=/mnt/boot /dev/sda1
grub-install --boot-directory=/mnt/boot /dev/sda
However the above doesn't create /mnt/boot/grub/grub.cfg. Try doing it directly
grub-mkconfig -o /mnt/boot/grub/grub.cfg
from a Live CD and you will get
/usr/sbin/grub-probe: error: cannot find a device for / (is /dev mounted?).
My solution is a bit ugly but it gets the job done:
cp /usr/sbin/grub-mkconfig /usr/sbin/grub-mkconfig1
vi /usr/sbin/grub-mkconfig1
...
grub-mkconfig1 -o /mnt/boot/grub/grub.cfg
Here is are the changes between the original and modified scripts:
root@ubuntu:/etc/grub.d# diff -u /usr/sbin/grub-mkconfig /usr/sbin/grub-mkconfig1
--- /usr/sbin/grub-mkconfig 2011-10-01 12:40:46.000000000 +0000
+++ /usr/sbin/grub-mkconfig1 2012-04-09 16:20:57.667520982 +0000
@@ -128,11 +128,11 @@
mkdir -p ${GRUB_PREFIX}

# Device containing our userland. Typically used for root= parameter.
-GRUB_DEVICE="`${grub_probe} --target=device /`"
-GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true
+GRUB_DEVICE=/dev/loop7
+GRUB_DEVICE_UUID=

# Device containing our /boot partition. Usually the same as GRUB_DEVICE.
-GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`"
+GRUB_DEVICE_BOOT="`${grub_probe} --target=device /mnt/boot`"
GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true

# Filesystem for the device containing our userland. Used for stuff like
To fix this properly we probably would need to find out why this command fails on an Ubuntu Live CD
root@ubuntu:/etc/grub.d# grub-probe --target=device /
grub-probe: error: cannot find a device for / (is /dev mounted?).
and adapt the whole chain of Grub2 scripts to work from a Live CD (would be nice!)

In my final step I manually edit /mnt/boot/grub/grub.cfg to make sure the order of boot menu entries and their names are what I prefer them to be.

All looks good; fingers crossed I'm heading for my reboot :)
Bingo, success!