# Version: 20100414.2
## Aims:
# - Do not configure VM in this script - except vrdp port
# - If run as root, get list of VM's to action from /etc/vbox/init.d
# - If run as a user, get list of VM's to action from $HOME/.VirtualBox/init.d
## Actions:
# - start: run VM
# - stop: save VM state
# - status: showvminfo
# - restart|force-reload: start+stop
# - poweroff: send acpi power off sequence to the guest
## Todo:
# - fix the startvm incantation to get useful exit codes. eg nice will complain if a non-root user tries to use
# a value less than 0. sudo will complain if the user does not exist.
# VBoxHeadless probably has many things to complain about.
# - get list of VM's from /etc/vbox/init.d
# - tidy up comments, debug echo's, etc
# - make sure all variables are properly quoted. ie "$VM_NAME" instead of
# $VM_NAME
# - add GPL license
# - add debian update-rc.d control info: begin INIT info -> end init info
# from /etc/rc.d/skeleton
## Wishlist:
# - teleport control
# - make a debian package or get this included in the official VirtualBox debian package
### BEGIN INIT INFO
# Provides: vbox
# Required-Start: $network vboxnet vboxdrv
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: VirtualBox server autostart
# Description: Enable service provided by daemon.
### END INIT INFO
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/usr/sbin:/usr/bin:/sbin:/bin
MANAGE_CMD=/usr/bin/VBoxManage
HEADLESS_CMD=/usr/bin/VBoxHeadless
SCRIPTNAME=/etc/init.d/virtualbox
CONFIG_DIR=/etc/vbox/vms
### hacky internal configuration should *really* come from a config file
VM_NAME="Windows XP"
VM_OWNER="vbox"
VM_VRDP="3389"
VM_NICE="-1"
echo VM_NAME: $VM_NAME VM_OWNER: $VM_OWNER VM_NICE: $VM_VRDP VM_NICE=$VM_NICE
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
# Load the VERBOSE setting and other rcS variables
[ -f /etc/default/rcS ] && . /etc/default/rcS
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
# Load network defaults. Use this if there is any extra network stuff to do first.
[ -f /etc/vbox/network ] && . /etc/vbox/network
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
# get state
do_status
case "$vm_status" in
running)
echo "$VM_NAME" is already running
return 1
;;
"poweroff")
echo $VM_NAME is starting as user $VM_OWNER with priority $VM_NICE
# Need to sleep between startvm else we get a GURU_MEDITATION(crash)
sleep 1
## this command tested to start vm successfully. what a mouthful and the exit code is crud:
nice -${VM_NICE} sudo -H -u $VM_OWNER $HEADLESS_CMD --startvm "$VM_NAME" --vrdpport $VM_VRDP > /dev/null 2>&1 &
##
echo 'exit code:' $?
# case $? in
# 0)
# echo started "$VM_NAME"
# return 0
#;;
# *)
# echo failed to start "$VM_NAME"
# return 1
#;;
# esac
;;
saved)
echo $VM_NAME is resuming as user $VM_OWNER with priority $VM_NICE
# Need to sleep between startvm else we get a GURU_MEDITATION(crash)
sleep 1
## this command tested to start vm successfully. what a mouthful and the exit code is crud:
# we cannot change the vrdp port on a vm in saved state
nice -${VM_NICE} sudo -H -u $VM_OWNER $HEADLESS_CMD --startvm "$VM_NAME" > /dev/null 2>&1 &
##
echo 'exit code:' $?
# use return handler from poweroff
return 0
;;
*)
echo "$VM_NAME" is not in an awkward state: "$vm_status"
return 2
;;
esac
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
do_status
case "$vm_status" in
"poweroff"|saved)
echo "$VM_NAME" is already stopped. Exact state: "$vm_status"
return 1
;;
running)
sudo -H -u $VM_OWNER $MANAGE_CMD controlvm "$VM_NAME" savestate || {
echo Failed to stop "$VM_NAME".
return 2
}
echo "$VM_NAME" suspended.
return 0
;;
*)
echo $VM_NAME is in awkward state: $vm_status
return 3
;;
esac
}
do_poweroff()
{
### need to check if state is running
sudo -H -u $VM_OWNER $MANAGE_CMD controlvm "$VM_NAME" acpipowerbutton
##### need error handler *********************
}
#
# Display "State" field from showinfo action
#
do_status()
{
# sudo -H -u $VM_OWNER $MANAGE_CMD showvminfo "$VM_NAME"|grep "^State:\s*.*$"
#vm_status=`sudo -H -u $VM_OWNER $MANAGE_CMD showvminfo "$VM_NAME" | grep '^State' | sed 's/^State:\s*//' | sed 's/\s(since.*$//'`
vm_status=`sudo -H -u $VM_OWNER $MANAGE_CMD showvminfo "$VM_NAME" --machinereadable | grep 'VMState=' | cut -d '"' -f2`
#vm_status=$(VBoxManage showvminfo $VMNAME --machinereadable | grep 'VMState=' | cut -d '"' -f2)
}
case "$1" in
start)
# (#IFS=/
# cd $CONFPATH
# echo $CONFPATH
# pwd
# for conf in *.conf; do
# echo $CONFPATH/$conf
# . $CONFPATH/$conf
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $VM_NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
# done;)
;;
stop)
# (#IFS=/
# cd "$CONFPATH"
# for conf in *.conf; do
# . "$CONFPATH"/$conf
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $VM_NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2|3) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
# done;)
;;
restart|force-reload)
# (#IFS=/
# cd "$CONFPATH"
# for conf in *.conf; do
# . "$CONFPATH"/$conf
[ "$VERBOSE" != no ] && log_daemon_msg "Restarting $VM_NAME"
do_stop
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2|3) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
# done;)
;;
status)
# (#IFS=/
# cd "$CONFPATH"
# for conf in *.conf; do
# . "$CONFPATH"/$conf
do_status
echo "Status for $VM_NAME": ${vm_status}
# done;)
;;
poweroff)
do_poweroff
exit 3
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|poweroff|status}" >&2
exit 3
;;
esac