#!/bin/bash
#
# $Id: dagtalker 15387 2012-12-11 21:47:07Z yuri $
#
# process name: dagsnap_lander
# config: /etc/dagtalker.conf
# pidfile: /var/run/dagsnap_lander.pids
#
# chkconfig: 35 98 35
# description: Gets capture data off DAG card and saves to disk

exec 0>/dev/null

THISUSER=$USER #may be overriden in lander.conf (fixme)

#just for paths
LANDER_CONFIG=~plander/lander.conf #XXX
#read config
if [ -e $LANDER_CONFIG ]; then
    . $LANDER_CONFIG
else
    echo "ERROR: Config file $CONFIG does not exist" >&2
    exit 1
fi

. /etc/init.d/functions

DAGSNAP_LOCK=~plander/dagtalker_lock
DAGSNAP_PIDFILE=~plander/dagtalker

function command_not_found_handle () { 
    echo "Failed to execute: $@">&2;
    exit 1 
}

dagtalker_start() {
    local failed=0 running=0 notrunning=0 tostart=
    local n=${#LANDER_DAGSNAP[@]} failures=0
    local ds ds_opt ds_out ds_fs ds_wf
    for ((i=0; i<$n; ++i)); do
	ds=${LANDER_DAGSNAP[$i]}
	ds_out=${LANDER_OUTPUT_BASE[$i]}
	[ -z "$ds" ] && { 
	    echo -n "LANDER_DAGSNAP[$i] not set"; warning
	    echo
	    continue
	}
	[ -z "$ds_out" ] && { 
	    echo -n "LANDER_OUTPUT_BASE[$i] not set"; warning
	    echo
	    continue
	}
	if [ -f $DAGSNAP_LOCK.$i ]; then
	    status -p $DAGSNAP_PIDFILE.$i.pid $ds
	    case "$?" in
		( 0 ) #running
		    let '++running'
		    ;;
		( 1|2|3 ) #dead but pid exists/dead but locked/already stopped
		    let '++failed'
		    tostart="$tostart $i"
		    action "TALKER $i is dead, removing locks " \
			rm -f $DAGSNAP_PIDFILE.$i.pid $DAGSNAP_LOCK.$i || continue
		    ;;
	    esac
	else
	    let '++notrunning'
	    tostart="$tostart $i"
	fi
    done
    if [ "$running" == "$n" ]; then
	echo -n "ALL DAGSNAPs are already running ( $running/$n )"; success
	echo
	return 0
    fi
    if [ $running -gt 0 -a $failed -gt 0 ]; then
	echo -n "Warning ( failed: $failed, notrunning: $notrunning )"; warning
	echo
    fi


    for i in $tostart; do
	ds=${LANDER_DAGSNAP[$i]}
	ds_opt=${LANDER_DAGSNAP_OPTIONS[$i]}
	ds_out=${LANDER_OUTPUT_BASE[$i]}
	ds_fs=${LANDER_OUTPUT_FILESIZE[$i]:-$LANDER_OUTPUT_FILESIZE}
	ds_wf=${LANDER_WATCHFILE[$i]:-$LANDER_WATCHFILE}

	if [ -z "$ds_fs" ]; then
	    echo -n "Filesize for dagsnap $i is unknown"; failure
	    echo
	    continue
	fi
        #-N should be on localfs
	maxseqfile=~plander/.$(hostname -s).maxseq-$i
	[ -e $maxseqfile ] || echo "0" >$maxseqfile
	chown plander:$LANDER_GROUP_MAIN $maxseqfile

	OPTIONS="$ds_opt -B $ds_out/ -S $LANDER_OUTPUT_FILESIZE -N $maxseqfile"
	[ "$LANDER_USE_UTC" = "yes" ] && OPTIONS="$OPTIONS -U"
	[ "$ds_wf" != "" ] && OPTIONS="$OPTIONS -W ${ds_wf}"

	cd /tmp

        #check fs for writability 
	export DAEMON_COREFILE_LIMIT=unlimited

	echo -n $"Starting ($i) $ds: "
        #XXX use lockfile with timeout may be better...
	if [ -z "$LANDER_RUNAS_USER" -o "$LANDER_RUNAS_USER" == "$THISUSER" ]; then
            tmp=`mktemp $ds_out/tmp.XXXXXX 2>/dev/null` || {
		echo -n $"Cannot write to $ds_out "; failure
		echo
		let '++failures'
		continue
            }
            rm -f $tmp
	    nice $LANDER_DAGTALKER_NICE $ds $OPTIONS </dev/null 1>&0 2>&0 &
	    pid=$!
	else
            tmp=`su - $LANDER_RUNAS_USER -s /bin/bash -m -c "mktemp $ds_out/tmp.XXXXXX 2>/dev/null"` || { 
		echo -n $"User $LANDER_RUNAS_USER cannot write to $ds_out "; failure 
		echo
		let '++failures'
		continue
            }
            su -s /bin/bash - $LANDER_RUNAS_USER -c "rm -f $tmp"
	    pid=$(nice ${LANDER_DAGTALKER_NICE:-0} su -s /bin/bash - $LANDER_RUNAS_USER \
	                           -c "$ds $OPTIONS >/dev/null 1>&0 2>&0 & echo \$!")
	fi
	sleep 1s
        #get user info
	user=$USER
	[ -n "$SUDO_USER" ] && user="$SUDO_USER"
	date=`date +'%D %r'`
	date=${date// /_}

	if checkpid $pid; then
	    success "dagtalker $i startup"
	    RETVAL=0
	    echo $"$date $REPO $user" > $DAGSNAP_LOCK.$i
	    echo $pid > $DAGSNAP_PIDFILE.$i.pid
	else
	    failure "dagtalker $i startup"
	    RETVAL=1
	    let '++failures'
	fi
	echo
	sleep 3s
    done
    return $failures
}

dagtalker_stop() {
    local n=${#LANDER_DAGSNAP[@]} failures=0
    local ds
    for ((i=0; i<$n; ++i)); do
	ds=${LANDER_DAGSNAP[$i]}
	status -p $DAGSNAP_PIDFILE.$i.pid $ds
	case "$?" in
	    ( 0 ) #stop it
	        echo -n $"Stopping $ds: "
		if killproc -p $DAGSNAP_PIDFILE.$i.pid $ds -HUP; then
		    
		    rm -f $DAGSNAP_PIDFILE.$i.pid $DAGSNAP_LOCK.$i
		fi
		echo
		;;
	    ( 1|2|3 ) #dead but pid exists/dead but locked/already stopped
	        rm -f $DAGSNAP_PIDFILE.$i.pid $DAGSNAP_LOCK.$i
		;;
	esac
    done
}

dagtalker_reset() {
    local n=${#LANDER_DAGSNAP[@]} failures=0
    local ds reload=
    for ((i=0; i<$n; ++i)); do
        ds=${LANDER_DAGSNAP[$i]}
        status -p $DAGSNAP_PIDFILE.$i.pid $ds
        case "$?" in
            ( 0 ) #stop it
                [ $(basename $ds) != dagsnap_lander ] && continue	
                echo -n $"Dagtalker appears to be running, stop it first " ; warning
                echo
                continue
                ;;
            ( * ) 
                #dead but pid exists/dead but locked/already stopped
                #make sure modules are re-loaded
                if [ -z "$reload" ]; then
                    if /sbin/lsmod | /bin/grep -P '^dag\s' >/dev/null 2>&1; then
                        /sbin/rmmod dag dagmem
                    fi
                    #re-load dag modules (multiple of 80 bytes and 4K => multiple of 20K)
                    /sbin/modprobe dagmem $LANDER_DAGMEMOPTS
                    #tweak groups in dagload
                    sed "s/^group=.*/group=\"$LANDER_GROUP_RAW\"/1" /usr/bin/dagload | /bin/bash
                    reload=T
                fi
                dagdev=${LANDER_DAGDEV[$i]}
                if [ -z "$dagdev" ]; then 
                    echo -n "No DAGDEV is specified for $i, not resetting "; failure
                    echo
                    continue
                fi
                dagcard=$(dagdetect -n -d $dagdev)
                case $dagcard in
                    ( "DAG 4.3GE" ) bitimg="/usr/share/dag/xilinx/dag43gepcix-terf.bit" ;;
                    ( "DAG 4.5G2" ) bitimg="/usr/share/dag/xilinx/dag45g2pcix-terf-dsm.bit" ;;
                    ( "DAG 8.1SX" ) bitimg="/usr/share/dag/xilinx/dag81sxpci-bfs-eth.bit" ;;
                    (      *      ) echo $"UNKNOWN version of dag card: '$dagcard' (fixme)" >&2; continue ;;
                esac
                #XXX image and opts should be in config
                dagconfig -d "$dagdev" default
                dagreset -d "$dagdev"
                dagrom -vryp -d "$dagdev" < $bitimg
                dagconfig -d "$dagdev" ${LANDER_DAGCONFIG[$i]:-${LANDER_DAGCONFIG[0]}} \
		    slen=${LANDER_SNAPLENGTH[$i]:-${LANDER_SNAPLENGTH[0]}}
                #load filters
                floader="$LANDER_SCRIPTDIR/lander_install_filters.sh"
                if [ -x "$floader" ]; then
                    $floader "$dagdev"
                else
                    echo "Cannot load filters (cannot execute $floader $dagdev)" >&2;
                fi
                clockargs=${LANDER_DAGCLOCK_ARGS[$i]:-$LANDER_DAGCLOCK_ARGS}
                [ -n "$clockargs" ] && dagclock -d "$dagdev" $clockargs

                #record the time dag was reset
                touch /var/cache/dagreset.$dagdev
                ;;
        esac
    done
}

dagtalker_status() {
    local failed=0 running=0 notrunning=0 tostart=
    local n=${#LANDER_DAGSNAP[@]} success=0
    local ds ds_wf
    for ((i=0; i<$n; ++i)); do
	ds=${LANDER_DAGSNAP[$i]}
	ds_wf=${LANDER_WATCHFILE[$i]:-$LANDER_WATCHFILE}
	status -p $DAGSNAP_PIDFILE.$i.pid $ds
	if [ "$?" == "0" -a -f $DAGSNAP_LOCK.$i ]; then
	    local date fs user ignore
	    read date fs user ignore < $DAGSNAP_LOCK.$i
	    date=${date//_/ }
	    if [ -e $ds_wf ]; then
		echo -n $"Dumping on $fs, started on $date by $user "
		success
	    else
		echo -n $"Dumping on $fs is enabled on $date by $user, but waiting on watchfile $ds_wf "
		warning
	    fi
	    echo
	fi
    done
}

dagtalker_startmain() {
    REPO="main"
    dagtalker_start
}

dagtalker_startbackup() {
    #copy (possibly) array
    unset LANDER_OUTPUT_BASE
    for i in ${!LANDER_OUTPUT_BASE_BACKUP[*]}; do
	LANDER_OUTPUT_BASE[$i]=${LANDER_OUTPUT_BASE_BACKUP[$i]}
    done
    REPO="backup"
    unset LANDER_WATCHFILE
    dagtalker_start
}

dagtalker_movebackup() {
    cd "$LANDER_OUTPUT_BASE_BACKUP"
    export MAILTO=$LANDER_ADMIN
    nohup bash -c "if find . -xdev -type f -name '[0-9]*-[0-9]*-[0-9]*' -print | \
	                   sort | xargs -n 1 -I '{}' mv '{}' $LANDER_OUTPUT_BASE; then 
                       subj='moving backup from $(hostname -s): done'
		   else
                       subj='moving backup from $(hostname -s): fail'
		   fi
                   echo \$subj | mail -s \"\$subj\" $MAILTO" >/tmp/dagtalker.movebackup &
    disown
    return 0
}

case "$1" in
    ( reset )
        status $LANDER_DAGSNAP && {
	    echo $"Dagtalker appears to be running" 1>&2
	    exit 1;
	}
        dagtalker_reset
	;;
    ( start|start-main )
        if status $LANDER_DAGSNAP; then
	    dagtalker_stop
	    dagtalker_startmain
	else
	    #dagtalker_reset
	    dagtalker_startmain
	fi
	;;
    ( start-backup)
        if status $LANDER_DAGSNAP; then
	    dagtalker_stop
	else
	    : #dagtalker_reset
	fi
	dagtalker_startbackup
	;;
    ( stop )
	dagtalker_stop
	;;
    ( status )
	dagtalker_status
	;;
    ( restart|restart-main )
        dagtalker_stop
        dagtalker_startmain
	;;
    ( restart-backup )
	    dagtalker_stop
        dagtalker_startbackup
    ;;
    ( startifnotrunning )
	    status $LANDER_DAGSNAP >/dev/null 2>&1 || { dagtalker_stop; dagtalker_startmain; exit 1; }
	;;
    ( move-backup )
        dagtalker_movebackup
	;;
    *)
	echo $"Usage: `basename $0` {reset|start|start-backup|restart|restart-backup|startifnotrunning|stop|move-backup|status}"
	exit 1
esac

exit $?
