#!/bin/sh

prog="ctdb"

not_implemented_exit_code=1

usage ()
{
    cat >&2 <<EOF
Usage: $prog [-Y] cmd

A fake CTDB stub that prints items depending on the variables
FAKE_CTDB_PNN (default 0) depending on command-line options.
EOF
    exit 1
}

not_implemented ()
{
    echo "${prog}: command \"$1\" not implemented in stub" >&2
    exit $not_implemented_exit_code
}

# Don't set $POSIXLY_CORRECT here.
_temp=$(getopt -n "$prog" -o "Yvh" -l help -- "$@") || \
    usage

eval set -- "$_temp"

verbose=false
machine_readable=false

while true ; do
    case "$1" in
	-Y) machine_readable=true ; shift ;;
	-v) verbose=true ; shift ;;
	--) shift ; break ;;
	-h|--help|*) usage ;; # * shouldn't happen, so this is reasonable.
    esac
done

[ $# -ge 1 ] || usage

setup_tickles ()
{
    # Make sure tickles file exists.
    tickles_file="$CTDB_VARDIR/fake-ctdb/tickles"
    mkdir -p $(dirname "$tickles_file")
    touch "$tickles_file"
}

setup_pstore ()
{
    pstore_dir="$CTDB_VARDIR/fake-ctdb/pstore/$1"
    mkdir -p "$pstore_dir"
}

# For testing backward compatibility...
for i in $CTDB_NOT_IMPLEMENTED ; do
    if [ "$i" = "$1" ] ; then
	not_implemented "$i"
    fi
done

case "$1" in
    ip)
	# NOTE: all nodes share the same public addresses file.

	# This is completely stateless and IPs move unnecessarily.
	_f="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}"
	if [ -f "$_f" ] ; then
	    if $verbose ; then
		echo ":Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:"

	    else
		echo ":Public IP:Node:"
	    fi
	    # Here IPs are distributed across nodes in a stupid way...
	    _n=0
	    while read _ip _ifaces ; do
		case "_$ip" in
		    \#*) : ;;
		    *)
			# Find a node that is up... but don't loop forever.
			_orig=$_n
			while [ -f "${FAKE_CTDB_NODES_DOWN}/${_n}" ] ; do
			    _n=$(($_n + 1))
			    if [ _n -eq $FAKE_CTDB_NUMNODES ] ; then
				_n=0
			    fi
			    if [ $_n -eq $_orig ] ; then
				_n=-1 # Never down!  :-)
			    fi
			done
			if $verbose ; then
			    # If more than 1 interface, assume all
			    # addresses are on the 1st.
			    _first_iface="${_ifaces%%,*}"
			    # Only show interface if address is on
			    # this node.
			    _my_iface=""
			    if [ "PNN:$_n" = $(ctdb -Y pnn) ]; then
				_my_iface="$_first_iface"
			    fi
			    echo ":${_ip}:${_n}:${_my_iface}:${_first_iface}:${_ifaces}:"
			else
			    echo ":${_ip}:${_n}:"
			fi
		esac
	    done <"$_f"
	fi
	;;
    pnn|xpnn)
	# Defaults to 0
	echo "PNN:${FAKE_CTDB_PNN:-0}"
	;;
    gettickles)
	setup_tickles
	echo ":source ip:port:destination ip:port:"
	while read src dst ; do
	    echo ":${src}:${dst}:"
	done <"$tickles_file"
	;;
    addtickle)
	setup_tickles
	echo "$2 $3" >>"$tickles_file"
	;;
    deltickle)
	setup_tickles
	_t=$(grep -F -v "$2 $3" "$tickles_file")
	echo "$_t" >"$tickles_file"
	;;
    pstore)
	setup_pstore "$2"
	cat "$4" >"${pstore_dir}/$3"
	;;
    pfetch)
	setup_pstore "$2"
	cat "${pstore_dir}/$3" >"$4" 2>/dev/null
	;;
    ifaces)
	# Assume -Y.
	echo ":Name:LinkStatus:References:"
	_f="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}"
	if [ -r "$_f" ] ; then
	    while read _ip _iface ; do
		case "_$ip" in
		    \#*) : ;;
		    *)
			_status=1
			# For now assume _iface contains only 1.
			if [ -f "{FAKE_CTDB_IFACES_DOWN}/${_iface}" ] ; then
			    _status=0
			fi
			# Nobody looks at references
			echo ":${_iface}:${_status}:0"
		esac
	    done <"$_f" |
	    sort -u
	fi
	;;
    setifacelink)
	# Existence of file means CTDB thinks interface is down.
	_f="${FAKE_CTDB_IFACES_DOWN}/$2"
	case "$3" in
	    up)   rm -f "$_f" ;;
	    down) touch "$_f" ;;
	    *)
		echo "ctdb setifacelink: unsupported interface status $3"
		exit 1
	esac
	;;
    getdebug)
	case "${CTDB_DEBUGLEVEL:-0}" in
	    -3) _t="EMERG"  ;;
	    -2) _t="ALERT"  ;;
	    -1) _t="CRIT"   ;;
	    0) _t="ERR"     ;;
	    1) _t="WARNING" ;;
	    2) _t="NOTICE"  ;;
	    3) _t="INFO"    ;;
	    4) _t="DEBUG"   ;;
	    *) _t="ERR"     ;;
	esac

	cat<<EOF
:Name:Level:
:${_t}:${CTDB_DEBUGLEVEL}:
EOF
	;;
    checktcpport)
	for _i in $FAKE_TCP_LISTEN ; do
	    if [ "$2" = "${_i##*:}" ] ; then
		exit 98
	    fi
	done

	exit 0
	;;
    scriptstatus)
	$machine_readable || not_implemented "$1, without -Y"
	[ "$2" != "all" ] || not_implemented "scriptstatus all"
	# For now just assume everything is good.
	echo ":Type:Name:Code:Status:Start:End:Error Output...:"
	for _i in "$CTDB_BASE/events.d/"*.* ; do
	    _d1=$(date '+%s.%N')
	    _b="${_i##*/}" # basename

	    _f="$FAKE_CTDB_SCRIPTSTATUS/$_b"
	    if [ -r "$_f" ] ; then
		read _code _status _err_out <"$_f"
	    else
		_code="0"
		_status="OK"
		if [ ! -x "$_i" ] ; then
		    _status="DISABLED"
		    _code="-8"
		fi
		_err_out=""
	    fi
	    _d2=$(date '+%s.%N')
	    echo ":${2:-monitor}:${_b}:${_code}:${_status}:${_d1}:${_d2}:${_err_out}:"
	done
	;;
    *)
	not_implemented "$1"
esac
