"Fossies" - the Fresh Open Source Software Archive

Member "procmeter3-3.6+svn387/modules/stat-disk.c" (24 Dec 2010, 26678 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 "stat-disk.c" see the Fossies "Dox" file reference documentation.

    1 /***************************************
    2   $Header: /home/amb/CVS/procmeter3/modules/stat-disk.c,v 1.15 2008-12-07 17:35:47 amb Exp $
    3 
    4   ProcMeter - A system monitoring program for Linux - Version 3.5c.
    5 
    6   Disk statistics 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 <string.h>
   18 #include <stdio.h>
   19 #include <stdlib.h>
   20 #include <string.h>
   21 #include <ctype.h>
   22 
   23 #include <unistd.h>
   24 #include <dirent.h>
   25 #include <sys/stat.h>
   26 
   27 #include <linux/major.h>
   28 
   29 #include "procmeter.h"
   30 
   31 #define DISK        0
   32 #define DISK_READ   1
   33 #define DISK_WRITE  2
   34 #define N_OUTPUTS   3
   35 
   36 /* The interface information.  */
   37 
   38 /*+ The total disk statistics +*/
   39 ProcMeterOutput _outputs[N_OUTPUTS]=
   40 {
   41  /*+ The disk blocks accessed per second +*/
   42  {
   43   /* char  name[];          */ "Disk",
   44   /* char *description;     */ "The total number of disk blocks that are accessed per second.",
   45   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   46   /* short interval;        */ 1,
   47   /* char  text_value[];    */ "0 /s",
   48   /* long  graph_value;     */ 0,
   49   /* short graph_scale;     */ 25,
   50   /* char  graph_units[];   */ "(%d/s)"
   51  },
   52  /*+ The disk blocks read per second +*/
   53  {
   54   /* char  name[];          */ "Disk_Read",
   55   /* char *description;     */ "The number of disk blocks that are read per second.",
   56   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   57   /* short interval;        */ 1,
   58   /* char  text_value[];    */ "0 /s",
   59   /* long  graph_value;     */ 0,
   60   /* short graph_scale;     */ 25,
   61   /* char  graph_units[];   */ "(%d/s)"
   62  },
   63  /*+ The disk blocks write per second +*/
   64  {
   65   /* char  name[];          */ "Disk_Write",
   66   /* char *description;     */ "The number of disk blocks that are written per second.",
   67   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   68   /* short interval;        */ 1,
   69   /* char  text_value[];    */ "0 /s",
   70   /* long  graph_value;     */ 0,
   71   /* short graph_scale;     */ 25,
   72   /* char  graph_units[];   */ "(%d/s)"
   73  }
   74 };
   75 
   76 /*+ The per disk statistics for kernels older than 2.4.0 +*/
   77 ProcMeterOutput _disk_outputs_pre_240[N_OUTPUTS]=
   78 {
   79  /*+ The disk blocks accessed per second +*/
   80  {
   81   /* char  name[];          */ "Disk%d",
   82   /* char *description;     */ "The total number of disk blocks that are accessed per second on disk %d.",
   83   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   84   /* short interval;        */ 1,
   85   /* char  text_value[];    */ "0 /s",
   86   /* long  graph_value;     */ 0,
   87   /* short graph_scale;     */ 25,
   88   /* char  graph_units[];   */ "(%d/s)"
   89  },
   90  /*+ The disk blocks read per second +*/
   91  {
   92   /* char  name[];          */ "Disk%d_Read",
   93   /* char *description;     */ "The number of disk blocks that are read per second on disk %d.",
   94   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   95   /* short interval;        */ 1,
   96   /* char  text_value[];    */ "0 /s",
   97   /* long  graph_value;     */ 0,
   98   /* short graph_scale;     */ 25,
   99   /* char  graph_units[];   */ "(%d/s)"
  100  },
  101  /*+ The disk blocks write per second +*/
  102  {
  103   /* char  name[];          */ "Disk%d_Write",
  104   /* char *description;     */ "The number of disk blocks that are written per second on disk %d.",
  105   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  106   /* short interval;        */ 1,
  107   /* char  text_value[];    */ "0 /s",
  108   /* long  graph_value;     */ 0,
  109   /* short graph_scale;     */ 25,
  110   /* char  graph_units[];   */ "(%d/s)"
  111  }
  112 };
  113 
  114 /*+ The per disk statistics +*/
  115 ProcMeterOutput _disk_outputs[N_OUTPUTS]=
  116 {
  117  /*+ The disk blocks accessed per second +*/
  118  {
  119   /* char  name[];          */ "Disk_%s",
  120   /* char *description;     */ "The total number of disk blocks that are accessed per second on disk %s.",
  121   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  122   /* short interval;        */ 1,
  123   /* char  text_value[];    */ "0 /s",
  124   /* long  graph_value;     */ 0,
  125   /* short graph_scale;     */ 25,
  126   /* char  graph_units[];   */ "(%d/s)"
  127  },
  128  /*+ The disk blocks read per second +*/
  129  {
  130   /* char  name[];          */ "Disk_%s_R",
  131   /* char *description;     */ "The number of disk blocks that are read per second on disk %s.",
  132   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  133   /* short interval;        */ 1,
  134   /* char  text_value[];    */ "0 /s",
  135   /* long  graph_value;     */ 0,
  136   /* short graph_scale;     */ 25,
  137   /* char  graph_units[];   */ "(%d/s)"
  138  },
  139  /*+ The disk blocks write per second +*/
  140  {
  141   /* char  name[];          */ "Disk_%s_W",
  142   /* char *description;     */ "The number of disk blocks that are written per second on disk %s.",
  143   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  144   /* short interval;        */ 1,
  145   /* char  text_value[];    */ "0 /s",
  146   /* long  graph_value;     */ 0,
  147   /* short graph_scale;     */ 25,
  148   /* char  graph_units[];   */ "(%d/s)"
  149  }
  150 };
  151 
  152 /*+ The extra outputs with multiple disks +*/
  153 ProcMeterOutput *disk_outputs=NULL;
  154 
  155 /*+ The outputs. +*/
  156 ProcMeterOutput **outputs=NULL;
  157 
  158 /*+ The module. +*/
  159 ProcMeterModule module=
  160 {
  161  /* char name[];            */ "Stat-Disk",
  162  /* char *description;      */ "Disk usage statistics. [From /proc/diskstats or /proc/stat]",
  163 };
  164 
  165 
  166 /* The line buffer */
  167 static char *line=NULL;
  168 static size_t length=0;
  169 
  170 /* The current and previous information about the disk */
  171 static unsigned long long *current,*previous,*values[2];
  172 
  173 /* The information about the disks */
  174 static int ndisks=4;
  175 static unsigned *majors=NULL,*minors=NULL,*indexes=NULL;
  176 
  177 /* The estimated kernel version based on the file format */
  178 static int kernel_version_130=0;
  179 static int kernel_version_240=0;
  180 static int kernel_version_260=0;
  181 
  182 /* A function to add a disk */
  183 static int add_disk(char *devname);
  184 
  185 
  186 /*++++++++++++++++++++++++++++++++++++++
  187   Load the module.
  188 
  189   ProcMeterModule *Load Returns the module information.
  190   ++++++++++++++++++++++++++++++++++++++*/
  191 
  192 ProcMeterModule *Load(void)
  193 {
  194  return(&module);
  195 }
  196 
  197 
  198 /*++++++++++++++++++++++++++++++++++++++
  199   Initialise the module, creating the outputs as required.
  200 
  201   ProcMeterOutput **Initialise Returns a NULL terminated list of outputs.
  202 
  203   char *options The options string for the module from the .procmeterrc file.
  204   ++++++++++++++++++++++++++++++++++++++*/
  205 
  206 ProcMeterOutput **Initialise(char *options)
  207 {
  208  FILE *f;
  209 
  210  disk_outputs=(ProcMeterOutput*)malloc((N_OUTPUTS*ndisks)*sizeof(ProcMeterOutput));
  211 
  212  outputs=(ProcMeterOutput**)malloc((N_OUTPUTS*(ndisks+1)+1)*sizeof(ProcMeterOutput*));
  213 
  214  outputs[0]=NULL;
  215 
  216  /* Check for /proc/diskstats in kernel 2.6.x */
  217 
  218  f=fopen("/proc/diskstats","r");
  219  if(!f)
  220    {
  221     /* Verify the statistics from /proc/stat */
  222 
  223     f=fopen("/proc/stat","r");
  224     if(!f)
  225        fprintf(stderr,"ProcMeter(%s): Could not open '/proc/stat'.\n",__FILE__);
  226     else
  227       {
  228        /* cpu */
  229        if(!fgets_realloc(&line,&length,f))
  230           fprintf(stderr,"ProcMeter(%s): Could not read '/proc/stat'.\n",__FILE__);
  231        else
  232          {
  233           while(fgets_realloc(&line,&length,f)) /* cpu or disk or page or swap or intr or disk_io */
  234              if(line[0]=='d' && line[1]=='i' && line[2]=='s' && line[3]=='k')
  235                 break;
  236 
  237           if(!line[0])
  238              fprintf(stderr,"ProcMeter(%s): Unexpected 'disk' line in '/proc/stat'.\n"
  239                      "    expected: 'disk ...' or 'disk_io ...'\n"
  240                      "    found:    EOF\n",__FILE__);
  241           else if(!strncmp(line,"disk ",5)) /* kernel version < ~2.4.0-test4 */
  242             {
  243              unsigned long long d1,d2,d3,d4;
  244 
  245              if(sscanf(line,"disk %llu %llu %llu %llu",&d1,&d2,&d3,&d4)==4)
  246                {
  247                 int i,j;
  248                 int read_avail=0,write_avail=0;
  249                 int n=0;
  250 
  251                 /* disk_* or page */
  252                 while(fgets_realloc(&line,&length,f) && line[0]=='d') /* kernel version > ~1.3.0 */
  253                   {
  254                    if(sscanf(line,"disk_rblk %llu %llu %llu %llu",&d1,&d2,&d3,&d4)==4)
  255                       read_avail=1;
  256                    if(sscanf(line,"disk_wblk %llu %llu %llu %llu",&d1,&d2,&d3,&d4)==4)
  257                       write_avail=1;
  258                   }
  259 
  260                 if(read_avail && write_avail)
  261                    kernel_version_130=1;
  262 
  263                 for(i=0;i<N_OUTPUTS;i++)
  264                    for(j=0;j<ndisks;j++)
  265                      {
  266                       disk_outputs[i+j*N_OUTPUTS]=_disk_outputs_pre_240[i];
  267                       snprintf(disk_outputs[i+j*N_OUTPUTS].name, PROCMETER_NAME_LEN+1, _disk_outputs_pre_240[i].name, j);
  268                       disk_outputs[i+j*N_OUTPUTS].description=(char*)malloc(strlen(_disk_outputs_pre_240[i].description)+8);
  269                       sprintf(disk_outputs[i+j*N_OUTPUTS].description,_disk_outputs_pre_240[i].description,j);
  270                      }
  271 
  272                 for(i=0;i<N_OUTPUTS;i++)
  273                    if(i==DISK || (i==DISK_READ && read_avail) || (i==DISK_WRITE && write_avail))
  274                       outputs[n++]=&_outputs[i];
  275 
  276                 for(j=0;j<ndisks;j++)
  277                    for(i=0;i<N_OUTPUTS;i++)
  278                       if(i==DISK || (i==DISK_READ && read_avail) || (i==DISK_WRITE && write_avail))
  279                          outputs[n++]=&disk_outputs[i+j*N_OUTPUTS];
  280 
  281                 outputs[n]=NULL;
  282                }
  283              else
  284                 fprintf(stderr,"ProcMeter(%s): Unexpected 'disk' line in '/proc/stat'.\n"
  285                         "    expected: 'disk %%u %%u %%u %%u'\n"
  286                         "    found:    %s",__FILE__,line);
  287             }
  288           else if(!strncmp(line,"disk_io: ",9)) /* kernel version > ~2.4.0-test4 */
  289             {
  290              int maj,min,idx,num=8,nm,nr;
  291              unsigned long long d1,d2,d3,d4,d5;
  292              DIR *devdir,*devdiscsdir,*devmapperdir;
  293              char devname[PATH_MAX];
  294              struct dirent *ent;
  295              struct stat buf;
  296 
  297              kernel_version_240=1;
  298 
  299              ndisks=0;
  300 
  301              devdir=opendir("/dev");
  302              devdiscsdir=opendir("/dev/discs");
  303              devmapperdir=opendir("/dev/mapper");
  304 
  305              while((nr=sscanf(line+num," (%d,%d):(%llu,%llu,%llu,%llu,%llu)%n",&maj,&idx,&d1,&d2,&d3,&d4,&d5,&nm))==7 ||
  306                    (nr=sscanf(line+num," (%d,%d):(%llu,%llu,%llu,%llu)%n",&maj,&idx,&d1,&d2,&d3,&d4,&nm))==6)
  307                {
  308                 int done=0;
  309 
  310                 num+=nm;
  311 
  312                 kernel_version_240=nr;
  313 
  314                 /* This switch statement is the inverse of the one in /usr/include/linux/genhd.h */
  315 
  316                 switch (maj)
  317                   {
  318                   case DAC960_MAJOR+0:
  319                    min=idx<<3;
  320                    break;
  321                   case SCSI_DISK0_MAJOR:
  322                    min=idx<<4;
  323                    break;
  324                   case IDE0_MAJOR:      /* same as HD_MAJOR */
  325                   case XT_DISK_MAJOR:
  326                    min=idx<<6;
  327                    break;
  328                   case IDE1_MAJOR:
  329                    min=(idx-2)<<6;
  330                    break;
  331                   default:
  332                    min=0;
  333                   }
  334 
  335                 if(devmapperdir)
  336                   {
  337                    rewinddir(devmapperdir);
  338                    while((ent=readdir(devmapperdir)))
  339                      {
  340                       sprintf(devname,"/dev/mapper/%s",ent->d_name);
  341                       if(!lstat(devname,&buf) && S_ISBLK(buf.st_mode) && !S_ISLNK(buf.st_mode) &&
  342                          major(buf.st_rdev)==maj && minor(buf.st_rdev)==min)
  343                          done=add_disk(devname);
  344                      }
  345                   }
  346                 if(!done && devdiscsdir)
  347                   {
  348                    rewinddir(devdiscsdir);
  349                    while((ent=readdir(devdiscsdir)))
  350                      {
  351                       sprintf(devname,"/dev/discs/%s/disc",ent->d_name);
  352                       if(!lstat(devname,&buf) && S_ISBLK(buf.st_mode) && !S_ISLNK(buf.st_mode) &&
  353                          major(buf.st_rdev)==maj && minor(buf.st_rdev)==min)
  354                          done=add_disk(devname);
  355                      }
  356                   }
  357                 if(!done && devdir)
  358                   {
  359                    rewinddir(devdir);
  360                    while((ent=readdir(devdir)))
  361                      {
  362                       sprintf(devname,"/dev/%s",ent->d_name);
  363                       if(!lstat(devname,&buf) && S_ISBLK(buf.st_mode) && !S_ISLNK(buf.st_mode) &&
  364                          major(buf.st_rdev)==maj && minor(buf.st_rdev)==min)
  365                          done=add_disk(devname);
  366                      }
  367                   }
  368                 if(!done)
  369                   {
  370                    fprintf(stderr,"ProcMeter(%s): Cannot find disk in /dev, /dev/mapper, or /dev/discs for device %d:%d in '/proc/stat'.\n",__FILE__,maj,min);
  371                    continue;
  372                   }
  373                }
  374 
  375              if(devdir)
  376                 closedir(devdir);
  377              if(devdiscsdir)
  378                 closedir(devdiscsdir);
  379             }
  380           else
  381              fprintf(stderr,"ProcMeter(%s): Unexpected 'disk' line in '/proc/stat'.\n"
  382                      "    expected: 'disk ...' or 'disk_io ...'\n"
  383                      "    found:    %s",__FILE__,line);
  384          }
  385 
  386        fclose(f);
  387       }
  388    }
  389  else /* Found /proc/diskstats in kernel 2.6.x */
  390    {
  391     if(!fgets_realloc(&line,&length,f))
  392        fprintf(stderr,"ProcMeter(%s): Could not read '/proc/diskstats'.\n",__FILE__);
  393     else
  394       {
  395        int maj,min,nr;
  396        unsigned long long d1,d2,d3,d4,d5;
  397        DIR *devdir,*devdiscsdir,*devmapperdir;
  398        char devname[PATH_MAX];
  399        struct dirent *ent;
  400        struct stat buf;
  401 
  402        kernel_version_260=1;
  403 
  404        ndisks=0;
  405 
  406        devdir=opendir("/dev");
  407        devdiscsdir=opendir("/dev/discs");
  408        devmapperdir=opendir("/dev/mapper");
  409 
  410        do
  411          {
  412           int done=0;
  413 
  414           nr=sscanf(line,"%d %d %*s %llu %llu %llu %llu %llu",&maj,&min,&d1,&d2,&d3,&d4,&d5);
  415 
  416           if(nr<6)
  417              break;
  418 
  419           if(devmapperdir)
  420             {
  421               rewinddir(devmapperdir);
  422               while((ent=readdir(devmapperdir)))
  423                 {
  424                   sprintf(devname,"/dev/mapper/%s",ent->d_name);
  425                   if(!lstat(devname,&buf) && S_ISBLK(buf.st_mode) && !S_ISLNK(buf.st_mode) &&
  426                      major(buf.st_rdev)==maj && minor(buf.st_rdev)==min)
  427                     done=add_disk(devname);
  428                 }
  429             }
  430           if(!done && devdiscsdir)
  431             {
  432               rewinddir(devdiscsdir);
  433               while((ent=readdir(devdiscsdir)))
  434                 {
  435                   sprintf(devname,"/dev/discs/%s/disc",ent->d_name);
  436                   if(!lstat(devname,&buf) && S_ISBLK(buf.st_mode) && !S_ISLNK(buf.st_mode) &&
  437                      major(buf.st_rdev)==maj && minor(buf.st_rdev)==min)
  438                     done=add_disk(devname);
  439                 }
  440             }
  441           if(!done && devdir)
  442             {
  443              rewinddir(devdir);
  444              while((ent=readdir(devdir)))
  445                {
  446                 sprintf(devname,"/dev/%s",ent->d_name);
  447                 if(!lstat(devname,&buf) && S_ISBLK(buf.st_mode) && !S_ISLNK(buf.st_mode) &&
  448                    major(buf.st_rdev)==maj && minor(buf.st_rdev)==min)
  449                    done=add_disk(devname);
  450                }
  451             }
  452           if(!done)
  453             {
  454              fprintf(stderr,"ProcMeter(%s): Cannot find disk in /dev, /dev/mapper, or /dev/discs for device %d:%d in '/proc/diskstats'.\n",__FILE__,maj,min);
  455              continue;
  456             }
  457          }
  458        while(fgets_realloc(&line,&length,f));
  459 
  460        if(devdir)
  461           closedir(devdir);
  462        if(devdiscsdir)
  463           closedir(devdiscsdir);
  464       }
  465    }
  466 
  467  /* Add in the options from the config file. */
  468 
  469  if(options && (kernel_version_240 || kernel_version_260))
  470    {
  471     char *l=options;
  472 
  473     while(*l && *l==' ')
  474        l++;
  475 
  476     while(*l)
  477       {
  478        char *r=l,pr;
  479 
  480        while(*r && *r!=' ')
  481           r++;
  482 
  483        pr=*r;
  484        *r=0;
  485 
  486        if(!add_disk(l))
  487           fprintf(stderr,"ProcMeter(%s): Cannot find device for disk %s.\n",__FILE__,l);
  488 
  489        *r=pr;
  490        while(*r && *r==' ')
  491           r++;
  492 
  493        if(!*r)
  494           break;
  495 
  496        l=r;
  497       }
  498    }
  499 
  500  if(kernel_version_240 || kernel_version_260)
  501    {
  502     int i,j,n=0;
  503 
  504     for(i=0;i<N_OUTPUTS;i++)
  505        outputs[n++]=&_outputs[i];
  506 
  507     for(j=0;j<ndisks;j++)
  508        for(i=0;i<N_OUTPUTS;i++)
  509           outputs[n++]=&disk_outputs[i+j*N_OUTPUTS];
  510 
  511     outputs[n]=NULL;
  512    }
  513 
  514  values[0]=(unsigned long long*)calloc((N_OUTPUTS*(ndisks+1)),sizeof(unsigned long long));
  515  values[1]=(unsigned long long*)calloc((N_OUTPUTS*(ndisks+1)),sizeof(unsigned long long));
  516 
  517  current=values[0];
  518  previous=values[1];
  519 
  520  return(outputs);
  521 }
  522 
  523 
  524 /*++++++++++++++++++++++++++++++++++++++
  525   Add a disk (kernel version > ~2.4.0-test4).
  526 
  527   int add_disk Returns 1 if a disk was added.
  528 
  529   char *devname The name of the device to add.
  530   ++++++++++++++++++++++++++++++++++++++*/
  531 
  532 static int add_disk(char *devname)
  533 {
  534  struct stat buf;
  535  char *diskname=devname+strlen(devname);
  536  int maj,min,idx=0,i;
  537 
  538  if(stat(devname,&buf) || !S_ISBLK(buf.st_mode))
  539     return(0);
  540 
  541  maj=major(buf.st_rdev);
  542  min=minor(buf.st_rdev);
  543 
  544  /* This switch statement is the one in /usr/include/linux/genhd.h for kernels < 2.6.0 */
  545 
  546  if(kernel_version_240)
  547     switch (maj)
  548       {
  549       case DAC960_MAJOR+0:
  550        idx = (min & 0x00f8) >> 3;
  551        break;
  552       case SCSI_DISK0_MAJOR:
  553        idx = (min & 0x00f0) >> 4;
  554        break;
  555       case IDE0_MAJOR:  /* same as HD_MAJOR */
  556       case XT_DISK_MAJOR:
  557        idx = (min & 0x0040) >> 6;
  558        break;
  559       case IDE1_MAJOR:
  560        idx = ((min & 0x0040) >> 6) + 2;
  561        break;
  562       default:
  563        idx=0;
  564       }
  565 
  566  while(diskname>devname && *diskname!='/')
  567     diskname--;
  568 
  569  if(diskname==devname)
  570     return(0);
  571 
  572  diskname++;
  573 
  574  majors =(unsigned*)realloc((void*)majors ,(ndisks+1)*sizeof(unsigned));
  575  minors =(unsigned*)realloc((void*)minors ,(ndisks+1)*sizeof(unsigned));
  576  indexes=(unsigned*)realloc((void*)indexes,(ndisks+1)*sizeof(unsigned));
  577 
  578  if(ndisks>=3)
  579    {
  580     disk_outputs=(ProcMeterOutput*)realloc((void*)disk_outputs,(N_OUTPUTS*(ndisks+1))*sizeof(ProcMeterOutput));
  581 
  582     outputs=(ProcMeterOutput**)realloc((void*)outputs,(N_OUTPUTS*(ndisks+1+1)+1)*sizeof(ProcMeterOutput*));
  583    }
  584 
  585  for(i=0;i<N_OUTPUTS;i++)
  586    {
  587     disk_outputs[i+ndisks*N_OUTPUTS]=_disk_outputs[i];
  588     snprintf(disk_outputs[i+ndisks*N_OUTPUTS].name, PROCMETER_NAME_LEN, _disk_outputs[i].name, diskname);
  589     disk_outputs[i+ndisks*N_OUTPUTS].description=(char*)malloc(strlen(_disk_outputs[i].description)+strlen(devname));
  590     sprintf(disk_outputs[i+ndisks*N_OUTPUTS].description,_disk_outputs[i].description,devname);
  591    }
  592 
  593  majors[ndisks] =maj;
  594  minors[ndisks] =min;
  595  indexes[ndisks]=idx;
  596 
  597  ndisks++;
  598 
  599  return(1);
  600 }
  601 
  602 
  603 /*++++++++++++++++++++++++++++++++++++++
  604   Perform an update on one of the statistics.
  605 
  606   int Update Returns 0 if OK, else -1.
  607 
  608   time_t now The current time.
  609 
  610   ProcMeterOutput *output The output that the value is wanted for.
  611   ++++++++++++++++++++++++++++++++++++++*/
  612 
  613 int Update(time_t now,ProcMeterOutput *output)
  614 {
  615  static time_t last=0;
  616  int i;
  617 
  618  /* Get the statistics from /proc/stat */
  619 
  620  if(now!=last)
  621    {
  622     FILE *f;
  623     unsigned long long *temp;
  624 
  625     temp=current;
  626     current=previous;
  627     previous=temp;
  628 
  629     if(kernel_version_260)
  630       {
  631        f=fopen("/proc/diskstats","r");
  632        if(!f)
  633           return(-1);
  634 
  635        current[DISK_READ]=0;
  636        current[DISK_WRITE]=0;
  637 
  638        while(fgets_realloc(&line,&length,f))
  639          {
  640           int maj,min,nr;
  641           unsigned long long d1,d2,d3,d4,d5,dr,dw;
  642           int j;
  643 
  644           nr=sscanf(line,"%d %d %*s %llu %llu %llu %llu %llu",&maj,&min,&d1,&d2,&d3,&d4,&d5);
  645 
  646           if(nr==7)
  647              dr=d1,dw=d5;
  648           else if(nr==6)
  649              dr=d1,dw=d3;
  650           else
  651              break;
  652 
  653           for(j=0;j<ndisks;j++)
  654              if(majors[j]==maj && minors[j]==min)
  655                {
  656                 current[N_OUTPUTS*(j+1)+DISK_READ]=dr;
  657                 current[N_OUTPUTS*(j+1)+DISK_WRITE]=dw;
  658 
  659                 current[N_OUTPUTS*(j+1)+DISK]=dr+dw;
  660                }
  661 
  662           /* Add up the values to get the total, but ignore any 'whole disk' devices */
  663 
  664           if(((maj==IDE0_MAJOR || maj==IDE1_MAJOR || maj==IDE2_MAJOR || maj==IDE3_MAJOR ||
  665                maj==IDE4_MAJOR || maj==IDE5_MAJOR || maj==IDE6_MAJOR || maj==IDE7_MAJOR ||
  666                maj==IDE8_MAJOR || maj==IDE9_MAJOR) && (min%64)==0) ||
  667              ((maj==SCSI_DISK0_MAJOR || (maj>=SCSI_DISK1_MAJOR && maj<=SCSI_DISK7_MAJOR) ||
  668                (maj>=SCSI_DISK8_MAJOR && maj<=SCSI_DISK15_MAJOR)) && (min%16)==0) ||
  669              (maj==XT_DISK_MAJOR    && (min%64)==0) ||
  670              (maj==14               && (min%64)==0) ||
  671              (maj==MFM_ACORN_MAJOR  && (min%64)==0) ||
  672              (maj==ACSI_MAJOR       && (min%16)==0) ||
  673              (maj==PS2ESDI_MAJOR    && (min%64)==0) ||
  674              (maj==44               && (min%16)==0) ||
  675              (maj==45               && (min%16)==0) ||
  676              (maj>=48 && maj<=55    && (min%8)==0)  ||
  677              (maj>=COMPAQ_SMART2_MAJOR && maj<=COMPAQ_SMART2_MAJOR7 && (min%16)==0) ||
  678              (maj>=I2O_MAJOR && maj<=(I2O_MAJOR+7) && (min%16)==0) ||
  679              (maj==92               && (min%16)==0) ||
  680              (maj==UBD_MAJOR        && (min%16)==0) ||
  681              (maj==101              && (min%16)==0) ||
  682              (maj==102              && (min%16)==0) ||
  683              (maj>=COMPAQ_CISS_MAJOR && maj<=COMPAQ_CISS_MAJOR7 && (min%16)==0) ||
  684              (maj==VIODASD_MAJOR    && (min%8)==0)  ||
  685              (maj==ATARAID_MAJOR    && (min%16)==0) ||
  686              (maj>=136 && maj<=143  && (min%8)==0)  ||
  687              (maj==153              && (min%16)==0) ||
  688              (maj>=160 && maj<=161  && (min%32)==0) ||
  689              (maj==XENVBD_MAJOR     && (min%16)==0))
  690              ;
  691           else
  692             {
  693              current[DISK_READ] +=dr;
  694              current[DISK_WRITE]+=dw;
  695             }
  696          }
  697 
  698        current[DISK]=current[DISK_READ]+current[DISK_WRITE];
  699 
  700        fclose(f);
  701       }
  702     else
  703       {
  704        f=fopen("/proc/stat","r");
  705        if(!f)
  706           return(-1);
  707 
  708        while(fgets_realloc(&line,&length,f)) /* cpu or disk or page or swap or intr or disk_io */
  709           if(line[0]=='d' && line[1]=='i' && line[2]=='s' && line[3]=='k')
  710              break;
  711 
  712        if(!kernel_version_240) /* kernel version < ~2.4.0-test4 */
  713          {
  714           if(!kernel_version_130)
  715             {
  716              sscanf(line,"disk %llu %llu %llu %llu",&current[N_OUTPUTS*1+DISK],&current[N_OUTPUTS*2+DISK],
  717                                                     &current[N_OUTPUTS*3+DISK],&current[N_OUTPUTS*4+DISK]);
  718              current[DISK]=current[N_OUTPUTS*1+DISK]+current[N_OUTPUTS*2+DISK]+
  719                            current[N_OUTPUTS*3+DISK]+current[N_OUTPUTS*4+DISK];
  720             }
  721 
  722           /* disk_* or page */
  723           while(fgets_realloc(&line,&length,f) && line[0]=='d') /* kernel version > ~1.3.0 */
  724             {
  725              if(sscanf(line,"disk_rblk %llu %llu %llu %llu",&current[N_OUTPUTS*1+DISK_READ],&current[N_OUTPUTS*2+DISK_READ],
  726                                                             &current[N_OUTPUTS*3+DISK_READ],&current[N_OUTPUTS*4+DISK_READ])==4)
  727                 current[DISK_READ]=current[N_OUTPUTS*1+DISK_READ]+current[N_OUTPUTS*2+DISK_READ]+
  728                                    current[N_OUTPUTS*3+DISK_READ]+current[N_OUTPUTS*4+DISK_READ];
  729              if(sscanf(line,"disk_wblk %llu %llu %llu %llu",&current[N_OUTPUTS*1+DISK_WRITE],&current[N_OUTPUTS*2+DISK_WRITE],
  730                                                             &current[N_OUTPUTS*3+DISK_WRITE],&current[N_OUTPUTS*4+DISK_WRITE])==4)
  731                 current[DISK_WRITE]=current[N_OUTPUTS*1+DISK_WRITE]+current[N_OUTPUTS*2+DISK_WRITE]+
  732                                     current[N_OUTPUTS*3+DISK_WRITE]+current[N_OUTPUTS*4+DISK_WRITE];
  733             }
  734 
  735           if(kernel_version_130)
  736             {
  737              int j;
  738              for(j=1;j<=ndisks;j++)
  739                 current[N_OUTPUTS*j+DISK]=current[N_OUTPUTS*j+DISK_READ]+current[N_OUTPUTS*j+DISK_WRITE];
  740              current[DISK]=current[DISK_READ]+current[DISK_WRITE];
  741             }
  742          }
  743        else /* kernel version > ~2.4.0-test4 */
  744          {
  745           int num=8,nm,nr=0;
  746           int j;
  747 
  748           current[DISK_READ]=0;
  749           current[DISK_WRITE]=0;
  750 
  751           while(1)
  752             {
  753              unsigned maj,idx;
  754              unsigned long long d1,d3;
  755 
  756              if(kernel_version_240==6)
  757                 nr=sscanf(line+num," (%d,%d):(%*u,%llu,%*u,%llu)%n",&maj,&idx,&d1,&d3,&nm);
  758              else if(kernel_version_240==7)
  759                 nr=sscanf(line+num," (%d,%d):(%*u,%llu,%*u,%llu,%*u)%n",&maj,&idx,&d1,&d3,&nm);
  760 
  761              if(nr!=4)
  762                 break;
  763 
  764              for(j=0;j<ndisks;j++)
  765                 if(majors[j]==maj && indexes[j]==idx)
  766                   {
  767                    current[N_OUTPUTS*(j+1)+DISK_READ]=d1;
  768                    current[N_OUTPUTS*(j+1)+DISK_WRITE]=d3;
  769 
  770                    current[N_OUTPUTS*(j+1)+DISK]=d1+d3;
  771                   }
  772 
  773              current[DISK_READ] +=d1;
  774              current[DISK_WRITE]+=d3;
  775 
  776              num+=nm;
  777             }
  778 
  779           current[DISK]=current[DISK_READ]+current[DISK_WRITE];
  780          }
  781 
  782        fclose(f);
  783       }
  784 
  785     last=now;
  786    }
  787 
  788  for(i=0;i<(ndisks+1)*N_OUTPUTS;i++)
  789     if(output==outputs[i])
  790       {
  791        double value;
  792 
  793        if(previous[i]>current[i])
  794           value=0.0;
  795        else
  796           value=(double)(current[i]-previous[i])/output->interval;
  797 
  798        output->graph_value=PROCMETER_GRAPH_FLOATING(value/output->graph_scale);
  799        sprintf(output->text_value,"%.0f /s",value);
  800 
  801        return(0);
  802       }
  803 
  804  return(-1);
  805 }
  806 
  807 
  808 /*++++++++++++++++++++++++++++++++++++++
  809   Tidy up and prepare to have the module unloaded.
  810   ++++++++++++++++++++++++++++++++++++++*/
  811 
  812 void Unload(void)
  813 {
  814  int i,j;
  815 
  816  for(i=0;i<N_OUTPUTS;i++)
  817     for(j=0;j<ndisks;j++)
  818        free(disk_outputs[i+j*N_OUTPUTS].description);
  819 
  820  free(disk_outputs);
  821 
  822  free(outputs);
  823 
  824  free(values[0]);
  825  free(values[1]);
  826 
  827  if(line)
  828     free(line);
  829 }