#!/usr/local/bin/cbsd
#v11.2.1
MYARG="jname"
CBSDMODULE="jail"
ADDHELP="jconf=<path_to_file> - load and set settings from jconf\n"
EXTHELP="wf_jset.html"

. ${subr}

[ ! -f ${sharedir}/jail-arg ] && err 1 "${GREEN}no jail-arg file${NORMAL}";
. ${sharedir}/jail-arg

MYOPTARG="autorestart jconf ${JARG} nice"
MYDESC="Modify parameter for jail"
ADDHELP="mode=force for modification on the running jail\n"

. ${tools}
. ${strings}

init $*

emulator="jail"		# for jname_is_multiple
jname_is_multiple

if [ -n "${jail_list}" ]; then
	new_arg=

	for i in $*; do
		_is_jname=$( substr --pos=0 --len=5 --str=${i} )
		[ "${_is_jname}" = "jname" ] && continue
		new_arg="${new_arg} ${i}"
	done

	for jname in ${jail_list}; do
		jset jname=${jname} ${new_arg}
	done
	exit 0
fi

[ -z "${cbsd_queue_name}" ] && cbsd_queue_name="/clonos/jailscontainers/"
[ -z "${autorestart}" ] && autorestart=0

need_for_restart=0

# jid, interface, ip4_addr and jname must be set
modify_ipaddr()
{
	local _A _ip4_addr_old _pureip _inet _face _interface _IP4 _IP6 _MODIF _nIPs IFS _dhcp

	_A=$( cbsdsql local SELECT interface,ip4_addr,applytpl FROM jails WHERE jname=\"${jname}\" )
	sqllist "${_A}" _interface _ip4_addr_old applytpl

	if [ "${_interface}" = "0" ]; then
		${ECHO} "${argpart}: ${MAGENTA}on-the-fly currently disabled because option interface is "0"${NORMAL}"
		cbsdlogger NOTICE ${CBSD_APP}: modify_ipaddr: on-the-fly currently disabled because option interface is 0
		return 0
	fi

	IFS=","

	for _pureip in ${_ip4_addr_old}; do
		iptype ${_pureip}
		_inet=$?
		_iface=$( getnics-by-ip ip=${_pureip} )
		ipwmask ${_pureip}
		if [ -n "$IWM" ]; then
			case ${_inet} in
				1)
					_MODIF="inet"
					;;
				2)
					_MODIF="inet6"
					;;
			esac
			IFS=" "
			${ECHO} "${MAGENTA}Remove old IP: ${GREEN}/sbin/ifconfig ${_iface} ${_MODIF} ${IWM} -alias${NORMAL}"
			cbsdlogger NOTICE ${CBSD_APP}: modify_ipaddr: remove old IP: /sbin/ifconfig ${_iface} ${_MODIF} ${IWM} -alias
			/sbin/ifconfig ${_iface} ${_MODIF} ${IWM} -alias >/dev/null 2>/dev/null
			IFS=","
		fi
	done

	_IP4=""
	_IP6=""

	for _pureip in ${ip4_addr}; do
		if [ "${_pureip}" = "DHCP" ]; then
			_dhcp=$( dhcpd )
			if [ $? -eq 2 ]; then
				cbsdlogger WARNING ${CBSD_APP}: modify_ipaddr: No free IP address for DHCP in nodeippool
				err 1 "${MAGENTA}No free IP address for DHCP in nodeippool${NORMAL}"
			fi
			_pureip="${_dhcp}"
		fi
		iptype ${_pureip}
		_inet=$?
		_iface=$( getnics-by-ip ip=${_pureip} )
		ipwmask ${_pureip}
		if [ -n "$IWM" ]; then
			case ${_inet} in
				1)
					_MODIF="inet"
					if [ -z "${_IP4}" ]; then
						_IP4="${_pureip}"
					else
						_IP4="${_IP4},${_pureip}"
					fi
					;;
				2)
					_MODIF="inet6"
					if [ -z "${_IP6}" ]; then
						_IP6="${_pureip}"
					else
						_IP6="${_IP6},${_pureip}"
					fi
					;;
			esac
			[ "${mkhostsfile}" != "0" ] && mkjhosts ips="${IWM}" file="${data}/etc/hosts" hosts="${host_hostname}"
			IFS=" "
			${ECHO} "${MAGENTA}Setup new IP: ${GREEN}/sbin/ifconfig ${_iface} ${_MODIF} ${_pureip} alias${NORMAL}"
			cbsdlogger NOTICE ${CBSD_APP}: modify_ipaddr: setup new IP: /sbin/ifconfig ${_iface} ${_MODIF} ${_pureip} alias
			/sbin/ifconfig ${_iface} ${_MODIF} ${_pureip} alias
			IFS=","
		fi
	done

	IFS=" "

	[ -n "${_dhcp}" ] && ip4_addr=$( echo ${ip4_addr} | /usr/bin/sed s:DHCP:${_dhcp}:g )

	#construct ipX.addr string 
	_nIPs="ip4.addr=${_IP4} ip6.addr=${_IP6}"

	cbsdlogger NOTICE ${CBSD_APP}: modify_ipaddr: /usr/sbin/jail -m ${_nIPs} jid=${jid}
	/usr/sbin/jail -m ${_nIPs} jid=${jid}

	cbsdsql local UPDATE jails SET ${i}=\"${ip4_addr}\" WHERE jname=\"${jname}\"
	${ECHO} "${argpart}: ${MAGENTA}${ip4_addr}${NORMAL}"

	if [ -x "${moduledir}/cbsd_queue.d/cbsd_queue" ]; then
		[ "${cbsd_queue_name}" != "none" ] && cbsd_queue cbsd_queue_name=${cbsd_queue_name} id="${jname}" cmd=update ip4_addr="${ip4_addr}" status=1
	fi
}

# jid must be set
modify_allow_mount()
{
	cbsdsql local "UPDATE jails SET ${i}=\"${allow_mount}\" WHERE jname=\"${jname}\""
	/usr/sbin/jail -m allow.mount=${allow_mount} jid=${jid}
	${ECHO} "${argpart}: ${MAGENTA}${allow_mount}${NORMAL}"
}

# jid must be set
modify_allow_raw_sockets()
{
	cbsdsql local "UPDATE jails SET ${i}=\"${allow_raw_sockets}\" WHERE jname=\"${jname}\""
	/usr/sbin/jail -m allow.raw_sockets=${allow_raw_sockets} jid=${jid}
	${ECHO} "${argpart}: ${MAGENTA}${allow_raw_sockets}${NORMAL}"
}

# jid must be set
modify_allow_nullfs()
{
	local allow_mount

	cbsdsql local "UPDATE jails SET ${i}=\"${allow_nullfs}\" WHERE jname=\"${jname}\""
	/usr/sbin/jail -m allow.mount.nullfs=${allow_nullfs} jid=${jid}

	${ECHO} "${argpart}: ${MAGENTA}${allow_nullfs}${NORMAL}"
	[ ${allow_nullfs} -eq 0 ] && return 0

	# we need to force allow_mount too when allow_tmpfs sets to 1 and allow_mount is zero
	allow_mount=$( cbsdsql local "SELECT allow_mount FROM jails WHERE jname=\"${jname}\"" )
	if [ "${allow_mount}" = "0" ]; then
		cbsdsql local "UPDATE jails SET allow_mount=\"1\" WHERE jname=\"${jname}\""
		/usr/sbin/jail -m allow.mount=1 jid=${jid}
		${ECHO} "allow_mount: ${MAGENTA}1${NORMAL}"
	fi
}

# jid must be set
modify_allow_fusefs()
{
	local allow_mount

	cbsdsql local "UPDATE jails SET ${i}=\"${allow_fusefs}\" WHERE jname=\"${jname}\""
	/usr/sbin/jail -m allow.mount.fusefs=${allow_fusefs} jid=${jid}

	${ECHO} "${argpart}: ${MAGENTA}${allow_fusefs}${NORMAL}"
	[ ${allow_fusefs} -eq 0 ] && return 0

	# we need to force allow_mount too when allow_tmpfs sets to 1 and allow_mount is zero
	allow_mount=$( cbsdsql local "SELECT allow_mount FROM jails WHERE jname=\"${jname}\"" )
	if [ "${allow_mount}" = "0" ]; then
		cbsdsql local "UPDATE jails SET allow_mount=\"1\" WHERE jname=\"${jname}\""
		/usr/sbin/jail -m allow.mount=1 jid=${jid}
		${ECHO} "allow_mount: ${MAGENTA}1${NORMAL}"
	fi
}

# jid must be set
modify_allow_procfs()
{
	local allow_mount

	cbsdsql local "UPDATE jails SET ${i}=\"${allow_procfs}\" WHERE jname=\"${jname}\""
	/usr/sbin/jail -m allow.mount.procfs=${allow_procfs} jid=${jid}

	${ECHO} "${argpart}: ${MAGENTA}${allow_procfs}${NORMAL}"
	[ ${allow_procfs} -eq 0 ] && return 0

	# we need to force allow_mount too when allow_tmpfs sets to 1 and allow_mount is zero
	allow_mount=$( cbsdsql local "SELECT allow_mount FROM jails WHERE jname=\"${jname}\"" )
	if [ "${allow_mount}" = "0" ]; then
		cbsdsql local "UPDATE jails SET allow_mount=\"1\" WHERE jname=\"${jname}\""
		/usr/sbin/jail -m allow.mount=1 jid=${jid}
		${ECHO} "allow_mount: ${MAGENTA}1${NORMAL}"
	fi
}


# jid must be set
modify_allow_tmpfs()
{
	cbsdsql local "UPDATE jails SET ${i}=\"${allow_tmpfs}\" WHERE jname=\"${jname}\""
	/usr/sbin/jail -m allow.mount.tmpfs=${allow_tmpfs} jid=${jid}

	${ECHO} "${argpart}: ${MAGENTA}${allow_tmpfs}${NORMAL}"
	[ ${allow_tmpfs} -eq 0 ] && return 0

	# we need to force allow_mount too when allow_tmpfs sets to 1 and allow_mount is zero
	allow_mount=$( cbsdsql local "SELECT allow_mount FROM jails WHERE jname=\"${jname}\"" )
	if [ "${allow_mount}" = "0" ]; then
		cbsdsql local "UPDATE jails SET allow_mount=\"1\" WHERE jname=\"${jname}\""
		/usr/sbin/jail -m allow.mount=1 jid=${jid}
		${ECHO} "allow_mount: ${MAGENTA}1${NORMAL}"
	fi
}


# jid must be set
modify_allow_fdescfs()
{
	cbsdsql local "UPDATE jails SET ${i}=\"${allow_fdescfs}\" WHERE jname=\"${jname}\""
	/usr/sbin/jail -m allow.mount.fdescfs=${allow_fdescfs} jid=${jid}

	${ECHO} "${argpart}: ${MAGENTA}${allow_fdescfs}${NORMAL}"
	[ ${allow_fdescfs} -eq 0 ] && return 0

	# we need to force allow_mount too when allow_fdescfs sets to 1 and allow_mount is zero
	allow_mount=$( cbsdsql local "SELECT allow_mount FROM jails WHERE jname=\"${jname}\"" )
	if [ "${allow_mount}" = "0" ]; then
		cbsdsql local "UPDATE jails SET allow_mount=\"1\" WHERE jname=\"${jname}\""
		/usr/sbin/jail -m allow.mount=1 jid=${jid}
		${ECHO} "allow_mount: ${MAGENTA}1${NORMAL}"
	fi
}

# jid, nice must be set
modify_nice()
{

	local _formfile="${jailsysdir}/${jname}/helpers/jrctl.sqlite"

	if [ ! -r ${_formfile} ]; then
		${ECHO} "${MAGENTA}No such rctl file: ${GREEN}${_formfile}${NORMAL}"
		return 1
	fi

	cbsdsql ${_formfile} UPDATE forms set cur=\"${VAL}\" WHERE param=\"nice\"
	jrenice jname=${jname}
}

# jid, interface, ip4_addr and jname must be set
modify_cpuset()
{
	cbsdsql local UPDATE jails SET ${i}=\"${cpuset}\" WHERE jname=\"${jname}\"
	${ECHO} "${argpart}: ${MAGENTA}${cpuset}${NORMAL}"
	cpuset -c -l ${cpuset} -j ${jid}
}

# mount_src
modify_mount_src()
{
	local _ver _dst _mount_src

	#push new variable in tmp stack
	_mount_src="${mount_src}"

	. ${system}
	. ${jrcconf}

	#restore new variable
	mount_src="${_mount_src}"

	cbsdsql local "UPDATE jails SET ${i}=\"${mount_src}\" WHERE jname=\"${jname}\""

	${ECHO} "${argpart}: ${MAGENTA}${mount_src}${NORMAL}"

	. ${workdir}/universe.subr

	init_srcdir
	[ ! -d "${SRC_DIR}" ] && ${ECHO} "${MAGENTA}No such src dir: ${GREEN}${SRC_DIR}${NORMAL}"

	[ ${baserw} -eq 1 ] && path="${data}"
	_dst="${path}/usr/src"

	case "${mount_src}" in
		0)
			is_mounted ${_dst} && umount -f ${_dst}
			;;
		1)
			is_mounted ${_dst} && err 1 "${MAGENTA}Already mounted: ${GREEN}${_dst}${NORMAL}"
			[ ! -d "${_dst}" ] && mkdir -p ${_dst}
			${MOUNT_NULL_CMD} -oro ${SRC_DIR} ${_dst}
			;;
	esac
}


# mount_ports
modify_mount_ports()
{
	local _ver _dst _mount_ports

	#push new variable in tmp stack
	_mount_ports="${mount_ports}"

	. ${system}
	. ${jrcconf}

	#restore new variable
	mount_ports="${_mount_ports}"

	cbsdsql local "UPDATE jails SET ${i}=\"${mount_ports}\" WHERE jname=\"${jname}\""

	${ECHO} "${argpart}: ${MAGENTA}${mount_ports}${NORMAL}"

	[ ${baserw} -eq 1 ] && path="${data}"
	_dst="${path}/usr/ports"

	case "${mount_ports}" in
		0)
			is_mounted ${_dst}/distfiles && umount -f ${_dst}/distfiles
			is_mounted ${_dst} && umount -f ${_dst}
		;;
		1)
			[ ! -d /usr/ports ] && return 0
			is_mounted ${_dst} && err 1 "${MAGENTA}Already mounted: ${GREEN}${_dst}${NORMAL}"
			[ ! -d "${_dst}" ] && mkdir -p ${_dst}
			${MOUNT_NULL_CMD} -oro /usr/ports ${_dst}
			[ ! -d /usr/ports/distfiles ] && mkdir -p /usr/ports/distfiles
			${MOUNT_NULL_CMD} -orw /usr/ports/distfiles ${_dst}/distfiles
		;;
	esac
}


# mount_kernel
modify_mount_kernel()
{
	local _ver _dst _mount_kernel _src

	#push new variable in tmp stack
	_mount_kernel="${mount_kernel}"

	. ${system}
	. ${jrcconf}

	#restore new variable
	mount_kernel="${_mount_kernel}"

	cbsdsql local "UPDATE jails SET ${i}=\"${mount_kernel}\" WHERE jname=\"${jname}\""

	${ECHO} "${argpart}: ${MAGENTA}${mount_kernel}${NORMAL}"

	. ${workdir}/universe.subr
	init_kerneldir

	[ ${baserw} -eq 1 ] && path="${data}"
	_dst="${path}/boot/kernel"
	_src="${KERNEL_DIR}/boot/kernel"

	[ ! -d "${_src}" ] && err 1 "${MAGENTA}No such source kernel dir. Use buildkernel or repo for fetching kernel: ${GREEN}${_src}${NORMAL}"

	case "${mount_kernel}" in
		0)
			is_mounted ${_dst} && umount -f ${_dst}
			;;
		1)
			is_mounted ${_dst} && err 1 "${MAGENTA}Already mounted: ${GREEN}${_dst}${NORMAL}"
			[ ! -d "${_dst}" ] && /bin/mkdir -p ${_dst}
			${MOUNT_NULL_CMD} -oro ${_src} ${_dst}
			;;
	esac
}

need_action()
{
	eval VAL="\$$i"
	local oldval=

	case "${i}" in
		nic_hwaddr)
			oldval=$( cbsdsql ${jailsysdir}/${jname}/local.sqlite SELECT nic_hwaddr FROM jailnic )
			[ -z "${oldval}" ] && oldval="0"
			;;
		*)
			oldval=$( cbsdsql local SELECT ${i} FROM jails  WHERE jname=\"${jname}\" LIMIT 1 2>/dev/null )
			;;
	esac

	[ "${oldval}" != "${VAL}" ] && return 1

	return 0
}

update_jails()
{
	local tmpver=

	eval VAL="\$$i"

	# special word - we not update arch/ver to 'native'
	case "${i}" in
		arch)
			if [ "${VAL}" = "native" ]; then
				VAL=$( /usr/bin/uname -m )
				export $i="${VAL}"
			fi
			;;
		ver)
			if [ "${VAL}" = "native" ]; then
				tmpver=$( /usr/bin/uname -r )
				VAL=${tmpver%%-*}
				[ "${stable}" = "1" ] && VAL=${VAL%%.*}
				export $i="${VAL}"
			fi
			;;
		nic_hwaddr)
			cbsdsql ${jailsysdir}/${jname}/local.sqlite UPDATE jailnic SET nic_hwaddr=\"${VAL}\" WHERE name=\"epairb\"
			return 0
			;;
	esac

	if ! need_action; then
		cbsdsql local UPDATE jails SET ${i}=\"${VAL}\" WHERE jname=\"${jname}\"
		cbsdlogger NOTICE ${CBSD_APP}: ${argpart}: ${VAL}
		${ECHO} "${argpart}: ${MAGENTA}${VAL}${NORMAL}"

		# Update realtime info
		if [ -x "${moduledir}/cbsd_queue.d/cbsd_queue" ]; then
			case "${i}" in
				ip4_addr|host_hostname|protected)
					[ "${cbsd_queue_name}" != "none" ] && cbsd_queue cbsd_queue_name=${cbsd_queue_name} id="${jname}" cmd=update ip4_addr="${ip4_addr}" host_hostname="${host_hostname}" protected="${protected}" status=1
					;;
			esac
		fi

		need_for_restart=1
	fi
}

# MAIN
# here we get status from jstatus, not via jrcconf for non-overwriting params in args
jid=$( jstatus jname=${jname} )
[ $? -eq 0 ] && err 1 "${MAGENTA}No such jail: ${GREEN}${jname}${NORMAL}"

if [ -n "${jconf}" ]; then
	[ ! -r "${jconf}" ] && err 1 "${MAGENTA}No such jconf file: ${GREEN}${jconf}${NORMAL}"
	#jset jname=${jname} `/usr/bin/grep -v '#' ${jconf} | /usr/bin/grep .| /usr/bin/tr -d ";"`
	my_arg=$( /usr/bin/grep -v '#' ${jconf} | /usr/bin/grep . | /usr/bin/tr -d ";" | /usr/bin/sed 's/"/\\"/g' | /usr/bin/xargs )
	exec /bin/sh << EOF
/usr/local/bin/cbsd jset "$my_arg" autorestart=$autorestart
EOF
	exit 0

else
	my_arg="$@"
fi

for n in ${my_arg}; do

	argpart="${n%%=*}"

	[ "${argpart}" = "jconf" ] && continue
	[ "${argpart}" = "autorestart" ] && continue
	#[ "${argpart}" = "exec_stop" ] && continue
	#[ "${argpart}" = "exec_start" ] && continue
	[ "${argpart}" = "exec_poststop" ] && continue
	[ "${argpart}" = "exec_poststart" ] && continue

	for i in ${JARG} nice; do
		if [ "${argpart}" = "${i}" -a "${argpart}" != "jname" ]; then

			if need_action; then
				continue
			fi

			##### check for already running
			if [ ${jid} -ne 0  ]; then
				case "${argpart}" in
					"ip4_addr")
						cbsdlogger NOTICE ${CBSD_APP}: modify_ipaddr for ${jname}
						modify_ipaddr
						;;
					"cpuset")
						cbsdlogger NOTICE ${CBSD_APP}: modify_cpuset for ${jname}
						modify_cpuset
						;;
					"nice")
						cbsdlogger NOTICE ${CBSD_APP}: modify_nicee for ${jname}
						modify_nice
						;;
					astart|applytpl|floatresolv|exec_consolelog|devfs_ruleset|protected|hidden)
						update_jails
						;;
					mount_src)
						cbsdlogger NOTICE ${CBSD_APP}: modify_mount_src for ${jname}
						modify_mount_src
						;;
					mount_ports)
						cbsdlogger NOTICE ${CBSD_APP}: modify_mount_ports for ${jname}
						modify_mount_ports
						;;
					mount_kernel)
						cbsdlogger NOTICE ${CBSD_APP}: modify_mount_kernel for ${jname}
						modify_mount_kernel
						;;
					allow_mount)
						cbsdlogger NOTICE ${CBSD_APP}: modify_allow_mount for ${jname}
						modify_allow_mount
						;;
					allow_raw_sockets)
						cbsdlogger NOTICE ${CBSD_APP}: modify_allow_raw_sockets for ${jname}
						modify_allow_raw_sockets
						;;
					allow_nullfs)
						cbsdlogger NOTICE ${CBSD_APP}: modify_allow_nullfs for ${jname}
						modify_allow_nullfs
						;;
					allow_fusefs)
						cbsdlogger NOTICE ${CBSD_APP}: modify_allow_fusefs for ${jname}
						modify_allow_fusefs
						;;
					allow_tmpfs)
						cbsdlogger NOTICE ${CBSD_APP}: modify_allow_tmpfs for ${jname}
						modify_allow_tmpfs
						;;
					allow_procfs)
						cbsdlogger NOTICE ${CBSD_APP}: modify_allow_procfs
						modify_allow_procfs
						;;
					allow_fdescfs)
						cbsdlogger NOTICE ${CBSD_APP}: modify_allow_fdescfs
						modify_allow_fdescfs
						;;
					*)
						if [ ${autorestart} -eq 0 ]; then
							cbsdlogger NOTICE ${CBSD_APP}: on-the-fly currently unimplemented for ${argpart} for ${jname}
							${ECHO} "${argpart}: ${MAGENTA}on-the-fly currently unimplemented${NORMAL}"
						else
							update_jails
						fi
						;;
				esac
			else
				update_jails
			fi
		fi
	done
done

if [ ${need_for_restart} -eq 1 -a ${autorestart} -eq 1 ]; then
	cbsdlogger NOTICE ${CBSD_APP}: restart jail from jset via need_for_restart/autorestart flags for ${jname}
	jrestart ${jname}
fi

# exit code 0 is nessesary for dot()
exit 0
