#!/usr/local/bin/cbsd
#v13.0.9
MYARG="name"
MYOPTARG="lease_time lock pass skip"
MYDESC="return next free available nic by mask"
CBSDMODULE="sys"
ADDHELP="

${H3_COLOR}Description${N0_COLOR}:

Return next free available nic by mask. To avoid collision/race this script
use file-based lease db.

${H3_COLOR}Options${N0_COLOR}:

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}lease_time${N0_COLOR} - <num>, lease time in seconds, default: '6'.
 ${N2_COLOR}name${N0_COLOR}       - nic mask, e.g: 'epair', 'bridge'.

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd get-next-nic name=epair
 # cbsd get-next-nic name=bridge

"

. ${subrdir}/nc.subr
lock=1
pass=
lease_time=6
. ${cbsdinit}

# $1 - nicname (eg: bridge)
# if nicname=epair we search as epairXa
# show first available nic by type
# example:
#  ttt=$( get_next_nic bridge )
# return 1 when error
get_next_nic()
{
	local _i _j _epair _A _skiplist
	local _num=
	local _lease_file="${tmpdir}/get_next_nic.lease"
	local _lockfile_skiplist=
	local _cur_time _lease_time_end _lease_time
	local _skipme

	[ -z ${1} ] && return 1
	[ "${1}" = "epair" ] && _epair="a"

	# we need exclusive lock and lease time to prevent race condition
	# when function called at same time simultaneously.
	# Use file as lock/lease db.

	# todo: internal lockf for function
	_rotate_lease_file=$( rotate_lease_file -l ${_lease_file} )

	for _i in $( ${IFCONFIG_CMD} -l ); do
		if [ -n "${_rotate_lease_file}" ]; then
			_rotate_lease_file="${_rotate_lease_file} ${_i}"
		else
			_rotate_lease_file="${_i}"
		fi
	done

	for _num in $( ${JOT_CMD} 1000 ); do

		_skipme=0

		if [ -n "${_epair}" ]; then
			_checkif="${1}${_num}${_epair}"
		else
			_checkif="${1}${_num}"
		fi

		if [ -n "${_rotate_lease_file}" ]; then
			for _j in ${_rotate_lease_file}; do
				if [ "${_checkif}" = "${_j}" ]; then
					_skipme=1
					break
				fi
			done
		fi

		[ ${_skipme} -eq 1 ] && continue

		${IFCONFIG_CMD} ${_checkif} >/dev/null 2>&1

		if [ $? -eq 1 ]; then
			# no such/free interface
			_cur_time=$( ${DATE_CMD} +%s )
			_lease_time_end=$(( _cur_time + lease_time ))
			echo "${1}${_num}:${_lease_time_end}" >> ${_lease_file}
			echo "${1}${_num}" && return 0
		fi
	done

	return 1
}

LOCKFILE="${ftmpdir}/get_next_nic.lock"

# we need the atomicity of the operation to avoid collision
if [ -z "${pass}" ]; then
	if [ "${lock}" = "1" ]; then
		# rebuild arg list ( + add pass )
		# Pass '"' as \" in cmd
		INIT_IFS="${IFS}"
		IFS="~"
		cmd="$@"
		IFS="${INIT_IFS}"
		while [ -n "${1}" ]; do
			IFS="~"
			strpos --str="${1}" --search="="
			_pos=$?
			if [ ${_pos} -eq 0 ]; then
				shift
				continue
			fi
			_arg_len=$( strlen ${1} )
			_pref=$(( _arg_len - _pos ))
			ARG=$( substr --pos=0 --len=${_pos} --str="${1}" )
			VAL=$( substr --pos=$(( ${_pos} +2 )) --len=${_pref} --str="${1}" )
			if [ -z "${ARG}" -o -z "${VAL}" ]; then
				shift
				continue
			fi
			#printf "${ARG}='${VAL}' "
			shift
		done
		exec ${LOCKF_CMD} -s -t60 ${LOCKFILE} /usr/local/bin/cbsd get-next-nic ${cmd} pass=1
	fi
fi

get_next_nic "${name}"
exit $?
