Magic ISO Image Booting with GNU GRUB 2

Recently I needed to prepare a USB thumb drive with several Ubuntu installations. A little research quickly yielded many setup instructions, for example like the one from Pendrivesystem.com.  I was really surprised at how well this works and wanted to understand it better.

In essence all recipes rely on GNU GRUB in version 2 and the loopback feature that it contains and on the OS's ability to work off an ISO image. The loopback command mounts a CD or HDD image that contains the kernel and initrd from an ISO image. As a result one can put several ISO images on the boot media without the need to extract them. The OS then also mounts the ISO image and uses that instead of a CD/DVD drive.

So here is my version of the recipe, the USB thumb drive is in /dev/sdc in my examples:

1. partition & format device

I prefer to partition the device with parted because it aligns the partition at 1MB so that it leaves enough space for GRUB to embed itself into the first sectors of the disk:

$ export $DEV=/dev/sdc
$ sudo parted -s $DEV mklabel msdos mkpart primary ext2 0% 100% print
Model: Generic Flash Disk (scsi)
Disk /dev/sdc: 1035MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  1035MB  1034MB  primary  ext4

$ sudo mkfs.ext4 -qL INSTALL ${DEV}1

Note: It seems that many BIOS boot from this only if the partition is not marked active!

2. mount & install grub

$ sudo mount -vL INSTALL /mnt
mount: you didn't specify a filesystem type for /dev/sdc1
       I will try type ext4
/dev/sdc1 on /mnt type ext4 (rw)

$ sudo grub-install --boot-directory /mnt /dev/sdc
Installation finished. No error reported.

3. Add some ISOs that support loopback booting

$ sudo wget -P /mnt \
Length: 726663168 (693M) [application/x-iso9660-image]
Saving to: ‘/mnt/xubuntu-12.04.3-desktop-i386.iso’

100%[==============>] 726,663,168 2.71MB/s   in 6m 12s 

4. Create GRUB menu entry

$ sudo tee /mnt/grub/grub.cfg >/dev/null <<EOF
menuentry "XUbuntu 12.04.3 i386" {
    set iso=/xubuntu-12.04.3-desktop-i386.iso
    loopback loop $iso
    linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$iso noeject noprompt splash locale=de_DE bootkbd=de console-setup/layoutcode=de --
    initrd (loop)/casper/initrd.lz

Here the trick is to set a variable (iso) with the ISO file, loopback mount the iso image and load kernel/initrd from the ISO image. The same ISO image is also passed as a parameter to the booting OS.

5. Umount & try it out

Thermionix published a nice example of a fancy grub.cfg, it contains many examples for loopback booting with various distros and tools.