#!/bin/sh /etc/rc.common
START=91
STOP=10

EXTRA_COMMANDS="show"
EXTRA_HELP="	show	Show current configuration of tgtd"

NAME=tgt
PROG=/usr/sbin/tgtd
USE_PROCD=1

tgtadm="/usr/sbin/tgtadm --lld iscsi"
logger="logger -p daemon.err -s -t $NAME"

validate_lun_section() {
	uci_validate_section tgt lun $1 \
		'device:file' \
		'type:or("disk", "cd", "pt"):disk' \
		'bstype:or("rdwr", "aio", "sg"):rdwr' \
		'sync:bool:0' \
		'direct:bool:0' \
		'blocksize:uinteger' \
		'mode_page:string' \
		'product_id:string' \
		'product_rev:string' \
		'readonly:bool:0' \
		'removable:bool' \
		'scsi_id:string' \
		'scsi_sn:string' \
		'sense_format:range(0, 1)' \
		'vendor_id:string'
}

handle_lun() {
	local tgt_lun=$1
	local tgtid=$2
	local readonly device type bstype sync direct
	local my_tgtid=${tgt_lun%_*}
	local lun=${tgt_lun#*_}

	[ $my_tgtid -eq $tgtid ] || return 0

	validate_lun_section $tgt_lun || {
		$logger "Validation failed for LUN $tgt_lun"
		return 1
	}
	[ "$device" ] || {
		$logger "Device is required for target $tgt_lun"
		return 1
	}

	if [ $sync -ne 0 -o $direct -ne 0 ]; then
		local bsoflags
		[ $sync -ne 0 ] && bsoflags="sync"
		[ $direct -ne 0 ] && bsoflags="direct"
		[ $sync -ne 0 -a $direct -ne 0 ] && bsoflags="sync:direct"
		bsoflags="--bsoflags $bsoflags"
	fi

	blocksize=${blocksize+--blocksize=$blocksize}
	local params='' i
	for i in mode_page product_id product_rev readonly removable scsi_id scsi_sn sense_format vendor_id; do
		eval params=\${$i+$i=\$$i,}\$params
	done

	local _tgtadm="$tgtadm --mode logicalunit --tid $tgtid --lun $lun"
	$_tgtadm --op new --backing-store $device --device-type $type --bstype $bstype --bstype $bstype $bsoflags $blocksize || {
		$logger "Failed to create lun $tgt_lun"
		return 1
	}
	$_tgtadm --op update --param $params || {
		$logger "Failed to update lun $tgt_lun"
		return 1
	}
}

validate_account_section () {
	uci_validate_section tgt account $1 \
		'target:list(uinteger)' \
		'user:string' \
		'password:string' \
		'outgoing:bool:0'
}

handle_account() {
	local _tgtadm="$tgtadm --mode account"
	local user password target outgoing

	validate_account_section $1 || {
		$logger "Validation failed for account ${user:-$1}"
		return 1
	}
	[ "$user" ] || {
		$logger "User is required for account $1. Run 'uci show tgt.$1' and check options"
		return 1
	}
	[ "$target" ] || {
		$logger "Target is required for account $user"
		return 1
	}
	[ "$password" ] || {
		$logger "Password is required for account $user"
		return 1
	}
	$_tgtadm --op new --user "$user" --password "$password" || {
		$logger "Failed to create user $username"
		return 1
	}
}

bind_account_to_target() {
	local _tgtadm="$tgtadm --mode account"
	local tgtid=$2 user password outgoing

	validate_account_section $1 || {
		$logger "Validation failed for account ${user:-$1}"
		return 1
	}

	[ "$outgoing" -ne 0 ] && outgoing=--outgoing || outgoing=""
	local t
	for t in $target; do
		[ "$t" -eq "$tgtid" ] && {
			$_tgtadm --op bind --tid $tgtid --user "$user" $outgoing || {
				$logger "Failed to bind user $username to target $tgtid"
				return 1
			}
		}
	done
	return 0
}

validate_target_section() {
	uci_validate_section tgt target $1 \
		'name:string:iqn.2012-06.org.openwrt' \
		'allow_address:list(string):ALL' \
		'allow_name:list(string)'
}

handle_target() {
	local tgtid=$1
	local _tgtadm="$tgtadm --mode target"
	local name allow

	[ $tgtid -ge 0 ] || return 1
	validate_target_section $tgtid || {
		$logger "Validation failed for target $tgtid"
		return 1
	}
	$_tgtadm --op new --tid $tgtid --targetname $name || {
		$logger "Failed to create target $tgtid"
		return 1
	}
	local i
	for i in $allow_address; do
		$_tgtadm --op bind --tid $tgtid --initiator-address $i || {
			$logger "Failed to set allow $i to connect to target $tgtid"
			return 1
		}
	done
	for i in $allow_name; do
		$_tgtadm --op bind --tid $tgtid --initiator-name $i || {
			$logger "Failed to set allow $i to connect to target $tgtid"
			return 1
		}
	done
	config_foreach handle_lun lun $tgtid || return 1
	config_foreach bind_account_to_target account $tgtid || return 1
}

configure() {
	config_load $NAME
	$tgtadm --mode sys --op update --name State -v offline || {
		$logger "Failed to set system state to Offline"
		return 1
	}
	config_foreach handle_account account || return 1
	config_foreach handle_target target || return 1
	$tgtadm --mode sys --op update --name State -v ready || {
		$logger "Failed to set system state to Ready"
		return 1
	}
	return 0
}

validate_tgt_section() {
	uci_validate_section tgt options $1 \
		'iothreads:uinteger' \
		'portal:list(string)' \
		'nop_interval:uinteger' \
		'nop_count:uinteger'
}

start_service() {
	local iothreads portal nop_interval nop_count
	validate_tgt_section tgt || {
		$logger "Validation failed for tgt options"
		return 1
	}
	procd_open_instance
	procd_set_param command $PROG -f
	[ "$iothreads" ] && procd_append_param command -t $iothreads
	[ "${portal}${nop_interval}${nop_count}" ] && {
		local iscsi="" i
		for i in nop_interval nop_count; do
			eval iscsi=\${$i+$i=\$$i,}\$iscsi
		done
		for i in $portal; do
			iscsi="portal=$i,$iscsi"
		done
		procd_append_param command --iscsi $iscsi
	}
	procd_set_param respawn
	procd_close_instance
	logger -p daemon.info -t $NAME -s "Configuration will be loaded in seconds"
	( sleep 5; configure || { stop_service; exit 1; } ) &
}

stop_service() {
	$tgtadm --mode sys --op update --name State -v offline || {
		$logger "Failed to set system state to Offline"
		return 1
	}
	$tgtadm --mode target --op show \
		| awk '$1 == "Target" {sub(/:/,"",$2); print $2}' \
		| xargs -r -n1 $tgtadm --mode target --op delete --force --tid
	$tgtadm --mode sys --op delete
}

show() {
	$tgtadm --mode target --op show
}
