#!/bin/bash

#getting the config
source /etc/nlvmi/nlvmi.conf
if [ $LOGLEVEL -gt "1" ]; then echo "configuration loaded"; fi

#checking directories
echo $VMDIRECTORY | while read line; do IFS='|' read -r -a array
	for dir in "${array[@]}"; do
		if [ ! -d $dir ]; then echo "VMDIRECTORY wrong, $dir does not exist"; exit 1; fi
	done
done <<< "$line"

if [ ! -d $RUNDIRECTORY ]; then if [ $LOGLEVEL -gt "1" ]; then echo "creating $RUNDIRECTORY"; fi; mkdir -p $RUNDIRECTORY; fi

#checking database
function checkdb {
    if [ $DATABASETYPE == "sqlite" ]; then
        if [ ! -e $SQLITEFILE ]; then echo "sqlite configured, but db-file not present! create the db first!"; exit 1; fi
	SQCHECK=`sqlite3 $SQLITEFILE "SELECT name FROM sqlite_master WHERE type='table' AND name='vms'"`
	if [ $SQCHECK == "vms" ]; then
		if [ $LOGLEVEL -gt "1" ]; then echo "DB ready to use"; fi
	else
		echo "error accessing sqlite!"
		exit 1;
	fi
echo "sqlite ready to use";
    elif [ $DATABASETYPE == "mariadb" ]; then
        DBCON="mysql --disable-pager -u $MARIAUSER -p$MARIAPASS -h $MARIAHOST $MARIADB"
        declare -a DBC=`echo "SHOW TABLES FROM $MARIADB; " | $DBCON | sed 1d`
        if [ -z $DBC ]; then
            echo "mariadb connection failed"; exit 1
        fi
    fi
    return 0
}

#check if we are root and wrap if we are not
U=`/usr/bin/whoami`
if [ $U != "root" ]; then
	if [ ! -z $1 ]; then A=$1; else A="bla"; fi
	if [ ! -z $2 ]; then B=$2; else B="bla"; fi
	if [ ! -z $3 ]; then C=$3; else C="bla"; fi
	/usr/bin/wrap-nlvmi $A $B $C && exit
fi

#creating database
function createdb {
    if [ $LOGLEVEL -gt "1" ]; then echo "going to create the db"; fi
    if [ $DATABASETYPE == "sqlite" ]; then
        sqlite3 $SQLITEFILE "CREATE TABLE vms (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
                    vmname VARCHAR(50) NOT NULL,
		    user VARCHAR(50) NOT NULL,
                    server VARCHAR(50),
                    arch VARCHAR(50) NOT NULL,
		    cputype VARCHAR(50),
		    cpus INTEGER,
		    memory INTEGER,
                    usbdev VARCHAR(50),
                    kblang VARCHAR(50),
		    custom VARCHAR(50),
                    bootoption VARCHAR(2) NOT NULL,
		    autostart INTEGER,
                    drive1 VARCHAR(50),
		    format1 VARCHAR(50),
                    drive2 VARCHAR(50),
		    format2 VARCHAR(50),
                    drive3 VARCHAR(50),
		    format3 VARCHAR(50),
                    cdrom VARCHAR(50),
                    tapdev1 VARCHAR(50),
                    macaddr1 VARCHAR(50),
                    brdev1 VARCHAR(50),
                    tapdev2 VARCHAR(50),
                    macaddr2 VARCHAR(50),
                    brdev2 VARCHAR(50),
                    tapdev3 VARCHAR(50),
                    macaddr3 VARCHAR(50),
                    brdev3 VARCHAR(50),
                    vncport INTEGER,
                    websocket INTEGER,
                    vncpasswort VARCHAR(50)
	);"
        sqlite3 $SQLITEFILE "CREATE TABLE users (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
                    username VARCHAR(50) NOT NULL,
                    password VARCHAR(255),
		    admin INTEGER
	);"
	chown -R nobody $SQLITEFILE
    fi
    checkdb && echo "DB creation successful!" || (echo "Failed to create the DB"; exit 1)
}

#autostart VMs
function vmautostart {
	if [ $DATABASETYPE == "sqlite" ]; then
		sqlite3 $SQLITEFILE "SELECT id FROM vms WHERE autostart=1" | while read line; do
			IFS='|' read -r -a array <<< "$line"
			vmstart ${array[0]}
		done

	fi
}

#start single VM
function vmstart {
	if [ -z $1 ]; then echo "function start needs an id!"; exit 1; fi
	if [ $LOGLEVEL -gt "1" ]; then echo "startvm function entered for vmid $1"; fi
	sqlite3 $SQLITEFILE "SELECT * FROM vms WHERE id=$1" | while read line; do
			IFS='|' read -r -a array <<< "$line"
			if ! `id -u ${array[2]} &>/dev/null`; then
				useradd ${array[2]} -d /run/nlvmi -g nlvmi -M -s /bin/false -G kvm;
				if [ $LOGLEVEL -gt "1" ]; then echo "user ${array[2]} created"; fi
			fi
			if [ -e $RUNDIRECTORY/${array[1]}.* ]; then
				if [ $LOGLEVEL -gt "1" ]; then echo "chowning pid and monfiles "; fi
				chown ${array[2]}:nlvmi $RUNDIRECTORY/${array[1]}.*
			fi
                        if [ ! -z ${array[5]} ]; then CPUTYPE="-cpu ${array[5]}"; fi
                        if [ ! -z ${array[6]} ]; then SMP="-smp ${array[6]}"; fi
                        if [ ! -z ${array[7]} ]; then MEMORY="-m ${array[7]}"; fi
                        if [ ! -z ${array[8]} ]; then USBDEV="-usb -device usb-ehci,id=ehci -device usb-${array[8]},bus=usb-bus.0"; fi
                        if [ ! -z ${array[10]} ]; then CUSTOM="${array[10]}"; fi
                        if [ ! -z ${array[13]} ]; then DRIVE1="-drive file=${array[13]}"; chown ${array[2]}:nlvmi ${array[13]}; fi
                        if [ ! -z ${array[14]} ]; then FORMAT1=",format=${array[14]},if=virtio"; fi
                        if [ ! -z ${array[15]} ]; then DRIVE2="-drive file=${array[15]}"; chown ${array[2]}:nlvmi ${array[15]}; fi
                        if [ ! -z ${array[16]} ]; then FORMAT2=",format=${array[16]},if=virtio"; fi
                        if [ ! -z ${array[17]} ]; then DRIVE3="-drive file=${array[17]}"; chown ${array[2]}:nlvmi ${array[17]}; fi
                        if [ ! -z ${array[18]} ]; then FORMAT3=",format=${array[18]},if=virtio"; fi
                        if [ ! -z ${array[19]} ]; then CDROM="-cdrom ${array[19]}"; fi
                        if [ ! -z ${array[20]} ]; then TAPDEV1="-netdev tap,ifname=${array[20]},script=no,id=net0"; tunctl -t ${array[20]} -u ${array[2]} && ifconfig ${array[20]} up; fi
                        if [ ! -z ${array[21]} ]; then MACADDR1="-net nic,macaddr=${array[21]},model=virtio,netdev=net0"; fi
			if [ ! -z ${array[22]} ]; then BRDEV1="${array[22]}"; brctl addif ${array[22]} ${array[20]}; fi
                        if [ ! -z ${array[23]} ]; then TAPDEV2="-netdev tap,ifname=${array[23]},script=no,id=net0"; tunctl -t ${array[23]} -u ${array[2]} && ifconfig ${array[23]} up; fi
                        if [ ! -z ${array[24]} ]; then MACADDR2="-net nic,macaddr=${array[24]},model=virtio,netdev=net0"; fi
			if [ ! -z ${array[25]} ]; then BRDEV2="${array[25]}"; brctl addif ${array[25]} ${array[23]}; fi
                        if [ ! -z ${array[26]} ]; then TAPDEV3="-netdev tap,ifname=${array[26]},script=no,id=net0"; tunctl -t ${array[26]} -u ${array[2]} && ifconfig ${array[26]} up; fi
                        if [ ! -z ${array[27]} ]; then MACADDR3="-net nic,macaddr=${array[27]},model=virtio,netdev=net0"; fi
			if [ ! -z ${array[28]} ]; then BRDEV3="${array[28]}"; brctl addif ${array[28]} ${array[26]}; fi
			if [ ! -z ${array[30]} ]; then WEBSOCK=",websocket=${array[30]}"; else WEBSOCK=""; fi
                        if [ ! -z ${array[29]} ]; then VNCPORT="-vnc :${array[29]}$WEBSOCK,password"; fi
                        COMMAND=(su - ${array[2]} -s /bin/bash -c "${array[4]} -enable-kvm $CPUTYPE $MEMORY $SMP -boot ${array[11]} $USBDEV -k ${array[9]} -daemonize $DRIVE1$FORMAT1 $DRIVE2$FORMAT2 $DRIVE3$FORMAT3 $CDROM $MACADDR1 $TAPDEV1 $MACADDR2 $TAPDEV2 $MACADDR3 $TAPDEV3 $VNCPORT $CUSTOM -pidfile $RUNDIRECTORY/${array[1]}.pid -monitor unix:$RUNDIRECTORY/${array[1]}.mon,server,nowait")
			if [ $LOGLEVEL -gt "1" ]; then echo ${COMMAND[@]}; fi
			`"${COMMAND[@]}"`
			#Set VNC Password
			echo "change vnc password ${array[31]}" | socat - unix-connect:$RUNDIRECTORY/${array[1]}.mon >/dev/null
	done
	export VMFOUND="yes"
}

#stop VM
function vmstop {
        if [ ! -e $RUNDIRECTORY/$1.pid ]; then echo "pidfile $RUNDIRECTORY/$1.pid does not exist"; exit 1; fi
        if [ $LOGLEVEL -gt "1" ]; then echo "stopvm function entered for VM $1"; fi
        sqlite3 $SQLITEFILE "SELECT id,vmname FROM vms WHERE vmname='$1'" | while read line; do
                        IFS='|' read -r -a array <<< "$line"
                        echo "system_powerdown" | socat - unix-connect:$RUNDIRECTORY/${array[1]}.mon >/dev/null
			sleep 5s
                        STOPPED="no"
			COUNTER=0
                        while [ $STOPPED = "no" ]; do
				if [ $COUNTER == 200 ]; then
					kill `cat $RUNDIRECTORY/${array[1]}.pid`
					echo "${array[1]} forcefully killed!";
					STOPPED="yes"
				fi
				((COUNTER++))
	                        ps -ef | grep `cat $RUNDIRECTORY/${array[1]}.pid` | grep -v grep >/dev/null || STOPPED="yes"
				sleep 1s
                        done
        done
}

#stopall
function stopall {
	sqlite3 $SQLITEFILE "SELECT id,vmname FROM vms" | while read line; do
		IFS='|' read -r -a array <<< "$line"
		ps -ef | grep `cat $RUNDIRECTORY/${array[1]}.pid` | grep -v grep >/dev/null && (vmstop ${array[1]} &)
	done
}

#check if VM is running
function checkvm {
	if [ -z $1 ]; then echo "checkvm needs one argument!"; exit 1; fi
        ps -ef | grep `cat $RUNDIRECTORY/$1.pid` | grep -v grep >/dev/null && echo "VM is running" || echo "VM is not running"
}


#mainloop
if [ $# -gt 0 ]; then
    	if [ $1 == "createdb" ]; then
		createdb
    	elif [ $1 == "autostart" ]; then
		vmautostart
	elif [ $1 == "checkvm" ]; then
		if [ -z $2 ]; then echo "checkvm needs two arguments"; fi
		checkvm $2
	elif [ $1 == "start" ]; then
		if [ -z $2 ]; then echo "start needs a vmname!"; exit 1; fi
		VMFOUND="no"
		if [ $LOGLEVEL -gt "1" ]; then echo "searching for vmname $2"; fi
		sqlite3 $SQLITEFILE "SELECT id FROM vms WHERE vmname='$2'" | (while read line; do
			IFS='|' read -r -a arrays <<< "$line"
			declare VMFOUND="yes"
			export "$VMFOUND"
			vmstart $arrays
		done
			if [[ $VMFOUND == "no" ]]; then echo "no VM with that name found!"; exit 1; fi)
	elif [ $1 == "stop" ]; then
		if [ -z $2 ]; then echo "stop needs a vmname!"; exit 1; fi
		VMFOUND="no"
		if [ $LOGLEVEL -gt "1" ]; then echo "searching for vmname $2"; fi
		sqlite3 $SQLITEFILE "SELECT id FROM vms WHERE vmname='$2'" | (while read line; do
			IFS='|' read -r -a arrays <<< "$line"
			declare VMFOUND="yes"
			export "$VMFOUND"
echo "nana"
			vmstop $2
		done
			if [[ $VMFOUND == "no" ]]; then echo "no VM with that name found!"; exit 1; fi)
	elif [ $1 == "stopall" ]; then
		stopall
	elif [ $1 == "checkvm" ]; then
		if [ -z $2 ]; then echo "checkvm needs a vmname!"; exit 1; fi
		if [ -e $RUNDIRECTORY/$2.mon ]; then echo $2 running; else echo $2 stopped; fi
	fi
else
    checkdb
fi
