Skip to content

Instantly share code, notes, and snippets.

@tai
Created April 27, 2018 03:18
Show Gist options
  • Select an option

  • Save tai/0dcee25b044010a040f6019db1deb519 to your computer and use it in GitHub Desktop.

Select an option

Save tai/0dcee25b044010a040f6019db1deb519 to your computer and use it in GitHub Desktop.
#!/bin/sh
set -e
usage() {
local p=$(basename $0)
cat <<EOF >&2
$p - Simple wrapper to run QEMU/KVM in various configurations
Usage: $p <rootfs-or-image> <qemu-options...> -- <boot-options...>
Example:
# $p /n/sid64
# $p /n/sid64-snap00
# $p /n/sid64/boot/vmlinuz-4.14.0-3-amd64
# $p nfs:/n/sid64
# $p 9p:/n/sid64
# $p /some/image.qcow2
# $p /dev/sdx
# $p raw:/some/image.dd
# $p raw-virtio:/some/image.dd
# $p none -drive file=/foo/hdd.dd,cache=none,format=raw,if=virtio
# $p none -boot n -curses
# $p /n/sid64 -drive file=/foo/hdd.qcow2,cache=none
# $p /n/sid64 -bios OVMF.fd -curses
# $p /n/sid64 -device vfio-pci,host=00:1a.0,x-vga=on -vga none
# $p /n/sid64 -usb -device usb-host,hostbus=2,hostaddr=3
# NORUN=echo $p /n/sid64
# KVM_MEM=64G $p /n/sid64 -smp cpus=32
# KVM_IF0=br0 $p /n/sid64 -gdb tcp::1234 -- vsyscall=emulate
# KVM_IF1=br1 $p /n/sid64 -s -- crashkernel=128M
EOF
exit 1
}
log() { echo "$@" >&2; }
die() { log "$@"; exit 1; }
makeroot() {
local want=$1
local bn=$(basename $want)
local dn=$(dirname $want)
# either just use given path, or clone from skelton
while [ -n "$bn" ]; do
local skel="$dn/$bn"
if [ -d "$skel" ]; then
if [ "$skel" != "$want" ]; then
sudo btrfs sub snap "$skel" "$want" > /dev/null
fi
return
fi
bn=$(echo $bn | sed 's/.$//')
done
log "Failed to prepare: $want"
}
#
# Usage:
# findboot [tag:]<file-or-dir>
# Example:
# findboot /n/sid64
# findboot /n/sid64/boot/vmlinuz-1.2.3-amd64
# findboot nfs:/n/sid64
# findboot 9p:/n/sid64
#
findboot() {
local arg=$1
local src=${arg#*:}
local tag=$(test "$arg" = "$src" || echo ${arg%%:*})
local is_kernel_image=false
# skip if given as "empty"
case "$src" in
-|none) return 0;;
esac
# clone environment on-demand
test -e "$src" || makeroot ${src%%/boot/*}
# CASE: src is a block device or system image (> 100MB)
if [ -b "$src" -o $(stat -c %s "$src") -gt $((1024 * 1024 * 100)) ]; then
is_kernel_image=false
: ${tag:=raw-scsi}
# CASE: src is either a kernel or initrd image
elif [ -f "$src" ]; then
is_kernel_image=true
: ${tag:=nfs}
# CASE: src is a bootable rootfs
elif [ -d "$src/boot" ]; then
is_kernel_image=true
: ${tag:=nfs}
# use latest kernel image in /boot
src=$(ls -1v $src/boot/vmli* | egrep -vm1 '(old|bak)')
else
log "Not bootable: $src"
return 1
fi
local kernel initrd tty=ttyS0
if $is_kernel_image; then
# get info from kernel/initrd pathname
local ver=$(basename $src | cut -d- -f2-)
local loc=${src%%/boot/*}
initrd=$(ls -1v $loc/boot/init*${ver} | egrep -vm1 '(old|bak)')
kernel=$(ls -1v $loc/boot/vmli*${ver} | egrep -vm1 '(old|bak)')
# select QEMU and arch-specific options
case "$kernel" in
*aarch64*) : ${QEMU:=qemu-system-aarch64};;
*mipsel*) : ${QEMU:=qemu-system-mipsel};;
*x86_64*) : ${QEMU:=qemu-system-x86_64 --enable-kvm};;
*amd64*) : ${QEMU:=qemu-system-x86_64 --enable-kvm};;
*i386*) : ${QEMU:=qemu-system-i386 --enable-kvm};;
*mips*) : ${QEMU:=qemu-system-mips};;
*arm*) tty=ttyAMA0
: ${QEMU:=qemu-system-arm -M ${KVM_MACHINE:=versatilepb}};;
*) log "Unknown arch: $kernel"; return 1;;
esac
fi
#
# generate qemu options
#
case "$tag" in
raw) KVM_EXTRAS="-drive file=$src,cache=none,format=raw";;
raw-*) KVM_EXTRAS="-drive file=$src,cache=none,format=raw,if=${tag#raw-}";;
hdd-*) KVM_EXTRAS="-drive file=$src,cache=none,if=${tag#hdd-}";;
hda) KVM_EXTRAS="-drive file=$src,cache=none";;
sda) KVM_EXTRAS="-drive file=$src,cache=none,if=scsi";;
vda) KVM_EXTRAS="-drive file=$src,cache=none,if=virtio";;
nfs)
KVM_INITRD=$initrd
KVM_KERNEL=$kernel
KVM_APPEND="ip=dhcp root=/dev/nfs rw nfsroot=${KVM_NFS:=10.0.100.10}:$loc,tcp,soft,intr,nolock console=$tty"
;;
9p)
KVM_INITRD=$initrd
KVM_KERNEL=$kernel
KVM_APPEND="virtfsroot=9p::root9p boot=virtfs console=$tty"
KVM_EXTRAS="-virtfs local,path=$loc,mount_tag=root9p,security_model=none"
;;
*)
log "Unknown boot type: $tag"
return 1
esac
return 0
}
run() {
local arg=$1; shift
# just pass-through other args
local qemu_opt="$(echo $@ | awk -F-- '{ print $1 }')"
local boot_opt="$(echo $@ | awk -F-- '{ print $2 }')"
# setup boot configuration
findboot $arg || die "Failed to boot: $arg"
#
# NOTE:
# - snapshot saves to $TMPDIR
#
$NORUN sudo TMPDIR=${TMPDIR:=/var/tmp} ${QEMU:=kvm} \
-nographic -m ${KVM_MEM:=256M} \
-k ja -echr 0x14 \
-net nic,model=virtio,macaddr=$(macgen-qemu 0 $PPID) \
-net bridge,br=${KVM_IF0:=vz-fg} \
-net nic,model=virtio,macaddr=$(macgen-qemu 1 $PPID) \
-net bridge,br=${KVM_IF1:=vz-bg} \
${KVM_KERNEL:+-kernel $KVM_KERNEL} \
${KVM_INITRD:+-initrd $KVM_INITRD} \
${KVM_APPEND:+-append "$KVM_APPEND $boot_opt"} \
$KVM_EXTRAS $qemu_opt
}
test $# -gt 0 || usage
run "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment