#!/bin/bash

# Copyright 2018 Nikos Giotis, Athens, GR
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
#  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# vms-parse
# Purpose: more qemu virtual machines ! A simple parser for a set of
#          predefined keys in an associative array. Used by vms script.

vmsconf="$HOME/.vms/vms.conf"
if [ ! -f $vmsconf ]; then
    echo "Can't find vms.conf"; exit 1
fi
. "$vmsconf"

valid_vm() {
    if [ "${VM[name]}" == "" ]; then
        echo 'vm does not exist'
        exit 1
    fi

    if [ "${VM[uuid]}" == "" ]; then
        echo 'vm[uuid] is missing'
        exit 1
    fi
}

check_vm() {
    valid_vm
    pid=$( pgrep -f "${VM[uuid]}" )
    if [ "$pid" != "" ]; then
        echo -n "${VM[name]} is running as "
        echo $pid
        exit 1
    fi
}

get_rundir() {
    rundir="/var/run/${VM[name]}"
    if [ "${VM[secure]}" != "yes" ] && [ "$(id -u)" != "0" ]; then
        rundir="$HOME/.vms/run/${VM[name]}"
    fi
    echo $rundir
}

create_rundir() {
    RUNDIR=$(get_rundir)
    if [ -d $RUNDIR ]; then
        rm -rf $RUNDIR
    fi
    mkdir -p $RUNDIR
}

parse_vm() {
    declare -n selected_vm=$1
    VM[name]=${selected_vm[name]}
    VM[uuid]=${selected_vm[uuid]}
    VM[arch]=${selected_vm[arch]}
    for attr in ${!selected_vm[*]}; do
        VM[$attr]=${selected_vm[$attr]}
    done
    for attr in ${!selected_vm[*]}; do
        parse_attribute $attr
    done
    VM[pid]=$(get_rundir).pid
}

# ---- ?? -- review function names ..

unset VM; declare -A VM

valid_VM() {
    parse_vm $1
    valid_vm
}

secure_VM() {
    parse_vm $1
    if [ "${VM[secure]}" == "yes" ] && [ "$(id -u)" != "0" ]; then
        echo "no"
    else
        echo "yes"
    fi
}

rundir_VM() {
    parse_vm $1
    if [ "${VM[name]}" == "" ]; then
        echo 'vm does not exist'
        exit 1
    fi
    if [ "${VM[uuid]}" == "" ]; then
        echo 'vm[uuid] is missing'
        exit 1
    fi
    echo $(get_rundir)
}

process_VM() {
    parse_vm $1
    if [ "${VM[name]}" == "" ]; then
        echo 'vm does not exist'
        exit 1
    fi
    if [ "${VM[uuid]}" == "" ]; then
        echo 'vm[uuid] is missing'
        exit 1
    fi
    pid=$( pgrep -f "${VM[uuid]}" )
    if [ "$pid" != "" ]; then
        pgrep -f "${VM[uuid]}"
    fi
}

vnc_VM() {
    parse_vm $1
    if [ "${VM[vnc]}" != "" ]; then
        echo ${VM[vnc]}
    fi
}

status_VM() {
    parse_vm $1
    check_vm
}

info_VM() {
    parse_vm $1
    if [ "${VM[name]}" == "" ]; then
        echo "$1 does not exist"
        exit 1
    fi
    attrs=$(for attr in ${!VM[*]}; do echo $attr; done | sort)
    for attr in $attrs; do
        printf "%8s: %s\n" "$attr" "${VM[$attr]}"
    done
}

setup_VM() {
    parse_vm $1
    check_vm || exit 1
    create_rundir || exit 1
#    if [ ! -f ${VM[disk01]} ]; then
#        echo ${VM[disk01]} does not exist
#        exit 1
#    fi
}

parse_attribute() {
    if [[ $1 == disk* ]]; then
        DISKS="$DISKS -drive file=${VM[$1]}"
    elif [[ $1 == vde* ]]; then
        VDES="$VDES -netdev vde,id=${VM[$1]}"
    elif [[ $1 == br* ]]; then
        BRS="$BRS -netdev bridge,id=${VM[$1]}"
    elif [[ $1 == nic* ]]; then
        NICS="$NICS -device ${VM[$1]}"
    elif [[ $1 == extra* ]]; then
        EXTRAS="$EXTRAS ${VM[$1]}"
    elif [[ $1 == cpu ]]; then
        CPU="-cpu ${VM[cpu]}"
    elif [[ $1 == mem ]]; then
        MEM="-m ${VM[mem]}"
    elif [[ $1 == smp ]]; then
        SMP="-smp ${VM[smp]}"
    elif [[ $1 == rtc ]]; then
        RTC="-rtc ${VM[rtc]}"
    elif [[ $1 == bootcd ]]; then
        BOOTCD="-cdrom ${VM[bootcd]} -boot once=d"
    elif [[ $1 == vnc ]]; then
        VNC="-vnc :${VM[vnc]}"
    elif [[ $1 == kvm ]]; then
        if [[ ${VM[kvm]} == yes ]]; then
            KVM="-enable-kvm"
        fi
    elif [[ $1 == log ]]; then
        if [[ ${VM[log]} == yes ]]; then
            LOG="-D $(get_rundir).log"
        fi
    elif [[ $1 == daemon ]]; then
        if  [[ ${VM[daemon]} == yes ]]; then
            DAEMON='-daemonize'
        fi
    elif [[ $1 == secure ]]; then
        if [[ ${VM[secure]} == yes ]]; then
            rundir=$(get_rundir)
            SECURE="-runas nobody -daemonize -chroot $rundir"
        fi
    elif [[ $1 == serial ]]; then
        if [[ ${VM[serial]} == yes ]]; then
            SERIAL="-chardev socket,id=serial0,path=$(get_rundir).serial,server,nowait -serial chardev:serial0"
        fi
    elif [[ $1 == monitor ]]; then
        if [[ ${VM[monitor]} == yes ]]; then
            CONSOLE="-chardev socket,id=monitor,path=$(get_rundir).monitor,server,nowait -monitor chardev:monitor"
        fi
    fi
}
