#!/bin/bash

set -e
#set -x

LOCKDIR=/var/run/lock
LOCKFILE=${LOCKDIR}/$(basename ${0})
if [ "${1}" = "--nolock" ] ; then
        shift
else
        logger -t "udev" "===> Claming lock for $0 in ${LOCKFILE}"
        if ! flock -w 120 -x ${LOCKFILE} $0 --nolock $@ ; then
                exit 1
        fi
        exit 0
fi

# Script param (sent as env var):
# ID_BUS (example: scsi, ata)
# DEVPATH (example: /devices/pci0000:80/0000:80:08.2/0000:81:00.0/ata8/host7/target7:0:0/7:0:0:0/block/sdc)
#
# In fact, we see the variables as per:
# udevadm test -a -p  $(udevadm info -q path -n /dev/sdc)

CHASSIS_MANUFACTURER=$(dmidecode -s system-manufacturer)
CHASSIS_MODEL=$(dmidecode -s system-product-name)
CACHE_FILE=/run/oci-hdd-cache

case "${CHASSIS_MANUFACTURER}" in
"LinuxKVM")
	case "${CHASSIS_MODEL}" in
	"qemu-oci")
		if [ -n "$ID_BUS" ] && [ "$ID_BUS" = "scsi" ]; then
			card=$(echo $DEVPATH | cut -d/ -f5)
			target=$(echo $DEVPATH | cut -d/ -f8)
			if [ "$card" = "virtio0" ] ; then
				case "${target}" in
				"2:0:0:0") disk="sda" ;;
				"2:0:1:0") disk="sdb" ;;
				"2:0:2:0") disk="sdc" ;;
				"2:0:3:0") disk="sdd" ;;
				"2:0:4:0") disk="sde" ;;
				"2:0:5:0") disk="sdf" ;;
				"2:0:6:0") disk="sdg" ;;
				"2:0:7:0") disk="sdh" ;;
				"2:0:8:0") disk="sdi" ;;
				"2:0:9:0") disk="sdj" ;;
				*) logger -t "udev" "Device $DEVPATH detected but not supported"; exit 1 ;;
				esac
				logger -t "udev" "Adding symlink $disk for device $card-$target"
				echo $disk
				exit 0
			else
				logger -t "udev" "Device $DEVPATH detected but not supported"; exit 1
			fi
		else
			logger -t "udev" "Device $DEVPATH detected but not supported"; exit 1
		fi
	;;
	*)
		logger -t "udev" "Qemu chassis not supported, exit."
		exit 1
	;;
	esac
;;
"Dell Inc.")
	case "${CHASSIS_MODEL}" in
	"PowerEdge R410")
		# Here we have 2 internal SSDs on CDROM link and 4 SATA HDD
		if [ -n "$ID_BUS" ] && [ "$ID_BUS" = "ata" ]; then
			card=$(echo $DEVPATH | cut -d/ -f5)
			target=$(echo $DEVPATH | cut -d/ -f8)
			if   [ "$card" = "ata1" ] && [ "$target" = "0:0:0:0" ]; then disk="sda"
			elif [ "$card" = "ata1" ] && [ "$target" = "0:1:0:0" ]; then disk="sdb"
			elif [ "$card" = "ata2" ] && [ "$target" = "1:0:0:0" ]; then disk="sdc"
			elif [ "$card" = "ata3" ] && [ "$target" = "2:0:0:0" ]; then disk="sdd"
			elif [ "$card" = "ata4" ] && [ "$target" = "3:0:0:0" ]; then disk="sde"
			elif [ "$card" = "ata5" ] && [ "$target" = "4:0:0:0" ]; then disk="sdf"
			else logger -t "udev" "Device $DEVPATH detected but not supported."; exit 1
			fi
		else    
			logger -t "udev" "Device $DEVPATH detected but not supported"; exit 1
		fi
		logger -t "udev" "Adding symlink $disk for device $card-$target"
		echo "$disk"
		exit 0
	;;
	*)
		logger -t "udev" "Dell chassis not supported, exit."
		exit 1
	;;
	esac
;;
"HPE")
	case "${CHASSIS_MODEL}" in
	"ProLiant DL385 Gen10 Plus")
		card=$(echo $DEVPATH | cut -d/ -f6)
		# We expect here 2 SATA SSDs and 12 SAS HDD
		if [ -n "$ID_BUS" ] && [ "$ID_BUS" = "ata" ]; then
			target=$(echo $DEVPATH | awk -F '/' '{ print $9 }')
			if [ "$card" = "ata7" ] && [ "$target" = "6:0:0:0" ]; then
				disk="sda"
			elif [ "$card" = "ata8" ] && [ "$target" = "7:0:0:0" ]; then
				disk="sdb"
			else
				logger -t "udev" "Device $DEVPATH detected but not supported."
				exit 1
			fi
		elif [ -n "$ID_BUS" ] && [ "$ID_BUS" = "scsi" ]; then
			if   [ "${card}" = "host8" ] ; then
				usecache=false
				# read a cache file, if exist and recent
				if [ -f $CACHE_FILE ]; then
					lastentry=$(stat -c %Y $CACHE_FILE)
					lastvalid=$(date -d "now -3 min" +%s)
					if [ $lastentry -gt $lastvalid ]; then
						usecache=true
					else
						rm $CACHE_FILE
					fi
				elif [ -e $CACHE_FILE ]; then
					rm $CACHE_FILE
				fi
				# cache is recent and a file
				if $usecache; then
					# Just read from cache file...
					disk=$(grep $DEVNAME $CACHE_FILE | awk '{ print $2 }')
					if ! [ -n $disk ]; then
						logger -t "udev" "[Cache mode] Device $DEVPATH detected but not found."
						exit 1
					fi
				else
					disk=""

					# Parse the output of "ssacli controller slot=0 physicaldrive all show detail"
					# and build a cache file...
					TMPFILE=$(mktemp -t parse-hpe-drives.XXXXXX)
					# The grep here just helps because we later have less lines to parse.
					SLOT_NUM=$(ssacli controller all show | head -n 2 | tail -n 1 | sed -r 's/.*(Slot [0-9]+).*/\1/' | sed 's/Slot //')
					ssacli controller slot=${SLOT_NUM} physicaldrive all show detail | grep -E 'physicaldrive|Disk Name: /dev/' >$TMPFILE
					while IFS='' read -r LINE || [ -n "${LINE}" ]; do
						if echo ${LINE} | grep -q physicaldrive ; then
							PHYSDRIVE=$(echo ${LINE} | sed 's/^.*physicaldrive //')
							case "${PHYSDRIVE}" in
								# The format is:
								# ${SAS_PORT}:${BOX}:${BAY}
								# Since we don't care about ports, but where the drive is physically located
								# we use ${BOX}:${BAY}, so the physical location of the drives is deterministic
								# and we don't care the order of the ports.
								"1I:1:1"|"2I:1:1"|"3I:1:1") PHYDISK="sdc" ;;
								"1I:1:2"|"2I:1:2"|"3I:1:2") PHYDISK="sdd" ;;
								"1I:1:3"|"2I:1:3"|"3I:1:3") PHYDISK="sde" ;;
								"1I:1:4"|"2I:1:4"|"3I:1:4") PHYDISK="sdf" ;;
								"1I:2:1"|"2I:2:1"|"3I:2:1") PHYDISK="sdg" ;;
								"1I:2:2"|"2I:2:2"|"3I:2:2") PHYDISK="sdh" ;;
								"1I:2:3"|"2I:2:3"|"3I:2:3") PHYDISK="sdi" ;;
								"1I:2:4"|"2I:2:4"|"3I:2:4") PHYDISK="sdj" ;;
								"1I:3:1"|"2I:3:1"|"3I:3:1") PHYDISK="sdk" ;;
								"1I:3:2"|"2I:3:2"|"3I:3:2") PHYDISK="sdl" ;;
								"1I:3:3"|"2I:3:3"|"3I:3:3") PHYDISK="sdm" ;;
								"1I:3:4"|"2I:3:4"|"3I:3:4") PHYDISK="sdn" ;;
							esac
						elif echo ${LINE} | grep -q 'Disk Name: /dev/' ; then
							MY_DEV_NAME=$(echo ${LINE} | sed 's#^.*Disk Name: ##')
							if [ -n "${PHYDISK}" ] ; then
								echo "$MY_DEV_NAME $PHYDISK" >> $CACHE_FILE
								unset PHYDISK
							fi
							unset MY_DEV_NAME
						fi
					done <$TMPFILE
					rm -f ${TMPFILE}

					# Once it's built, just read from the cache file.
					disk=$(grep $DEVNAME $CACHE_FILE | awk '{ print $2 }')
					if ! [ -n $disk ]; then
						logger -t "udev" "[Normal mode] Device $DEVPATH detected but not found."
						exit 1
					fi
				fi
			else
				logger -t "udev" "Device $DEVPATH detected but not supported"; exit 1
			fi
		else
			logger -t "udev" "Device $DEVPATH detected but not supported"; exit 1
		fi
		logger -t "udev" "Adding symlink $disk for device $DEVPATH"
		echo "$disk"
		exit 0
	;;
	*)
		logger -t "udev" "HPE chassis not supported, exit."
		exit 1
	;;
	esac
;;
*)
	logger -t "udev" "Chassis not supported, exit."
	exit 1
;;
esac
