Pierre Palatin's corner

Random posts about some stuff I’ve been doing.

Automatically creating a disk image with partitions and bootloader.

Posted at — Jan 1, 2006

I’m often playing with tools to manipulate full system images for virtual machines and so I often need to create disk images. The attached script allows to create a disk image of an arbitrary size with partitions and a working grub bootloader. This kind of script can be a bit dangerous, so I put it there just as an example, be careful. It is using qemu-img to create the disk image (which can be easily replaced by dd), sfdisk to create the partitions, and grub to install a boot loader.

The script

{{ .Resources.GetMatch “createdisk” }} There is behind that a couple of not often documented issues.

Disk size

The PC partition table still uses the wonderful Cylinder/Head/Sector (a.k.a. CHS) scheme to address the disk. Of course, those values do not correspond anymore to any physical reality, but they are still here to annoy you. The idea with PC partition table is that partitions can start and stop only at CHS boundaries. Typically, you count 255 heads and 63 sectors, and you have a number of cylinders depending on the disk size. Usually one sector is 512 octets, so the math is easily done.

It is not a problem to have a disk size not strictly aligned with a CHS boundary. Worst thing is that you lose a few kilobytes, which is not an issue. However when it comes to creating a disk image from an host, you can have the following problem:

And now you have a problem if you look carefully. The mkfs called will determine (by default) the filesystem size based on the block device size. But if your disk size was not aligned on CHS boundaries, it means that you have more place on the disk image, hence on /dev/loop0 than you really have on the partition. Another way to say that is that the end of the filesystem will be after the end of the partition. And of course, fsck won’t be too thrilled about that.

There’s a couple of solutions:

Configuring grub

Grub can be easily put a disk image. In its default setup, it needs to have a few files on the partition to be able to boot and show up a menu. At the beginning, I was simply counting on the files provided by the linux distribution I was putting on the disk. However, it can be sometime incompatible with the grub version you’re using from the host machine. So you need to put grub files from the host machine first. I’m doing something along those lines after having mounted the partition on $INSTDIR:

cp /boot/grub/{stage1,stage2,e2fs_stage1_5} $INSTDIR/local/grub ln -s /boot/grub/menu.lst $INSTDIR/local/grub/menu.lst

I’m not putting the host file in the usual /boot/grub directory. The idea is that I’m going to put a full distribution image here, and I don’t want to override the real grub files. Moreover, this way, if I reinstall grub from the virtual machine afterwards, it will probably do the right thing by using files from /boot/grub.

Now, I just need to setup grub using the following commands:

grub --batch <<EOF device (hd0) ${IMGFILE} root (hd0,0) setup --prefix=/local/grub (hd0) quit EOF

There are two things here. I need to specify that hd0 is in fact my disk image using thedevice stanza, to avoid writing on the real disk. Then, I use –prefix in the setup command to make sure that grub will be using the files I copied from the host.