"Fossies" - the Fresh Open Source Software Archive

Member "procmeter3-3.6+svn387/modules/netdev.c" (24 Dec 2010, 13867 Bytes) of package /linux/misc/procmeter3-3.6+svn387.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "netdev.c" see the Fossies "Dox" file reference documentation.

    1 /***************************************
    2   $Header: /home/amb/CVS/procmeter3/modules/netdev.c,v 1.20 2008-05-05 18:45:35 amb Exp $
    3 
    4   ProcMeter - A system monitoring program for Linux - Version 3.5b.
    5 
    6   Network devices traffic source file.
    7   ******************/ /******************
    8   Written by Andrew M. Bishop
    9 
   10   This file Copyright 1998-2008 Andrew M. Bishop
   11   It may be distributed under the GNU Public License, version 2, or
   12   any higher version.  See section COPYING of the GNU Public license
   13   for conditions under which this file may be redistributed.
   14   ***************************************/
   15 
   16 
   17 #include <stdio.h>
   18 #include <stdlib.h>
   19 #include <string.h>
   20 
   21 #include "procmeter.h"
   22 
   23 /* The interface information.  */
   24 
   25 /*+ The template for the network devices +*/
   26 ProcMeterOutput _outputs[6]=
   27 {
   28  /*+ The total packets +*/
   29  {
   30   /* char  name[];          */ "Pkt_%s",
   31   /* char *description;     */ "The total number of packets per second on the %s network interface.",
   32   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   33   /* short interval;        */ 1,
   34   /* char  text_value[];    */ "0 /s",
   35   /* long  graph_value;     */ 0,
   36   /* short graph_scale;     */ 0, /* calculated later */
   37   /* char  graph_units[];   */ "(%d/s)"
   38  },
   39  /*+ The total bytes +*/
   40  {
   41   /* char  name[];          */ "Byte_%s",
   42   /* char *description;     */ "The total number of bytes per second on the %s network interface.",
   43   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   44   /* short interval;        */ 1,
   45   /* char  text_value[];    */ "0 kB/s",
   46   /* long  graph_value;     */ 0,
   47   /* short graph_scale;     */ 0, /* calculated later */
   48   /* char  graph_units[];   */ "(%dkB/s)"
   49  },
   50  /*+ The transmitted packets +*/
   51  {
   52   /* char  name[];          */ "Pkt_Tx_%s",
   53   /* char *description;     */ "The number of packets transmitted per second on the %s network interface.",
   54   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   55   /* short interval;        */ 1,
   56   /* char  text_value[];    */ "0 /s",
   57   /* long  graph_value;     */ 0,
   58   /* short graph_scale;     */ 0, /* calculated later */
   59   /* char  graph_units[];   */ "(%d/s)"
   60  },
   61  /*+ The transmitted bytes +*/
   62  {
   63   /* char  name[];          */ "Byte_Tx_%s",
   64   /* char *description;     */ "The number of bytes transmitted per second on the %s network interface.",
   65   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   66   /* short interval;        */ 1,
   67   /* char  text_value[];    */ "0 kB/s",
   68   /* long  graph_value;     */ 0,
   69   /* short graph_scale;     */ 0, /* calculated later */
   70   /* char  graph_units[];   */ "(%dkB/s)"
   71  },
   72  /*+ The received packets +*/
   73  {
   74   /* char  name[];          */ "Pkt_Rx_%s",
   75   /* char *description;     */ "The number of packets received per second on the %s network interface.",
   76   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   77   /* short interval;        */ 1,
   78   /* char  text_value[];    */ "0 /s",
   79   /* long  graph_value;     */ 0,
   80   /* short graph_scale;     */ 0, /* calculated later */
   81   /* char  graph_units[];   */ "(%d/s)"
   82  },
   83  /*+ The received bytes +*/
   84  {
   85   /* char  name[];          */ "Byte_Rx_%s",
   86   /* char *description;     */ "The number of bytes received per second on the %s network interface.",
   87   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   88   /* short interval;        */ 1,
   89   /* char  text_value[];    */ "0 kB/s",
   90   /* long  graph_value;     */ 0,
   91   /* short graph_scale;     */ 0, /* calculated later */
   92   /* char  graph_units[];   */ "(%dkB/s)"
   93  }
   94 };
   95 
   96 
   97 /*+ The outputs. +*/
   98 ProcMeterOutput **outputs=NULL;
   99 
  100 /*+ The module. +*/
  101 ProcMeterModule module=
  102 {
  103  /* char name[];            */ "Network",
  104  /* char *description;      */ "The network devices and the amount of traffic on each of them. [From /proc/net/dev]  "
  105                                "(Use 'options=ppp0' in the configuration file to specify extra network devices."
  106 };
  107 
  108 
  109 /* The line buffer */
  110 static char *line=NULL;
  111 static size_t length=0;
  112 
  113 /* The format to use to read the data depending on the kernel version */
  114 static char *proc_net_dev_format=NULL;
  115 static char *proc_net_dev_format1="%llu %*u %*u %*u %*u %llu"; /* kernel version < ~2.1.28 */
  116 static char *proc_net_dev_format2="%llu %llu %*u %*u %*u %*u %llu %llu"; /* ~2.1.28 < kernel version < ~2.1.80 (two possiblities) */
  117 static char *proc_net_dev_format3="%llu %llu %*u %*u %*u %*u %*u %*u %llu %llu"; /* ~2.1.91 < kernel version */
  118 
  119 /* The information about the network devices */
  120 static int ndevices=0;
  121 static unsigned long *current=NULL,*previous=NULL;
  122 static char **device=NULL;
  123 
  124 /* A function to add a new device */
  125 static void add_device(char *dev);
  126 
  127 
  128 /*++++++++++++++++++++++++++++++++++++++
  129   Load the module.
  130 
  131   ProcMeterModule *Load Returns the module information.
  132   ++++++++++++++++++++++++++++++++++++++*/
  133 
  134 ProcMeterModule *Load(void)
  135 {
  136  return(&module);
  137 }
  138 
  139 
  140 /*++++++++++++++++++++++++++++++++++++++
  141   Initialise the module, creating the outputs as required.
  142 
  143   ProcMeterOutput **Initialise Returns a NULL terminated list of outputs.
  144 
  145   char *options The options string for the module from the .procmeterrc file.
  146   ++++++++++++++++++++++++++++++++++++++*/
  147 
  148 ProcMeterOutput **Initialise(char *options)
  149 {
  150  FILE *f;
  151 
  152  outputs=(ProcMeterOutput**)malloc(sizeof(ProcMeterOutput*));
  153  outputs[0]=NULL;
  154 
  155  /* Verify the statistics from /proc/net/dev */
  156 
  157  f=fopen("/proc/net/dev","r");
  158  if(!f)
  159     fprintf(stderr,"ProcMeter(%s): Could not open '/proc/net/dev'.\n",__FILE__);
  160  else
  161    {
  162     if(!fgets_realloc(&line,&length,f))
  163        fprintf(stderr,"ProcMeter(%s): Could not read '/proc/net/dev'.\n",__FILE__);
  164     else
  165        if(strcmp(line,"Inter-|   Receive                  |  Transmit\n") && /* kernel version < ~2.1.80 */
  166           strcmp(line,"Inter-|   Receive                           |  Transmit\n") && /* ~2.1.80 < kernel version > ~2.1.91 */
  167           strcmp(line,"Inter-|   Receive                                                |  Transmit\n")) /* ~2.1.91 < kernel version */
  168           fprintf(stderr,"ProcMeter(%s): Unexpected header line 1 in '/proc/net/dev'.\n",__FILE__);
  169        else
  170          {
  171           fgets_realloc(&line,&length,f);
  172           if(strcmp(line," face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n") && /* kernel version < ~2.1.28 */
  173              strcmp(line," face |bytes    packets errs drop fifo frame|bytes    packets errs drop fifo colls carrier\n") && /* ~2.1.28 < kernel version < ~2.1.80 */
  174              strcmp(line," face |bytes    packets errs drop fifo frame|bytes    packets errs drop fifo colls carrier multicast\n") && /* ~2.1.80 < kernel version < ~2.1.91 */
  175              strcmp(line," face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n")) /* ~2.1.91 < kernel version */
  176              fprintf(stderr,"ProcMeter(%s): Unexpected header line 2 in '/proc/net/dev'.\n",__FILE__);
  177           else
  178             {
  179              if(!strcmp(line," face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n"))
  180                 proc_net_dev_format=proc_net_dev_format1; /* kernel version < ~2.1.28 */
  181              else if(!strcmp(line," face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n"))
  182                 proc_net_dev_format=proc_net_dev_format3; /* ~2.1.91 < kernel version */
  183              else
  184                 proc_net_dev_format=proc_net_dev_format2; /* ~2.1.28 < kernel version < ~2.1.80 (two possiblities) */
  185 
  186              while(fgets_realloc(&line,&length,f))
  187                {
  188                 int i;
  189                 char *dev=line;
  190                 long long rxp=0,txp=0,rxb=0,txb=0;
  191 
  192                 for(;*dev==' ';dev++) ;
  193                 for(i=strlen(line);i>6 && line[i]!=':';i--); line[i++]=0;
  194                 if(!strcmp(&line[i]," No statistics available.\n") ||
  195                    (proc_net_dev_format==proc_net_dev_format1 && sscanf(&line[i],proc_net_dev_format,&rxp,&txp)==2) ||
  196                    (proc_net_dev_format!=proc_net_dev_format1 && sscanf(&line[i],proc_net_dev_format,&rxb,&rxp,&txb,&txp)==4))
  197                    add_device(dev);
  198                }
  199             }
  200          }
  201 
  202     fclose(f);
  203    }
  204 
  205  /* Get the other options */
  206 
  207  if(options)
  208    {
  209     char *l=options;
  210 
  211     while(*l && *l==' ')
  212        l++;
  213 
  214     while(*l)
  215       {
  216        char *r=l,pr;
  217 
  218        while(*r && *r!=' ')
  219           r++;
  220 
  221        pr=*r;
  222        *r=0;
  223 
  224        add_device(l);
  225 
  226        *r=pr;
  227        while(*r && *r==' ')
  228           r++;
  229 
  230        if(!*r)
  231           break;
  232 
  233        l=r;
  234       }
  235    }
  236 
  237  current =(unsigned long*)calloc(sizeof(long),ndevices);
  238  previous=(unsigned long*)calloc(sizeof(long),ndevices);
  239 
  240  return(outputs);
  241 }
  242 
  243 
  244 /*++++++++++++++++++++++++++++++++++++++
  245   Add a new device to the list.
  246 
  247   char *dev The name of the device to add.
  248   ++++++++++++++++++++++++++++++++++++++*/
  249 
  250 static void add_device(char *dev)
  251 {
  252  int pscale,bscale,nstats;
  253  int i;
  254 
  255  for(i=0;i<ndevices;i++)
  256     if(!strcmp(device[i],dev))
  257        return;
  258 
  259  if(*dev=='l' || *dev=='d') /* 'lo' or 'dummy' devices. */
  260     pscale=100,bscale=100,nstats=1;
  261  else
  262     if(*dev=='s' || *dev=='p' || (*dev=='f' && *(dev+1)=='l') || *dev=='i')
  263        /* 'sl' or 'ppp'/'plip' or 'flip' or 'isdn'/'ippp' devices. */
  264        pscale=5,bscale=1,nstats=3;
  265     else /* other devices */
  266        pscale=50,bscale=100,nstats=3;
  267 
  268  if(proc_net_dev_format!=proc_net_dev_format1)
  269     nstats*=2;
  270 
  271  outputs=(ProcMeterOutput**)realloc((void*)outputs,(ndevices+nstats+1)*sizeof(ProcMeterOutput*));
  272  device=(char**)realloc((void*)device,(ndevices+nstats+1)*sizeof(char*));
  273 
  274  for(i=0;nstats;nstats--)
  275    {
  276     outputs[ndevices]=(ProcMeterOutput*)malloc(sizeof(ProcMeterOutput));
  277     device[ndevices]=(char*)malloc(strlen(dev)+1);
  278 
  279     *outputs[ndevices]=_outputs[i];
  280     snprintf(outputs[ndevices]->name, PROCMETER_NAME_LEN+1, _outputs[i].name, dev);
  281     outputs[ndevices]->description=(char*)malloc(strlen(dev)+strlen(_outputs[i].description)+4);
  282     sprintf(outputs[ndevices]->description,_outputs[i].description,dev);
  283     if(i%2)
  284        outputs[ndevices]->graph_scale=bscale;
  285     else
  286        outputs[ndevices]->graph_scale=pscale;
  287 
  288     strcpy(device[ndevices],dev);
  289 
  290     ndevices++;
  291 
  292     if(proc_net_dev_format==proc_net_dev_format1)
  293        i+=2;
  294     else
  295        i++;
  296    }
  297 
  298  outputs[ndevices]=NULL;
  299 }
  300 
  301 
  302 /*++++++++++++++++++++++++++++++++++++++
  303   Perform an update on one of the statistics.
  304 
  305   int Update Returns 0 if OK, else -1.
  306 
  307   time_t now The current time.
  308 
  309   ProcMeterOutput *output The output that the value is wanted for.
  310   ++++++++++++++++++++++++++++++++++++++*/
  311 
  312 int Update(time_t now,ProcMeterOutput *output)
  313 {
  314  static time_t last=0;
  315  int j;
  316 
  317  /* Get the statistics from /proc/net/dev */
  318 
  319  if(now!=last)
  320    {
  321     FILE *f;
  322     unsigned long *temp;
  323 
  324     temp=current;
  325     current=previous;
  326     previous=temp;
  327 
  328     for(j=0;outputs[j];j++)
  329        current[j]=0;
  330 
  331     f=fopen("/proc/net/dev","r");
  332     if(!f)
  333        return(-1);
  334 
  335     fgets_realloc(&line,&length,f);
  336     fgets_realloc(&line,&length,f);
  337     while(fgets_realloc(&line,&length,f))
  338       {
  339        int i;
  340        long long rxp=0,txp=0,rxb=0,txb=0;
  341        char *dev=line;
  342 
  343        for(;*dev==' ';dev++) ;
  344        for(i=strlen(line);i>6 && line[i]!=':';i--); line[i++]=0;
  345        if(proc_net_dev_format==proc_net_dev_format1)
  346           sscanf(&line[i],proc_net_dev_format,&rxp,&txp);
  347        else
  348           sscanf(&line[i],proc_net_dev_format,&rxb,&rxp,&txb,&txp);
  349 
  350        for(j=0;outputs[j];j++)
  351           if(!strcmp(device[j],dev))
  352             {
  353              if(proc_net_dev_format==proc_net_dev_format1 && outputs[j+1] && !strcmp(device[j+1],dev))
  354                {
  355                 current[  j]=rxp+txp;
  356                 current[++j]=txp;
  357                 current[++j]=rxp;
  358                }
  359              else if(proc_net_dev_format!=proc_net_dev_format1 && outputs[j+2] && !strcmp(device[j+2],dev))
  360                {
  361                 current[  j]=rxp+txp;
  362                 current[++j]=rxb+txb;
  363                 current[++j]=txp;
  364                 current[++j]=txb;
  365                 current[++j]=rxp;
  366                 current[++j]=rxb;
  367                }
  368              else if(proc_net_dev_format==proc_net_dev_format1)
  369                 current[j]=txp;
  370              else /* proc_net_dev_format!=proc_net_dev_format1 */
  371                {
  372                 current[  j]=txp;
  373                 current[++j]=txb;
  374                }
  375              break;
  376             }
  377       }
  378 
  379     fclose(f);
  380 
  381     last=now;
  382    }
  383 
  384  for(j=0;outputs[j];j++)
  385     if(output==outputs[j])
  386       {
  387        double value;
  388 
  389        if(current[j]==0) /* stopped ppp0 device */
  390           value=0.0;
  391        else if(previous[j]>current[j]) /* wrap around of 32 bit counter */
  392           value=(4.294967296e9-(double)(previous[j]-current[j]))/output->interval;
  393        else
  394           value=(double)(current[j]-previous[j])/output->interval;
  395 
  396        if(proc_net_dev_format!=proc_net_dev_format1 && j%2)
  397           value/=1024.0;
  398 
  399        output->graph_value=PROCMETER_GRAPH_FLOATING(value/output->graph_scale);
  400        if(proc_net_dev_format!=proc_net_dev_format1 && j%2)
  401           sprintf(output->text_value,"%.1f kB/s",value);
  402        else
  403           sprintf(output->text_value,"%.0f /s",value);
  404 
  405        return(0);
  406       }
  407 
  408  return(-1);
  409 }
  410 
  411 
  412 /*++++++++++++++++++++++++++++++++++++++
  413   Tidy up and prepare to have the module unloaded.
  414   ++++++++++++++++++++++++++++++++++++++*/
  415 
  416 void Unload(void)
  417 {
  418  int i;
  419 
  420  if(outputs)
  421    {
  422     for(i=0;outputs[i];i++)
  423       {
  424        free(outputs[i]->description);
  425        free(outputs[i]);
  426       }
  427     free(outputs);
  428    }
  429  if(current)
  430     free(current);
  431  if(previous)
  432     free(previous);
  433  if(device)
  434    {
  435     for(i=0;i<ndevices;i++)
  436        free(device[i]);
  437     free(device);
  438    }
  439 
  440  if(line)
  441     free(line);
  442 }