#!/bin/sh basedir="`dirname "$0"`/.." TAPUTIL="$basedir/bin/taputil" SUDO="/usr/bin/sudo" #VM_NAME="xp.intra.ogris.net" if [ -z "$VM_NAME" ]; then script="`basename "$0"`" script=${script%%.sh} VM_NAME=${script##[0-9]} port=${script%%$VM_NAME} fi VM_VNC=${VM_VNC:-$port} VM_MEM=${VM_MEM:-2048} VM_CPU=${VM_CPU:-"host"} VM_MACHINE=${VM_MACHINE:-"pc"} VM_CPUS=${VM_CPUS:-2} VM_CDROMS=${VM_CDROMS:-1} VM_EXTRA=${VM_EXTRA:-""} VM_LAUNCH_VNC=${VM_LAUNCH_VNC:-1} VM_FILE_NAME0=${VM_FILE_NAME0:-$VM_NAME} #VM_FILE_TYPE0="virtio" #VM_FILE_CACHE0="none" #... #VM_FILE_NAME9=... #VM_FILE_TYPE9=... #VM_FILE_CACHE9=... #VM_NET_MAC0=${VM_NET_MAC0:-"52:54:00:00:0$VM_MAC:00"} #VM_NET_TAP0=${VM_NET_TAP0:-"0$VM_VNC"} VM_NET_TYPE0=${VM_NET_TYPE0:-"virtio"} #VM_NET_BRIDGE0={$VM_NET_BRIDGE0:-"00"} #... #VM_NET_MAC3=${VM_NET_MAC0:-"52:54:00:00:0$VM_MAC:03"} #VM_NET_TAP3=... #VM_NET_TYPE3=... #VM_NET_BRIDGE3=... VM_PORT=${VM_PORT:-$((VM_VNC+6666))} VM_MAC=${VM_MAC:-$VM_VNC} VM_PIDDIR=${VM_PIDDIR:-"/tmp/kvmlib-$UID"} VM_PID=${VM_PID:-"$VM_PIDDIR/$VM_NAME.pid"} # for remote shutdown via net rpc: #VM_SHUT_DOMAIN="XP" #VM_SHUT_USER="administrator" #VM_SHUT_PASS="secret" #VM_SHUT_HOST="192.168.1.13" [ -z "$VM_NAME" ] && { echo "no VM_NAME" >&2; exit 1; } [ -z "$VM_VNC" ] && { echo "no VM_VNC" >&2; exit 1; } [ -x "$TAPUTIL" ] || { echo "no $TAPUTIL" >&2; exit 1; } [ -x "$SUDO" ] || { echo "no $SUDO" >&2; exit 1; } [ -z "$UID" ] && { echo "no UID set" >&2; exit 1; } if [ ! -d "$VM_PIDDIR" ]; then mkdir -p -m 0700 "$VM_PIDDIR" || exit 1 fi if [ `stat -c %a-%u $VM_PIDDIR` != "700-$UID" ]; then echo "$VM_PIDDIR is not owned by you and/or has lax permissions" >&2 exit 1 fi function vm_vnc() { local xpos=$((VM_VNC%2*850)) local ypos=$((VM_VNC/2*650)) nohup vncviewer :"$VM_VNC" -geometry "+$xpos+$ypos" >/dev/null 2>&1 & } function vm_nics() { local mode="$1" local nicmac local nictap local nictype local nicbridge local bridge local port local i nics="" for i in {0..3}; do eval nicmac=\$VM_NET_MAC$i eval nictap=\$VM_NET_TAP$i eval nictype=\$VM_NET_TYPE$i eval nicbridge=\$VM_NET_BRIDGE$i [ -z "$nicmac" -a -z "$nictap" -a -z "$nictype" -a -z "$nicbridge" ] && continue nicmac=${nicmac:-"52:54:00:00:0$VM_MAC:0$((i+1))"} bridge=`printf %02d $i` port=`printf %02d $VM_VNC` nictap=${nictap:-"${bridge}${port}"} nictype=${nictype:-"virtio"} nicbridge=${nicbridge:-"${bridge}"} if [ "$nictype" != "none" ]; then nics="$nics -net nic,vlan=$i,model=$nictype,macaddr=$nicmac \ -net tap,vlan=$i,ifname=tap$nictap,script=no,downscript=no" "$SUDO" "$TAPUTIL" "$mode" "$nictap" "$nicbridge" || exit 1 fi done } function vm_start() { local files local filename local filetype local filecache local i local have_cdrom local cdroms echo "Starting $VM_NAME" vm_nics "add" files="" for i in {0..9}; do eval filename=\$VM_FILE_NAME$i eval filetype=\$VM_FILE_TYPE$i eval filecache=\$VM_FILE_CACHE$i filetype=${filetype:-"virtio"} filecache=${filecache:-"none"} [ -n "$filename" -a "$filename" != "none" ] && files="$files \ -drive format=raw,cache=$filecache,file=$basedir/disks/$filename.raw,if=$filetype,discard=unmap,detect-zeroes=unmap" done have_cdrom=-1 for i in "$@"; do [ "$i" = "-cdrom" ] && have_cdrom=0 done cdroms="" for i in {0..3}; do [ $i -lt $VM_CDROMS -a $have_cdrom -ne $i ] && cdroms="$cdroms \ -drive readonly=on,media=cdrom,if=ide,bus=1,unit=$i" done qemu-system-x86_64 --enable-kvm -k de -rtc base=utc -daemonize -m "$VM_MEM" \ -name "$VM_NAME" -cpu "$VM_CPU" -machine "$VM_MACHINE" -smp "$VM_CPUS" \ $files \ $nics \ $cdroms \ -soundhw ac97 \ -balloon virtio \ -vnc :"$VM_VNC" -monitor tcp::"$VM_PORT",server,nowait \ -pidfile "$VM_PID" \ $VM_EXTRA \ "$@" sleep 1 if [ "$VM_LAUNCH_VNC" = "1" ]; then vm_vnc fi echo >/dev/tcp/localhost/$VM_PORT } function vm_kill() { echo "Killing $VM_NAME" p=`cat "$VM_PID"` || return rm -f "$VM_PID" kill -9 "$p" } function vm_term() { echo "Terminating $VM_NAME" p=`cat "$VM_PID"` || return kill "$p" echo -n "waiting 10 seconds for $VM_NAME to get terminated" for i in {0..10}; do sleep 1 echo -n "." p=`cat "$VM_PID" 2>/dev/null` || { echo "ok"; return; } kill -0 "$p" 2>/dev/null || { echo "ok"; rm -f "$VM_PID"; return; } done vm_kill } function vm_quit() { local i local p echo "Quitting $VM_NAME" echo quit >/dev/tcp/localhost/$VM_PORT echo -n "waiting 30 seconds for $VM_NAME to quit" for i in {0..30}; do sleep 1 echo -n "." p=`cat "$VM_PID" 2>/dev/null` || { echo "ok"; return; } kill -0 "$p" 2>/dev/null || { echo "ok"; rm -f "$VM_PID"; return; } done vm_term } function vm_stop() { local i local p echo "Stopping $VM_NAME" [ -n "$VM_SHUT_HOST" ] && net rpc shutdown -f \ -U "$VM_SHUT_DOMAIN"'\'"$VM_SHUT_USER"'%'"$VM_SHUT_PASS" -t 2 \ -I "$VM_SHUT_HOST" echo system_powerdown >/dev/tcp/localhost/$VM_PORT echo -n "waiting 150 seconds for $VM_NAME to shutdown" for i in {0..180}; do sleep 1 echo -n "." p=`cat "$VM_PID" 2>/dev/null` || { echo "ok"; return; } kill -0 "$p" 2>/dev/null || { echo "ok"; rm -f "$VM_PID"; return; } done vm_quit } function vm_cmd() { exec telnet localhost $VM_PORT } function vm_status() { echo -n "$VM_NAME: " p=`cat "$VM_PID" 2>/dev/null` || { echo "not running"; return; } kill -0 "$p" 2>/dev/null || { echo "not running"; return; } echo "pid=$p" } case "$1" in start) shift vm_start "$@" ;; stop) vm_stop vm_nics "del" ;; status) vm_status ;; quit) vm_quit vm_nics "del" ;; term) vm_term vm_nics "del" ;; kill) vm_kill vm_nics "del" ;; vnc) vm_vnc ;; cmd) vm_cmd ;; *) echo "usage: $0 [ option ... ]" >&2 exit 1 ;; esac