#!/bin/bash
#
# Time-stamp: <2004-10-13 14:33:20 hcz>
# netcount-upd, automatically generated by make from netcount-upd.in. DO NOT EDIT!
# 
# netcount-upd
# Update net counter & logs for use by the "netcount" program
# 
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#



# (C) 2002 Heike C. Zimmerer (hcz@hczim.de)
#
# 2004-10-13 On some machines, pppd removes its lock file long enough
# before exiting to cause problems.  If we are within ip-down,
# $PPPD_PID is used instead of the contents of the lock file.  A
# better way would be to have pppd not remove its lock file before
# ip-down has finished.  After all, it does not exit before that.
#
# 2004-05-12 nc_up removed on start/restart also.
#
# 2003-05-22 Changed umask.  Changed parsing of counter values.
#
# 2003-04-01 "restart" as command-line argument re-added, since this is
# used by the existing boot.local script,
#
# 2003-03-13 Added nc-up file generation for use by nstat. Cosmetic
# changes. -hcz
#
# 2003-02-21 On ip-down, uses environment variables instead of
# /proc/net/dev. Requirement for bc lifted. -hcz
#
# 2003-01-17 repeated readout of kernel counter -hcz
#
# 2003-01-14 logging changed (now logs actual time instead of time of
# last sample), debug option + log added       - hcz@hczim.de
#

debug=0		# <> 0 : write debug log

# file names:
logdir=/var/log/netcount			# directory for sample and netcount logs
logfil=$logdir/netcount.log	# log written by this script
nc_sample=$logdir/nc-sample	# sample log
nc_up=$logdir/nc-up		# last ip-up or -down action
dbgfil=$logdir/netcount.dbg	# debugging log


# dump environment (for testing)
(
    echo "================================================"
    date
    echo "argc: $#, argv: $*"
    set
) > $logdir/ncu-$1


abort() {
    echo 'usage: netcount-upd up|down|snap|reset' 1>&2
    echo '(should only be called as sub-process by programs)'
    exit 1
}
[ $# -lt 1 ] && abort

umask 022

case $1 in
  up) echo $IPLOCAL > $nc_up;;
  down) rm -f $nc_up;;
  snap) ;;
  restart | reset) rm -f $nc_sample $nc_up; exit 0;; # reset snapshot log
  *) abort;;
esac
mode=$1

# create log directory if it doesn't exist. Exit
# if unsuccessful:
[ -d $logdir ] || mkdir -p $logdir || exit 2

# get actual values:
curDate=$(date -Iseconds)
curTime=$(date +%s)
curDate=${curDate%[-+]*}	# remove time zone indicator

rep=0				# debugging counter

# Abort if more than one pppd is running
pids=$(pidof pppd)
if [ "$debug" != 0 ]; then
    printf "%s pidof pppd: %s\n" $curDate "$pids" >> $dbgfil
fi
set x $pids
if [ $# -gt 2 ]; then
    echo "$curDate Error: more than one pppd running: $pids" >> $logfil
    exit 0
fi

# Get actual values.
if [ "$mode" = down ]; then
    # Using /proc/net/dev during ip-down presents a runaway condition:
    # Even if pppd is still running, it might be no more when reading
    # /proc/net/dev, since ip-down is run asynchronously.  We have to
    # resort to the traffic values from ip-down's environment here.
    if [ -z "$BYTES_RCVD" ]; then 
	exit 0			# Urgs. Can't happen if called from pppd
    fi
    curRxB=$BYTES_RCVD
    curTxB=$BYTES_SENT
    # There are two versions of pppd around, one using %d for BYTES_RCVD and
    # BYTES_SENT, the other patched to use %u. We have to correct
    # the %d version to get the same behaviour as /proc/net/dev if
    # it puts out negative values:
    [ $curRxB -lt 0 ] && curRxB=$((curRxB + 2**32))
    [ $curTxB -lt 0 ] && curTxB=$((curTxB + 2**32))
else				# not in ip-down: use values from /proc/net/dev
    if ! [ -e /var/run/ppp0.pid ]; then # pppd not running
	rm -f $nc_sample	# counter no longer valid
	[ "$debug" != 0 ] && 
	    printf "%s %s %s no pppd\n" ${curDate%T*} ${curDate#*T} $mode \
		>> $dbgfil
	exit 0			# nothing left to be done
    fi
    # read actual state
    #
    # reading the kernel's network device counter isn't an atomic
    # operation, so we have to check carefully. I know the following
    # is problematic because it causes a loop in case of doing a
    # sample while there is high traffic. In cases of network up and
    # downs, nothing can happen.  In case of much larger throughput
    # you might remove the loop and risk the minimal probability of an
    # incorrect read-out:
    counter(){
	grep '^ *ppp0:' /proc/net/dev
    }
    ist=$(counter)
    while [ "$(counter)" != "$ist" ]; do
	ist="$(counter)"
	let rep=$rep+1		# debug only
    done


    if [ -z "$ist" ]; then
	[ -e "$nc_sample" ] && rm $nc_sample	# contents no more valid
	exit 0			# ppp0 not started - exit silently
    fi

    # note: if RxB has more than 9 digits, the first and the second
    # argument concatenate to one, since the space character in between
    # gets lost. So we strip the leading text.
    ist=${ist#*ppp0:}                         # strip 1st argument
    set X $ist
    # $ist: X 3540310 3385 0 0 0 0 0 0 181196 2371 0 0 0 0 0 0
    #         $2                       ${10}
    curRxB=$2
    curTxB=${10}
fi

if [ "$mode" = down ]; then
    # pppd sets $PPPD_PID (though it's not documented in the man page)
    pppd_pid=${PPPD_PID:-void}
else
    if [ -e /var/run/ppp0.pid ]; then # pppd running
        pppd_pid=$(cat /var/run/ppp0.pid) # get actual pppd-pid
    fi
    # Check again due to possible runaway condition
    if ! [ -e /var/run/ppp0.pid ]; then
        pppd_pid="void"
    fi
fi


# $nc_sample contains:
# 2002-09-01T23:02+0200 1030901707 1903793230 1620280341 3765
# Datum	                Datum      Rx Bytes   Tx Bytes   pppd-pid
# oldDate               oldTime    oldRxB     oldTxB     oldpid
# read previous state
if [ -f $nc_sample  ]; then
    read oldDate oldTime oldRxB oldTxB oldpid < $nc_sample
    # check if the same pppd is still running
    if [ "$oldpid" != "$pppd_pid" ]; then # pid has changed, so..
	mode=boot-$mode
	oldTime=$curTime
	oldRxB=0
	oldTxB=0		   # ...kernel counters have been reset
    fi
    # calculate differences
    diffTime=$((curTime - oldTime))
    diffRxB=$((curRxB - oldRxB))
    [ $diffRxB -lt 0 ] && diffRxB=$((diffRxB + 2**32))
    diffTxB=$((curTxB - oldTxB))
    [ $diffTxB -lt 0 ] && diffTxB=$((diffTxB + 2**32))

    # Don't log if nothing happened. Always log if debug mode
    [ "$debug" = "0" ] && [ $diffRxB = "0" -o $diffTxB = "0" ] && exit 0
else
    mode=boot-$mode
    oldDate=unknown		# insert "don't care" values into debug log,..
    oldRxB=0
    oldTxB=0
    diffTime=0
    diffRxB=$curRxB 
    diffTxB=$curTxB		# since counters have been restarted
fi


# Output debug entry
# (current values vs. values read from $nc_sample)
[ "$debug" != 0 ] && 
    printf "%s %-5s Old: %s Rx: %u - %u  Tx: %u - %u rep: %u pids: %d %d\n"\
	$curDate $mode $oldDate $curRxB $oldRxB \
	    $curTxB $oldTxB $rep $oldpid $pppd_pid \
		>> $dbgfil


# output netcount log entry
printf "%s %s  sec: %6u  Rx: %12u  Tx: %12u %s\n" \
        ${curDate%T*} ${curDate#*T} $diffTime $diffRxB $diffTxB $mode \
	    >> $logfil

# if pppd still running, save actual values (sample log). Else clear
# sample log:
if [ $pppd_pid != "void" ]; then
    echo $curDate $curTime $curRxB $curTxB $pppd_pid > $nc_sample
else
    rm -f $nc_sample		# counter has finished
fi
