#!/bin/bash
. /etc/profile >/dev/null
. /etc/tos/scripts/scripts

tempfile=/tmp/iscsi_$$

ntfs_mount=/usr/bin/ntfs-3g
ntfs_mount_opt="-o rw,noatime,big_writes,async,iocharset=utf8"

exfat_mount=/sbin/mount.exfat-fuse
exfat_mount_opt="-o umask=000,iocharset=utf8,shortname=mixed,quiet,utf8,flush"

vfat_mount=/bin/mount
vfat_mount_opt="-o umask=000,iocharset=utf8,shortname=mixed,quiet,utf8,flush"

hfs_mount=/bin/mount
hfs_mount_opt="-t hfsplus -o force,rw,umask=0,nls=utf8,nodecompose"

ext4_mount=/bin/mount
ext4_mount_opt="-o rw"

mainVol=$(get_main_volume)
if [ -z "$mainVol" ]; then
	exit 1
fi

searchKey() {
	local string=$1
	local key=$2
	echo "$string" | grep "$key" >/dev/null
	return $?
}

targetAttr() {
	local iName=$1
	local ipadress=""
	local ip=""
	iscsiadm -m node -T $iName -d0 | while read line; do
		searchKey "$line" "BEGIN RECORD"
		[ $? -eq 0 ] && {
			ipadress=""
			ip=""
		}
		searchKey "$line" "node.discovery_address"
		[ $? -eq 0 ] && {
			ipadress=$(echo "$line" | awk -F' = ' '{print $2}')
		}
		searchKey "$line" "node.discovery_port"
		[ $? -eq 0 ] && {
			ipadress="${ipadress}:$(echo "$line" | awk -F' = ' '{print $2}')"
		}
		searchKey "$line" "node.conn\[0\].address"
		[ $? -eq 0 ] && {
			ip=$(echo "$line" | awk -F' = ' '{print $2}')
		}
		searchKey "$line" "node.conn\[0\].port"
		[ $? -eq 0 ] && {
			ip="${ip}:$(echo "$line" | awk -F' = ' '{print $2}')"
		}
		searchKey "$line" "END RECORD"
		[ $? -eq 0 ] && {
			[ "$ipadress" = "$ip" ] && {
				echo $ipadress
				return 0
			}
		}
	done
	return 1
}

targetStat() {
	local iName=$1
	local ip=$2
	local state=""
	local start=0
	iscsiadm -m session -P3 2>/dev/null >$tempfile
	while read line; do
		searchKey "$line" "Target: "
		[ $? -eq 0 ] && start=0
		searchKey "$line" "Target: $iName"
		if [ $? -eq 0 ]; then
			start=1
			continue
		fi
		if [ $start -lt 1 ]; then
			continue
		fi
		searchKey "$line" "Current Portal: $ip"
		[ $? -eq 0 ] && {
			let start=start+1
			continue
		}
		#start log process...
		if [ $start -gt 1 ]; then
			searchKey "$line" "iSCSI Connection State:"
			[ $? -eq 0 ] && {
				state=$(echo "$line" | awk -F': ' 'gsub(" ","_",$2) {print $2}')
				continue
			}
			searchKey "$line" "Channel 00 Id 0 Lun:"
			[ $? -eq 0 ] && {
				local LUNID=$(echo "$line" | awk -F': ' '{print $2}')
				read line #读取下一行
				searchKey "$line" "Attached scsi disk"
				[ $? -eq 0 ] && state="$state,$(echo "$line" | awk '{print $4}'),$LUNID"
			}
		fi
	done <$tempfile
	rm -f $tempfile
	#stdout the result...
	echo $state
	return 0
}

mountdevice() {
	local iName=$1
	local state=$2
	local disks=(${state//,/ })
	local shortname=${iName##*.}
	unset disks[0]

	mainraid=$(get_main_volume)
  	[ -z "$mainraid" ] && exit 1
	local iscsidir="${mainraid}/@iscsi"
	[ ! -d $iscsidir ] && mkdir -m 555 $iscsidir
	for ((i = 1; i < ${#disks[@]}; i = i + 2)); do
		local blkname=${disks[$i]}
		local index=${disks[$i + 1]}
		local blk=/dev/$blkname
		local partition="${blk}1"
		[ ! -b "$blk" -o ! -b $partition ] && continue
		local mountpath="${iscsidir}/${shortname}-${index}"
		[ ! -d "$mountpath" ] && mkdir -m 555 "$mountpath"
		df-json | grep $mountpath >/dev/null
		[ $? -eq 0 ] && continue
		local fs=$(blkid $partition -o export | awk -F= '/TYPE/ {print $2}')
		if [ "$fs" = "ntfs" ]; then
			${ntfs_mount} ${ntfs_mount_opt} ${partition} "${mountpath}" >/dev/null
		elif [ "$fs" = "vfat" ]; then
			${vfat_mount} ${vfat_mount_opt} ${partition} "${mountpath}" >/dev/null
		elif [ "$fs" = "exfat" ]; then
			${exfat_mount} ${exfat_mount_opt} ${partition} "${mountpath}" >/dev/null
		elif [ "$fs" = "hfsplus" ]; then
			fsck.hfsplus -f ${partition} >/dev/null
			${hfs_mount} ${hfs_mount_opt} ${partition} "${mountpath}" >/dev/null
		else
			${ext4_mount} ${ext4_mount_opt} ${partition} "${mountpath}" >/dev/null
		fi
		df-json | grep $mountpath >/dev/null
		[ $? -eq 0 ] && {
			opdatabase "add" "${shortname}-${index}"
		}
	done
}

opdatabase() {
	local act=$1
	local foldername=$2
	local device="@iscsi"
	local mntpath=$mainVol/$device/$foldername
	[ -z "$foldername" ] && return 1
	local folder=$(tersql -sql "select folder_id from share where foldername='$foldername'" -only)
	if [ $? -ne 0 ]; then
		return
	fi
	if [ "$act" = "add" ]; then
		local folderid=$(echo $folder | jq -r .folder_id)
		tersql -sql "insert into share(foldername,device,mntpath,owner,oplock,hidden,type,description,extend) VALUES('$foldername','$device','$mntpath','admin',0,0,'LFS','','')"
	elif [ "$act" = "del" ]; then
		tersql -sql "DELETE FROM share WHERE foldername = '$foldername'"
	fi
}

loadconf() {
	local iName=$1
	local shortname=${iName##*.}
	local configfile=/etc/iscsid/.${shortname}.conf
	[ ! -d /etc/iscsid ] && mkdir -m 755 /etc/iscsid
	if [ -f $configfile ]; then
		local user=$(grep '^user' $configfile | cut -d'=' -f2 | tr -d '[:space:]')
		[ ! -z "$user" ] && {
			iscsiadm -m node -T ${iName} -o update -n node.session.auth.username -v ${user}
		}
		local pass=$(grep '^pass' $configfile | cut -d'=' -f2 | tr -d '[:space:]')
		[ ! -z "$pass" ] && {
			iscsiadm -m node -T ${iName} -o update -n node.session.auth.password -v ${pass}
			iscsiadm -m node -T ${iName} -o update -n node.session.auth.authmethod -v CHAP
		}
		local head=$(grep '^head' $configfile | cut -d'=' -f2 | tr -d '[:space:]')
		[ "$head" = "1" ] && {
			iscsiadm -m node -T ${iName} -o update --name=node.conn[0].iscsi.HeaderDigest --value=CRC32C
		}
		local data=$(grep '^data' $configfile | cut -d'=' -f2 | tr -d '[:space:]')
		[ "$data" = "1" ] && {
			iscsiadm -m node -T ${iName} -o update --name=node.conn[0].iscsi.DataDigest --value=CRC32C
		}
	fi
}

checkConfStatus(){
	local iName=$1
	local shortname=${iName##*.}
	local configfile=/etc/iscsid/.${shortname}.conf
	local status
	if [ -f $configfile ]; then
		status=$(grep '^status' $configfile | cut -d'=' -f2 | tr -d '[:space:]')
		[ "$status" == "true" ] && return 1
	fi
	return 0
}

# 用于在后台挂载 iSCSI 设备的函数
background_mountdevice() {
    local iName=$1
    local ipadress=$2
    local state=$3
    local max_attempts=60
    local max_login_attempts=10
    local attempt=0
    local logged_in=false

	# 确保网络就绪
    until ping -c 1 -W 1 ${ipadress%:*} &> /dev/null; do
        sleep 1
        ((attempt++))
        if [ $attempt -ge $max_attempts ]; then
            echo "Network to $ipadress not ready, skipping $iName."
            return 1
        fi
    done

	# 尝试登录iSCSI
    if [[ -z "$state" || ! "$state" =~ LOGGED_IN ]]; then
        loadconf "$iName"
        iscsiadm --mode node --targetname "$iName" --portal "$ipadress" --login
        attempt=0 # 重置尝试次数
        while [ $attempt -lt $max_login_attempts ]; do
            state=$(targetStat "$iName" "$ipadress")
            if [[ "$state" =~ LOGGED_IN ]]; then
                logged_in=true
                break
            fi
            sleep 1
            ((attempt++))
        done
        if [ "$logged_in" = false ]; then
            echo "iSCSI target $iName at $ipadress did not log in in time."
            return 1
        fi
    fi


    # 获取所有 LUN 的状态
    read -ra luns <<< $(echo $state | awk 'BEGIN {FS=","; OFS=","} {for (i=2; i<=NF; i+=2) print $i,$(i+1)}')

    # 对每个 LUN，检查对应的设备节点是否出现
    for lun_pair in "${luns[@]}"; do
    	local blkname=$(echo $lun_pair | cut -d',' -f1)
    	local lun_id=$(echo $lun_pair | cut -d',' -f2)
      local device_path="/dev/disk/by-path/"
      attempt=0
      while [ $attempt -lt $max_attempts ]; do
          local device=$(ls ${device_path}*ip-${ipadress}-iscsi-${iName}-lun-${lun_id} 2> /dev/null)
          if [ ! -z "$device" ]; then
              break
          fi
          sleep 1
          ((attempt++))
      done
      if [ $attempt -eq $max_attempts ]; then
          echo "LUN $lun_id of $iName at $ipaddress did not become ready in time."
          return 1
      fi
    done

    # 如果所有LUN设备都已就绪，进行挂载
    if [ ${#luns[@]} -gt 0 ]; then
        mountdevice "$iName" "$state"
    fi
}

service_restart() {
	local svrname=$1
	[ ! -e /etc/sc.d/$svrname ] && return 1
	local state=$(service $svrname status)
	echo "$state" | grep "running" >/dev/null
	if [ $? -eq 0 ]; then
		service $svrname restart >/dev/null
	else
		service $svrname start >/dev/null
	fi
	return 0
}


pids=$(pidof iscsid)
mountPids=()
if [ ! -z "$pids" ]; then
	targetlist=$(iscsiadm --mode node -P1 | awk -F': ' '/Target/ {print $2}')
	for iName in $targetlist; do
		checkConfStatus "$iName"
		[ $? -ne 1 ] && continue
		ipadress=$(targetAttr "$iName")
		state=$(targetStat "$iName" "$ipadress")
		echo $iName $ipadress $state
		# 在后台启动挂载操作
    background_mountdevice "$iName" "$ipadress" "$state"
	done
	df-json | egrep /Volume[0-9]+/@iscsi >/dev/null
	[ $? -eq 0 ] && {
		service_restart samba
		service_restart ftp
		service_restart nfs
	}
else
	smb_status=$(ps -ef | grep smbd | grep -v grep | wc -l)
	ftp_status=$(ps -ef | grep smbftpd | grep -v grep | wc -l)
	nfs_status=$(ps -ef | grep nfsd | grep -v grep | wc -l)
	# stop the iscsid
	[ $smb_status -gt 0 ] && service samba stop
	[ $ftp_status -gt 0 ] && service ftp stop
	[ $nfs_status -gt 0 ] && service nfs-server stop
	df-json | awk '/\/Volume[0-9]+\/@iscsi/ {print $8}' | while read line; do
		umount $line
		[ -d $line ] && rm -fr $line
		foldername=$(basename "$line")
		opdatabase "del" "${foldername}"
	done
	[ $smb_status -gt 0 ] && service samba start
	[ $ftp_status -gt 0 ] && service ftp start
	[ $nfs_status -gt 0 ] && service nfs-server start
fi
