#!/bin/bash
#
# scsi_reserve persistent reservation service for lvm
#
# chkconfig: - 25 75
# description: start/stop persistent reservation service for lvm

### BEGIN INIT INFO
# Provides:		scsi_reserve
# Required-Start:	cman
# Required-Stop:	cman
# Default-Start:
# Default-Stop:
# Short-Description:	start/stop persistent reservation service for lvm
# Description:		start/stop persistent reservation service for lvm
### END INIT INFO

. /etc/init.d/functions

# read in config file if it exists
#
if [ -f /etc/sysconfig/scsi_reserve ] ; then
    . /etc/sysconfig/scsi_reserve
    echo "/etc/sysconfig/scsi_reserve has been deprecated in favour of /etc/sysconfig/cluster"
    echo "Please consider switching to the new file"
fi

[ -f /etc/sysconfig/cluster ] && . /etc/sysconfig/cluster

# check that cman is running
#
if ! cman_tool status &> /dev/null ; then
    logger -t scsi_reserve \
	"[error] cman does not appear to be running"
    exit 1
fi

# check if cluster is configured for fence_scsi
#
if ! fence_scsi_test -t fence ; then
    logger -t scsi_reserve \
	"[error] cluster not configured for scsi reservations"
    exit 1
fi

# check for sg_persist command provided by sg3_utils package
#
if ! sg_persist -V &> /dev/null ; then
    logger -t scsi_reserve \
	"[error] unable to exec sg_persist"
    exit 1
fi

# get physical volumes (devices) that are part of cluster volumes
#
scsi_devices=$( vgs --config 'global { locking_type = 0 }' \
                    --noheadings -o vg_attr,pv_name 2> /dev/null \
              | awk ' $1 ~ /.*c$/ { print $2 } ' )

if [ -z "$scsi_devices" ] ; then
    logger -t scsi_reserve \
	"[error] did not find devices in cluster volumes"
    exit 1
fi

# get the cluster id from cman
#
cluster_id=$( cman_tool status | grep -i "Cluster ID" \
            | awk -F": " '{ print $2 }' )

if [ -z "$cluster_id" ] ; then
    logger -s -t scsi_reserve \
	"[error] unable to determine cluster id"
    exit 1
fi

# get the node id from cman
#
node_id=$( cman_tool status | grep -i "Node ID" \
         | awk -F": " '{ print $2 }' )

if [ -z "$node_id" ] ; then
    logger -t scsi_reserve \
	"[error] unable to determine node id"
    exit 1
fi

# generate unique key using cluster_id and node_id
#
key=$( printf "%x%.4x" $cluster_id $node_id )

if [ -z "$key" ] ; then
    logger -t scsi_reserve \
	"[error] unable to generate key"
    exit 1
fi

################################################################################

case $1 in

    start)

	error=0
	count=0

	echo -n "Starting scsi_reserve:"

	for dev in $scsi_devices
	do
	  # check if our key is already resgistered with this device
	  #
	  if sg_persist -n -d $dev -i -k | grep -qiE "^[[:space:]]*0x$key" ; then
	      logger -t scsi_reserve \
		"[info] already registered with $dev (key=0x$key)"
	      continue
	  fi

	  # create the scsi registration
	  #
	  if ! sg_persist -n -d $dev -o -I -S $key &> /dev/null ; then
	      logger -t scsi_reserve \
		"[error] unable to register device $dev (key=0x$key)"
	      : $[ count = $count + 1 ]
	      error=1
	  else
	      logger -t scsi_reserve \
		"[info] registered with device $dev (key=0x$key)"
	  fi

	  # check to see if reservation already exists
	  #
	  if sg_persist -n -d $dev -i -r | grep -qiE "^[[:space:]]*Key=0x" ; then
	      logger -t scsi_reserve \
		"[info] reservation already exists on $dev"
	      continue
	  fi

	  # create the scsi reservation
	  #
	  if ! sg_persist -n -d $dev -o -R -K $key -T 5 &> /dev/null ; then
	      logger -t scsi_reserver \
		"[error] unable to create reservation on $dev (key=0x$key)"
	      : $[ count = $count + 1 ]
	      error=1
	  fi
	done

	# leave fence domain if any errors occured during registration
	#
	if [ $error -eq 0 ] ; then
	    success
	else
	    logger -t scsi_reserve \
		"[info] $count errors during registration"
	    logger -t scsi_reserve \
		"[info] leaving the fence domain"
	    fence_tool leave
	    failure
	fi

	touch /var/lock/subsys/scsi_reserve

	echo

	;; # end of start

    stop)

	error=0
	count=0

	echo -n "Stopping scsi_reserve:"

	for dev in $scsi_devices
	do
	  # get list of keys registered with this device
	  #
	  key_list=$( sg_persist -n -d $dev -i -k | grep -iE "^[[:space:]]*0x" )

	  # check that our key is registered with this device
	  #
	  if ! sg_persist -d $dev -i -k | grep -qiE "^[[:space:]]*0x$key" ; then
	      logger -t scsi_reserve \
		"[info] not registered with $dev (key=0x$key)"
	      continue
	  fi

	  # check if our key is the reservation holder
	  #
	  if sg_persist -n -d $dev -i -r 2>/dev/null | grep -qiE "$key" ; then
	      if echo "$key_list" | grep -qivE "$key" ; then
		  logger -t scsi_reserve \
		      "[error] unable to remove registration on $dev (key=0x$key)"
		  : $[ count = $count + 1 ]
		  error=1
		  continue
	      fi
	  fi

	  # remove registration for this device
	  #
	  if ! sg_persist -n -d $dev -o -G -K $key -S 0 &> /dev/null ; then
	      logger -t scsi_reserve \
		"[error] failed to remove registration on $dev (key=0x$key)"
	      : $[ count = $count + 1 ]
	      error=1
	  else
	      logger -t scsi_reserve \
		"[info] removed registration on $dev (key=0x$key)"
	  fi

	done

	# report success or failure
	#
	if [ $error -eq 0 ] ; then
	    success
	else
	    logger -t scsi_reserve \
		"[info] $count errors occured during unregistration"
	    failure
	fi

	rm -f /var/lock/subsys/scsi_reserve

	echo

	;; # end of stop

    status)

	error=0

	for dev in $scsi_devices
	do
	  if sg_persist -n -d $dev -i -k | grep -qiE "$key" ; then
	      devices[${#devices[@]}]=$dev
	  fi
	done

	if [ -z "$devices" ] ; then
	    echo "No registered devices found."
	else
	    echo "Found ${#devices[@]} registered device(s):"

	    for i in "${devices[@]}"
	    do
	      echo $i
	    done
	fi

	;; # end of status

    restart|reload)
	$0 stop
	$0 start
	;;

    *)
	echo $"Usage: $0 {start|stop|restart|reload|status}"
	exit 1

esac

exit $error
