#!/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
name=
. ${cbsdinit}

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

# $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= _name=
	local _lease_file="${tmpdir}/get_next_nic.lease"
	local _cur_time _lease_time_end
	local _skipme _lease_file_skip _newif

	[ -z ${1} ] && return 1
	_name="${1}"
	[ "${_name}" = "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
	_lease_file_skip=$( rotate_lease_file -l ${_lease_file} )

	# append skip list by local ifaces
	for _i in $( ${IFCONFIG_CMD} -l ); do
		if [ -n "${_lease_file_skip}" ]; then
			_lease_file_skip="${_lease_file_skip} ${_i}"
		else
			_lease_file_skip="${_i}"
		fi
	done

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

		_skipme=0

		# due to epair has extra postfix (a/b), store parent iface as _newif
		_newif="${_name}${_num}"

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

		if [ -n "${_lease_file_skip}" ]; then
			for _j in ${_lease_file_skip}; do
				if [ "${_newif}" = "${_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 "${_newif}:${_lease_time_end}" >> ${_lease_file}
			sync
			echo "${_newif}" && return 0
		fi
	done

	return 1
}

if [ -n "${pass}" ]; then
	get_next_nic "${name}"
	exit $?
fi

exec ${LOCKF_CMD} -s -t12 ${LOCKFILE} /usr/local/bin/cbsd get-next-nic "$*" pass=1
