#!/usr/local/bin/cbsd
#v13.0.8
CBSDMODULE="jail"
MYARG=""
MYOPTARG="jname fromfile"
MYDESC="CBSD sysrc wrapper"
ADDHELP="\

${H3_COLOR}Description${N0_COLOR}:

sysrc(8) wrapper for CBSD. Safely edit system rc files in jail.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}jname=${N0_COLOR}   - work in with jail, can be mask.
 ${N2_COLOR}fromfile${N0_COLOR} - include file for read sysrc_enable, sysrc_disable list

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd sysrc jname=test ifconfig_eth0_ipv6+=\"inet6 accept_rtadv\"

 # cbsd sysrc jname='*' sshd_flags=\"-oUseDNS=no\"

 # cat > /tmp/myrc.txt <<EOF
sysrc_disable=\"syslogd cron\"
sysrc_enable=\"sshd inetd\"
EOF
 # cbsd sysrc jname=test fromfile=/tmp/myrc.txt

${H3_COLOR}See also${N0_COLOR}:

 cbsd service --help

"

EXTHELP="modules/bsdconf.d"

. ${subrdir}/nc.subr
cbsd_api=0
. ${cbsdinit}
. ${system}

#defines
_MYDIR=$( ${DIRNAME_CMD} `${REALPATH_CMD} $0` )

emulator="jail" # for jname_is_multiple
jail_list=
jname_is_multiple

# -n "name of the tools" - show <name> in Info string, e.g: -n jexec, -n "pkg install" ...
# -o uniq_name_of_the_task (one world)
sysrc_multi_init()
{
	local _jname

	while getopts "c:n:o:" opt; do
		case "${opt}" in
			c) cmd="${OPTARG}" ;;
			n) _multiple_consumer_name="${OPTARG}" ;;
			o) task_owner="${OPTARG}" ;;
		esac
		shift $(($OPTIND - 1))
	done

	[ -z "${task_owner}" ] && err 1 "${N1_COLOR}multiple_processing_spawn: empty -o multiple_task_owner${N0_COLOR}"

	. ${subrdir}/multiple.subr
	${ECHO} "${N1_COLOR}Hint: Press ${N2_COLOR}'Ctrl+t'${N1_COLOR} to see last logfile line for active task${N0_COLOR}" 1>&2
	task_id=
	task_id_cur=
	task_owner="${task_owner}"
	# spawn command for all jail
	for _jname in ${jail_list}; do
		task_id_cur=$( task mode=new logfile=${tmpdir}/${task_owner}.${_jname}.log.$$ client_id=${_jname} autoflush=0 owner=${task_owner} /usr/bin/env NOCOLOR=1 /usr/local/bin/cbsd sysrc jname=${_jname} ${cmd} 2>/dev/null )
		sleep 0.1               # dont brute taskdb
		if ! is_number "${task_id_cur}"; then
			task_id="${task_id} ${task_id_cur}"
		fi
	done

	multiple_task_id_all=$( echo ${task_id} | ${TR_CMD} " " "," )
	sleep 0.5
	multiple_processing_spawn -o ${task_owner} -n "${_multiple_consumer_name}"
}

if [ -z "${jname}" -a -n "${ojname}" ]; then
	# inherit jname env
	jname="${ojname}"
fi

# check for cloud function when CBSDfile exist
Makefile="${CBSD_PWD}/CBSDfile"
if [ -r "${Makefile}" ]; then
	[ -z "${CBSDFILE_RECURSIVE}" ] && ${ECHO} "${N1_COLOR}found CBSDfile: ${N2_COLOR}${Makefile}${N0_COLOR}"
	. ${Makefile}

	all_jail_list=$( ${GREP_CMD} -E '^jail_[a-zA-Z0-9_@%:][-a-zA-Z0-9_@%:]*\(\)$' ${Makefile} | ${XARGS_CMD} | ${TR_CMD} -d "()" | ${SED_CMD} s#jail_##g )
	[ -z "${all_jail_list}" ] && err 1 "${N1_COLOR}${CBSD_APP}: no jail found${N0_COLOR}"

	if [ -n "${jname}" ]; then
		found=0
		for i in ${all_jail_list}; do
			if [ "${i}" = "${jname}" ]; then
				found=1
				break
			fi
		done
		[ ${found} -eq 0 ] && err 1 "${N1_COLOR}${CBSD_APP}: no such jail: ${N2_COLOR}${jname}${N0_COLOR}"
		all_jail_list="${jname}"
	fi

	if [ -n "${CLOUD_URL}" -a -n "${CLOUD_KEY}" ]; then
		cbsd_api=1
	else
		cbsd_api=0
	fi
else
	cbsd_api=0
fi


# MAIN for multiple jails
if [ -n "${jail_list}" -a ${cbsd_api} -eq 0 ]; then
	# multiple
	if [ -n "${jail_list}" ]; then
		JLIST="${jail_list}"
	fi

	task_owner="sysrc_multiple_query"
	_args=

	# trim for jname= in "$*"
	for i in $*; do
		prefix=
		prefix=$( substr --pos=0 --len=6 --str="${i}" )
		[ "${prefix}" = "jname=" ] && continue
		if [ -n "${_args}" ]; then
			_args="${_args} ${i}"
		else
			_args="${i}"
		fi
	done
	sysrc_multi_init -c "${_args}" -o ${task_owner} -n "sysrc query"

	err 0 "${N1_COLOR}Multiple sysrc: ${N2_COLOR}done${N0_COLOR}"
fi

ARGS=

# exclude jname= and fromfile= params from args str, re-add quotes
OIFS="${IFS}"
IFS="~"

ARGS=$( while [ -n "${1}" ]; do
	IFS="~"
	strpos --str="${1}" --search="="
	_pos=$?
	if [ ${_pos} -eq 0 ]; then
		# not params=value form
		#printf "${1} "         # (printf handles -args (with dashes)
		echo -n "${1} "
		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}" )

	case "${ARG}" in
		fromfile|jname)
			shift
			continue
			;;
	esac

	printf "${ARG}=\"${VAL}\" "
	shift
done )

# strip extra space
ARGS=$( echo ${ARGS} | ${SED_CMD} 's/.$//' )
IFS="${OIFS}"

if [ ${cbsd_api} -eq 1 ]; then
	CURL_CMD=$( which curl )
	[ -z "${CURL_CMD}" ] && err 1 "${N1_COLOR}cloud up requires curl, please install: ${N2_COLOR}pkg install -y curl${N0_COLOR}"
	[ -z "${CBSDFILE_RECURSIVE}" ] && ${ECHO} "${N1_COLOR}main cloud api: ${N2_COLOR}${CLOUD_URL}${N0_COLOR}" 1>&2
	_cid=$( ${miscdir}/cbsd_md5 "${CLOUD_KEY}" )

	for jname in ${all_jail_list}; do
		[ -z "${jname}" ] && return 1
		_ssh=$( ${CURL_CMD} --no-progress-meter -H "cid:${_cid}" ${CLOUD_URL}/api/v1/status/${jname} 2>&1 )
		_ret=$?
		if [ ${_ret} -ne 0 ]; then
			${ECHO} "${N1_COLOR}${CBSD_APP} error: curl error: ${N2_COLOR}${_ssh}${N0_COLOR}"
			${ECHO} "${CURL_CMD} --no-progress-meter -H \"cid:XXXXX\" ${CLOUD_URL}/api/v1/status/${jname}"
			continue
		fi
		_ssh_pref=$( substr --pos=0 --len=3 --str="${_ssh}" )
		if [ "${_ssh_pref}" != "ssh" ]; then
			${ECHO} "${N1_COLOR}${CBSD_APP} error: curl error: ${N2_COLOR}${_ssh}${N0_COLOR}"
			${ECHO} "${CURL_CMD} --no-progress-meter -H \"cid:XXXXX\" ${CLOUD_URL}/api/v1/status/${jname}"
			continue
		fi
		_ssh_len=$( strlen "${_ssh}" )
		_ssh_post=$( substr --pos=5 --len=${_ssh_len} --str="${_ssh}" )
		#echo "${SSH_CMD} ${_ssh_post}"
		# rewrite
		if [ -n "${SUDO_USER}" ]; then
			if [ -r /home/${SUDO_USER}/.ssh/id_ed25519 ]; then
				_ssh_sudo_arg="-oIdentityFile=/home/${SUDO_USER}/.ssh/id_ed25519"
			elif [ -r /home/${SUDO_USER}/.ssh/id_rsa ]; then
				_ssh_sudo_arg="-oIdentityFile=/home/${SUDO_USER}/.ssh/id_rsa"
			else
				date
			fi
		fi
		jexec_cmd="${SSH_CMD} -tt -oStrictHostKeyChecking=no -oConnectTimeout=5 -oServerAliveInterval=10 ${_ssh_sudo_arg} ${_ssh_post}"
		exec_cmd="/usr/local/cbsd/misc/cbsdsysrc ${ARGS}"
		echo "[debug] exec $jname: $jexec_cmd ${exec_cmd}"
		${jexec_cmd} ${exec_cmd}
	done
	exit 0
fi

if [ -n "${fromfile}" ]; then
	if [ -r "${fromfile}" ]; then
		. ${fromfile}
	else
		err 1 "${N1_COLOR}${CBSD_APP}: unable to open fromfile: ${N2_COLOR}${fromfile}${N0_COLOR}"
	fi
fi

[ -z "${ARGS}" -a -z "${fromfile}" ] && err 1 "${N1_COLOR}Empty command${N0_COLOR}"

## MAIN ##
if [ -n "${jname}" ]; then
	. ${subrdir}/rcconf.subr
	[ $? -eq 1 ] && err 1 "${N1_COLOR}${CBSD_APP}: no such jail: ${N2_COLOR}${jname}${N0_COLOR}"

	[ ! -d ${data}/etc ] && err 1 "${N1_COLOR}${CBSD_APP}: no such /etc directory in jail: ${N2_COLOR}${jname}${N0_COLOR}"
	exec_cmd="/usr/local/cbsd/misc/cbsdsysrc -qf ${data}/etc/rc.conf"
else
	data=
	exec_cmd="/usr/local/cbsd/misc/cbsdsysrc"
fi

[ ! -f "${data}/etc/rc.conf" ] && ${TOUCH_CMD} ${data}/etc/rc.conf

if [ -z "${fromfile}" ];then
	echo "${exec_cmd} ${ARGS}"
	/bin/sh <<EOF
${exec_cmd} ${ARGS}
EOF
	ret=$?
else
	for i in ${sysrc_enable}; do
		${exec_cmd} ${i}_enable="YES"
	done

	for i in ${sysrc_disable}; do
		${exec_cmd} ${i}_enable="NO"
	done
fi

exit ${ret}
