#!/usr/local/bin/cbsd
#v12.0.4
CBSDMODULE="jail,sys"
MYARG="mode"
MYOPTARG="arch baseonly jname service ver"
MYDESC="CBSD service wrapper"
ADDHELP="\

${H3_COLOR}Description${N0_COLOR}:

 service(8) wrapper for CBSD. Control (start/stop/etc.) or list system services.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}jname=${N0_COLOR}     - work in with jail. Also can be path to basejail.
 ${N2_COLOR}mode=${N0_COLOR}      - work mode, "list" or "action":
              - list   - to show service list but apply IGNORE_SERVICES list
                         from srvbrowser.conf file;
              - action - passthru command to service, e.g:
                'stop', 'start', 'onestop', 'onestart', 'status', 'enable', 'disable';
 ${N2_COLOR}baseonly=${N0_COLOR}  - when 1, show services only from FreeBSD 
                    distribition (use basejail dir).
 ${N2_COLOR}service=${N0_COLOR}   - specify service name for mode=action.

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd service jname=jail1 mode=action sshd enable
 # cbsd service jname=jail1 mode=action sshd start
 # cbsd service jname=jail1 mode=list
 # cbsd service mode=list baseonly=1 jname=/usr/jails/basejail/base_amd64_amd64_13.0

${H3_COLOR}See also${N0_COLOR}:

 cbsd sysrc --help

"

EXTHELP="modules/bsdconf.d"

. ${subrdir}/nc.subr
unset jname baseonly arch ver service
cbsd_api=0
jname=
ojname=
. ${cbsdinit}

[ -n "${jname}" ] && ojname="${jname}"

. ${system}

srv_list()
{
	readconf ${platform}-srvbrowser.conf

	local _i _x _skip
	srv_list=

	for _i in $( ${exec_cmd} -l ); do
		_skip=0
		for _x in ${IGNORE_SERVICES}; do
			[ "${_x}" = "${_i}" ] && _skip=1
		done
		[ ${_skip} -eq 0 ] && srv_list="${srv_list} ${_i}"
	done

	for i in ${srv_list}; do
		echo ${i}
	done
}

# -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)
service_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} ${ENV_CMD} NOCOLOR=1 /usr/local/bin/cbsd service 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}"
}

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

# MAIN
emulator="jail" # for jname_is_multiple

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

# jname can be as path, detect it:
prefix=$( substr --pos=0 --len=1 --str=${jname} )
if [ "${prefix}" = "/" ]; then
	[ ! -r ${jname}/bin/sh ] && err 1 "${N1_COLOR}${CBSD_APP}: file hier not found: ${N2_COLOR}${jname}${N0_COLOR}"
	jname_as_path=1
else
	jname_as_path=0
fi

# check for cloud function when CBSDfile exist
Makefile="${CBSD_PWD}/CBSDfile"
if [ ${jname_as_path} -eq 0 -a -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

if [ -n "${all_jail_list}" ]; then
	jail_list="${all_jail_list}"
else
	jail_list=
	jname_is_multiple
fi

if [ -n "${jail_list}" ]; then
	num_jails=0
	for i in ${jail_list}; do
		num_jails=$(( num_jails + 1 ))
	done
	if [ ${num_jails} -eq 1 ]; then
		jname="${jail_list}"
		unset jail_list
	fi
fi

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

	task_owner="service_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

	case "${mode}" in
		list)
			task_owner="service_multiple_list"
			service_multi_init -c "${_args}" -o ${task_owner} -n "service list"
			;;
		action)
			task_owner="service_multiple_action"
			service_multi_init -c "${_args}" -o ${task_owner} -n "service action"
			;;
	esac

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

cmd=

# trim for jname=, service=, mode= and action= in "$*"
for i in $*; do
	prefix5=
	prefix6=
	prefix8=
	prefix9=

	prefix5=$( substr --pos=0 --len=5 --str="${i}" )
	[ "${prefix5}" = "mode=" ] && continue

	prefix6=$( substr --pos=0 --len=6 --str="${i}" )
	[ "${prefix6}" = "jname=" ] && continue

	prefix8=$( substr --pos=0 --len=8 --str="${i}" )
	[ "${prefix8}" = "service=" ] && continue

	prefix9=$( substr --pos=0 --len=9 --str="${i}" )
	[ "${prefix9}" = "baseonly=" ] && continue

	if [ -n "${cmd}" ]; then
		cmd="${cmd} ${i}"
	else
		cmd="${service} ${i}"
	fi
done

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="${SERVICE_CMD} ${cmd}"
		echo "[debug] exec $jname: $jexec_cmd ${exec_cmd}"
		${jexec_cmd} ${exec_cmd}
	done
	exit 0
fi

[ -z "${jname}" ] && err 1 "${N1_COLOR}please set: ${N2_COLOR}${jname}${N0_COLOR}"

## MAIN ##
if [ ${jname_as_path} -eq 1 ]; then
	if [ "${baseonly}" = "1" ]; then
		[ ! -d "${jname}/dev" ] && err 1 "${N1_COLOR}no such /dev: ${N2_COLOR}${jname}${N0_COLOR}"
		exec_cmd="${CHROOT_CMD} ${jname} ${SERVICE_CMD}"
		${MOUNT_CMD} -t devfs devfs ${BASE_DIR}/dev
		TRAP="${TRAP} ${UMOUNT_CMD} ${BASE_DIR}/dev;"
		trap "${TRAP}" HUP INT ABRT BUS TERM EXIT
	else
		exec_cmd="${SERVICE_CMD}"
	fi
else
	data=
	. ${subrdir}/rcconf.subr
	[ $? -eq 1 ] && err 1 "${N1_COLOR}No such jail: ${N2_COLOR}${jname}${N0_COLOR}"
	[ ${jid} -eq 0 ] && err 1 "Jail is offline"
	[ ! -d "${data}/etc" ] && err 1 "${N1_COLOR}No such etc dir: ${N2_COLOR}${data}/etc${N0_COLOR}"
#	permit any action, e.g: configtest ?
	[ ${baserw} -eq 1 ] && path=${data}
	exec_cmd="jexec jname=${jname} ${SERVICE_CMD}"
fi

case "${mode}" in
	list)
		srv_list
		;;
	*)
		[ -z "${cmd}" ] && err 1 "${N1_COLOR}Empty command${N0_COLOR}"
		${exec_cmd} ${cmd}
		errcode=$?
		;;
esac

exit ${errcode}
