tar2vm 3.03 KB
Newer Older
Michael Shigorin's avatar
Michael Shigorin committed
1
#!/bin/bash -e
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

. 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")"
Michael Shigorin's avatar
Michael Shigorin committed
30
DEFSIZE="$((3 * $TARSIZE / 2))"
31 32
DISKSIZE="${3:-${DEFSIZE:-268435456}}"
# ...and in megabytes
Michael Shigorin's avatar
Michael Shigorin committed
33
DISKSIZEM="$(($DISKSIZE / 1048576))"
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

# 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"
Michael Shigorin's avatar
Michael Shigorin committed
71 72
dd if=/dev/zero of="$IMG" conv=notrunc \
	bs=1 count=1 seek="$(($DISKSIZE - 1))"
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
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