Grub2 multiple ISO booting

I recently needed to boot from a USB key to install Xubuntu, in my case Xubuntu 11.04 using alternate CD. I used Unetbootin before for this job, however one thing I did not like is that it expands the ISO onto the USB. While this can be beneficial in some cases – e.g. when you actually want to change the files already present on the ISO, I wanted to just drop ISO onto the USB key and boot from it verbatim. Here’s what worked for me using Grub2.

VM for testing

I’m going to use Qemu VM for testing this. The VM will have a small HDD, a DVD reader and a USB key. To simulate the HDD and USB key, let’s create two images:

$ qemu-img create -f qcow2 sda.img 5G
$ qemu-img create -f qcow2 sdb.img 1G

sda is the HDD, sdb is the USB stick. I will put the following distributions there and add them to the Grub2 boot menu:

 30M slitaz-3.0.iso
 11M tinycore_3.8.4.iso
640M xubuntu-11.04-alternate-amd64.iso

In order to actually do this, I downloaded the desktop variant of Xubuntu 11.04. I’ll use it to boot the VM initially and prepare the USB stick from within VM.

Here are the links you can use to download these:

Obviously, you can use other versions, especially if newer ones come in in the meantime, or try other distributions. Note also that Xubuntu links from the above are amd64 versions, so if you want 32-bit check this page.

Starting the VM

First, let’s boot Xubuntu 11.04 desktop:

$ qemu-system-x86_64 -m 512 -hda sda.img -hdb sdb.img -cdrom xubuntu-11.04-desktop-amd64.iso -boot d

Choose the first option “Try Xubuntu without installing” and boot the Xubuntu. When it boots, open the terminal by right clicking on the desktop and choosing Applications/Accessories/Terminal Emulator. Let’s confirm we have both disks as expected:

ubuntu@ubuntu:~$ sudo fdisk -cul
Disk /dev/sda: 5368 MB, 5368709120 bytes
255 heads, 63 sectors/track, 652 cylinders, total 10485760 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xa9af789e

Disk /dev/sda doesn't contain a valid partition table

Disk /dev/sdb: 1073 MB, 1073741824 bytes
139 heads, 8 sectors/track, 1885 cylinders, total 2097152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x5e2afaf3

Disk /dev/sdb doesn't contain a valid partition table

Let’s make a LVM partition on sda:

ubuntu@ubuntu:~$ sudo fdisk -cu /dev/sda
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xa9af789e.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First sector (2048-10485759, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-10485750, default 10485759): 
Using default value 10485759

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 8e
Changed system type of partition 1 to 8e (Linux LVM)

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

and a Linux partition on sdb:

ubuntu@ubuntu:~$ sudo fdisk -cu /dev/sdb
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x5e2afaf3.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First sector (2048-2097151, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-2097151, default 2097151): 
Using default value 2097151

Command (m for help): a
Partition number (1-4): 1

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

Let’s now format /dev/sdb1 as ext4:

ubuntu@ubuntu:~$ sudo mkfs.ext4 /dev/sdb1
mke2fs 1.41.14 (22-Dec-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
65536 inodes, 261888 blocks
13094 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=268435456
8 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376

Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 32 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

Note other partition types should work – e.g. vfat might be a better choice if you have Windows machines around that might access this USB.

We have all set up now to install and configure Grub2.

Copying the ISO files from host to guest USB stick

Qemu has a built-in router that exposes host within the guest on IP 10.0.2.2. This can be used to communicate with the host and can be handy when copying files between hosts. My host is Ubuntu 11.10-beta1, but should not matter going forward. I will be using SMB with Samba to copy this. First, make sure you have a share on the host and that all ISO files are there. To create a share on the host from command line, you can do this:

$ net usershare add isos /path/to/isos "" "" guest_ok=y

The above adds a share called isos to the path where you saved isos (/path/to/isos) and allows guest access.

From within guest, we’ll mount this, but in Xubuntu 11.04 desktop live CD we need to install smbfs first. Here are all the steps:

ubuntu@ubuntu:~$ sudo apt-get install smbfs
... <installation information> ...
ubuntu@ubuntu:~$ mkdir isos
ubuntu@ubuntu:~$ sudo smbmount //10.0.2.2/isos isos
Password:
ubuntu@ubuntu:~$ cd isos
ubuntu@ubuntu:~/isos$ ls -1hs
total 1.5G
 30M slitaz-3.0.iso
 11M tinycore_3.8.4.iso
640M xubuntu-11.04-alternate-amd64.iso
688M xubuntu-11.04-desktop-amd64.iso

Let’s copy all but the desktop ISO to our USB stick:

ubuntu@ubuntu:~$ mkdir sdb1
ubuntu@ubuntu:~$ sudo mount /dev/sdb1 sdb1
ubuntu@ubuntu:~$ mkdir sdb1/isos
ubuntu@ubuntu:~/isos$ sudo cp lubu-528.iso slitaz-3.0.iso tinycore_3.8.4.iso xubuntu-11.04-alternate-amd64.iso ~/sdb1/isos
ubuntu@ubuntu:~/isos$ cd ..
ubuntu@ubuntu:~$

This will take a few minutes to complete.

Installing Grub2

We can install Grub2 using this:

ubuntu@ubuntu:~$ sudo grub-install --root-directory=sdb1 /dev/sdb
Installation finished. No error reported.

The only thing left is to make a configuration with the above-mentioned distributions:

ubuntu@ubuntu:~$ cd ~/sdb1/boot/grub
ubuntu@ubuntu:~/sdb1/boot/grub$ sudo sh -c "cat > grub.cfg"
menuentry "SliTaz 3.0" {
  set iso=/isos/slitaz-3.0.iso
  loopback loop $iso
  linux (loop)/boot/bzImage isofrom=$iso boot=live --
  initrd (loop)/boot/rootfs.gz autologin
}
menuentry "Tinycore 3.8.4" {
  loopback loop /isos/tinycore_3.8.4.iso
  linux (loop)/boot/bzImage --
  initrd (loop)/boot/tinycore.gz
}
menuentry "Xubuntu 11.04 alternate" {
  set iso=/isos/xubuntu-11.04-alternate-amd64.iso
  loopback loop $iso
  linux (loop)/install/vmlinuz findiso=$iso file=/cdrom/preseed/xubuntu.seed quiet --
  initrd  (loop)/install/initrd.gz
}
^D
ubuntu@ubuntu:~/sdb1/boot/grub$ cd 
ubuntu@ubuntu:~$ sudo umount sdb1
ubuntu@ubuntu:~$ sudo umount isos

^D means press Ctrl+D to send EOF to cat. After this, we are all set to try to boot from our newly created USB stick. Close the current Qemu instance and launch another one like this:

$ qemu-system-x86_64 -m 512 -hda sdb.img -hdb sda.img -boot c

Note that the order is reversed, as we can only boot from the first HDD. You should be presented with the menu we just created and be able to boot the 3 distributions.

Installing Xubuntu 11.04 alternate on the above system

You may be wondering why I have a 5GB /dev/sda (well, /dev/sdb now after exchanging sda and sdb to be able to boot from USB) at all. I used this to test Xubuntu install before I installed on a physical machine. Anyway, this worked pretty much excellent provided one additional step on VM. Not sure if this is related to using ext4 on the USB, but if I’m not mistaken doing this on a physical machine worked fine without any intervention. Anyway, the issue was that Xubuntu alternate installer could not detect the CD-ROM, even though findiso parameter has been supplied. This was easy to fix – go to the second console (Alt-F2) and do this:

$ mv /dev/sr0 /dev/sr0a
$ mount /dev/sda1 /mnt
$ ln -s /mnt/isos/xubuntu-11.04-alternate-amd64.iso /dev/sr0

This will basically put the Xubuntu alternate CD in place of what really should be CD-ROM (/dev/sr0 in this case). Now just repeat the CD-ROM detection step and you’ll be all set. Installing Xubuntu went like a charm from withing Qemu and also on another physical machine.