#!/bin/bash -e # usage: # tar2vm chroot.tar image.raw [size_in_bytes] . shell-error if [ $# -lt 2 ]; then fatal "error: tar2vm needs at least two arguments" fi # this needs env_keep sudo setup to actually work if [ -n "$GLOBAL_BUILDDIR" ]; then WORKDIR="$GLOBAL_BUILDDIR/vmroot" else WORKDIR="$(mktemp --tmpdir -d vmroot-XXXXX)" fi [ -n "$WORKDIR" ] || fatal "couldn't come up with suitable WORKDIR" [ -n "$GLOBAL_DEBUG" ] || message "WORKDIR: $WORKDIR" # a tarball containing chroot with a kernel TAR="$1" [ -s "$TAR" ] || fatal "source tarball doesn't really exist" # a path to the image to be generated IMG="$2" [ -d "$(dirname "$IMG")" ] || fatal "target directory doesn't exist" # image size in bytes (256M is a fallback) TARSIZE="$(stat -Lc %s "$TAR")" DEFSIZE="$((2 * $TARSIZE))" DISKSIZE="${3:-${DEFSIZE:-268435456}}" # ...and in megabytes DISKSIZEM="$(($DISKSIZE / 1048576))" # tested to work: ext[234], jfs ROOTFSTYPE="${4:-ext4}" # single root partition hardwired so far, # add another image for swap if needed ROOTDEV="/dev/sda1" # last preparations... for i in losetup parted kpartx mkfs."$ROOTFSTYPE"; do if ! type -t "$i" >&/dev/null; then fatal "$i required but not found" fi done LOOPDEV="$(losetup --find)" ROOTFS="$WORKDIR/chroot" exit_handler() { rc=$? if [ -n "$ROOTFS" ]; then umount "$ROOTFS"{/dev,/proc,/sys,} if [ -n "$LOOPDEV" ]; then kpartx -d "$LOOPDEV" losetup --detach "$LOOPDEV" fi rm -r -- "$ROOTFS" rmdir -- "$WORKDIR" fi exit $rc } trap exit_handler EXIT # prepare disk image and a filesystem inside it rm -f -- "$IMG" dd if=/dev/zero of="$IMG" conv=notrunc \ bs=1 count=1 seek="$(($DISKSIZE - 1))" losetup "$LOOPDEV" "$IMG" parted --script "$LOOPDEV" mklabel msdos parted --script "$LOOPDEV" mkpart primary ext2 1 "$DISKSIZEM" kpartx -a "$LOOPDEV" LOOPDEV1="/dev/mapper/$(basename "$LOOPDEV")p1" mkfs."$ROOTFSTYPE" "$LOOPDEV1" # mount and populate it mkdir -pm755 "$ROOTFS" mount "$LOOPDEV1" "$ROOTFS" tar -C "$ROOTFS" --numeric-owner -xf "$TAR" for i in /dev /proc /sys; do mount --bind "$i" "$ROOTFS$i"; done # NB: different storage modules might be needed for non-kvm echo "$LOOPDEV1 / $ROOTFSTYPE defaults 1 1" >> "$ROOTFS/etc/fstab" echo "MODULES_PRELOAD=sd_mod ata_piix $ROOTFSTYPE" >> "$ROOTFS/etc/initrd.mk" KERNEL="$(readlink $ROOTFS/boot/vmlinuz | sed 's,vmlinuz-,,')" chroot "$ROOTFS" make-initrd -k "$KERNEL" sed -i "s,$LOOPDEV1,$ROOTDEV," "$ROOTFS/etc/fstab" # configure and install bootloader REGEXP='^([0-9]+) heads, ([0-9]+) sectors/track, ([0-9]+) cylinders.*$' set -- $(fdisk -l "$LOOPDEV" | grep -E "$REGEXP" | sed -r "s@$REGEXP@\1 \2 \3@") LILO_COMMON="lba32 delay=1 vga=0 image=/boot/vmlinuz initrd=/boot/initrd.img append=\"root=$ROOTDEV rootdelay=3\" label=linux" cat > "$ROOTFS"/etc/lilo-loop.conf << EOF boot=$LOOPDEV disk=$LOOPDEV bios=0x80 heads=$1 sectors=$2 cylinders=$3 partition=$LOOPDEV1 start=63 $LILO_COMMON EOF chroot "$ROOTFS" lilo -C /etc/lilo-loop.conf cat > "$ROOTFS"/etc/lilo.conf << EOF boot=${ROOTDEV%[0-9]*} $LILO_COMMON EOF if [ -n "$SUDO_USER" ]; then chown "$SUDO_USER" "$IMG" "$ROOTFS" "$WORKDIR" fi