/*
 * $Id: proc_meminfo.c,v 1.1 2001/03/15 22:16:13 jpormann Exp jpormann $
 *
 * procstatd - Copyright (c) 1999 by Robert G. Brown, rgb@phy.duke.edu
 *         GPL version 2b (b for beverage) granted.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * procstatd - A daemon to extract statistics from /proc/stat and publish them
 *         on demand via a socket connection or broadcast.
 */

#include "procstatd.h"

void init_proc_meminfo()
{

 int i,numfields;

 /* 
  * Open /proc/stat.
  */
 stat_fd[PROC_MEMINFO] = fopen("/proc/meminfo","r");

 /*
  * If the open succeeded, the file descriptor is nonzero.  We then
  * initialize all stats derived from /proc/stat.  Put values into
  * stats[FIELD].{name,source,avail,current,previous,rate}
  */

 /* /proc/meminfo */
 if(stat_fd[PROC_MEMINFO]){
   while(TRUE){
     /* Normal EOF causes break from while loop */
     if((fgets(statbuf,BUFLEN,stat_fd[PROC_MEMINFO]) == NULL)) break;
     /* parse the line into fields */
     numfields = parse(statbuf,fields,MAXFIELDNUMBER,BUFLEN);

     /*
      * Now we go down a simple lookup table to assemble each statistic
      * by name.  fields[] now contains the parsed fields from a line of
      * /proc/stat.  We identify the line by its first entry (the name
      * of the /proc/stat entity) and use the following values to build 
      * one or more statistics.
      */
     /* Memory Usage */
     if(strncmp(fields[0],"Mem",3) == 0 && strlen(fields[0]) == 3){
       /* MEM_TOTAL */
       sprintf(stats[MEM_TOTAL].name,"mem_total");	/* Label it. */
       stats[MEM_TOTAL].source = PROC_MEMINFO;		/* Tag its source for xref */
       stats[MEM_TOTAL].avail = 1;			/* Yes, we found it */
       stats[MEM_TOTAL].current = atof(fields[1])/1.0e+6;	/* current value */
       /* MEM_USED */
       sprintf(stats[MEM_USED].name,"mem_used");	/* Label it. */
       stats[MEM_USED].source = PROC_MEMINFO;		/* Tag its source for xref */
       stats[MEM_USED].avail = 1;			/* Yes, we found it */
       stats[MEM_USED].current = atof(fields[2])/1.0e+6;	/* current value */
       /* MEM_FREE */
       sprintf(stats[MEM_FREE].name,"mem_free");	/* Label it. */
       stats[MEM_FREE].source = PROC_MEMINFO;		/* Tag its source for xref */
       stats[MEM_FREE].avail = 1;			/* Yes, we found it */
       stats[MEM_FREE].current = atof(fields[3])/1.0e+6;	/* current value */
       /* MEM_SHARED */
       sprintf(stats[MEM_SHARED].name,"mem_shared");	/* Label it. */
       stats[MEM_SHARED].source = PROC_MEMINFO;		/* Tag its source for xref */
       stats[MEM_SHARED].avail = 1;			/* Yes, we found it */
       stats[MEM_SHARED].current = atof(fields[4])/1.0e+6;	/* current value */
       /* MEM_BUFF */
       sprintf(stats[MEM_BUFF].name,"mem_buff");	/* Label it. */
       stats[MEM_BUFF].source = PROC_MEMINFO;		/* Tag its source for xref */
       stats[MEM_BUFF].avail = 1;			/* Yes, we found it */
       stats[MEM_BUFF].current = atof(fields[5])/1.0e+6;	/* current value */
       /* MEM_CACHE */
       sprintf(stats[MEM_CACHE].name,"mem_cache");	/* Label it. */
       stats[MEM_CACHE].source = PROC_MEMINFO;		/* Tag its source for xref */
       stats[MEM_CACHE].avail = 1;			/* Yes, we found it */
       stats[MEM_CACHE].current = atof(fields[6])/1.0e+6;	/* current value */
     } /* end Mem: */
     /* Memory Usage */
     if(strncmp(fields[0],"Swap",4) == 0 && strlen(fields[0]) == 4){
       /* MEM_SWAP_TOTAL */
       sprintf(stats[MEM_SWAP_TOTAL].name,"mem_swap_total");	/* Label it. */
       stats[MEM_SWAP_TOTAL].source = PROC_MEMINFO;		/* Tag its source for xref */
       stats[MEM_SWAP_TOTAL].avail = 1;			/* Yes, we found it */
       stats[MEM_SWAP_TOTAL].current = atof(fields[1])/1.0e+6;	/* current value */
       /* MEM_SWAPUSED */
       sprintf(stats[MEM_SWAP_USED].name,"mem_swap_used");	/* Label it. */
       stats[MEM_SWAP_USED].source = PROC_MEMINFO;		/* Tag its source for xref */
       stats[MEM_SWAP_USED].avail = 1;			/* Yes, we found it */
       stats[MEM_SWAP_USED].current = atof(fields[2])/1.0e+6;	/* current value */
       /* MEM_SWAP_FREE */
       sprintf(stats[MEM_SWAP_FREE].name,"mem_swap_free");	/* Label it. */
       stats[MEM_SWAP_FREE].source = PROC_MEMINFO;		/* Tag its source for xref */
       stats[MEM_SWAP_FREE].avail = 1;			/* Yes, we found it */
       stats[MEM_SWAP_FREE].current = atof(fields[3])/1.0e+6;	/* current value */
     } /* End Swap: */
   } /* End while(TRUE) */
 }

} /* End init_proc_meminfo() */

void get_proc_meminfo()
{
 int i,numfields;

 /* 
  * Now, for a clever trick.  We'll reset the files without actually
  * closing or reopening them.  Perhaps we can save the overhead of
  * an open/close (presumed relatively large, as one has to stat the
  * files in question on EACH open).
  */

 /* PROC_MEMINFO */
 errno = 0;
 if(stat_fd[PROC_MEMINFO]){
   rewind(stat_fd[PROC_MEMINFO]);	/* void, so tough to check errors */
 } else {
   return;
 }
 if(errno == EBADF){
   fprintf(stderr,"Error: The /proc/meminfo file descriptor/stream is not seekable.\n");
   fclose(stat_fd[PROC_MEMINFO]); 
   fprintf(stderr,"Closing and reopening /proc/meminfo.\n");
   stat_fd[PROC_MEMINFO] = fopen("/proc/meminfo","r");
 }

 while(TRUE){
   /* Normal EOF causes break from while loop */
   if((fgets(statbuf,BUFLEN,stat_fd[PROC_MEMINFO]) == NULL)) break;
   /* parse the line into fields */
   numfields = parse(statbuf,fields,MAXFIELDNUMBER,BUFLEN);

   /*
    * Now we go down a simple lookup table to assemble each statistic
    * by name.  fields[] now contains the parsed fields from a line of
    * /proc/meminfo.  We identify the line by its first entry (the name
    * of the /proc/meminfo entity) and use the following values to build 
    * one or more statistics.
    */
   /* Memory Usage */
   if(strncmp(fields[0],"Mem",3) == 0 && strlen(fields[0]) == 3){
     /* MEM_TOTAL */
     stats[MEM_TOTAL].previous = stats[MEM_TOTAL].current;	/* previous value */
     stats[MEM_TOTAL].current = atof(fields[1])/1.0e+6;	/* current value */
     /* MEM_USED */
     stats[MEM_USED].previous = stats[MEM_USED].current;	/* previous value */
     stats[MEM_USED].current = atof(fields[2])/1.0e+6;	/* current value */
     /* MEM_FREE */
     stats[MEM_FREE].previous = stats[MEM_FREE].current;	/* previous value */
     stats[MEM_FREE].current = atof(fields[3])/1.0e+6;	/* current value */
     /* MEM_SHARED */
     stats[MEM_SHARED].previous = stats[MEM_SHARED].current;	/* previous value */
     stats[MEM_SHARED].current = atof(fields[4])/1.0e+6;	/* current value */
     /* MEM_BUFF */
     stats[MEM_BUFF].previous = stats[MEM_BUFF].current;	/* previous value */
     stats[MEM_BUFF].current = atof(fields[5])/1.0e+6;	/* current value */
     /* MEM_CACHE */
     stats[MEM_CACHE].previous = stats[MEM_CACHE].current;	/* previous value */
     stats[MEM_CACHE].current = atof(fields[6])/1.0e+6;	/* current value */
   } /* end Mem: */
   /* Memory Usage */
   if(strncmp(fields[0],"Swap",4) == 0 && strlen(fields[0]) == 4){
     /* MEM_SWAP_TOTAL */
     stats[MEM_SWAP_TOTAL].previous = stats[MEM_SWAP_TOTAL].current;	/* previous value */
     stats[MEM_SWAP_TOTAL].current = atof(fields[1])/1.0e+6;	/* current value */
     /* MEM_SWAPUSED */
     stats[MEM_SWAP_USED].previous = stats[MEM_SWAP_USED].current;	/* previous value */
     stats[MEM_SWAP_USED].current = atof(fields[2])/1.0e+6;	/* current value */
     /* MEM_SWAP_FREE */
     stats[MEM_SWAP_FREE].previous = stats[MEM_SWAP_FREE].current;	/* previous value */
     stats[MEM_SWAP_FREE].current = atof(fields[3])/1.0e+6;	/* current value */
   } /* End Swap: */
 } /* End of while(TRUE) */

} /* End of get_proc_meminfo */

void eval_proc_meminfo()
{

 int i,numfields;

 for(i=0;i<N_STATS;i++){
   switch(i) {
     /* 
      * MEM_USER, MEM_FREE, MEM_BUFF, MEM_CACHE, MEM_SWAP
      * are all straight values.
      */
     case MEM_TOTAL:
     case MEM_USED:
     case MEM_FREE:
     case MEM_SHARED:
     case MEM_BUFF:
     case MEM_CACHE:
     case MEM_SWAP_TOTAL:
     case MEM_SWAP_USED:
     case MEM_SWAP_FREE:
       stats[i].rate = stats[i].current;
       if(stats[i].rate < 0.0) stats[i].rate = 0.0;
       break;
     default:
       break;
   } /* End case switch */
 } /* End loop through enumerated types */

} /* End eval_proc_meminfo */
