update grub2 without hardware access (e.g. in a chroot)?

I'm writing a script that takes a master KVM image, converts it to VDI, makes a few changes to it, and offers it up for download.

I need to update the kernel boot parameters for some of the newly created images. Normally one would edit the GRUB_CMDLINE_LINUX_DEFAULT setting in /etc/default/grub, and then run update-grub. Of course, I can only do this in a chroot, which fails: '/usr/sbin/grub-probe: error: cannot find a device for / (is /dev mounted?).'

Bind mounting /dev from the running system into the chroot allows update-grub to run, but results in a broken grub.cfg (wrong root device from the image's perspective).

If I just use sed to add the kernel parameters I need, it will get the image booting, but subsequent runs of update-grub (from inside the now-running image) will cause trouble.

So my current solution is:

  1. edit parameters in /etc/default/grub
  2. bind mount /dev into the chroot
  3. run update-grub in the chroot
  4. use sed to fix erroneous device nodes in /boot/grub/grub.cfg

Please tell me there is a better way.


The correct answer is to mount /dev into the chroot, and use a $CHROOT/boot/grub/device.map file to tell grub that (hd0) (from the image's perspective) is actually the loopback file that you've "partitioned" (and then mounted into your chroot with kpartx et c).

# generate grub configs and install it to the generated blockdev
chroot $MR update-grub 2> /dev/null
chroot $MR grub-mkconfig -o /boot/grub/grub.cfg 2> /dev/null
cat > $MR/boot/grub/device.map <<EOF
(hd0)   ${LOOPDEV}
EOF
chroot $MR grub-install ${LOOPDEV} 2> /dev/null

After you're done installing grub to the "mbr" of the loopdev, you should rm the device.map file because it won't be accurate from the image's perspective once it actually boots.

I have a script that builds complete qcow2 images for ubuntu 13.10 saucy x64 here:

https://github.com/sneak/kvm-ubuntu-imagebuilder/blob/master/buildimage.sh#L211

Good luck.


Note that this answer assumes that your disk is partitioned.

sneak's answer works for Debian wheezy which runs grub 1.99, but not for grub2. You'll want to use UUID's (as recommended by the grub devs) to reference devices/partitions.
Here's the problem: kpartx (the tool used to map partitions), doesn't create symlinks in /dev/disk/by-uuid, which grub uses to verify that it can use the detected UUID when generating the config, so it falls back to the device path. To rectify that simply symlink the device yourself (ln -s /dev/sdX /dev/disk/by-uuid/$(blkid -s UUID -o value /dev/sdX)).

I hope this helps, if not you then maybe somebody else who stumbles upon this question the way I did, because man figuring this out took quite some time.