/*
 *========================================================================
 * $Id: get_proc_sysvipc.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/sysvipc/[msg,sem,shm] to extract shared memory
 * and SysV IPC statistics.  Not quite clear that it is the best way to
 * present the summaries but we'll do it for the moment.
 */

void get_proc_sysvipc(xmlNodePtr proc)
{

 int i,numfields,bufcnt,buftot;
 struct timeval tv;
 xmlNodePtr sysvipc,msgval,semval,shmval;

 if(verbose==102){
   fprintf(stderr,"Starting get_proc_sysvipc().\n");
 }

 /* 
  * Create <sysvipc> child of <proc> node.  Everything below
  * will belong to this
  */
 sysvipc = xmlNewChild(proc,NULL,(xmlChar*) "sysvipc",NULL);
 gettimeofday(&tv,0);
 sprintf(outbuf,"%d",tv.tv_sec);
 xmlSetProp(sysvipc,(xmlChar*) "tv_sec",(xmlChar*) outbuf);
 sprintf(outbuf,"%d",tv.tv_usec);
 xmlSetProp(sysvipc,(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_SYSVIPC_MSG*/
 errno = 2;
 if(stat_fd[PROC_SYSVIPC_MSG]){
   rewind(stat_fd[PROC_SYSVIPC_MSG]);	/* void, so tough to check errors */
 } else {
   xmlSetProp(sysvipc,(xmlChar*) "available",(xmlChar*) "no");
   return;
 }
 if(errno == EBADF){
   fprintf(stderr,"Error: The %s file descriptor/stream is not seekable.\n",procpaths[PROC_SYSVIPC_MSG]);
   fclose(stat_fd[PROC_SYSVIPC_MSG]); 
   fprintf(stderr,"Closing and reopening %s.\n",procpaths[PROC_SYSVIPC_MSG]);
   stat_fd[PROC_SYSVIPC_MSG] = fopen(procpaths[PROC_SYSVIPC_MSG],"r");
 }

 if(verbose == 102){
   fprintf(stderr,"Rewound %s.\n",procpaths[PROC_SYSVIPC_MSG]);
 }

 bufcnt = 0;
 buftot = 0;
 while(TRUE){

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

   if(verbose == 102){
     fprintf(stderr,"Parsing %s\n",statbuf);
   }

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

   /*
    * This is a bit complicated, but a lot better than the old way of
    * deriving SysV IPC value summaries.  It is a cooked result -- we only
    * want totals.
    *
    * SO, we skip the first line (fields[0] == "key"), count the remaining
    * lines (number of msg, sem or shm buffers) and sum the size(s) in
    * column 4 (fields[3]).  This "should" exactly match what used to
    * be returned by ipcstuff.c in procstat.d.
    */

   /*
    * Ignore line starting with key
    */
   if(verbose == 129){
     fprintf(stderr,"Doing line starting with %s\n",fields[0]);
   }
   if( strncmp(fields[0],"key",3) != 0 ){
     bufcnt++;
     buftot += atof(fields[3]);
   }
 }

 /*
  * bufcnt should count open buffers; buftot should be total size
  * of all buffers (summed).  Now we send it back.
  */
 sprintf(outbuf,"%d",bufcnt);
 msgval = xmlNewChild(sysvipc,NULL,(xmlChar*) "msgbufs",(xmlChar*) outbuf);
 sprintf(outbuf,"%d",buftot);
 msgval = xmlNewChild(sysvipc,NULL,(xmlChar*) "msgtot",(xmlChar*) outbuf);

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

 if(verbose == 102){
   fprintf(stderr,"Rewound %s.\n",procpaths[PROC_SYSVIPC_SEM]);
 }

 bufcnt = 0;
 buftot = 0;
 while(TRUE){

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

   if(verbose == 102){
     fprintf(stderr,"Parsing %s\n",statbuf);
   }

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

   /*
    * This is a bit complicated, but a lot better than the old way of
    * deriving SysV IPC value summaries.  It is a cooked result -- we only
    * want totals.
    *
    * SO, we skip the first line (fields[0] == "key"), count the remaining
    * lines (number of msg, sem or shm buffers) and sum the size(s) in
    * column 4 (fields[3]).  This "should" exactly match what used to
    * be returned by ipcstuff.c in procstat.d.
    */

   /*
    * Ignore line starting with key
    */
   if(verbose == 129){
     fprintf(stderr,"Doing line starting with %s\n",fields[0]);
   }
   if( strncmp(fields[0],"key",3) != 0 ){
     bufcnt++;
     buftot += atof(fields[3]);
   }
 }

 /*
  * bufcnt should count open buffers; buftot should be total size
  * of all buffers (summed).  Now we send it back.
  */
 sprintf(outbuf,"%d",bufcnt);
 semval = xmlNewChild(sysvipc,NULL,(xmlChar*) "sembufs",(xmlChar*) outbuf);
 sprintf(outbuf,"%d",buftot);
 semval = xmlNewChild(sysvipc,NULL,(xmlChar*) "semtot",(xmlChar*) outbuf);

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

 if(verbose == 102){
   fprintf(stderr,"Rewound %s.\n",procpaths[PROC_SYSVIPC_SHM]);
 }

 bufcnt = 0;
 buftot = 0;
 while(TRUE){

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

   if(verbose == 102){
     fprintf(stderr,"Parsing %s\n",statbuf);
   }

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

   /*
    * This is a bit complicated, but a lot better than the old way of
    * deriving SysV IPC value summaries.  It is a cooked result -- we only
    * want totals.
    *
    * SO, we skip the first line (fields[0] == "key"), count the remaining
    * lines (number of msg, sem or shm buffers) and sum the size(s) in
    * column 4 (fields[3]).  This "should" exactly match what used to
    * be returned by ipcstuff.c in procstat.d.
    */

   /*
    * Ignore line starting with key
    */
   if(verbose == 129){
     fprintf(stderr,"Doing line starting with %s\n",fields[0]);
   }
   if( strncmp(fields[0],"key",3) != 0 ){
     bufcnt++;
     buftot += atof(fields[3]);
   }
 }

 /*
  * bufcnt should count open buffers; buftot should be total size
  * of all buffers (summed).  Now we send it back.
  */
 sprintf(outbuf,"%d",bufcnt);
 shmval = xmlNewChild(sysvipc,NULL,(xmlChar*) "shmbufs",(xmlChar*) outbuf);
 sprintf(outbuf,"%d",buftot);
 shmval = xmlNewChild(sysvipc,NULL,(xmlChar*) "shmtot",(xmlChar*) outbuf);

}

