#!/bin/bash

set -e
#set -x

if [ $(id -u) -ne 0 ]; then
	echo "$0 needs root: please use sudo."
	exit 1
fi

# Source Auxilium (args parser)
. /usr/share/auxilium/auxilium.sh

auxilium_init $(basename $0) -m 'Displays list of devices and their physical location'

auxilium_add locate -s l -t str -m 'A device to locate (/dev/sdx or /dev/disk/fo-sort/Box0'
auxilium_add redmine -s r -t opt -m 'Format for redmine'
auxilium_add field -s f -t str -l "id|businfo|vendor|serial|product|version|physid|description|fo_name" -d "serial" -m 'Field to display under Device Name'
auxilium_add csv -t opt -m 'Return a CSV formatted list of devices (Fo_name,Kernel_name,Size,Model,Serial,Firmware)'


if [ -f "/usr/share/ferreus-orbit/common.sh" ]; then
	. "/usr/share/ferreus-orbit/common.sh"
elif [ -f "share/common.sh" ] ; then
	. "share/common.sh"
elif [ -f "../share/common.sh" ] ; then
	. "../share/common.sh"
else
	echo "Cannot load common.sh: exiting"
	exit 1
fi

auxilium_parse "$@"

fo_lock

fo_load_lshw

fo_get_name_by_name(){
	local width="$2"
	local locate="False"
	local name="$1"
	[ "${name}" == "$AUXILIUM_ARG_locate" ] && locate="True"
	[ "$USE_FO_NAME" -eq -1 ] && fullname="/dev/${name}" || fullname=${name}
	mount | grep -q /srv/node/${name} || fullname="${UNMOUNTED}${fullname}"
	fo_center_align "$width" "$locate" "$fullname"
}

fo_get_field_by_name(){
	local name="$1"
	local field="$AUXILIUM_ARG_field"
	local width="$2"
	local locate="False"
	local realname=$(realpath "${SORTED_PATH}/${name}" 2>/dev/null)
	local maj_min=$(printf "%d:%d\n" $(stat -c "0x%t 0x%T" $realname 2>/dev/null))
	[ "${name}" == "$AUXILIUM_ARG_locate" ] && locate="True"
	if [ "${field}" == "fo_name" ]; then
		local use_fo=$USE_FO_NAME
		USE_FO_NAME=1
		eval $(udevadm info -q property --export ${realname} 2>/dev/null)
		local f=$(fo_get_sorted_name)
		USE_FO_NAME=$use_fo
	else
		local f=$(cat ${FO_CACHE_FILE_LSHW}|jq -r ".|select(.dev==\"${maj_min}\").${field}" 2>/dev/null | cut -d$'\n' -f1)
	fi
	fo_center_align "$width" "$locate" "$f" 
}

fo_get_field_by_did(){
	local did="$1"
	local name="$2"
	local field="$AUXILIUM_ARG_field"
	local width="$3"
	local locate="False"
	[ "${name}" == "$AUXILIUM_ARG_locate" ] && locate="True"
	local dg=$(cat ${FO_CACHE_FILE_STORCLI}|jq -r ".[]|to_entries[]|select(.key==0).value|select(.DID==${did}).DG")
	if [ "${field}" == "fo_name" ]; then
		local use_fo=$USE_FO_NAME
		USE_FO_NAME=1
		eval $(udevadm info -q property --export /dev/${name} 2>/dev/null)
		local f=$(fo_get_sorted_name)
		USE_FO_NAME=$use_fo
	else
		local SMT_OUT=$(mktemp)
		smartctl -i -d megaraid,${did} /dev/sda >${SMT_OUT} || true
		case "$field" in
		"vendor")
			local f=$(cat ${SMT_OUT} | grep "^[Vendor]" | awk 'FS=":" {print $NF}')
			;;
		"serial")
			local f=$(cat ${SMT_OUT} | grep "^Serial [nN]umber" | awk 'FS=":" {print $NF}')
			;;
		"product")
			local f=$(cat ${SMT_OUT} | grep -E "^Device Model|^Product" | awk 'FS="n:" {print $NF}')
			;;
		"description")
			local f=$(cat ${SMT_OUT} | grep "LU is fully provisioned" >/dev/null && local descr="RAID0 Disk" || local descr="RAIDn Disk")
			;;
		"version")
			local f=$(cat ${SMT_OUT} | grep -m1 -e "^Revision:" -e "^Firmware Version"  | awk 'FS=":" {print $NF}')
			;;
		*)
			local f=$(cat ${FO_CACHE_FILE_LSHW}|jq -r ".|select(.dev==\"${maj_min}\").${field}" 2>/dev/null | cut -d$'\n' -f1)
			;;
		esac
		rm -f ${SMT_OUT}
	fi
	fo_center_align "$width" "$locate" "$f" 
}

fo_get_name_by_bus(){
	local businfo="$1"
	local width="$2"
	local locate="False"
	local name=$(cat ${FO_CACHE_FILE_LSHW}|jq -r ".|select(.businfo==\"${businfo}\").logicalname[1]" 2>/dev/null)
	name=$(basename "${name}")
	if [ -z "$name" ]; then
	  name=$(cat ${FO_CACHE_FILE_LSHW}|jq -r ".|select(.businfo==\"${businfo}\").logicalname" 2>/dev/null)
	fi
	[ "$(basename "${name}")" == "$AUXILIUM_ARG_locate" ] && locate="True"
  fo_center_align "$width" "$locate" "$name"
}

fo_get_field_by_bus(){
	local businfo="$1"
	local field="$AUXILIUM_ARG_field"
	local width="$2"
	local locate="False"

	local name=$(cat ${FO_CACHE_FILE_LSHW}|jq -r ".|select(.businfo==\"${businfo}\").logicalname[1]" 2>/dev/null)
	name=$(basename "${name}")
	[ "$(basename "${name}")" == "$AUXILIUM_ARG_locate" ] && locate="True"
	if [ "${field}" == "fo_name" ]; then
		local realname=$(cat ${FO_CACHE_FILE_LSHW}|jq -r ".|select(.businfo==\"${businfo}\").logicalname[0]" 2>/dev/null)
		if [ -z "$realname" ]; then
			realname=$(cat ${FO_CACHE_FILE_LSHW}|jq -r ".|select(.businfo==\"${businfo}\").logicalname" 2>/dev/null)
		fi
		local use_fo=$USE_FO_NAME
		USE_FO_NAME=1
		eval $(udevadm info -q property --export ${realname})
		local f=$(fo_get_sorted_name)
		USE_FO_NAME=$use_fo
	else
		local f=$(cat ${FO_CACHE_FILE_LSHW}|jq -r ".|select(.businfo==\"${businfo}\").${field}" 2>/dev/null)
	fi
	fo_center_align "$width" "$locate" "$f" 
}

fo_disk_status(){
	for disk in $(sort -u <(ls /srv/node/) <(ls /dev/| grep -E "sd[a-z]"|grep -v "[0-9]")); do
		if [ -e ${SORTED_PATH}/${disk} ] || [ -e /srv/node/${disk} ] || [ -e /dev/${disk} ]; then
			if [ -e ${SORTED_PATH}/${disk} ]; then
							local realname=$(realpath "${SORTED_PATH}/${disk}" 2>/dev/null || echo "/dev/${disk}")
			elif [ -e /srv/node/${disk} ]; then
							local realname=$(mount | grep "/srv/node/${disk}"| awk '{print $1}')
			elif [ -z $(mount | grep "/dev/${disk}") ]; then
							local realname="/dev/${disk}"
			fi
			maj_min=$(printf "%d:%d\n" $(stat -c "0x%t 0x%T" $realname))
			local status=$(cat ${FO_CACHE_FILE_LSHW}|jq -r ".|select(.dev==\"${maj_min}\")" 2>/dev/null)
			local kname=$(basename ${realname})
			local size=$(echo $status|jq -rs '.[0].size')
			if [ -z "${FO_MEGARAID}" ]; then
				[ "$USE_FO_NAME" -eq -1 ] && local name="/dev/${disk}" || local name=${disk}
				local model=$(echo $status|jq -rs '.[0].product')
				local sn=$(echo $status|jq -rs '.[0].serial')
				local fw=$(echo $status|jq -rs '.[0].version')
				local descr=$(echo $status|jq -rs '.[0].description')
				printf "%s,%s,%s,%s,%s,%s,%s\n" "${name}" "${kname}" "${size}" "${model}" "${sn}" "${fw}" "${descr}"
			else
				fo_load_storcli
				local dg=$(fo_get_dev_ascii ${disk})
				local dids=$(cat ${FO_CACHE_FILE_STORCLI}|jq -r ".[]|to_entries[]|select(.key==0).value|select(.DG==${dg}).DID")
				for did in ${dids}; do
					local name="sd$(fo_get_dev_letter ${did})"
					[ "$USE_FO_NAME" -eq -1 ] && local name="/dev/${disk}" || local name=${name}
					local SMT_OUT=$(mktemp)
					smartctl -i -d megaraid,${did} /dev/sda >${SMT_OUT} || true
					local model=$(cat ${SMT_OUT} | grep -E "^Device Model|^Product" | awk 'FS=":" {print $NF}')
					local sn=$(cat ${SMT_OUT} | grep "^Serial [nN]umber" | awk 'FS=":" {print $NF}')
					local fw=$(cat ${SMT_OUT} | grep -m1 -e "^Revision:" -e "^Firmware Version"  | awk 'FS=":" {print $NF}')
					cat ${SMT_OUT} | grep "LU is fully provisioned" >/dev/null && local descr="RAID0 Disk" || local descr="RAIDn Disk"
					rm -f ${SMT_OUT}
					printf "%s,%s,%s,%s,%s,%s,%s\n" "${name}" "${kname}" "${size}" "${model}" "${sn}" "${fw}" "${descr}"
				done
			fi
		fi
	done
}

fo_display_array(){
	if [ "$1" == "--header" ]; then
		local header='True'
		shift 1
	elif [ "$1" == "--footer" ]; then
		local footer='True'
		shift 1
	fi
	local fo_name=$1
	local k_name=$2
	[ "${3}" == "null" ] && local size=0 || local size=$3
	local model=$4
	local sn=$5
	local fw=$6
	local descr=$7
	[ -n "$AUXILIUM_ARG_redmine" ] && arrow=' <--'
	let "lentotal = LEN_MODEL + LEN_SN + 70"
	if [ -n "${header}" ]; then
		fo_repeat_char '_' $lentotal;echo
		printf -- "|%-11s|%-12s|%-10s| %-${LEN_MODEL}s | %-${LEN_SN}s |%-10s|%-15s|\n" "$fo_name" "$k_name" "$size" "$model" "$sn" "$fw" "$descr"
		printf -- "|-----------|------------|----------|-$(fo_repeat_char '-' ${LEN_MODEL})-|-$(fo_repeat_char '-' ${LEN_SN})-|----------|---------------|\n"
	elif [ -n "${footer}" ]; then
		fo_repeat_char '¯' $lentotal;echo
	else
		if [ "${fo_name}" == "${AUXILIUM_ARG_locate}" ] && [ -d "$SORTED_PATH" ];then
			printf -- "|${RED}%-11s|%-12s|%+10s| %-${LEN_MODEL}s | %-${LEN_SN}s |%-10s|%-15s${NORM}|\n" "${fo_name}${arrow}" "/dev/${k_name}" "$(numfmt  --to=iec-i --suffix=B --format=" %6.1f " ${size})" "$model" "$sn" "$fw" "$descr"
		elif [ "${k_name}" == "${AUXILIUM_ARG_locate}" ] && [ ! -d "$SORTED_PATH" ];then
			printf -- "|${RED}%-11s|%-12s|%+10s| %-${LEN_MODEL}s | %-${LEN_SN}s |%-10s|%-15s${NORM}|\n" "${fo_name}${arrow}" "/dev/${k_name}" "$(numfmt  --to=iec-i --suffix=B --format=" %6.1f " ${size})" "$model" "$sn" "$fw" "$descr"
		else
			printf -- "|%-11s|%-12s|%+10s| %-${LEN_MODEL}s | %-${LEN_SN}s |%-10s|%-15s|\n" "${fo_name}" "/dev/${k_name}" "$(numfmt  --to=iec-i --suffix=B --format=" %6.1f " ${size})" "$model" "$sn" "$fw" "$descr"
		fi
	fi
}

readonly st=$(fo_disk_status)
if [ -z "$AUXILIUM_ARG_csv" ]; then
  LEN_SN=18
	LEN_MODEL=18
	while IFS="," read -r fo k size model serial firmware description
	do
		[ "${#serial}" -gt "$LEN_SN" ] && LEN_SN=${#serial}
		[ "${#model}" -gt "$LEN_MODEL" ] && LEN_MODEL=${#model}
	done <<< $(printf "${st}")
	fo_display_array --header "FO name" "Kernel name" Size Model Serial Firmware Description
	while IFS="," read -r fo k size model serial firmware description
	do
		fo_display_array "$fo" "$k" "$size" "$model" "$serial" "$firmware" "$description"
	done <<< $(printf "${st}")
	fo_display_array --footer;echo
	LEN_FIELD=18
	[ "$AUXILIUM_ARG_field" == "serial" ] && LEN_FIELD=$LEN_SN
	[ "$AUXILIUM_ARG_field" == "model" ] && LEN_FIELD=$LEN_MODEL

  fo_build_dispo
	underscore=$(fo_repeat_char '_' ${LEN_FIELD})
	minus=$(fo_repeat_char '-' ${LEN_FIELD})
	higher=$(fo_repeat_char '¯' ${LEN_FIELD})
	FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{UNDERSCORE}%${underscore}%g")
	FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{MINUS}%${minus}%g")
	FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{HIGHER}%${higher}%g")
	for name in $(sort -u <(ls /srv/node/) <(ls /dev/|grep -E "sd[a-z]"|grep -v "[0-9]")); do
		if [ -z "${FO_MEGARAID}" ]; then
			n=$(fo_get_name_by_name "$name" ${LEN_FIELD})
			f=$(fo_get_field_by_name "$name" ${LEN_FIELD})
			FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{${name}}%${n}%g")
			FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{SN_${name}}%${f}%g")
		else
			fo_load_storcli
			dg=$(udevadm info -q path /dev/${name} | cut -d/ -f7| cut -d: -f3 )
			dids=$(cat ${FO_CACHE_FILE_STORCLI}|jq -r ".[]|to_entries[]|select(.key==0).value|select(.DG==${dg}).DID")
		  for did in ${dids}; do
				n=$(fo_get_name_by_name "$name" ${LEN_FIELD})
				f=$(fo_get_field_by_did "$did" "$name" ${LEN_FIELD})
				FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{Disk${did}}%${n}%")
				FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{SN_Disk${did}}%${f}%")
			done
		fi
	done
	# final replace {new_line} by \n and @ by \
  FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{new_line}%\n%g"| tr '@' '\\')
	printf "${FO_DISPOSITION}\n"
else
	printf "${st}\n"
fi