/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/usr/ccs/lib/libperfstat/simplelvmstat.c 1.4.1.3         */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2008,2011              */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
static char sccsid[] = "@(#)96        1.4.1.3  src/bos/usr/ccs/lib/libperfstat/simplelvmstat.c, libperfstat, bos720 7/15/11 02:56:20";
/* Sample program to display all the logical volumes and              */ 
/* volume groups						      */ 

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <sys/proc.h>
#include <libperfstat.h>
#include <wpars/wparcfg.h>


/* Check value returned by malloc for NULL */

#define CHECK_FOR_MALLOC_NULL(X) {  if ((X) == NULL) {\
                                       perror ("malloc");\
                                       exit(2);\
                                       }\
				 }

/* WPAR ID for global will always be zero */

#define IS_GLOBAL(X) (!(X)) 

/* Define the default interval and count values */

#define INTERVAL_DEFAULT 1
#define COUNT_DEFAULT 1

/* declare structures for storing logical volume and volume group info */

perfstat_logicalvolume_t *lvinfo_new, *lvinfo_old;
perfstat_volumegroup_t *vginfo_new, *vginfo_old;

perfstat_id_t first;

int lv_total, vg_total;
int interval = INTERVAL_DEFAULT, count = COUNT_DEFAULT;

/* support for remote node statistics collection in a cluster environment */
perfstat_id_node_t nodeid;
char nodename[MAXHOSTNAMELEN];
int collect_remote_node_stats = 0;

/*
 *Name: showusage
 *      function to display the correct usage 
 *
 */

void showusage(char *cmd)
{
   fprintf (stderr, "usage: %s [-i <interval in seconds> ] [-c <number of iterations> ] [-n <node name in the cluster> ]\n", cmd);
   exit(1);
}

/*
 *Name: do_initialisation
 *           get the total counts of logical volume and volume group and allocate memory 
 *
 */

void do_initialisation() {

   strcpy(first.name, NULL);

   if (collect_remote_node_stats){
        strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
        nodeid.spec = NODENAME;
       /*Get the total logical volumes and check for error */
       lv_total = perfstat_logicalvolume_node(&nodeid, NULL, sizeof(perfstat_logicalvolume_t), 0);
    
       /*Get the total volume groups and check for errors */
       vg_total = perfstat_volumegroup_node(&nodeid, NULL, sizeof(perfstat_volumegroup_t), 0);
   }
   else{
       /*Get the total logical volumes and check for error */
       lv_total = perfstat_logicalvolume(NULL, NULL, sizeof(perfstat_logicalvolume_t), 0);
    
       /*Get the total volume groups and check for errors */
       vg_total = perfstat_volumegroup(NULL, NULL, sizeof(perfstat_volumegroup_t), 0);
   } 

   if (lv_total <= 0){
	perror("perfstat_logicalvolume");
	exit(1);
   }
   if (vg_total <= 0){
	perror("perfstat_volumegroup");
	exit(1);
   }

   /*Allocate memory to hold old and new structures */

   lvinfo_new = (perfstat_logicalvolume_t *)malloc (sizeof(perfstat_logicalvolume_t) * lv_total);
   CHECK_FOR_MALLOC_NULL(lvinfo_new);

   lvinfo_old = (perfstat_logicalvolume_t *)malloc (sizeof(perfstat_logicalvolume_t) * lv_total);
   CHECK_FOR_MALLOC_NULL(lvinfo_old);

   vginfo_new = (perfstat_volumegroup_t *)malloc (sizeof(perfstat_volumegroup_t) * vg_total);
   CHECK_FOR_MALLOC_NULL(vginfo_new);

   vginfo_old = (perfstat_volumegroup_t *)malloc (sizeof(perfstat_volumegroup_t) * vg_total);
   CHECK_FOR_MALLOC_NULL(vginfo_old);

}

/*
 *Name: do_cleanup
 *      frees all the memory allocated for data structures
 *
 */

void do_cleanup(){
   if (lvinfo_new)
       free(lvinfo_new);
 
   if (lvinfo_old)
       free(lvinfo_old);
 
   if (vginfo_new)
       free(vginfo_new);
 
   if (vginfo_old)
       free(vginfo_old);
}
   
/*
 *Name: display_lvm
 *      collects all logical volumes and volume groups and displays them
 *
 */

void display_lvm() {

   int i = 0, rc = 0;
  
   if (collect_remote_node_stats){
       strncpy(nodeid.u.nodename, nodename, MAXHOSTNAMELEN);
       nodeid.spec = NODENAME;
       /* Get the perfstat_logicalvolume data, rc has the number of structures returned*/
       rc = perfstat_logicalvolume_node(&nodeid, lvinfo_old, sizeof(perfstat_logicalvolume_t), lv_total);
       if (rc <= 0){
           perror("perfstat_logicalvolume_node");
           exit(1);
       }

       /*Get the perfstat_volumegroup data */
       rc = perfstat_volumegroup_node(&nodeid, vginfo_old, sizeof(perfstat_volumegroup_t), vg_total);
       if (rc <= 0){
           perror("perfstat_volumegroup_node");
           exit(1);
       }
   }
   else{
       /* Get the perfstat_logicalvolume data, rc has the number of structures returned*/
       rc = perfstat_logicalvolume(&first, lvinfo_old, sizeof(perfstat_logicalvolume_t), lv_total);
       if (rc <= 0){
           perror("perfstat_logicalvolume");
           exit(1);
       }

       /*Get the perfstat_volumegroup data */
       rc = perfstat_volumegroup(&first, vginfo_old, sizeof(perfstat_volumegroup_t), vg_total);
       if (rc <= 0){
           perror("perfstat_volumegroup");
           exit(1);
       }
   }
 
   while(count){
      sleep(interval);
      
      if (collect_remote_node_stats){
          rc = perfstat_logicalvolume_node(&nodeid, lvinfo_new, sizeof(perfstat_logicalvolume_t), lv_total);
      }
      else{
          rc = perfstat_logicalvolume(&first, lvinfo_new, sizeof(perfstat_logicalvolume_t), lv_total);
      }
      if (rc <= 0){
          perror("perfstat_logicalvolume");
          exit(1);
      }
 
      /*
       *  LV      -  logical volume name
       *  VG      -  Volume group name
       *  size    - size of the logical volume
       *  iocount - number of read and write
       */

      printf("\n%10s %10s %10s %10s\n", " LV ", " VG " , " size ", " iocnt ");
      printf("%10s %10s %10s %10s\n", "===", "===", "======", "======"); 
      
      for (i = 0; i < rc; i++){
           printf("%10s %10s %10llu %10llu\n", lvinfo_new[i].name, lvinfo_new[i].vgname, 
		lvinfo_new[i].ppsize, (lvinfo_new[i].iocnt - lvinfo_old[i].iocnt));
      }

      if (collect_remote_node_stats){
          rc = perfstat_volumegroup_node(&nodeid, vginfo_new, sizeof(perfstat_volumegroup_t), vg_total);
      }
      else{
          rc = perfstat_volumegroup(&first, vginfo_new, sizeof(perfstat_volumegroup_t), vg_total);
      }
      if (rc <= 0){
          perror("perfstat_volumegroup");
          exit(1);
      }

      /*
       *  VG     - volume group name
       *  Disks  - number of disks
       *  lvcount- number of logivalvolume
       *  iocount- number of read and write requests
       */
    
      printf("\n%10s %10s %10s %10s\n", " VG ", " Disks ", " lvcount ", " iocount ");
      printf("%10s %10s %10s %10s\n", "====", "======", "=======", "=======");

      for (i = 0; i < rc; i++){
           printf("%10s %10llu %10llu %10llu\n", vginfo_new[i].name, vginfo_new[i].total_disks, 
		vginfo_new[i].total_logical_volumes, (vginfo_new[i].iocnt - vginfo_old[i].iocnt)); 
      }
      count--;
      memcpy(lvinfo_old, lvinfo_new, (sizeof(perfstat_logicalvolume_t) * lv_total));
      memcpy(vginfo_old, vginfo_new, (sizeof(perfstat_volumegroup_t) * vg_total));
  }

   do_cleanup();    
}

/* 
 *Name: main
 *
 */

int main(int argc, char *argv[]) 
{
   int i, cid, rc;

   cid = corral_getcid();
   
   /*Display the usage message and exit if called inside WPAR */
   if (!IS_GLOBAL(cid)){
	showusage(argv[0]);
   }

   /* Process the arguments */
   while ((i = getopt(argc, argv, "i:c:n:")) != EOF)
   {
       switch(i)
       {
           case 'i':               /* Interval */
                    interval = atoi(optarg);
                    if( interval <= 0 )
                        interval = INTERVAL_DEFAULT;
                    break;
           case 'c':               /* Number of interations */
                    count = atoi(optarg);
                    if( count <= 0 )
                        count = COUNT_DEFAULT;
                    break;
           case 'n':               /* Node name in a cluster environment */
                    strncpy(nodename, optarg, MAXHOSTNAMELEN);
                    nodename[MAXHOSTNAMELEN-1] = '\0';
                    collect_remote_node_stats = 1;
                    break;
           default:
                   /* Invalid arguments. Print the usage and terminate */
                   showusage(argv[0]);
       }
   }

   /* perfstat_config needs to be called to enabled LV and VG collection */
   perfstat_config(PERFSTAT_ENABLE|PERFSTAT_LV, NULL);

   if(collect_remote_node_stats)
   {   /* perfstat_config needs to be called to enable cluster statistics collection */
       rc = perfstat_config(PERFSTAT_ENABLE|PERFSTAT_CLUSTER_STATS, NULL);
       if (rc == -1)
       {
           perror("cluster statistics collection is not available");
           exit(-1);
       }
   }

   do_initialisation();

   display_lvm();

   if(collect_remote_node_stats)
   {   /* Now disable cluster statistics by calling perfstat_config */
       perfstat_config(PERFSTAT_DISABLE|PERFSTAT_CLUSTER_STATS, NULL);
   }
   perfstat_config(PERFSTAT_DISABLE|PERFSTAT_LV, NULL);

}

