/*
 *
 * 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.
 */

/* this module by John B. Pormann, jpormann@ee.duke.edu */

/* but much was stolen from ipcs.c by : */
/* Original author unknown, but may be "krishna balasub@cis.ohio-state.edu
   Modified Sat Oct  9 10:55:28 1993 for 0.99.13 */
/* Patches from Mike Jagdis (jaggy@purplet.demon.co.uk) applied Wed Feb
  8 12:12:21 1995 by faith@cs.unc.edu to print numeric uids if no
  passwd file entry.
  Patch from arnolds@ifns.de (Heinz-Ado Arnolds) applied Mon Jul 1
  19:30:41 1996 by janl@math.uio.no to add code missing in case PID:
  clauses.
  Patched to display the key field -- hy@picksys.com 12/18/96
*/


#include "procstatd.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <sys/shm.h>

/* taken from a comment inside <sys/sem.h> */
union semun
{
  int val;
  struct semid_ds *buf;
  unsigned short int *array;
  struct seminfo *__buf;
};


void init_ipcstuff()
{
 int i,numfields;
 int maxid, ipcid, id;
 struct shmid_ds shmseg;
 struct shm_info shm_info1;
 struct shminfo shminfo1;
 struct ipc_perm* ipcp = &shmseg.shm_perm;
 struct passwd* pw;
 int num_shm=0, shm_tot=0;
 union semun arg;
 struct semid_ds semary;
 struct seminfo seminfo1;
 int num_sem=0, sem_tot=0;
 struct msqid_ds msgque;
 struct msginfo msginfo1;
 int num_msg=0, msg_tot=0;

 maxid = shmctl( 0, SHM_INFO, (struct shmid_ds*)&shm_info1 );
 if( maxid >= 0 ) {
   for(id=0;id<=maxid;id++) {
      ipcid = shmctl( id, SHM_STAT, &shmseg );
      if( ipcid >= 0 ) {
         num_shm++;
         shm_tot += shmseg.shm_segsz;
      }
   }
 }

 sprintf( stats[SHM_NUM].name, "shm_num" );
 stats[SHM_NUM].source = IPCS;
 stats[SHM_NUM].avail = 1;
 stats[SHM_NUM].current = num_shm;
 sprintf( stats[SHM_TOT].name, "shm_tot" );
 stats[SHM_TOT].source = IPCS;
 stats[SHM_TOT].avail = 1;
 stats[SHM_TOT].current = shm_tot;

 arg.array = (ushort*)&seminfo1;
 maxid = semctl( 0, 0, SEM_INFO, arg );
 if( maxid >= 0 ) {
   for(id=0;id<=maxid;id++) {
      arg.buf = (struct semid_ds*)&semary;
      ipcid = semctl( id, 0, SEM_STAT, arg );
      if( ipcid >= 0 ) {
         num_sem++;
         sem_tot += semary.sem_nsems;
      }
   }
 }

 sprintf( stats[SEM_NUM].name, "sem_num" );
 stats[SEM_NUM].source = IPCS;
 stats[SEM_NUM].avail = 1;
 stats[SEM_NUM].current = num_sem;
 sprintf( stats[SEM_TOT].name, "sem_tot" );
 stats[SEM_TOT].source = IPCS;
 stats[SEM_TOT].avail = 1;
 stats[SEM_TOT].current = sem_tot;

 maxid = msgctl( 0, MSG_INFO, (struct msqid_ds*)&msginfo1 );
 if( maxid >= 0 ) {
   for(id=0;id<=maxid;id++) {
      ipcid = msgctl( id, MSG_STAT, &msgque );
      if( ipcid >= 0 ) {
         num_msg++;
         /* could accumulate msgque.msg_qnum */
         msg_tot += msgque.msg_cbytes;
      }
   }
 }

 sprintf( stats[MSG_NUM].name, "msg_num" );
 stats[MSG_NUM].source = IPCS;
 stats[MSG_NUM].avail = 1;
 stats[MSG_NUM].current = num_msg;
 sprintf( stats[MSG_TOT].name, "msg_tot" );
 stats[MSG_TOT].source = IPCS;
 stats[MSG_TOT].avail = 1;
 stats[MSG_TOT].current = msg_tot;
}

void get_ipcstuff()
{
 int i,numfields;
 int maxid, ipcid, id;
 struct shmid_ds shmseg;
 struct shm_info shm_info1;
 struct shminfo shminfo1;
 struct ipc_perm* ipcp = &shmseg.shm_perm;
 struct passwd* pw;
 int num_shm=0, shm_tot=0;
 union semun arg;
 struct semid_ds semary;
 struct seminfo seminfo1;
 int num_sem=0, sem_tot=0;
 struct msqid_ds msgque;
 struct msginfo msginfo1;
 int num_msg=0, msg_tot=0;

 maxid = shmctl( 0, SHM_INFO, (struct shmid_ds*)&shm_info1 );
 if( maxid >= 0 ) {
   for(id=0;id<=maxid;id++) {
      ipcid = shmctl( id, SHM_STAT, &shmseg );
      if( ipcid >= 0 ) {
         num_shm++;
         shm_tot += shmseg.shm_segsz;
      }
   }
 }

 stats[SHM_NUM].current = num_shm;
 stats[SHM_TOT].current = shm_tot;

 arg.array = (ushort*)&seminfo1;
 maxid = semctl( 0, 0, SEM_INFO, arg );
 if( maxid >= 0 ) {
   for(id=0;id<=maxid;id++) {
      arg.buf = (struct semid_ds*)&semary;
      ipcid = semctl( id, 0, SEM_STAT, arg );
      if( ipcid >= 0 ) {
         num_sem++;
         sem_tot += semary.sem_nsems;
      }
   }
 }

 stats[SEM_NUM].current = num_sem;
 stats[SEM_TOT].current = sem_tot;

 maxid = msgctl( 0, MSG_INFO, (struct msqid_ds*)&msginfo1 );
 if( maxid >= 0 ) {
   for(id=0;id<=maxid;id++) {
      ipcid = msgctl( id, MSG_STAT, &msgque );
      if( ipcid >= 0 ) {
         num_msg++;
         /* could accumulate msgque.msg_qnum */
         msg_tot += msgque.msg_cbytes;
      }
   }
 }

 stats[MSG_NUM].current = num_msg;
 stats[MSG_TOT].current = msg_tot;
}

void eval_ipcstuff()
{
  stats[SHM_NUM].rate = stats[SHM_NUM].current;
  if(stats[SHM_NUM].rate < 0.0) stats[SHM_NUM].rate = 0.0;
  stats[SHM_TOT].rate = stats[SHM_TOT].current;
  if(stats[SHM_TOT].rate < 0.0) stats[SHM_TOT].rate = 0.0;

  stats[SEM_NUM].rate = stats[SEM_NUM].current;
  if(stats[SEM_NUM].rate < 0.0) stats[SEM_NUM].rate = 0.0;
  stats[SEM_TOT].rate = stats[SEM_TOT].current;
  if(stats[SEM_TOT].rate < 0.0) stats[SEM_TOT].rate = 0.0;

  stats[MSG_NUM].rate = stats[MSG_NUM].current;
  if(stats[MSG_NUM].rate < 0.0) stats[MSG_NUM].rate = 0.0;
  stats[MSG_TOT].rate = stats[MSG_TOT].current;
  if(stats[MSG_TOT].rate < 0.0) stats[MSG_TOT].rate = 0.0;
}

