#!/bin/bash
SZ_PATTERN_TIMEOUT="mount.nfs: Connection timed out"
SZF_SYSTEMCTL="/usr/syno/bin/synosystemctl"
SZ_SYSTEMCTL_GET_ENABLE_STATUS="${SZF_SYSTEMCTL} get-enable-status"
SZ_SYSTEMCTL_GET_ACTIVE_STATUS="${SZF_SYSTEMCTL} get-active-status"
SZ_NFS_SERVER="nfs-server"
EINVAL=22

function nfsping()
{
	local output=""
	local ret=0
	local times_ping=${2:-1}
	local enable_status=""
	local active_status=""
	local timeout_cnt=0

	if ! [[ "$times_ping" =~ ^[1-9][0-9]*$ ]]; then
		echo 'Invalid argument. "times of ping" should be a positive decimal.'
		return $EINVAL
	fi

	# Return 0 (healthy) if nfs-server is disabled
	enable_status=$(${SZ_SYSTEMCTL_GET_ENABLE_STATUS} ${SZ_NFS_SERVER})
	if [ ${enable_status} == "disabled" ]; then
		return 0
	fi

	# Return 1 if nfs-server is failed
	active_status=$(${SZ_SYSTEMCTL_GET_ACTIVE_STATUS} ${SZ_NFS_SERVER})
	if [ ${active_status} == "failed" ]; then
		return 1
	fi

	# Ping NFS server to confirm health in other situations
	# Create dummy mount point
	if [ ! -d "/mnt" ]; then
		mkdir -p "/mnt"
	fi

	for ((i=0; i<times_ping; i++))
	do
		# Ping NFS server with NFSPROC_NULL to confirm nfsd can response a request.
		# Timeout might be 1s for PMAPPROC_GETPORT or 10s for NFSPROC_NULL.
		output=$(/sbin/mount.nfs --fake localhost:/ /mnt -o vers=3,soft,retry=0,tcp 2>&1)
		ret=$?
		if [ "$SZ_PATTERN_TIMEOUT" =  "$output" ]; then
			timeout_cnt=$[$timeout_cnt + 1]
		fi
		if [ "$ret" -eq 0 ]; then
			# Once NFS server can respond normally, we think it is not dead totally.
			return 0
		fi
	done
	##
	# If NFS server cannot respond normally (ret != 0) all the time, then we check timeout count
	# to decide if NFS server is still alive.
	#
	# If timeout count == ping times, we recognize the NFS server is not healthy,
	# and return 1 to trigger HA failover.
	#
	# If timeout count != ping times, we return the last error code.
	##
	if [ $timeout_cnt -eq $times_ping ]; then
		ret=1
	else
		# Prevent error of 'mount' tool from triggering HA failover
		[ $ret -eq 1 ] && ret=${EINVAL}
	fi

	return $ret
}

case $1 in
	--ping)
		nfsping "$@"
		ret=$?
	;;
	*)
		echo "Usage $0 --ping [times of ping]"
	;;
esac
exit $ret
