# 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