#! /bin/sh
# Sun VirtualBox
# Linux kernel module init script

#
# Copyright (C) 2006-2009 Sun Microsystems, Inc.
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
# you can redistribute it and/or modify it under the terms of the GNU
# General Public License (GPL) as published by the Free Software
# Foundation, in version 2 as it comes in the "COPYING" file of the
# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
#

# chkconfig: 35 30 70
# description: VirtualBox Linux kernel module
#
### BEGIN INIT INFO
# Provides:       vboxdrv virtualbox-ose
# Required-Start: $remote_fs $network
# Required-Stop:  $remote_fs
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Short-Description: VirtualBox Linux kernel module
### END INIT INFO

. /lib/lsb/init-functions

test -d /usr/share/doc/virtualbox-ose -a -x /usr/bin/VBoxHeadless || exit 0

# Include virtualbox-ose defaults if available
[ -r /etc/default/virtualbox-ose ] && . /etc/default/virtualbox-ose

# set list of all active users if asked to do so
if [ "$SHUTDOWN_USERS" = "all" ]; then
	SHUTDOWN_USERS=""
	for i in /tmp/.vbox-*-ipc; do
		SHUTDOWN_USERS="$SHUTDOWN_USERS $(echo $i|cut -d'-' -f2)"
	done
fi

if [ "$LOAD_VBOXDRV_MODULE" != 1 ]; then
	log_success_msg "virtualbox-ose disabled; edit /etc/default/virtualbox-ose"
	exit 0
fi

running()
{
    lsmod | grep -q "$1[^_-]"
}

start()
{
	log_begin_msg "Starting VirtualBox kernel modules"
	
	if ! running vboxdrv; then
		# HACK: disable the hardware performance counter framework
		if [ -e /proc/sys/kernel/perf_counter_paranoid ]; then
			if [ $(cat /proc/sys/kernel/perf_counter_paranoid) -ne 2 ]; then
				log_warning_msg "Disabling the hardware performance counter framework"
				echo 2 > /proc/sys/kernel/perf_counter_paranoid 
			fi
		fi
		
		if ! modprobe vboxdrv > /dev/null 2>&1; then
			if ! find /lib/modules/`uname -r` -name "vboxdrv\.*" 2>/dev/null|grep -q vboxdrv; then
				log_failure_msg "No suitable module for running kernel found"
			else
				log_failure_msg "modprobe vboxdrv failed. Please use 'dmesg' to find out why"
			fi
			log_end_msg 1
			return 1
		fi
	fi
	
	if ! running vboxnetflt; then
		if ! modprobe vboxnetflt > /dev/null 2>&1; then
			if ! find /lib/modules/`uname -r` -name "vboxnetflt\.*" 2>/dev/null|grep -q vboxnetflt; then
				log_failure_msg "No suitable vboxnetflt module for running kernel found"
			else
				log_failure_msg "modprobe vboxnetflt failed. Please use 'dmesg' to find out why"
			fi
			log_end_msg 1
			return 1
		fi
	fi
	
	if ! running vboxnetadp; then
		if ! modprobe vboxnetadp > /dev/null 2>&1; then
			if ! find /lib/modules/`uname -r` -name "vboxnetadp\.*" 2>/dev/null|grep -q vboxnetadp; then
				log_failure_msg "No suitable vboxnetadp module for running kernel found"
			else
				log_failure_msg "modprobe vboxnetadp failed. Please use 'dmesg' to find out why"
			fi
			log_end_msg 1
			return 1
		fi
	fi
	
	log_end_msg 0
}

stop()
{
	log_begin_msg "Stopping VirtualBox kernel modules"
	
	if running vboxnetadp; then
		if ! rmmod vboxnetadp 2>/dev/null; then
			log_failure_msg "Cannot unload module vboxnetadp"
			log_end_msg 1
			return 1
		fi
	fi
	
	if running vboxdrv; then
		if running vboxnetflt; then
			if ! rmmod vboxnetflt 2>/dev/null; then
				log_failure_msg "Cannot unload module vboxnetflt"
				log_end_msg 1
				return 1
			fi
		fi
		
		if ! rmmod vboxdrv 2>/dev/null; then
			log_failure_msg "Cannot unload module vboxdrv"
			log_end_msg 1
			return 1
		fi
	fi
	
	log_end_msg 0
}

# enter the following variables in /etc/default/virtualbox-ose:
#   SHUTDOWN_USERS="foo bar"  
#     check for running VMs of user foo and user bar
#   SHUTDOWN=poweroff
#   SHUTDOWN=acpibutton
#   SHUTDOWN=savestate
#     select one of these shutdown methods for running VMs
stop_vms()
{
	if ! pidof VBoxSVC > /dev/null; then
		return 0
	fi
	
	wait=0
	
	for i in $SHUTDOWN_USERS; do
		if [ -d /tmp/.vbox-$i-ipc ]; then
			export VBOX_IPC_SOCKETID="$i"
			VMS=`VBoxManage --nologo list runningvms 2>/dev/null`
			if [ $? -eq 0 -a -n "$VMS" ]; then
				VMS=`echo "$VMS" | sed -e 's/^".*".*{\(.*\)}/\1/'`
				if [ "$SHUTDOWN" = "poweroff" ]; then
					log_action_msg "Powering off remaining VMs from user $i"
					for v in $VMS; do
						VBoxManage --nologo controlvm $v poweroff
						wait=10
					done
				elif [ "$SHUTDOWN" = "acpibutton" ]; then
					log_action_msg "Sending ACPI power button event to remaining VMs from user $i"
					for v in $VMS; do
						VBoxManage --nologo controlvm $v acpipowerbutton
						wait=30
					done
				elif [ "$SHUTDOWN" = "savestate" ]; then
					log_action_msg "Saving state of remaining VMs from user $i"
					for v in $VMS; do
						VBoxManage --nologo controlvm $v savestate
						wait=30
					done
				fi
			fi
		fi
	done
	
	# wait for some seconds when doing ACPI shutdown
	if [ "$wait" -ne 0 ]; then
		log_action_begin_msg "Waiting for $wait seconds for VM shutdown"
		sleep $wait
		log_action_end_msg 0
	fi
	return 0
}

dmnstatus()
{
	if running vboxdrv; then
		if running vboxnetflt; then
			if running vboxnetadp; then
				echo "VirtualBox kernel modules (vboxdrv, vboxnetflt and vboxnetadp) are loaded."
			else
				echo "VirtualBox kernel modules (vboxdrv and vboxnetflt) are loaded."
			fi
		else
		  echo "VirtualBox kernel module is loaded."
		fi
		
		for i in $SHUTDOWN_USERS; do
			if [ -d /tmp/.vbox-$i-ipc ]; then
				export VBOX_IPC_SOCKETID="$i"
				VMS=`VBoxManage --nologo list runningvms 2>/dev/null`
				if [ $? -eq 0 -a -n "$VMS" ]; then
					VMS=`echo "$VMS" | sed -e 's/^".*".*{\(.*\)}/\1/'`
					echo "The following VMs are currently running:"
					for v in $VMS; do
						echo "  $v"
					done
				fi
			fi
		done
		return 0
	else
		echo "VirtualBox kernel module is not loaded."
		return 3
	fi
}

case "$1" in
start)
	start
	;;
stop)
	stop_vms && stop
	;;
stop_vms)
	stop_vms
	;;
restart|force-reload)
	stop_vms && stop && start
	;;
status)
	dmnstatus
	;;
*)
	echo "Usage: $0 {start|stop|stop_vms|restart|force-reload|status}"
	exit 1
esac
