/*
 *========================================================================
 * $Id: get_proc_meminfo.c 163 2005-09-14 22:54:20Z rgb $
 *
 * See copyright in copyright.h and the accompanying file COPYING
 *========================================================================
 */

#include "xmlsysd.h"

/*
 * This routine parses /proc/stat and packs its values into doc.
 */

void get_proc_meminfo(xmlNodePtr proc)
{

 int i,numfields;
 struct timeval tv;
 xmlNodePtr meminfo,memory,swap,meminfovalue;
 unsigned long int memtotal,memfree,memused,swaptotal,swapfree,swapused;

 if((verbose == D_ALL) || (verbose == D_GETPROC)){
   printf("D_GETPROC: Starting get_proc_meminfo().  Use -v %d to focus.\n",D_GETPROC);
 }

 /* 
  * Create a timestamped child of meminfo node.  Everything below
  * will belong to this
  */
 meminfo = xmlNewChild(proc,NULL,(xmlChar*) "meminfo",NULL);
 gettimeofday(&tv,0);
 sprintf(outbuf,"%d",tv.tv_sec);
 xmlSetProp(meminfo,(xmlChar*) "tv_sec",(xmlChar*) outbuf);
 sprintf(outbuf,"%d",tv.tv_usec);
 xmlSetProp(meminfo,(xmlChar*) "tv_usec",(xmlChar*) outbuf);


 /* 
  * Now, for a clever trick.  We RESET the files without actually
  * closing or reopening them.  This should save the overhead of
  * an open/close (presumed relatively large, as one has to 
  * allocate/free certain kernel structures and meminfo the file in question 
  * on EACH open/close).
  */

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

 if((verbose == D_ALL) || (verbose == D_GETPROC)){
   fprintf(stderr,"Rewound %s.\n",procpaths[PROC_MEMINFO]);
 }

 while(TRUE){

   /* Normal EOF causes break from while loop */
   if((fgets(statbuf,K,stat_fd[PROC_MEMINFO]) == NULL)) break;

   if((verbose == D_ALL) || (verbose == D_GETPROC)){
     fprintf(stderr,"Parsing %s",statbuf);
   }

   /* parse the line into fields */
   numfields = parse(statbuf,fields,MAXFIELDNUMBER,K);

   /*
    * 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.
    *
    * 9/16/04 -- some hacks required for the 2.6 kernel.
    *
    *  a) Eliminated old "free" format in favor of Field: value unit
    *
    *  b) This requires line by line parsing AND rescaling of the
    * read values OR the addition of an attribute to the tag.  I suppose
    * the best way to keep xmlsysd lean (at the expense of libwulf fatness)
    * is to add the attribute to the tag in xmlsysd (default value 1 byte)
    * and then add the (re)scaling to libwulf.  This would let me
    * anticipate e.g. mb units if I knew they were gonna use this instead
    * of MB or something else entirely.
    *
    * c) Grrr.
    */

   /*
    * MemTotal:
    */
   if(strncmp(fields[0],"MemTotal",8) == 0 && strlen(fields[0]) == 8){
     memory = xmlNewChild(meminfo,NULL,(xmlChar*) "memory",NULL);
     meminfovalue = xmlNewChild(memory,NULL,(xmlChar*) "total",(xmlChar*) fields[1]);
     xmlSetProp(meminfovalue,(xmlChar*) "unit",(xmlChar*) fields[2]);
     memtotal = strtoul(fields[1],NULL,10);
   }

   /*
    * MemFree (and MemUsed, except there isn't one any more):
    */
   if(strncmp(fields[0],"MemFree",7) == 0 && strlen(fields[0]) == 7){
     meminfovalue = xmlNewChild(memory,NULL,(xmlChar*) "free",(xmlChar*) fields[1]);
     xmlSetProp(meminfovalue,(xmlChar*) "unit",(xmlChar*) fields[2]);
     memfree = strtoul(fields[1],NULL,10);
     memused = memtotal - memfree;
     sprintf(fields[1],"%u",memused);
     meminfovalue = xmlNewChild(memory,NULL,(xmlChar*) "used",(xmlChar*) fields[1]);
     xmlSetProp(meminfovalue,(xmlChar*) "unit",(xmlChar*) fields[2]);
   }

   /*
    * Buffers:
    */
   if(strncmp(fields[0],"Buffers",7) == 0 && strlen(fields[0]) == 7){
     meminfovalue = xmlNewChild(memory,NULL,(xmlChar*) "buffers",(xmlChar*) fields[1]);
     xmlSetProp(meminfovalue,(xmlChar*) "unit",(xmlChar*) fields[2]);
   }

   /*
    * Cached:
    */
   if(strncmp(fields[0],"Cached",6) == 0 && strlen(fields[0]) == 6){
     meminfovalue = xmlNewChild(memory,NULL,(xmlChar*) "cached",(xmlChar*) fields[1]);
     xmlSetProp(meminfovalue,(xmlChar*) "unit",(xmlChar*) fields[2]);
   }

   /*
    * SwapTotal:
    */
   if(strncmp(fields[0],"SwapTotal",9) == 0 && strlen(fields[0]) == 9){
     swap = xmlNewChild(meminfo,NULL,(xmlChar*) "swap",NULL);
     meminfovalue = xmlNewChild(swap,NULL,(xmlChar*) "total",(xmlChar*) fields[1]);
     xmlSetProp(meminfovalue,(xmlChar*) "unit",(xmlChar*) fields[2]);
     swaptotal = strtoul(fields[1],NULL,10);
   }

   /*
    * SwapFree (and SwapUsed, except there isn't one any more):
    */
   if(strncmp(fields[0],"SwapFree",8) == 0 && strlen(fields[0]) == 8){
     meminfovalue = xmlNewChild(swap,NULL,(xmlChar*) "free",(xmlChar*) fields[1]);
     xmlSetProp(meminfovalue,(xmlChar*) "unit",(xmlChar*) fields[2]);
     swapfree = strtoul(fields[1],NULL,10);
     swapused = swaptotal - swapfree;
     sprintf(fields[1],"%u",swapused);
     meminfovalue = xmlNewChild(swap,NULL,(xmlChar*) "used",(xmlChar*) fields[1]);
     xmlSetProp(meminfovalue,(xmlChar*) "unit",(xmlChar*) fields[2]);
   }

 }

}

