#!/bin/bash
# 
# netdump	This starts, stops, and reloads the netconsole
#		and netcrashdump facility
#
# chkconfig: - 50 50
# description: Initialize console side of netconsole and netcrashdump facility
# config: /etc/sysconfig/netdump
#

# Copyright 2002 Red Hat, Inc.
#
# Based in part on a shell script by
# Andreas Dilger   Sep 26, 2001

PATH=/sbin:/usr/sbin:$PATH
RETVAL=0

# Check that networking is up.
. /etc/sysconfig/network
if [ ${NETWORKING} = "no" ]
then
    exit 0
fi

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

# Default values
LOCALPORT=6666
DEV=eth0
NETDUMPADDR=
NETDUMPMACADDR=
NETDUMPPORT=6666
IDLETIMEOUT=

SYSLOGADDR=
SYSLOGPORT=514
SYSLOGMACADDR=

[ -f /etc/sysconfig/netdump ] || exit 0
. /etc/sysconfig/netdump
[ -z "$NETDUMPADDR" ] && {
    echo "Server address not specified in /etc/sysconfig/netdump" 1>&2
    exit 1
}


usage ()
{
    echo "Usage: service netdump {start|stop|status|restart|condrestart|propagate}" 1>&2
    RETVAL=1
}

dquad_to_hex ()
{
    echo $1 | sed -e "s/[()]//g" -e "s/\./ /g" | while read I0 I1 I2 I3 ; do
	printf "0x%02X%02X%02X%02X" $I0 $I1 $I2 $I3
    done
}

print_address_info ()
{
    # fill the arp cache with needed data and print info for host
    # usage: print_address_info host
    local host=$1
    local oldIFS arp_output line

    arping -c 1 -I $DEV $host &> /dev/null
    [ $? -ne 0 ] && echo "$prog: cannot arp $host" 1>&2 && usage

    # output from arp -a of the form:
    # good: host.domain (A.B.C.D) at 00:50:BF:06:48:C1 [ether] on eth0
    #           1           2      3         4            5     6   7
    # bad:  ? (A.B.C.D) at  on eth0
    arp_output="$(LC_ALL=C arp -a | grep -v incomplete)"
    oldIFS=$IFS 
    IFS=$'\n'
    for line in $arp_output; do
        IFS=$oldIFS
        set - foo $line
        shift
        if [ "$2" = "($host)" ] || expr "$1" : "$host" &>/dev/null; then
            echo HOSTNAME=$1 IPADDR=$2 AT=$3 MAC=$4 \
                 TYPE=$5 ON=$6 IFACE=$7
            return
        fi
    done
    IFS=$oldIFS

    #if we reach here the operation has failed
    echo 1>&2 "$prog: cannot find $host in arp cache"
    usage
}

random_hex_int ()
{
    dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -x | awk '/0000000/ {print $2$3}'
}

ip_of_device ()
{
    LC_ALL=C /sbin/ifconfig $1 | sed 's/:/ /' | awk '/inet addr/ {print $3}'
}

start ()
{
    # netdump/netconsole server
    NETDUMPOPTS=
    eval $(print_address_info $NETDUMPADDR)
    [ "$HOSTNAME" = "?" -a -z "$MAC" ] && \
	echo "$prog: can't resolve $NETDUMPADDR MAC address" 1>&2 && usage

    [ -z "$NETDUMPMACADDR" ] && NETDUMPMACADDR=$MAC
    [ -z "$DEV" ] && DEV=$IFACE
    [ "$DEV" = "$IFACE" -a "$TYPE" != "[ether]" ] && \
	echo "$prog: $DEV must be an ethernet interface" 1>&2 && usage

    # Now we are ready to tell the netdump server how to talk to us
    MAGIC1=$(random_hex_int)
    MAGIC2=$(random_hex_int)
    LOCALADDR=$(ip_of_device $DEV)
    ssh -x -i /etc/sysconfig/netdump_id_dsa netdump@$NETDUMPADDR echo "$MAGIC2$MAGIC1" \> /var/crash/magic/$LOCALADDR || echo "$prog: could not ssh to server $NETDUMPADDR"
	    
    IPHEX=`dquad_to_hex $IPADDR`
    eval $(echo $NETDUMPMACADDR | sed "s/:/ /g" | ( read M0 M1 M2 M3 M4 M5;
           echo M0=$M0\; M1=$M1\; M2=$M2\; M3=$M3\; M4=$M4\; M5=$M5\; ))
    TGTMAC="netdump_target_eth_byte0=0x$M0 netdump_target_eth_byte1=0x$M1 \
	    netdump_target_eth_byte2=0x$M2 netdump_target_eth_byte3=0x$M3 \
	    netdump_target_eth_byte4=0x$M4 netdump_target_eth_byte5=0x$M5 \
	    netlog_target_eth_byte0=0x$M0 netlog_target_eth_byte1=0x$M1 \
	    netlog_target_eth_byte2=0x$M2 netlog_target_eth_byte3=0x$M3 \
	    netlog_target_eth_byte4=0x$M4 netlog_target_eth_byte5=0x$M5"
    MHZ="mhz=$(awk '/cpu MHz/ { print int($4) ; exit }' < /proc/cpuinfo)"
    if [ "$MHZ" == 0 ] ; then
	# something went wrong; make some reasonable guess
	MHZ=1000
    fi
    if [ -n "$IDLETIMEOUT" ] ; then
	IDLETIMEOUT="idle_timeout=$IDLETIMEOUT"
    fi
    NETDUMPOPTS="magic1=0x$MAGIC1 magic2=0x$MAGIC2 \
	dev=$DEV netdump_target_ip=$IPHEX netlog_target_ip=$IPHEX \
	source_port=$LOCALPORT netdump_target_port=$NETDUMPPORT \
	netlog_target_port=$NETDUMPPORT \
	$TGTMAC $MHZ $IDLETIMEOUT"

    SYSLOGOPTS=
    # syslogd server, if any
    if [ -n "$SYSLOGADDR" ] ; then
	eval $(print_address_info $SYSLOGADDR)
	[ -z "$SYSLOGMACADDR" ] && SYSLOGMACADDR=$MAC
	SYSLOGIPHEX=`dquad_to_hex $IPADDR`
	eval $(echo $SYSLOGMACADDR | sed "s/:/ /g" | ( read M0 M1 M2 M3 M4 M5;
	       echo M0=$M0\; M1=$M1\; M2=$M2\; M3=$M3\; M4=$M4\; M5=$M5\; ))
	SYSLOGMAC="syslog_target_eth_byte0=0x$M0 syslog_target_eth_byte1=0x$M1 \
		syslog_target_eth_byte2=0x$M2 syslog_target_eth_byte3=0x$M3 \
		syslog_target_eth_byte4=0x$M4 syslog_target_eth_byte5=0x$M5"
	SYSLOGOPTS="syslog_target_ip=$SYSLOGIPHEX syslog_target_port=$SYSLOGPORT $SYSLOGMAC"
    fi

    logger -p daemon.info -t netdump: inserting netconsole module with arguments \
	$NETDUMPOPTS $SYSLOGOPTS
    action $"initializing netdump" modprobe netconsole \
	$NETDUMPOPTS $SYSLOGOPTS
    touch /var/lock/subsys/netdump
}

stop ()
{
    action $"disabling netdump" rmmod netconsole
    rm -f /var/lock/subsys/netdump
}

status ()
{
    if /sbin/lsmod | grep netconsole >/dev/null 2>&1 ; then
	echo "netdump module loaded"
    else
	echo "netdump module not loaded"
    fi
}


restart ()
{
    stop
    start
}

condrestart ()
{
    [ -e /var/lock/subsys/netdump ] && restart
}

propagate ()
{
    # propagate netdump ssh public key to the crashdump server
    cat /etc/sysconfig/netdump_id_dsa.pub | \
	ssh -x netdump@$NETDUMPADDR cat '>>' /var/crash/.ssh/authorized_keys2
}

case "$1" in
    start) start ;;
    stop) stop ;;
    status) status ;;
    restart|reload) restart ;;
    condrestart) condrestart ;;
    propagate) propagate ;;
    *) usage ;;
esac

exit $RETVAL