/*
 * ifstat.c - display statistics about incoming and outgoing traffic
 * 
 * Copyright (C) 2004  Jochen Eisinger <jochen@penguin-breeder.org>
 * 
 * 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
 *
 */
/* cc -O ifstat.c -lkstat -o ifstat */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <kstat.h>

uint64_t in=0, out=0;
int errflag=0;
   
kstat_ctl_t *kc;

void getstats(char *ifs)
{
    kstat_t *ksp;
    kstat_named_t *knp;


    ksp = kstat_lookup(kc, NULL, -1, ifs);
    if (ksp && kstat_read(kc, ksp, NULL) >= 0) {
        knp = (kstat_named_t *)kstat_data_lookup(ksp, "rbytes64");
        if (knp)
            in = knp->value.ui64;
	else {
            knp = (kstat_named_t *)kstat_data_lookup(ksp, "rbytes32");
            if (knp)
            	in = knp->value.ui32;
	}
        knp = (kstat_named_t *)kstat_data_lookup(ksp, "obytes64");
        if (knp)
            out = knp->value.ui64;
	else {
            knp = (kstat_named_t *)kstat_data_lookup(ksp, "obytes32");
            if (knp)
		out = knp->value.ui32;
	}
    }
    else
      errflag=1;


}

char cnt_foo[4][64];

char *cnt(int n,uint64_t c)
{
 double d;

 if (c < 1000) {
   sprintf(cnt_foo[n],"%3d.0  B", c);
 } else if (c < (999 * 1024)) {
   d = c;
   d /= 1024.0;
   sprintf(cnt_foo[n],"%5.1f KB", d);
 } else if (c < (999 * 1024 * 1024)) {
  d = c;
  d /= 1024.0;
  d /= 1024.0;
  sprintf(cnt_foo[n],"%5.1f MB", d);
 } else {
  d = c;
  d /= 1024.0;
  d /= 1024.0;
  d /= 1024.0;
  sprintf(cnt_foo[n],"%5.1f GB", d);
 } 
 return cnt_foo[n];
}

char trf_foo[4][64];

char *trf(int n,uint64_t c)
{
 double d=c;

 d *= 8.0;
 if (d < 999) {
   sprintf(trf_foo[n],"%5.1f  bps", d);
 } else if (d < (999 * 1024)) {
   d /= 1024.0;
   sprintf(trf_foo[n],"%5.1f kbps", d);
 } else {
   d /= 1024.0;
   d /= 1024.0;
   sprintf(trf_foo[n],"%5.1f mbps", d);
 } 
 return trf_foo[n];
}

int main(int argc, char **argv)
{
  uint64_t oi,oo,si,so,ai,ao;
  uint64_t avg[2][10] = {{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0}};
  int ptr=0,ctr;

  if (argc != 2) {
    printf("usage: %s <interface>\n", argv[0]);
    return 1; 
  }

  if ((kc = kstat_open()) == NULL) {
    printf("%s: could not attach to kstat\n", argv[0]);
    return 2;
  }

  getstats(argv[1]);

  if (errflag) {
    printf("%s: unkown interface %s\n", argv[0],argv[1]);
    return 3;
  }
  si = in; so = out;

  printf("interface %s:\n"
    " total bytes     | since start     || current traffic     | 10s average\n",
    argv[1]);
  puts("     in      out |     in      out ||       in        out |       in        out");

  for (;;) {
    sleep(1);
    oi=in;
    oo=out;
    getstats(argv[1]);
    avg[0][ptr] = in - oi;
    avg[1][ptr] = out - oo;
    ptr = (ptr+1) % 10;
    ai=ao=0;
    for (ctr=0;ctr<10; ctr++) {
     ai+=avg[0][ctr];
     ao+=avg[1][ctr];
    }
    ai /= 10;
    ao /= 10;
    printf("%s %s|%s %s||%s %s|%s %s\r",
	cnt(2,in),cnt(3,out), cnt(0,in - si), cnt(1,out - so), 
        trf(0,in - oi), trf(1,out - oo),trf(2,ai),trf(3,ao));
    fflush(stdout);

  }

}

