#!/bin/sh
# -*- indent-tabs-mode: nil -*-

# PROVIDE: fbhyve
# REQUIRE: LOGIN FILESYSTEMS
# KEYWORD: shutdown nojail
#

# @(#)%%SIMPLEVERSIONTAG%%

#
# Add the following lines to /etc/rc.conf to enable bhyve:
#
# fbhyve_enable (bool):  Set to "NO" by default.
#                        Acts as default for all listed VMs.
#                        Set it to "YES" to enable bhyve.
# fbhyve_list (str):     Set to "" by default.
#                        Define the names of your VMs here.
# fbhyve_tmux_session_prefix (str):  All tmux session names will have this
#                                    prefix string.
# fbhyve_configdir (str): Where by default config files for all VMs live.
#                         Default: $PREFIX/etc/fbhyve
#
#
# fbhyve_<vm>_enable (bool):  Allow to enable or disable a specific VM.
#                             Set to $fbhyve_enable by default.
# fbhyve_<vm>_config (str):   The bhyve configuration file to use to.
#                             The default is $fbhyve_configdir/<vm>.conf
#

. /etc/rc.subr

name="fbhyve"
desc="Manage system bhyve virtual machines"
rcvar="fbhyve_enable"

start_precmd="fbhyve_pre_start"
stop_postcmd="fbhyve_post_stop"
status_cmd="fbhyve_status"


load_rc_config $name

: ${fbhyve_enable:="NO"}
: ${fbhyve_list=}
: ${fbhyve_tmux_session_prefix:="${name}_"}
: ${fbhyve_configdir:="%%FBHYVE_ETCDIR%%"}


_fbhyve_vm_exists() {
    local _p
    for _p in ${fbhyve_list}; do
        [ "${_p}" = "$1" ] && return 0;
    done
    return 1
}


if [ $# -eq 2 ]; then
    _vm="$2"
    if ! _fbhyve_vm_exists "${_vm}"; then
        echo "ERROR: no VM named \`${_vm}' in \`fbhyve_list'" 1>&2
        exit 1
    fi
    echo "-- VM: ${_vm} --"
    _session="${fbhyve_tmux_session_prefix}${_vm}"
    _window="${_session}_console"
    eval fbhyve_enable="\${fbhyve_${_vm}_enable:-${fbhyve_enable}}"
    eval fbhyve_config="\${fbhyve_${_vm}_config:-\"${fbhyve_configdir}/${_vm}.conf\"}"
else
    _ec=0
    _swap=$*; shift; _vmarglist=$*
    _vmlist=${_vmarglist:-${fbhyve_list}}
    set -- ${_swap}
    for _vm in ${_vmlist}; do
        "$0" "$1" "${_vm}"
        _vmec=$?
        if [ ${_vmec} -gt ${_ec} ]; then
            _ec=${_vmec}
        fi
    done
    exit ${_ec}
fi

_rundir="%%FBHYVE_RUNDIR%%"
pidfile="${_rundir}/${_vm}.pid"
procname="bhyve:"         # something like bhyve: <vmname> (bhyve)

required_dirs="${_rundir}"
required_files="${fbhyve_config}"

command="%%LOCALBASE%%/bin/tmux"

command_args="new-session -ds ${_session} -n ${_window} \"sh -c 'echo \\\$\\\$ >\\\"${pidfile}\\\"; /usr/sbin/bhyve -k \\\"${fbhyve_config}\\\" \\\"${_vm}\\\"'\""


fbhyve_status()
{
    local _pid _rc

    _rc=0
    _pid=$(check_pidfile "$pidfile" "$procname")
    if [ -n "${_pid}" ]; then
        echo "VM ${_vm} is running as pid $_pid."
    else
        echo "VM ${_vm} is not running."
        _rc=1
    fi

    if ${command} has-session -t ${_session} 2>/dev/null; then
	echo "tmux session ${_session} exists."
        if [ ${_rc} -gt 0 ]; then
            _rc=2
        fi
    else
	echo "tmux session ${_session} does not exist."
        if [ ${_rc} -gt 0 ]; then
            _rc=2
        fi
    fi
    return ${_rc}
}


fbhyve_pre_start() {
    if ! load_kld -m vmm vmm.ko; then
        echo "ERROR: Cannot load kernel module \`vmm'" 1>&2
        return 1
    fi
    if [ -e "/dev/vmm/${_vm}" ]; then
        echo "ERROR: VM \`${_vm}' already created in the VM monitor" 1>&2
        return 1
    fi
    if ${command} has-session -t "${_session}" 2>/dev/null; then
        echo "ERROR: tmux session \`${_session}' already exists" 1>&2
        return 1
    fi
    return 0
}


fbhyve_post_stop() {
    if [ -e "/dev/vmm/${_vm}" ]; then
        /usr/sbin/bhyvectl --vm="${_vm}" --destroy
    fi
    if ${command} has-session -t "${_session}" 2>/dev/null; then
        ${command} kill-session -t "${_session}"
    fi
    rm -f "${pidfile}"
    return 0
}


run_rc_command "$1"
