#!/bin/sh
#
#	/etc/rc.d/init.d
#
# Automatic/manual startup of PPP connectivity to RAC's virtual UART
#
# chkconfig: 2345 20 80
# description: Starts PPP connection to the Dell Remote Assistant Controller, \
#					which allows remote management of computing devices.
# processname: racser
# config: /etc/sysconfig/racser
# config: /etc/ppp/peers/racser

# Source function library.
. /etc/rc.d/init.d/functions

program=`basename $0`
service="racser"
pppfile="/etc/ppp/peers/${service}"
cfgfile="/etc/sysconfig/${service}"

# Source service configuration file, if available
[ -f ${cfgfile} ] && . ${cfgfile}
RETVAL=0
LANG=C	# run in 'C' locale

racsvc="pppd (RAC) services"
racpci="1028:0008"
emsg=
norac="RAC pci device not found"
notty="no RAC tty device found"
maddr=
irqno=
ttyid=

# test for the RAC pci device, ensure setserial available.
#  if found, save IRQ, I/O ADDR, and chosen tty from RAC PPP client script
function testrac
{
	which setserial >/dev/null 2>&1
	[ $? -ne 0 ] && { emsg="'setserial' not found"; return 1; }
	irqno=`lspci -d ${racpci} -v 2>/dev/null|grep "IRQ " 2>/dev/null`
	[ -z "${irqno}" ] && { emsg=${norac}; return 1; }
	irqno=${irqno##* }
	maddr=`lspci -d ${racpci} -v 2>/dev/null|grep "I/O " 2>/dev/null`
	[ -z "${maddr}" ] && { emsg=${norac}; return 1; }
	maddr=${maddr% [*}
	maddr=${maddr##* }
	# desired tty is 1st word on last line of RAC PPP client script
	ttyid=`tail -n1 ${pppfile} 2>/dev/null|cut -d' ' -f1`
	[ -z "${ttyid}" -o ! -c /dev/${ttyid} ] && { emsg=${notty}; return 2; }
	return 0
}

# find an available tty, or the one already in use by RAC
function get_ttyname
{
	# ensure that RAC is present
	racinfo=`lspci -d "$racpci" -v 2>/dev/null|grep "I/O " 2>/dev/null`
	[ -z "${racinfo}" ] && { emsg=${norac}; return 1; }

	# check whether the RAC device is already in use by serial
	racinfo=${racinfo% [*}
	uaddr=`echo ${racinfo##* }|tr [a-f] [A-F]`
	laddr=`echo ${racinfo##* }|tr [A-F] [a-f]`
	taginfo="port"
	serfile="/proc/tty/driver/serial"

	hit=`cat ${serfile}|grep -v unknown|grep "${taginfo}:${laddr}\|${taginfo}:${uaddr}\|${taginfo}:0000${laddr}\|${taginfo}:0000${uaddr}"`
	if [ -n "$hit" ]; then
		ttyname="ttyS"`echo $hit|cut -f1 -d':'`
	else
		# RAC port not yet in use; pick lowest available ttyno >= 2
		hit=99999
		shopt -s extglob
		for i in `ls /dev/ttyS+([[:digit:]])`
		{
			ttyno=${i#/dev/ttyS}
			if [ ${ttyno} -ge 2 -a ${ttyno} -lt $hit ]; then
				bzy=`cat ${serfile} 2>/dev/null|grep -v unknown|grep "^${ttyno}:"`
				[ -z "${bzy}" ] && hit=${ttyno}
			fi
		}
		[ $hit -eq 99999 ] && { emsg=${notty}; return 2; }	# none found
		taginfo=
		ttyname="ttyS$hit"
	fi

	# check for pre-configured tty name
	if [ -n "$RACSER_TTY" -a ! "$RACSER_TTY" = "$ttyname" ]; then

		# if tty for RAC device is being changed, 'unset' prior tty
		[ -n "$taginfo" ] && setserial /dev/${ttyname} -z \
												uart unknown port 0x0 irq 0x0
		ttyname=${RACSER_TTY}
	fi
	return 0
}

# update the ttyname in the RAC PPP client script
function set_chatty
{
	get_ttyname
	rc=$?

	# ensure that ttyname is valid, and RAC PPP client script exists
	[ $rc -ne 0 -o ! -c /dev/${ttyname} -o ! -e ${pppfile} ] && return $((rc+1))

	# tty is 1st word on last line of RAC PPP client script
	ttyid=`tail -n1 ${pppfile}|cut -d' ' -f1`

	# if tty already correct, just leave
	[ "${ttyid}" = "${ttyname}" ] && return 0

	sed "s/^${ttyid} /${ttyname} /" <${pppfile} >/tmp/.racchat
	mv -f /tmp/.racchat ${pppfile} && chmod 644 ${pppfile}
	return $?
}

# get pid of RAC pppd instance, if running
racppp=`ps --no-headers -C "pppd call ${service}\$" -o"%p"`

# See how we were called.
case "$1" in
  start)
	if [ -n "${racppp}" ]; then
		echo -n "${racsvc} already running..."
		RETVAL=1
		#failure "$program $1"
	else
		set_chatty				# get/update RAC PPP client script ttyname
		RETVAL=$?
		[ $RETVAL -eq 0 ] && { testrac ; RETVAL=$? ; }

		if [ $RETVAL -ne 0 ]; then
			echo -n "Probe of RAC board: "
			[ -n "${emsg}" ] && echo -n "${emsg} "
			failure "$program $1"
		else
			echo -n "Starting ${racsvc}: "
			# set serial characteristics for RAC device
			setserial /dev/${ttyid} \
				port 0x${maddr} irq ${irqno} ^skip_test autoconfig
			setserial /dev/${ttyid} \
				uart 16550A baud_base 1382400	\
				close_delay 0 closing_wait infinite
			# now start pppd
			/sbin/modprobe -q ppp >/dev/null 2>&1
			/sbin/modprobe -q ppp_async >/dev/null 2>&1
			daemon pppd call ${service}
			RETVAL=$?
		fi
	fi
	echo
	;;
  stop)
	#if the process exists kill otherwise no need to kill
	if [ -n "${racppp}" ]; then
		echo -n "Stopping ${racsvc}: "
		kill ${racppp}
		[ $? -ne 0 ] && RETVAL=1
		[ $RETVAL -eq 0 ] && success "$program $1" || failure "$program $1"
		echo
	fi
	;;
  status)
	echo -n "Checking ${racsvc}: "
	if [ -z "${racppp}" ]; then
		echo -n "not running "
		RETVAL=1
	fi
	[ $RETVAL -eq 0 ] && success "$program $1" || failure "$program $1"
	echo
	;;
  probe)
	echo -n "Probe of RAC board: "
	testrac
	RETVAL=$?
	[ $RETVAL -eq 0 ] && success "$program $1" || failure "$program $1"
	echo
	;;
  *)
	echo "Usage: ${service} {start|stop|status|probe}"
	RETVAL=1
esac

exit $RETVAL
