#!/bin/bash
##############################################################################
# This script can be used to process the xferlog-files which are generated
# by the ftpd. In the xferlog, one line is stored per file-transfer.
# This script counts the number of transfers, the number of seconds which
# are used for that and the number of kilobytes transferred. This information
# is stored in the ftpstat-file called /var/log/atsar/ftpstat,
# containing one line per xferlog with the following format:
#
#       field  1: output: cumulative_transfers
#       field  2: output: cumulative_seconds
#       field  3: output: cumulative_kbytes
#       field  4: input:  cumulative_transfers
#       field  5: input:  cumulative_seconds
#       field  6: input:  cumulative_kbytes
#       field  7: date of last processed logfile-message
#       field  8: time of last processed logfile-message
#       field  9: last processed offset in the xferlog-file
#       field 10: name of the xferlog-file
#       field 11: symbolic name (shown in atsar output)
#
# Every time this script is started, it reads the information from the
# ftpstat-file. For every xferlog-file it continues scanning at the point
# that it stopped the previous time. At the end of a run, the information
# in de ftpstat-file will be updated with the new figures.
#
# Note that this script should be activated with regular intervals.
# Obviously the information in the ftpstat-file is not accurate any more
# if between two runs of this script *all* generations of the
# xferlog-files have been cyclicly refilled.
#
# This script must be started without command-line parameters.
# ============================================================================
# Author: Gerlof Langeveld - AT Computing Nijmegen, Holland
# Date:   August  1999 - Initial
#         October 1999 - Separate counters for output and input
#         March   2001 - Configurable name for xferlog-file
#         March   2001 - More than one FTP-log file supported
##############################################################################
CONFIGF=/etc/atsar.conf
FTPSTAT=/var/log/atsar/ftpstat

##############################################################################
# if no statistics-file exists yet, one will be created
##############################################################################
if [ ! -f $FTPSTAT ]
then
	> $FTPSTAT	# file exists anyhow  even if no logfile present

	if [ ! -f $CONFIGF ]
	then
		exit 0
	fi

	CURDATE=`date +%Y%m%d`
	CURTIME=`date +%H%M%S`

	# generate one line for every logfile
	#
	while read CURTYPE CURLOGF CURNAME REST 
	do
		if [ "$CURTYPE" != "FTP" -o "$CURLOGF" = "" -o "$CURNAME" = "" ]
		then
			continue
		fi

		if [ -f $CURLOGF ]
		then
			CUROFFSET=`ls -l $CURLOGF | awk '{print $5}'`

			echo "0 0 0 0 0 0 $CURDATE $CURTIME $CUROFFSET $CURLOGF $CURNAME" >> $FTPSTAT
		fi
	done < $CONFIGF

	exit 0
else
        if [ ! -s $FTPSTAT ]   # file exists and is empty ?
        then
                exit 0
        fi
fi



##############################################################################
# function: awk-session counts the number of FTP-requests per type
##############################################################################
function ftp_process
{
	$NEXTCMD 2> /dev/null | awk '
	BEGIN {
        	months["Jan"] =  1
        	months["Feb"] =  2
        	months["Mar"] =  3
        	months["Apr"] =  4
        	months["May"] =  5
        	months["Jun"] =  6
        	months["Jul"] =  7
        	months["Aug"] =  8
        	months["Sep"] =  9
        	months["Oct"] = 10
        	months["Nov"] = 11
        	months["Dec"] = 12

        	needcheck="y"
        	cnt=0

        	# gather shell-parameters
        	prevdate="'"$CURDATE"'"
        	prevtime="'"$CURTIME"'"
        	prevstamp=prevdate prevtime     # YYYYMMDDHHMMSS
	
        	newoffset="'"$NEWOFFSET"'"

        	ocumxfer="'"$OCUMXFER"'"
        	ocumsecs="'"$OCUMSECS"'"
        	ocumsize="'"$OCUMSIZE"'"

        	icumxfer="'"$ICUMXFER"'"
        	icumsecs="'"$ICUMSECS"'"
        	icumsize="'"$ICUMSIZE"'"
			ftplogf= "'"$CURLOGF"'"
			ftpname= "'"$CURNAME"'"
	}

	needcheck=="y" {
        	linetime=$4
        	gsub(/:/, "", linetime)                 # get format HHMMSS

        	linestamp = sprintf("%04d%02d%02d%s",
                 	$5, months[$2], $3, linetime)  # get YYYYMMDDHHMMSS
	
        	if (linestamp < prevstamp)              # check for proper date
                	next

        	needcheck="n"   # from now on no checks any more because log-lines
                        	# are delivered in chronological order!
	}

	{ # for every new log-line ....
        	cnt++
	
		if ($12 == "i")
		{
        		icumxfer++
        		icumsecs+=$6
        		icumsize+=$8/1024
		}
		else
		{
        		ocumxfer++
        		ocumsecs+=$6
        		ocumsize+=$8/1024
		}
	
        	lastday=$3                 # remember info of last processed line
        	lastmon=$2
        	lastyear=$5
        	lasttime=$4
	}
	
	END {
        	if (cnt > 0)
        	{
                	lastdate = sprintf("%04d%02d%02d",
                                	lastyear, months[lastmon], lastday)
                	gsub(/:/, "", lasttime)
        	}
        	else
        	{
                	lastdate=prevdate
                	lasttime=prevtime
        	}
	
        	printf("%lf %lf %lf %lf %lf %lf %08ld %06ld %ld %s %s\n",
       	         		ocumxfer, ocumsecs, ocumsize,
	                	icumxfer, icumsecs, icumsize,
				lastdate, lasttime, newoffset,
				ftplogf,  ftpname)
	}' >> $FTPSTAT.new
}

#############################################################################
# statistics-file is found; read every line and cut into pieces
#############################################################################
#
> $FTPSTAT.new

while read OCUMXFER OCUMSECS OCUMSIZE  ICUMXFER ICUMSECS ICUMSIZE 	\
           CURDATE  CURTIME  CUROFFSET CURLOGF  CURNAME  REST
do
	#
	# check which log-files are modified since the previous scan;
	# there may have been zero or more logfile-rotations
	#
	XFERNEW=
	XFERNEWGZ=
	XFERCNT=0
	
	for XFERFILE in ${CURLOGF}*
	do
        	if [ $XFERFILE -ot $FTPSTAT ]   # this xfer-file not modified since
        	then                            # last write of statistics-file?
                	break                   # then subsequent names also older
        	fi
	
        	# remember file to be processed
	
        	case $XFERFILE in
          	  *.gz) XFERNEWGZ="$XFERFILE $XFERNEWGZ"
                	;;
                  *) 	XFERNEW="$XFERFILE $XFERNEW"
                	;;
        	esac

        	let XFERCNT+=1                  # count files to be processed
	done
	
	#
	# check which xferlog-files contain new information
	#
	case $XFERCNT in
        	####################################################################
        	# no ftp-transfers since previous check?
	
     	0) 	echo $OCUMXFER $OCUMSECS $OCUMSIZE  $ICUMXFER $ICUMSECS $ICUMSIZE  \
           	     $CURDATE  $CURTIME  $CUROFFSET $CURLOGF  $CURNAME >> $FTPSTAT.new
		continue
        	;;
	
        	####################################################################
        	# only xferlog itself is modified (no logfile-rotation);
        	# an efficient scan can be done by skipping the part which has
        	# been processed before
	
     	1) 	if [ "$CUROFFSET" -eq 0 ]
			then
				NEXTCMD="cat $CURLOGF"
			else
				NEXTCMD="dd skip=1 ibs=$CUROFFSET if=$CURLOGF"
			fi
        	;;
	
        	####################################################################
        	# apparantly xferlogs have been rotated since the previous run;
        	# the log-lines from all modified xferlog-files are concatenated
        	# in chronological order (so filenames are in reversed order) which
        	# allows the awk-selection to skip lines which have been processed
        	# before; note that the remembered offset does not necessarily
        	# belong to the oldest file, because a complete cycle might
        	# have been occurred since the previous run
	
     	*) 	if [ "$XFERNEWGZ" != "" ]
        	then
                	NEXTCMD="zcat $XFERNEWGZ | cat - $XFERNEW"
        	else
                	NEXTCMD="cat $XFERNEW"
        	fi
        	;;
	esac
	
	#
	# Process new ftp-transfers
	#
	NEWOFFSET=`ls -l $CURLOGF | awk '{print $5}'`    # to be stored by awk

	ftp_process    # activate awk-session

done < $FTPSTAT

mv $FTPSTAT.new $FTPSTAT

exit 0
