/************************************************************/
/*                                                          */
/* Module ID  - monstat.                                    */
/*                                                          */
/* Function   - Generate monitor data for the Linux system. */
/*                                                          */
/* Called By  - N/A.                                        */
/*                                                          */
/* Calling To - N/A.                                        */
/*                                                          */
/* Parameters - None.                                       */
/*                                                          */
/* Notes      - (1) Uses /dev/cpmon to communicate.         */
/*                                                          */
/*              (2) ....................................... */
/*                                                          */
/*                                                          */
/* Name       - Neale Ferguson.                             */
/*                                                          */
/* Date       - April, 2000.                                */
/*                                                          */
/*                                                          */
/* Associated    - (1) Refer To ........................... */
/* Documentation                                            */
/*                 (2) Refer To ........................... */
/*                                                          */
/* Based on code found in vmstat.c:                         */
/*    Copyright 1994 by Henry Ware <al172@yfn.ysu.edu>.     */
/*    Copyleft same year.                                   */
/*                                                          */
/************************************************************/
 
/************************************************************/
/*                                                          */
/*                     DEFINES                              */
/*                     -------                              */
/*                                                          */
/************************************************************/
 
#define MONDEV  "/dev/cpmon"
#define VERSION Version: 1.00, last modified 20 April 2000
#define PROGNAME "monstat"
#define NDEBUG !DEBUG
 
#define BUFFSIZE 1024
#define FALSE 0
#define TRUE 1
 
#ifdef __s390x__
# define APPLMON_START_REC 0x80
# define APPLMON_STOP_REC  0x81
# define APPLMON_GEN_EVENT 0x82
# define APPLMON_START_CON 0x83
# define APPLMON_PUT_SAMP  0x84
#else
# define APPLMON_START_REC 0x00
# define APPLMON_STOP_REC  0x01
# define APPLMON_GEN_EVENT 0x02
# define APPLMON_START_CON 0x03
# define APPLMON_PUT_SAMP  0x04
#endif

/* Use 'l' as magic number */
#define APPLMON_IOC_MAGIC  'l'

#define APPLMON_IOCRESET    _IO(APPLMON_IOC_MAGIC, 0)
#define MONSETPROD          _IOW(APPLMON_IOC_MAGIC, 1, char *)

/*=============== End of Defines ===========================*/
 
/************************************************************/
/*                                                          */
/*              INCLUDE STATEMENTS                          */
/*              ------------------                          */
/*                                                          */
/************************************************************/
 
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include "proc/sysinfo.h"
#include "proc/version.h"
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/dir.h>
#include <dirent.h>
 
/*================== End of Include Statements =============*/
 
/************************************************************/
/*                                                          */
/*              TYPE DEFINITIONS                            */
/*              ----------------                            */
/*                                                          */
/************************************************************/
 
 
/*================== End of Type Definitions ===============*/
 
/************************************************************/
/*                                                          */
/*             FUNCTION PROTOTYPES                          */
/*             -------------------                          */
/*                                                          */
/************************************************************/
 
int main(int, char **);
void crash(char *);
void getstat(unsigned *, unsigned *, unsigned *, unsigned long *,
             unsigned *, unsigned *, unsigned *, unsigned *,
             unsigned *, unsigned *, unsigned *);
void getmeminfo(unsigned *, unsigned *, unsigned *, unsigned *);
void getrunners(unsigned *, unsigned *, unsigned *);
 
/*================== End of Prototypes =====================*/
 
/************************************************************/
/*                                                          */
/*           GLOBAL VARIABLE DECLARATIONS                   */
/*           ----------------------------                   */
/*                                                          */
/************************************************************/
 
int    linux_version_code = LINUX_VERSION(2,0,0);
static char buff[BUFFSIZE];
 
/*============== End of Variable Declarations ==============*/
 
/************************************************************/
/*                                                          */
/*                 M A I N L I N E                          */
/*                 ---------------                          */
/************************************************************/
 
int
main(int argc, char **argv)
{
 int fd, l_monitor;
 const char format[]="~%2u %2u %2u %6u %6u %6u %6u %3u "
                     "%3u %5u %5u %4u %5u %3u %3u %3u~";
 unsigned int  i,hz;
 unsigned int  running,blocked,swapped;
 unsigned int  cpu_use, cpu_nic, cpu_sys;
 unsigned int  duse,dsys,didl,div,divo2;
 unsigned int  memfree,membuff,swapused, memcache;
 unsigned long cpu_idl;
 unsigned int  pgpgin, pgpgout, pswpin, pswpout;
 unsigned int  inter,ticks,ctxt;
 unsigned int  per = 0;
 unsigned long num = 0;
 struct {
    char  fcn;
    char  len;
    char  buffer[512];
 } mon;
 char *product_id = "MONSTATDRIVER000";
 
    fd = open(MONDEV, O_RDWR);
    if (fd < 0)
       crash(MONDEV);
    mon.fcn = APPLMON_GEN_EVENT;
    ioctl(fd, MONSETPROD, product_id);
    per     = 10;
 
    getrunners(&running,&blocked,&swapped);
    getmeminfo(&memfree,&membuff,&swapused,&memcache);
    getstat(&cpu_use,&cpu_nic,&cpu_sys,&cpu_idl,
            &pgpgin,&pgpgout,&pswpin,&pswpout,
            &inter,&ticks,&ctxt);
    duse  = cpu_use + cpu_nic;
    dsys  = cpu_sys;
    didl  = cpu_idl%UINT_MAX;
    div   = (duse+dsys+didl);
    hz    = sysconf(_SC_CLK_TCK); /* get ticks/s from system */
    divo2 = div/2;
    sprintf(mon.buffer,format,
            running,blocked,swapped,
            swapused,memfree,membuff,memcache,
            (pswpin*4*hz+divo2)/div,
            (pswpout*4*hz+divo2)/div,
            (pgpgin*hz+divo2)/div,
            (pgpgout*hz+divo2)/div,
            (inter*hz+divo2)/div,
            (ctxt*hz+divo2)/div,
            (100*duse+divo2)/div,
            (100*dsys+divo2)/div,
            (100*didl+divo2)/div);
    mon.len   = strlen(mon.buffer);
    l_monitor = mon.len + 2;
    if (write(fd, (char *) &mon, l_monitor) < 0)
       crash(MONDEV);
 
    /*-----------------------------------------------------------*/
    /* Main loop...                                              */
    /*-----------------------------------------------------------*/
    for(;i==i;) {
       sleep(per);
       getmeminfo(&memfree,&membuff,&swapused,&memcache);
       getstat(&cpu_use,&cpu_nic,&cpu_sys,&cpu_idl,
               &pgpgin,&pgpgout,&pswpin,&pswpout,
               &inter,&ticks,&ctxt);
       duse  = cpu_use + cpu_nic;
       dsys  = cpu_sys;
       didl  = cpu_idl%UINT_MAX;
       div   = (duse+dsys+didl);
       divo2 = div / 2;
       sprintf(mon.buffer,format,
               running,blocked,swapped,
               swapused,memfree,membuff,memcache,
               (pswpin*4*hz+divo2)/div,
               (pswpout*4*hz+divo2)/div,
               (pgpgin*hz+divo2)/div,
               (pgpgout*hz+divo2)/div,
               (inter*hz+divo2)/div,
               (ctxt*hz+divo2)/div,
               (100*duse+divo2)/div,
               (100*dsys+divo2)/div,
               (100*didl+divo2)/div);
       mon.len   = strlen(mon.buffer);
       l_monitor = mon.len + 2;
       if (write(fd, (char *) &mon, l_monitor) < 0)
          crash(MONDEV);
    }
    if (close(fd) < 0)
       crash(MONDEV);
    exit(EXIT_SUCCESS);
}
 
/*===================== End of Function ====================*/
 
/************************************************************/
/*                                                          */
/* Name     -                                               */
/*                                                          */
/* Function -                                               */
/*                                                          */
/************************************************************/
 
void
crash(char *filename)
{
   perror(filename);
   exit(EXIT_FAILURE);
}
 
/*===================== End of Function ====================*/
 
/************************************************************/
/*                                                          */
/* Name     -                                               */
/*                                                          */
/* Function -                                               */
/*                                                          */
/************************************************************/
 
void
getstat(unsigned *cuse,      unsigned *cice, unsigned *csys,
        unsigned long *cide, unsigned *pin,  unsigned *pout,
        unsigned *sin,       unsigned *sout,
        unsigned *itot,      unsigned *i1,   unsigned *ct)
{
 static int stat;
 char* b;
 
   if ((stat=open("/proc/stat", O_RDONLY, 0)) != -1) {
      buff[BUFFSIZE-1] = 0;  /* ensure null termination in buffer */
      read(stat,buff,BUFFSIZE-1);
      close(stat);
      *itot = 0;
      *i1 = 1;   /* ensure assert below will fail if the sscanf bombs */
      b = strstr(buff, "cpu ");
      sscanf(b, "cpu  %u %u %u %lu", cuse, cice, csys, cide);
      b = strstr(buff, "page ");
      sscanf(b, "page %u %u", pin, pout);
      b = strstr(buff, "swap ");
      sscanf(b, "swap %u %u", sin, sout);
      b = strstr(buff, "intr ");
      sscanf(b, "intr %u %u", itot, i1);
      b = strstr(buff, "ctxt ");
      sscanf(b, "ctxt %u", ct);
      assert(*itot>*i1);
   }
   else {
     crash("/proc/stat");
   }
}
 
/*===================== End of Function ====================*/
 
/************************************************************/
/*                                                          */
/* Name     -                                               */
/*                                                          */
/* Function -                                               */
/*                                                          */
/************************************************************/
 
void
getmeminfo(unsigned *memfree,  unsigned *membuff,
           unsigned *swapused, unsigned *memcache)
{
 unsigned** mem;
 
   if (!(mem = meminfo()))
      crash("/proc/meminfo");
 
   *memfree  = mem[meminfo_main][meminfo_free]    >> 10;
   *membuff  = mem[meminfo_main][meminfo_buffers] >> 10;
   *swapused = mem[meminfo_swap][meminfo_used]    >> 10;
   *memcache = mem[meminfo_main][meminfo_cached]  >> 10;
}
 
/*===================== End of Function ====================*/
 
/************************************************************/
/*                                                          */
/* Name     -                                               */
/*                                                          */
/* Function -                                               */
/*                                                          */
/************************************************************/
 
void
getrunners(unsigned int *running, unsigned int *blocked,
           unsigned int *swapped)
{
 static struct direct *ent;
 static char filename[80];
 static int fd;
 static unsigned size;
 static char c;
 DIR    *proc;
 
   *running = 0;
   *blocked = 0;
   *swapped = 0;
 
   if ((proc=opendir("/proc"))==NULL)
      crash("/proc");
 
   while((ent=readdir(proc))) {
      if (isdigit(ent->d_name[0])) {
         sprintf(filename, "/proc/%s/stat", ent->d_name);
         if ((fd = open(filename, O_RDONLY, 0)) != -1) {
            read(fd,buff,BUFFSIZE-1);
            sscanf(buff, "%*d %*s %c %*d %*d %*d %*d %*d %*u "
                         "%*u %*u %*u %*u %*d %*d %*d %*d "
                         "%*d %*d %*u %*u %*d %*u %u %*u "
                         "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u\n",
                          &c,&size);
            close(fd);
 
            if (c=='R') {
               if (size>0)
                  (*running)++;
               else
                  (*swapped)++;
            }
            else
            {
               if (c=='D') {
                  if (size>0)
                     (*blocked)++;
                  else
                     (*swapped)++;
               }
            }
         }
      }
   }
   closedir(proc);
 
   (*running)--;
}
 
/*===================== End of Function ====================*/
