#!/bin/bash

### BEGIN INIT INFO
# Provides:          rawdev
# Required-Start:    $syslog $local_fs
# Required-Stop:     $syslog $local_fs
# Default-Start:     3 5
# Default-Stop:      0 1 2 6
# Short-Description: Raw Partition Setup
# Description:       Raw Partition Setup
### END INIT INFO

# chkconfig: 35 98 02
# description: Raw Partition Setup

# Place this file at /etc/init.d/rawdev (or
# /etc/rc.d/init.d/rawdev) and make symlinks to
#   /etc/rc.d/rc0.d/K02rawdev
#   /etc/rc.d/rc1.d/K02rawdev
#   /etc/rc.d/rc2.d/K02rawdev
#   /etc/rc.d/rc3.d/S98rawdev
#   /etc/rc.d/rc4.d/S98rawdev
#   /etc/rc.d/rc5.d/S98rawdev
# Or check out the chkconfig program, if you have it.
#
## EDIT FROM HERE, if you absolutely must. Rather use /etc/sysconfig/rawdev, though.

# The "raw" command
RAWCMD=/usr/sbin/raw

# Prefix for raw devices [including device name, but not its consecutive number]
RAWPFX=/dev/raw

# The device(s) we're binding
RAWDEV[0]=
RAWDEV[1]=
RAWDEV[2]=
RAWDEV[3]=
RAWDEV[4]=

## STOP EDITING HERE

# The name of this script
MYNAME="rawdev"

# Source the sysconfig file, if present
if [ -f /etc/sysconfig/rawdev ]; then
    . /etc/sysconfig/rawdev
else
    echo "${MYNAME}: Please create /etc/sysconfig/rawdev"
fi

# Return values acc. to LSB for all commands but status:
# 0 - success
# 1 - generic or unspecified error
# 2 - invalid or excess argument(s)
# 3 - unimplemented feature (e.g. "reload")
# 4 - insufficient privilege
# 5 - program is not installed
# 6 - program is not configured
# 7 - program is not running
# 
# Note that starting an already running service, stopping
# or restarting a not-running service as well as the restart
# with force-reload (in case signalling is not supported) are
# considered a success.

if ! test -x ${RAWCMD}; then
    echo "${MYNAME}: Cannot execute ${RAWCMD}"
    exit 5
fi
CTR=0
while [ -n "${RAWDEV[${CTR}]}" ]; do
    if ! test -b ${RAWDEV[${CTR}]}; then
	echo "${MYNAME}: ${RAWDEV[${CTR}]} is not a block device"
	exit 6
    fi
    CTR=$((CTR + 1))
done

# Check for echo -n vs echo \c
if echo '\c' | grep -s c >/dev/null 2>&1 ; then
    ECHO_N="echo -n"
    ECHO_C=""
else
    ECHO_N="echo"
    ECHO_C='\c'
fi

# get_majorminor
# Returns the "major:minor" numbers for a given device
# Arguments: device name as $1
get_majorminor() {
    local DEV=$1

    [ -z "${DEV}" ] && return 1

    # See if device exists (must be a block special)
    if [ ! -b ${DEV} ]; then
	return 1
    fi

    # List it and grep out the numbers
    echo "`ls -l ${DEV} | tr -s ' ' | cut -f 5,6 -d ' ' | sed 's/, /:/'`"
    return 0
}

# get_occupant
# Returns the "major:minor" numbers of the partition occupying a raw device
# Arguments: raw device name as $1
get_occupant() {
    local DEV=$1

    [ -z "${DEV}" ] && return 1

    # See if device exists (must be a character special)
    if [ ! -c ${DEV} ]; then
	return 1
    fi

    # Query it and grep out the numbers
    ${RAWCMD} -q ${DEV} | sed 's/^.*major \([0-9]*\), minor \([0-9]*\).*$/\1:\2/'

    return 0
}

# Parse command line parameters.
case $1 in
  start)
	# See if the rawctl device exists, wait for up to five seconds
	echo -n "${MYNAME}: Checking for /dev/rawctl... "
	CTR=0
	while [ ! -c /dev/rawctl ] && [ ${CTR} -lt 5 ]; do
	    echo -n "."
	    sleep 1
	    CTR=$((CTR + 1))
	done
	if [ ${CTR} -lt 5 ]; then
	    echo "OK."
	else
	    echo "ERROR: /dev/rawctl not found."
	    exit 1
	fi

	# Bind the partitions to raw devices
	echo "${MYNAME}: Binding disk partitions to raw devices:"
	CTR=0
	# Walk through the configured device list
	while [ -n "${RAWDEV[${CTR}]}" ]; do
	    ${ECHO_N} "${MYNAME}:  - ${RAWDEV[${CTR}]}: "${ECHO_C}

	    # Obtain major and minor number for our partition, since
	    # we're going to need them in occupied raw device tests
	    MMDEV="`get_majorminor ${RAWDEV[${CTR}]}`"

	    # Search for the next available raw device, checking if those
	    # occupied haven't been occupied by our current partition
	    DEV=1
	    BRK=0
	    while [ ${DEV} -lt 256 ]; do
		# Does the device exist?
		if ${RAWCMD} -q ${RAWPFX}${DEV} > /dev/null 2>&1; then
		    CDEV="`get_occupant ${RAWPFX}${DEV}`"
		    # Is it occupied at all?
		    if [ "${CDEV}" = "0:0" ]; then
			# OK! We got ourselves a free raw device!
			break
		    # Now, has it been occupied by OUR partition?
		    elif [ "${CDEV}" = "${MMDEV}" ]; then
			echo "already mapped to ${RAWPFX}${DEV}." 
			BRK=1
			break
		    fi
		else
		    # OK! We got ourselves a free raw device!
		    break
		fi
		DEV=$((DEV + 1))
	    done
	    if [ ${DEV} -eq 256 ]; then
		echo "ran out of raw devices!"
		exit 1
	    elif [ ${BRK} -eq 1 ]; then
		CTR=$((CTR + 1))
		continue
	    fi

	    # Map the partition
	    ${RAWCMD} ${RAWPFX}${DEV} ${RAWDEV[${CTR}]}
	    CTR=$((CTR + 1))
	done
	;;
  stop)
	# Unbind the partitions from raw devices
	echo "${MYNAME}: Unbinding disk partitions from raw devices:"
	CTR=0
	# Walk through the configured device list
	while [ -n "${RAWDEV[${CTR}]}" ]; do
	    ${ECHO_N} "${MYNAME}:  - ${RAWDEV[${CTR}]}: "${ECHO_C}

	    # Obtain major and minor number for our partition, since
	    # we're going to need them in occupied raw device tests
	    MMDEV="`get_majorminor ${RAWDEV[${CTR}]}`"

	    # Search for the raw device occupied by our current partition
	    DEV=1
	    BRK=0
	    while [ ${DEV} -lt 256 ]; do
		# Is the device available?
		if ! ${RAWCMD} -q ${RAWPFX}${DEV} > /dev/null 2>&1; then
		    DEV=$((DEV + 1))
		    continue
		fi

		# Now, has it been occupied by OUR partition?
		CDEV="`get_occupant ${RAWPFX}${DEV}`"
		if [ ! "${CDEV}" = "${MMDEV}" ]; then
		    DEV=$((DEV + 1))
		    continue
		fi

		# OK, we found our partition.
		break
	    done

	    if [ ${DEV} -eq 256 ]; then
		echo "apparently not mapped."
		CTR=$((CTR + 1))
		continue
	    fi

	    # Unmap the partition
	    ${RAWCMD} ${RAWPFX}${DEV} 0 0

	    # Proceed to next device
	    CTR=$((CTR + 1))
	done
	;;
  restart)
	$0 stop
	$0 start
	;;
  status)
	# Unbind the partitions from raw devices
	echo "${MYNAME}: Checking status of configured disk partitions:"
	CTR=0
	# Walk through the configured device list
	while [ -n "${RAWDEV[${CTR}]}" ]; do
	    ${ECHO_N} "${MYNAME}:  - ${RAWDEV[${CTR}]}: "${ECHO_C}

	    # Obtain major and minor number for our partition, since
	    # we're going to need them in occupied raw device tests
	    MMDEV="`get_majorminor ${RAWDEV[${CTR}]}`"

	    # Search for the raw device occupied by our current partition
	    DEV=1
	    BRK=0
	    while [ ${DEV} -lt 256 ]; do
		# Is the device available?
		if ! ${RAWCMD} -q ${RAWPFX}${DEV} > /dev/null 2>&1; then
		    DEV=$((DEV + 1))
		    continue
		fi

		# Now, has it been occupied by OUR partition?
		CDEV="`get_occupant ${RAWPFX}${DEV}`"
		if [ ! "${CDEV}" = "${MMDEV}" ]; then
		    DEV=$((DEV + 1))
		    continue
		fi

		# OK, we found our partition.
		break
	    done

	    if [ ${DEV} -eq 256 ]; then
		echo "apparently not mapped."
		CTR=$((CTR + 1))
		continue
	    fi

	    echo "mapped to ${RAWPFX}${DEV}"

	    # Proceed to next device
	    CTR=$((CTR + 1))
	done
	;;
  *)
	# Print help
	echo "Usage: $0 {start|stop|restart|status}" 1>&2
	exit 1
	;;
esac

