#!/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|mount_point|majmin|scsi|vendor|serial|model|firmware|size|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 (id,kname,mount-point,scsi,majmin,status,vendor,model,serial,firmware,size,description)'


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_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"
	[ "$(basename ${name} 2>/dev/null)" == "$AUXILIUM_ARG_locate" ] && locate="True"
	if [ "${field}" == "fo_name" ]; then
		local use_fo=$USE_FO_NAME
		USE_FO_NAME=1
		local f=$(fo_get_sorted_name)
		USE_FO_NAME=$use_fo
	else
		f=$(fo_get_disk_info ${name} ${field})
	fi
	fo_center_align "$width" "$locate" "$f" 
}


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
	if [ -n "$AUXILIUM_ARG_redmine" ]; then
		arrow='--> '
		LEN_ARROW=4
	fi
	let "lentotal = LEN_ARROW + LEN_MODEL + LEN_SN + LEN_MOUNT + 55"
	let "lenm = LEN_MOUNT + LEN_ARROW"
	if [ -n "${header}" ]; then
		fo_repeat_char '_' $lentotal;echo
		printf -- "|%-${lenm}s|%-12s|%-10s|%-${LEN_MODEL}s|%-${LEN_SN}s|%-10s|%-15s|\n" "$fo_name" "$k_name" "$size" "$model" "$sn" "$fw" "$descr"
		printf -- "|$(fo_repeat_char '-' ${lenm})|------------|----------|$(fo_repeat_char '-' ${LEN_MODEL})|$(fo_repeat_char '-' ${LEN_SN})|----------|---------------|\n"
	elif [ -n "${footer}" ]; then
		fo_repeat_char '¯' $lentotal;echo
	else
		if [ ! -z "${fo_name}" ] && [ "$(basename ${fo_name} 2>/dev/null)" == "${AUXILIUM_ARG_locate}" ] && [ "${USE_FO_NAME}" -ne "-1" ];then
			printf -- "|${RED}%-${lenm}s|%-12s|%+10s|%-${LEN_MODEL}s|%-${LEN_SN}s|%-10s|%-15s${NORM}|\n" "${arrow}${fo_name}" "${k_name}" "${size}" "$model" "$sn" "$fw" "$descr"
		elif [ ! -z "${k_name}" ] && [ "$(basename ${k_name} 2>/dev/null)" == "${AUXILIUM_ARG_locate}" ] && [ "${USE_FO_NAME}" -eq "-1" ];then
			printf -- "|${RED}%-${lenm}s|%-12s|%+10s|%-${LEN_MODEL}s|%-${LEN_SN}s|%-10s|%-15s${NORM}|\n" "${arrow}${fo_name}" "${k_name}" "${size}" "$model" "$sn" "$fw" "$descr"
		else
			printf -- "|%-${lenm}s|%-12s|%+10s|%-${LEN_MODEL}s|%-${LEN_SN}s|%-10s|%-15s|\n"  "${fo_name}" "${k_name}" "${size}" "$model" "$sn" "$fw" "$descr"
		fi
	fi
}

fo_write_disks_infos(){
	local did=$1
	local kname=$2
	local mount_point=$3
	local scsi=$4
	local majmi=$5
	local vendor=$6
	local model=$7
	local serial=$8
	local version=$9
	shift 9
	local size=$1
	local descr=$2
	eval $(udevadm info -q property --export ${kname})
	local majmin="${MAJOR}:${MINOR}"
	if fo_check_raid; then
		local descr="RAIDx Disk"
		local dids=$(fo_get_did)
		[ -e "$kname" ] && local dev=$kname || local dev="/dev/sda"
		for did in $dids; do
			unset vendor model serial version
			while IFS=: read k_smt v_smt; do
				k_smt=$(echo $k_smt)
				case $k_smt in
					"Vendor")
						vendor=$(echo ${v_smt})
						;;
					Serial\ [Nn]umber)
						serial=$(echo ${v_smt})
						;;
					"Device Model"|"Product")
						model=$(echo ${v_smt})
						;;
					"Revision"|"Firmware Version")
						version=$(echo ${v_smt})
						;;
					"LU is fully provisioned")
						descr="RAID0 Disk"
						;;
				esac
			done <<< "$(smartctl -i -d megaraid,${did} ${kname} 2>/dev/null)"
			printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" \
						"${did}" \
						"$kname" \
						"$mount_point" \
						"$scsi" \
						"$majmin" \
						"$vendor" \
						"$model" \
						"$serial" \
						"$version" \
						"$size" \
						"$descr" >> $FO_CACHE_DISKS_INFOS
		done
		unset did kname mount_point scsi majmin size descr
	else
		printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" \
					"${id}" \
					"$kname" \
					"$mount_point" \
					"$scsi" \
					"$majmin" \
					"$vendor" \
					"$model" \
					"$serial" \
					"$version" \
					"$size" \
					"$descr" >> $FO_CACHE_DISKS_INFOS
	fi
}

fo_load_disks_infos(){
	# File format : did,kname,mountpoint,scsi,majmin,
	# vendor,model,serial,version,size,description
	#id,kname,mountpoint,scsi,majmin,status,vendor,model,serial,version,size,description
	fo_use_cache_file "${FO_CACHE_DISKS_INFOS}" && return 0|| true
	fo_use_cache_file "${FO_CACHE_FILE_LSHW}" || lshw -c disk 2>/dev/null > "${FO_CACHE_FILE_LSHW}" || true
  for disk in $(ls -d /srv/node/*/ | cut -d/ -f4); do
		local realname=$(mount | grep "/srv/node/${disk}" | cut -d' ' -f1)
		if [ -z $realname ]; then
		 	local status="Missing"
			printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" "" "" "/srv/node/${disk}" "" "" "" "" "" "" 0 "" >> $FO_CACHE_DISKS_INFOS
		fi
	done
	while IFS=: read k v; do
		k=$(echo ${k})
		[ -z "$skip" ] || continue
		case "$k" in
		'*-cdrom')
				[ ! -z "$id" ] && fo_write_disks_infos "${id}" "$kname" "$mount_point" "$scsi" "$majmin" "$vendor" "$model" "$serial" "$version" "$size" "$descr"
				unset id kname mount_point scsi majmin vendor model serial version size descr
				local skip=1
		;;
		'*-disk')
			if [ -z "$v" ]; then
				[ ! -z "$id" ] && fo_write_disks_infos "${id}" "$kname" "$mount_point" "$scsi" "$majmin" "$vendor" "$model" "$serial" "$version" "$size" "$descr"
				unset id kname mount_point scsi majmin vendor model serial version size descr
				local skip=1
			else
				[ ! -z "$id" ] && fo_write_disks_infos "${id}" "$kname" "$mount_point" "$scsi" "$majmin" "$vendor" "$model" "$serial" "$version" "$size" "$descr"
				unset skip kname id mount_point scsi majmin vendor model serial version size descr
				local id=${v}
			fi
			;;
		'description')
			local descr=$(echo ${v})
		;;
		'logical name')
			case "$v" in
			" /dev/"*)
				local kname=$(echo ${v})
				;;
			" /srv/node/"*)
				local mount_point=$(echo ${v})
				;;
			esac
		;;
		'vendor')
			local vendor=$(echo ${v})
		;;
		'product')
			local model=$(echo ${v})
		;;
		'bus info')
			local scsi=$(echo ${v} | cut -d@ -f2)
		;;
		'version')
			local version=$(echo ${v})
		;;
		'serial')
			local serial=$(echo ${v})
		;;
		'size')
			local size=$(echo ${v} | cut -d' ' -f1)
		;;
		esac
	done < ${FO_CACHE_FILE_LSHW}
	[ -z "$skip" ] && fo_write_disks_infos "$id" "$kname" "$mount_point" "$scsi" "$majmin" "$vendor" "$model" "$serial" "$version" "$size" "$descr"
}

fo_get_disk_info(){
	local field=$2
	[ -e "$1" ] && local search=",${1}," || local search="^${1},"
	while IFS=, read id kname mount_point scsi majmin vendor model serial fw size descr; do
		case "$field" in
		id)
			echo ${id}
		;;
		majmin)
			echo ${majmin}
		;;
		scsi)
			echo ${scsi}
		;;
		vendor)
			echo ${vendor}
		;;
		serial)
			echo ${serial}
		;;
		model)
			echo ${model}
		;;
		firmware)
			echo ${fw}
		;;
		description)
			echo ${descr}
		;;
		mount_point)
			echo ${id}
		;;
		size)
			echo ${size}
		;;
		esac
	done <<< $(grep ${search} ${FO_CACHE_DISKS_INFOS})
}

main(){
	fo_load_disks_infos || true
	if [ -z "$AUXILIUM_ARG_csv" ]; then
		LEN_SN=18
		LEN_MODEL=18
		LEN_MOUNT=15
		while IFS="," read -r id kname mount_point scsi majmin vendor model serial fw size descr
		do
			[ "${#serial}" -gt "$LEN_SN" ] && LEN_SN=${#serial}
			[ "${#model}" -gt "$LEN_MODEL" ] && LEN_MODEL=${#model}
			[ "${#mount_point}" -gt "$LEN_MOUNT" ] && LEN_MOUNT=${#mount_point}
		done < $FO_CACHE_DISKS_INFOS
		fo_display_array --header "Mount point" "Kernel name" Size Model Serial Firmware Description
		while IFS="," read -r id kname mount_point scsi majmin vendor model serial fw size descr
		do
			fo_display_array "$mount_point" "$kname" "$size" "$model" "$serial" "$fw" "$descr"
		done < $FO_CACHE_DISKS_INFOS
		fo_display_array --footer;echo
		local LEN_FIELD=18
		[ "$AUXILIUM_ARG_field" == "serial" ] && LEN_FIELD=$LEN_SN
		[ "$AUXILIUM_ARG_field" == "model" ] && LEN_FIELD=$LEN_MODEL

		fo_build_dispo
		local underscore=$(fo_repeat_char '_' ${LEN_FIELD})
		local minus=$(fo_repeat_char '-' ${LEN_FIELD})
		local higher=$(fo_repeat_char '¯' ${LEN_FIELD})
		local 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 $(ls -d /srv/node/*/ | cut -d/ -f4); do
			local realname=$(mount| grep "/srv/node/${name}"|cut -d' ' -f1)
			eval $(udevadm info -q property --export ${realname} 2>/dev/null)
			local n=$(fo_get_name_by_name "$name" ${LEN_FIELD})
			local f=$(fo_get_field_by_name "/srv/node/$name" ${LEN_FIELD})
			FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{${name}}%${n}%g" 2>/dev/null)
			FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{SN_${name}}%${f}%g" 2>/dev/null)
		done
		for name in $(ls /dev/|grep -E "sd[a-z]"|grep -v "[0-9]"); do
			realname="/dev/${name}"
			if ! mount | grep -q "on ${realname}"; then
				[ "${name}" == "$AUXILIUM_ARG_locate" ] && locate="True" || unset locate
				local n=$(fo_center_align "${LEN_FIELD}" "$locate" "${realname}")
				local f=$(fo_get_field_by_name "$realname" ${LEN_FIELD})
				FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{/dev/${name}}%${n}%g" 2>/dev/null)
				FO_DISPOSITION=$(printf "${FO_DISPOSITION}"|sed "s%{SN_/dev/${name}}%${f}%g" 2>/dev/null)
			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
		cat "$FO_CACHE_DISKS_INFOS"
	fi
}

main