#!/bin/sh

. /opt/etc/functions.openrc

CONFIG=/opt/etc/hddmon.conf

TEMP_WARN=43
TEMP_SHUTDOWN=54
HDD_DATABASE=/opt/var/smart.hdd

HDD_NEW_DATABASE=/tmp/smart.hdd
WARNINGS=0
CRITICAL=0
LOCKFILE=/tmp/hddmon.lock
TMP=/tmp/hdtemp.tmphaha

if [ -f $LOCKFILE ]; then
	exit 1;
fi

if [ -f $CONFIG ]; then
	.	$CONFIG
fi

touch $LOCKFILE

# Get current state of HDDs

if [ -f $HDD_NEW_DATABASE ]; then
	rm -f $HDD_NEW_DATABASE
fi

for HDD in `ls /dev/sd?`; do
	rm -f $TMP > /dev/null 2>&1
	[ -n "${IGNORE_HDDS}" ] && echo ${IGNORE_HDDS} | grep $(basename $HDD) > /dev/null && continue;
	smartctl -a $HDD > $TMP
#	echo "== $HDD"
	if [ `cat $TMP | wc -l` -le 10 ]; then
#	USB memstick? SES device? Hardly broken HDD? Just ignore it.
#		echo "Unable to get SMART for $HDD"
#		WARNINGS=$(($WARNINGS + 1))
		continue
	fi
	if (grep '^ATA' $TMP > /dev/null 2>&1); then
		MODEL=`grep 'Device Model:' $TMP | awk '{print $3;}'`
		SERIAL=`grep 'Serial Number:' $TMP | awk '{print $3;}'`
		TEMPERATURE=`grep ^194 $TMP | awk '{print $10;}'`
		[ "${TEMPERATURE}" = "" ] && TEMPERATURE=`grep ^190 $TMP | awk '{print $10;}'`
		REALLOCATED=`grep Reallocated_Sector $TMP | awk '{print $10;}'`
		PENDING=`grep ^197 $TMP | awk '{print $10;}'`
		[ "${PENDING}" = "" ] && PENDING=0
		DEFECTS=$(($REALLOCATED + $PENDING))
#		echo "$HDD SATA MODEL $MODEL SERIAL $SERIAL TEMPERATURE $TEMPERATURE DEFECTS $DEFECTS"
		echo "SATA $MODEL $SERIAL $TEMPERATURE $DEFECTS $HDD" >> ${HDD_NEW_DATABASE}
		continue;
	fi
	if (grep 'SAS' $TMP > /dev/null 2>&1); then
		VENDOR=`grep 'Vendor:' $TMP | awk '{print $2;}'`
		PRODUCT=`grep 'Product:' $TMP | awk '{print $2;}'`
		MODEL=${VENDOR}"-"${PRODUCT}
		SERIAL=`grep 'Serial number:' $TMP | awk '{print $3;}'`
		TEMPERATURE=`grep 'Current Drive Temperature:' $TMP | awk '{print $4;}'`
		DEFECTS=`grep 'Elements in grown defect list:' $TMP | awk '{print $6;}'`
#		echo "$HDD SAS MODEL $MODEL SERIAL $SERIAL TEMPERATURE $TEMPERATURE DEFECTS $DEFECTS"
		echo "SAS $MODEL $SERIAL $TEMPERATURE $DEFECTS $HDD" >> ${HDD_NEW_DATABASE}
		continue;
	fi
done

rm -f $TMP

if ! [ -f $HDD_DATABASE ]; then
	# First call
	cat $HDD_NEW_DATABASE > $HDD_DATABASE
fi

# Search for added/removed devices

NUMHDD=`cat $HDD_NEW_DATABASE|wc -l`
OLDNUMHDD=`cat $HDD_DATABASE|wc -l`

if [ $OLDNUMHDD -ne $NUMHDD ]; then
	update_me
	echo "${ME}: number of HDD changed, old $OLDNUMHDD, new $NUMHDD"
	WARNINGS=$(($WARNINGS + 1))
fi

# Compare new state with prevous one, line by line reading of new database

update_me

for HDDNO in `seq 1 $NUMHDD`; do
	HDD_NEW_STATE=`cat $HDD_NEW_DATABASE | head -n $HDDNO | tail -n 1`
	SERIAL=`echo $HDD_NEW_STATE|awk '{print $3}'`
	TEMPERATURE=`echo $HDD_NEW_STATE|awk '{print $4}'`
	DEFECTS=`echo $HDD_NEW_STATE|awk '{print $5}'`
	HDD_STATE=`grep $SERIAL $HDD_DATABASE`
	if [ $? -eq 0 ]; then
		OLD_DEFECTS=`echo $HDD_STATE|awk '{print $5}'`
		if [ "$OLD_DEFECTS" = "" ]; then
			echo "${ME}: unable to get prev num_defects for $SERIAL (old state: [$HDD_STATE])"
			OLD_DEFECTS=0
		fi
	else
		echo "${ME}: drive $SERIAL previously unknown"
		OLD_DEFECTS=0
	fi
	if test $DEFECTS -gt $OLD_DEFECTS; then
		echo "${ME}: $SERIAL: number of defects increased from $OLD_DEFECTS to $DEFECTS."
		WARNINGS=$(($WARNINGS + 1))
	fi
	if test $TEMPERATURE -ge $TEMP_WARN; then
		if test $TEMPERATURE -ge $TEMP_SHUTDOWN; then
			echo "${ME}: $SERIAL: HDD(s) OVERHEATED, $TEMPERATURE, powering server off!"
			CRITICAL=$(($CRITICAL + 1))
		else
			echo "${ME}: $SERIAL: overheating, $TEMPERATURE."
		fi
		WARNINGS=$(($WARNINGS + 1))
	fi
done

cat $HDD_NEW_DATABASE > $HDD_DATABASE
rm $HDD_NEW_DATABASE

if test $WARNINGS -gt 0; then
	update_me
	echo "${ME}: Total warnings: ${WARNINGS}"
fi

if test $CRITICAL -gt 0; then
	shutdown -hP +1 "HDD_Overheat_${CRITICAL}"
fi

if ! [ -z $REPORT_FILE ]; then
	cat $HDD_DATABASE > $REPORT_FILE
fi
	
rm -f $LOCKFILE
