#!/bin/bash
# -*- mode: sh; tab-width: 8; coding: utf-8-unix -*-

PREFIX=/usr/local
ROLE=proxy
base=proxy_libvirt_lib
# shellcheck disable=SC2154
[ -z "$USER" ] && USER=$(id -un )
# /sbin/ifconfig on Debian morons and /bin/ifconfig on Gentoo
. /usr/local/bin/usr_local_tput.bash || exit 2


. /usr/local/bin/proxy_ping_lib.bash || exit 2

## proxy_libvirt_test_dnsmasq
proxy_libvirt_test_dnsmasq () { DBUG proxy_libvirt_test_dnsmasq $* ;
    proxy_rc_service libvirtd status </dev/null >/dev/null || {
	DBUG $prog libvirtd not running ; return 0
    }

    if ls /var/lib/libvirt/dnsmasq/*conf >/dev/null 2>/dev/null ; then
	dbug $prog checking libvirtd dnsmasq conf
	PROXY_WLAN=$( proxy_get_if )
	retval=$?
	[ $retval -eq 0 -a -n "$PROXY_WLAN" ] || {
	    ERROR proxy_get_if empty wlan7 retval=$retval
	    return 2$retval
	}
	for elt in bind-interfaces except-interface=$PROXY_WLAN no-dhcp-interface=$PROXY_WLAN ; do
 	  for file in /var/lib/libvirt/dnsmasq/*conf ; do
	    if ! grep -q $elt $file ; then
		[ -f $file.$$ ] || cp -p $file $file.$$
		echo $elt >> $file
	      fi
	    done
	  done
	if ls /var/lib/libvirt/dnsmasq/*conf.$$ >/dev/null 2>/dev/null ; then
	    dbug $prog restarting libvirtd dnsmasq conf
	    # FixMe: use virsh net-update net-edit
	    # ps ax | grep dnsmasq|grep -v grep|while read pid rest ; do kill -HUP $pid; done
	    for file in  /var/lib/libvirt/dnsmasq/*conf.$$ ; do
		pid=$( grep ^pid-file= $file|sed -e 's/.*=//' )
		[ $? -ne 0 -o -z "$pid" ] && WARN $prog not pid-file in $file && continue
		[ -f $pid ] || dbug $prog no pid-file in $file && continue
		pid=$( cat $pid )
		dbug $prog HUPing libvirtd dnsmasq $pid
		kill -HUP $pid ||  WARN $prog error killing $file $pid && continue
	    done
	  fi
	fi

    return 0
}

## proxy_libvirt_clean_virbr1_rules
proxy_libvirt_clean_virbr1_rules () {
    local line
    proxy_iptables_save | \
	grep -e '-A LIBVIRT_[OUTINP]* -i virbr[12] .* --dport [56][378] -j ACCEPT' | \
	sed -e 's/-A/-D/' | while read line ; do
	proxy_iptables $line
	done
    return 0
}

## proxy_libvirt_no_autostart
proxy_libvirt_no_autostart () { DBUG proxy_libvirt_no_autostart $* ;
    proxy_libvirt_hung || return 1

    proxy_virsh net-list --autostart | while read n s a p ; do
	[ "$a" = yes ] || continue
	virsh net-autostart $n --disable || { ERROR $prog net-autostart $n --disable ; return 1 ; }
	dbug $prog net-autostart $n --disable
	[ "$s" = active ] || continue
	virsh net-destroy $n || { dbug $prog net-destroy $n ; return 2 ; }
	dbug $prog net-destroy $n
      done
    return 0
}

## proxy_libvirt_status tests and checks logs - noisy
proxy_libvirt_status () { proxy_libvirt_status_host $* ; return $? ; }
proxy_libvirt_status_host () { DBUG proxy_libvirt_status $* ;
    /etc/init.d/virtlogd status  >/dev/null || /etc/init.d/virtlogd start || return 1$?
    /etc/init.d/libvirtd status  >/dev/null || /etc/init.d/libvirtd start || return 2$?

    if ! proxy_rc_service libvirtd status >/dev/null ; then
	DBUG proxy_libvirt_status proxy_rc_service libvirtd start
	proxy_rc_service libvirtd start || return 3$?
    fi

    if ! proxy_rc_service libvirtd status >/dev/null ; then
	ERROR proxy_libvirt_status proxy_rc_service libvirtd not started
        return 4
    fi
    if [ ! -e /run/libvirt/libvirt-sock ] ; then
	WARN proxy_libvirt_status no /run/libvirt/libvirt-sock
    fi
    if [ ! -e /run/libvirt/virtlogd-sock ] ; then
	WARN proxy_libvirt_status no /run/libvirt/virtlogd-sock
    fi
    # virtlockd-sock

    # shellcheck disable=SC2154
    [ -z "$GATEW_DOM" ] && GATEW_DOM="$( proxy_testforge_get_gateway_dom )"
    if [ -n "$GATEW_DOM" ] ; then
	proxy_libvirt_list | grep -q $GATEW_DOM
	[ $? -ne 0 ] && DBUG proxy_libvirt_status $GATEW_DOM not in virsh list
	#? && return 3
    else
	WARN proxy_libvirt_status null GATEW_DOM
    fi
    return 0
}

## proxy_libvirt_restart
proxy_libvirt_restart () { DBUG proxy_libvirt_restart $* ;
    # tests restarts

    proxy_libvirt_start || return 3$?
    proxy_libvirt_test || return 4$?

    [ -x /etc/libvirt/hooks/network ] || return 7$?
    /etc/libvirt/hooks/network || return 8$?

    proxy_ping_firewall_restart
    # /etc/modules-load.d/firewall.conf

    return 0
}

## proxy_libvirt_start_guest
proxy_libvirt_start_guest () {
    local dire=$1

    [ ! -f /etc/init.d/qemu-guest-agent ] && return 0
    proxy_rc_service qemu-guest-agent status >/dev/null \
	|| proxy_rc_service qemu-guest-agent start || return 2$?

    return $?
}

# proxy_libvirt_test_host
proxy_libvirt_test_host () {
    local dire=$1
    [ -z "$dire" ] && MODE="$( proxy_whonix_mode )" && dire=$MODE
    [ -n "$MODE" ] || MODE=host
    if [ $MODE = tor ] ; then
	proxy_rc_service tor status >/dev/null || \
	    { echo ERROR: $prog tor is not running ; return 2 ; }
	# different for selector
    fi
    $PREFIX/bin/proxy_ping_test.bash to_tor || return 6$?
    return $?
}

# proxy_libvirt_test_guest
proxy_libvirt_test_guest () {
    [ -e /dev/virtio-ports/org.qemu.guest_agent.0 ] || \
	echo WARN: /dev/virtio-ports/org.qemu.guest_agent.0 not created
    proxy_rc_service qemu-guest-agent status
    return $?
}

## proxy_libvirt_status tests and checks logs - noisy
proxy_libvirt_test () { DBUG proxy_libvirt_test $* ;
    [ -e /dev/virtio-ports ] && proxy_libvirt_test_guest || \
	    proxy_libvirt_test_host
    return $?
}

## proxy_libvirt_status tests and checks logs - noisy
proxy_libvirt_test_host () { DBUG proxy_libvirt_test_host $* ;
    proxy_libvirt_status || return 1$?

    [ -f /var/log/libvirt/libvirtd.log ] && \
	INFO proxy_libvirt_test /var/log/libvirt/libvirtd.log && \
	tail /var/log/libvirt/libvirtd.log
    # shellcheck disable=SC2154
    [ -z "$GATEW_DOM" ] && GATEW_DOM="$( proxy_testforge_get_gateway_dom )"
    if [ -n "$GATEW_DOM" ] ; then
	if [ -f /var/log/libvirt/qemu/$GATEW_DOM.log ] ; then
	    INFO proxy_libvirt_test /var/log/libvirt/qemu/$GATEW_DOM.log
	    tail /var/log/libvirt/qemu/$GATEW_DOM.log
	else
	    WARN proxy_libvirt_test missing /var/log/libvirt/qemu/$GATEW_DOM.log
	fi
    else
	WARN proxy_libvirt_test null GATEW_DOM
    fi
    proxy_libvirt_test_dnsmasq || return 6$?

    return 0
}

## proxy_libvirt_start
proxy_libvirt_start () { DBUG proxy_libvirt_start $* ;
    proxy_ping_firewall_modules
    proxy_libvirt_hung || return 2

    proxy_rc_service libvirtd status >/dev/null 2>/dev/null || \
        proxy_rc_service libvirtd start || return 3$?

    return 0
}

## proxy_libvirt_hung
proxy_libvirt_hung () { DBUG proxy_libvirt_hung $* ;
    # 1 means hung
    [ -f /etc/init.d/libvirtd ] || return 0
    if [ ! -e /run/libvirt/libvirt-sock ] || ! proxy_rc_service libvirtd status >/dev/null ; then
	INFO proxy_libvirt_hung proxy_rc_service libvirtd start
	proxy_rc_service libvirtd start || return 1
	sleep $DELAY
    fi
    /etc/init.d/libvirtd status 2>/dev/null >/dev/null || return 1
    a=$( /etc/init.d/libvirtd status |grep '├─' |grep -c -v '/usr/s.*bin' )
    # hung processes will hang proxy_virsh list
    [ $? -eq 0 -a $a -gt 1 ] && {
	WARN proxy_libvirt_hung - too many subprocesses $a
	return 1
    }
    # ├─  820 /usr/sbin/libvirtd
    # ├─ 2221 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/Whonix-External.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper
    # ├─28153 /bin/sh /etc/libvirt/hooks/network Whonix-External plugged begin -
    # ├─28154 bash /usr/local/bin/proxy_libvirt_hook_network.bash Whonix-External plugged begin -
    return 0
}

## proxy_libvirt_list
proxy_libvirt_list () { DBUG proxy_libvirt_list $* ;
    local a
    proxy_libvirt_hung || return 10
    proxy_virsh list
    return $?
}

## proxy_libvirt_clean_iptables
proxy_libvirt_clean_iptables () {
    local i int dir dcp prot port

    for dir in i ; do
	for int in virbr2 virbr1; do
	    dcp=67
	    [ $dir = i ] || dcp=68
	    for port in 53 $dcp ; do
		[ $dir = i ] && table=INP || table=OUT
		for prot in udp tcp; do
		    proxy_iptables_save | grep -q -e "-A LIBVIRT_$table -i $int -p $prot -m $prot --dport $port -j ACCEPT" || continue
		    iptables -D LIBVIRT_$table -$dir $int -p $prot -m $prot --dport $port -j ACCEPT || \
			echo WARN: $?  -D LIBVIRT_$table -$dir $int -p $prot -m $prot --dport $port -j ACCEPT
		done
	    done
	done
    done

    for dir in o ; do
	for int in virbr2 virbr1; do
	    dcp=68
	    [ $dir = o ] || dcp=67
	    for port in 53 68 ; do
		table=OUT
		[ $dir = i ] && table=INP
		for prot in udp tcp; do
		    proxy_iptables_save | grep -q -e "-A LIBVIRT_$table -i $int -p $prot -m $prot --dport $port -j ACCEPT" || continue
		    iptables -D LIBVIRT_$table -$dir $int -p $prot -m $prot --dport $port -j ACCEPT || \
			echo WARN: $?  -D LIBVIRT_$table -$dir $int -p $prot -m $prot --dport $port -j ACCEPT
		done
	    done
	done
    done

    return 0
}

# DBUG 0=$0
base=proxy_libvirt_lib
if [ -x /usr/bin/basename ] && \
       [  $( basename -- "$0" .bash ) = $base \
	 -o $( basename -- "$0" .sh ) = $base ] ; then
    [ "$#" -eq 1 ] && [ "$1" = '-h' -o "$1" = '--help' ] && \
	echo USAGE: $0 && grep '^[a-z].*()\|^## ' $0 | sed -e 's/().*//' && exit 0
    "$@"
    exit $?
  fi
