#!/bin/bash
PSTORAGE_ISCSI_LIB=/usr/libexec/vstorage-iscsi/vstorage_functions
ROOT=""
IQN=""
PORTAL_ADDR=""
PORTAL_ADDR_COUNT=0
USER=""
ARGS=("${@}")
NEW_SCSI_TGT=""
NEW_SCSI_TRANSPORT=""
PARAM=""

function print_usage {
	exec 1>&2
	echo " "
	echo "Change parameters for specified iSCSI target."
	echo "Usage:"
	echo " $CTL_TOOL ${CMD} -t,--target IQN"
	echo "                       [-e,--engine ENGINE] [-s,--transport TRANSPORT]"
	echo "                       [-a,--address ADDR] [-u,--user USER] [-l,--limit TYPE=VALUE]"
	echo "Options:"
	echo "  -t,--target IQN                 target's IQN."
	echo "  -a,--address ADDR               New address for specified target."
	echo "  -u,--user USER                  New user name for CHAP authentication."
	echo "  -u -,--user -                   Disable CHAP authentication."
	echo "  -l, --limit TYPE=VALUE          IO/IOPS limit (max_kbps, max_iops)."
	echo "  -e,--engine ENGINE              SCSI target engine (tgtd, tcm)"
	echo "  -s,--transport TRANSPORT        SCSI transport protocol (iscsi, fc)"
	echo " "
	exit 1
}

function check_param {

	if [ -z "$PARAM" ]; then
		PARAM="$1"
		return
	fi

	if [ -n "$PARAM" -a "$PARAM" != "$1" ]; then
		echo "Can't change different parameters at once." 1>&2
		print_usage
	fi
}

function parse_args {
	if [ ${#} -eq 0 ]; then
		echo "Command not specified, expected 'set'" 1>&2
		exit 1
	fi

	[ ${#} -eq 1 ] && print_usage

	LIMITS=()
	CMD="${1}"; shift
	while [ "${#}" -gt 0 ]; do
		case "${1}" in
			"-h"|"--help")
				print_usage
				;;
			"-r"|"--root")
				[ -z "${2}" ] && print_usage
				ROOT="${2}"
				shift
				shift
				;;
			"-t"|"--target")
				[ -z "${2}" ] && print_usage
				IQN="${2}"
				shift
				shift
				;;
			"-u"|"--user")
				[ -z "${2}" ] && print_usage
				USER="${2}"
				check_param USER
				shift
				shift
				;;
			"-a"|"--address")
				[ -z "${2}" ] && print_usage
				if [ -z "$PORTAL_ADDR" ] ; then
					PORTAL_ADDR="${2}"
				else
					PORTAL_ADDR="${PORTAL_ADDR} ${2}"
				fi
				check_param PORTAL_ADDR
				(( ++PORTAL_ADDR_COUNT ))
				shift
				shift
				;;
			"-l"|"--limit")
				[ -z "${2}" ] && print_usage
				LIMITS+=("${2}")
				shift
				shift
				;;
			"-e"|"--engine")
				[ -z "${2}" ] && print_usage
				NEW_SCSI_TGT="${2}"
				check_param NEW_SCSI_TGT
				shift
				shift
				;;
			"-s"|"--transport")
				[ -z "${2}" ] && print_usage
				NEW_SCSI_TRANSPORT="${2}"
				check_param NEW_SCSI_TRANSPORT
				shift
				shift
				;;
			*)
				echo "Unknown option '${1}'." 1>&2
				print_usage
				;;
		esac
	done

	if [ -z "$IQN" ] ; then
		echo "Target (-t,--target) must be specified." 1>&2
		print_usage
	fi

	if [ -z "$PARAM" ] && [ ${#LIMITS[@]} -eq 0 ] ; then
		echo "No parameters to set." 1>&2
		print_usage
	fi
}

function update_param() {
	local param="${1}"
	local value="${2}"

	tmp=`mktemp "${ISCSI_ROOT}/tmp/new-${param}-${IQN}.XXXXXXXX"`
	if [ $? -ne 0 ] ; then
		echo "Can't create temporary file." 1>&2
		return 1
	fi

	msg=`echo "$value" | echo_fsync "$tmp"`
	if [ $? -ne 0 ]; then
		echo "$msg" 1>&2
		echo "Unable save ${param} in $tmp" 1>&2
		rm -f "$tmp"
		return 2
	fi

	msg=`mv -f "$tmp" "$ISCSI_ROOT/$IQN/control/${param}" 2>&1`
	if [ $? -ne 0 ]; then
		echo "$msg" 1>&2
		echo "Failed to move $tmp in $ISCSI_ROOT/$IQN/control/${param}" 1>&2
		rm -f "$tmp"
		return 3
	fi

	return 0
}

function do_set_portal_addr() {
	local addr=$PORTAL_ADDR
	pcs_iscsi_set_env "$IQN" "fast_check"
	[ $? -ne 0 ] && return 1

	if [ "$SCSI_TRANSPORT" == "fc" -a "$PORTAL_ADDR_COUNT" -gt 1 ] ; then
		echo "Can't set more than one address for FC target" 1>&2
		return 2
	fi

	echo "[$PORTAL_ADDR]"
	PORTAL_ADDR=`${SCSI_TRANSPORT}_validate_addr "$PORTAL_ADDR"`
	[ $? -ne 0 ] && print_usage
	echo "-> [$PORTAL_ADDR]"

	update_param "address" "$PORTAL_ADDR"
	return $?
}

function do_set_scsi_target() {
	if [ "$NEW_SCSI_TGT" != "tgtd" -a "$NEW_SCSI_TGT" != "tcm" ] ; then
		echo "Unknown SCSI target engine \"${NEW_SCSI_TGT}\"" 1>&2
		print_usage
	fi

	pcs_iscsi_set_env "$IQN" "fast_check"
	[ $? -ne 0 ] && return 1

	[ "$SCSI_TGT" == "$NEW_SCSI_TGT" ] && return 0

	SCSI_TGT="${NEW_SCSI_TGT}"
	${SCSI_TGT}_check_scsi_transport
	[ $? -ne 0 ] && print_usage

	update_param "metadata" "${SCSI_TGT} ${SCSI_TRANSPORT}"
	return $?
}

function do_set_scsi_transport {
	pcs_iscsi_set_env $IQN "fast_check"
	[ $? -ne 0 ] && return 1

	[ "$SCSI_TRANSPORT" == "$NEW_SCSI_TRANSPORT" ] && return 0
	SCSI_TRANSPORT="${NEW_SCSI_TRANSPORT}"
	${SCSI_TGT}_check_scsi_transport
	[ $? -ne 0 ] && print_usage

	update_param "metadata" "${SCSI_TGT} ${SCSI_TRANSPORT}" && \
		update_param "address" ""

	rc=$?
	if [ $rc -eq 0 ] ; then
		echo "Target ${IQN} has SCSI transport '$SCSI_TRANSPORT'"
		echo "Target ${IQN} has empty address list now, update it now!!!"
	fi

	return $rc
}

function do_set_parameters {
	pcs_iscsi_check_target $IQN
	for (( i=0; i < ${#LIMITS[@]}; i++ )); do
		local limit_type=$(echo ${LIMITS[$i]} | cut -d "=" -f1)
		local limit_value=$(echo ${LIMITS[$i]} | cut -d "=" -f2)
		pcs_iscsi_set_limit "$IQN" "$limit_type" "$limit_value"
		if [ $? -ne 0 ]; then
			echo "Failed to set limit ${LIMITS[$i]} for target \"$IQN\"" 1>&2
			return 5
		fi
	done

	if [ -f "$ISCSI_SHM/.running/$IQN" ]; then
		if [ ${#LIMITS[@]} -gt 0 ]; then
			return 0
		else
			echo "Can't set parameters for running target, please stop it first." 1>&2
			return 1
		fi
	fi

	if [ -n "$USER" ] ; then
		pcs_iscsi_set_chap_account "$IQN" "$USER" "${ISCSI_ROOT}/$IQN"
		if [ $? -ne 0 ]; then
			echo "Failed to change CHAP account." 1>&2
			return 2
		fi
	fi

	if [ -n "$PORTAL_ADDR" ] ; then
		do_set_portal_addr
		return $?
	fi

	if [ -n "$NEW_SCSI_TGT" ] ; then
		do_set_scsi_target
		return $?
	fi

	if [ -n "$NEW_SCSI_TRANSPORT" ] ; then
		do_set_scsi_transport
		return $?
	fi

	return 0
}

if [ ! -x $PSTORAGE_ISCSI_LIB ] ; then
	echo "Unable find executable $PSTORAGE_ISCSI_LIB" 1>&2
	exit 1
fi

source $PSTORAGE_ISCSI_LIB
[ -f $ISCSI_ETC/config ] && source $ISCSI_ETC/config

parse_args "${ARGS[@]}"

ISCSI_ROOT=`pcs_iscsi_get_root "${ROOT}"`
pcs_iscsi_check_root
pcs_iscsi_lock_exec do_set_parameters
exit $?

