#! /bin/sh
# #############################################################################

       NAME_="bytetraf"
       HTML_="monitor network traffic"
    PURPOSE_="display network traffic on an interface"
   SYNOPSIS_="$NAME_ [-hml] <n>s|m|h|d <interface>"
   REQUIRES_="standard GNU commands, /proc fs"
    VERSION_="1.0"
       DATE_="2004-07-20; last update: 2004-12-16"
     AUTHOR_="Dawid Michalczyk <dm@eonworks.com>"
        URL_="www.comp.eonworks.com"
   CATEGORY_="net"
   PLATFORM_="Linux"
      SHELL_="bash"
 DISTRIBUTE_="yes"

# #############################################################################
# This program is distributed under the terms of the GNU General Public License

usage () {

echo >&2 "$NAME_ $VERSION_ - $PURPOSE_
Usage: $SYNOPSIS_
Requires: $REQUIRES_
Options:
     <n>s|m|h|d, n is an integer referring to time interval in
                 seconds|minutes|hours|days which refers to the frequency of how
                 often to display traffic info
     <interface>, is the name of network interface as found in /proc/net/dev file
     -h, usage and options (this help)
     -m, manual
     -l, see this script"
    exit 1
}

manual() { echo >&2 "

NAME

    $NAME_ $VERSION_ - $PURPOSE_

SYNOPSIS

    $SYNOPSIS_

DESCRIPTION

    Output format example:

    13:53:21 int: ppp0 recv: [+6270] 5.789.621  tran: [+393] 537.478  rate: 6663 b/s

    Output explanation for each column:

    13:53:21 - time
    int: - short for interface
    ppp0 - interface type
    recv: - marks received bytes start
    [+6270] - received 6270 bytes since last time interval specified as <n>s|m|h|d
    5.789.621 - received 5.789.621 bytes since the interface has been up
    tran: - marks transferred bytes start
    [+393] - transferred 393 bytes since last time interval specified as <n>s|m|h|d
    537.478 - transferred 537.478 bytes since the interface has been up
    rate: - speed in bytes/s of the total traffic
    6663 b/s - 6663 bytes/s

NOTE

    This script relies on the structure of the output generated by kernels 2.2.x and
    2.4.x in /proc/net/dev file.

AUTHOR

    $AUTHOR_ Suggestions and bug reports are welcome.
    For updates and more scripts visit $URL_

"; exit 1; }

# define net interface
interface=$2

# local funcs
byte_count() {

    while read line;do

        if [[ $line == ${interface}:* ]];then
             [[ $1 == r ]] && { set -- ${line#*:}; echo $1; }
             [[ $1 == t ]] && { set -- ${line#*:}; echo $9; }
        fi

    done < /proc/net/dev
}

string_intDelim() {
    echo $1 | sed '{ s/$/@/; : loop; s/\(...\)@/@.\1/; t loop; s/@//; s/^\.//; }'
}

interface_check() {
    grep $interface /proc/net/dev &>/dev/null
    [ $? != 0 ] && { echo >&2 $interface is not up, cant find it in /proc/net/dev; exit 1; }
}

# args check
[ $# -eq 0 ] && { echo >&2 missing argument, type $NAME_ -h for help; exit 1; }

# enabling extended globbing
shopt -s extglob 

# arg handling and execution
case $1 in

    -h) usage ;;
    -m) manual ;;
    -l) more $0; exit 1 ;;
    +([0-9])[smhd] ) # main execution

        [ $2 ] || { echo >&2 missing second argument, type $NAME_ -h for help; exit 1; }
        interface_check

        intg=${1%[s|m|h|d]*}
        unit=${1##*[!s|m|h|d]}

        [[ $unit == s ]] && div=1
        [[ $unit == m ]] && div=60
        [[ $unit == h ]] && div=3600
        [[ $unit == d ]] && div=86400

        while grep $interface < /proc/net/dev &>/dev/null ;do
              
            received=$(byte_count r)
            transmit=$(byte_count t)
            sleep $1 # time interval for how often to grab data from /proc/net/dev
            nreceived=$(byte_count r)
            ntransmit=$(byte_count t)
            rdiff=$((( $nreceived - $received )))
            tdiff=$((( $ntransmit - $transmit )))
            rate=$((( ($rdiff + $tdiff) / ( $div * $intg ) )))
            echo "$(date +%H:%M:%S) \
int: $interface   \
recv: [+${rdiff}] $(string_intDelim $received)   \
tran: [+${tdiff}] $(string_intDelim $transmit)   \
rate: ${rate} b/s"

        done ;;
    
    *) echo invalid or missing argument, type $NAME_ -h for help ; exit 1 ;;
esac
