#!/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 sfdisk 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='^Disk .*: ([0-9]+) cylinders, ([0-9]+) heads, ([0-9]+) sectors/track*$'
set -- $(sfdisk -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
  cylinders=$1
  heads=$2
  sectors=$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