/**********************************************************************
 * Copyright (c) 2005, 2009 Scapa Technologies Limited and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: perflin.c,v 1.3 2009/08/07 00:52:02 jwest Exp $
 * 
 * Contributors: 
 * Scapa Technologies Limited - Initial API and implementation
 * Spundun Bhatt (spundun@gmail.com), with the support and encouragement of the University of Southern California Information Sciences Institute Distributed Scalable Systems Division.
 **********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include <errno.h>
#include <dirent.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <sys/ioctl.h>
#include "perflin.h"

#include <fcntl.h>
#include <mntent.h>
#include <sys/unistd.h>
#include <sys/dir.h>
#include <sys/sysinfo.h>
#include <unistd.h>

static int VERBOSE = FALSE;
static int pageSize = 0;

static int buflen = 8;
static char* buff = NULL;

static int cpuCount = 1;

static HashTable* treeHash;
static HashTable* filtersHash;
static HashTable* variablesHash;
static HashTable* previousValues; // Used to cache previous results 
static HashTable* processHash;
static HashTable* currentValues;

static HashTable* counterSeen;

static char** results = NULL;
static int max = 0;
static int size = 0;

static char* agent_type = "LinuxAgent";

/*************************************************************************************/

void crash(char* error)
{
	printf("Error - crash in ");
	printf("%s\n",error);
	exit(1);
}

void addToArray(char* string)
{
	if (results == NULL || max == 0)
	{
		max = 128;
		size = 0;
		results = malloc(sizeof(char*)*(max));
	}

	if (size+1 == max)
	{
		max = (max)*2;
		results = realloc(results, sizeof(char*)*(max));	
	}

	results[size] = string;
	size = size + 1;
}

void addToResultsArray(char* id, char* result)
{
	// Format the id-result string and add to the tree,no need ot free resultstring here - done in PerfmonAgent
  	char* resultString = malloc(sizeof(char)*(1+strlen(id)+strlen(result)+3));
	sprintf(resultString,"%s%c%s%c",id,'\0',result,'\0');
	addToArray(resultString);
}

void addToTreeArray(char* pid, char* id, char* name, char* desc, char* suffix)
{
	// Format the tree string and add it to the getTree results array 'array'
  	char* treeString = malloc(sizeof(char)*(1+strlen(id)+strlen(pid)+strlen(name)+strlen(desc)+strlen(suffix)+10));
	if (strchr(id,'C') == NULL)
		sprintf(treeString,"%s%c%s%c%s%c%s%c%s%c%d%c",pid,'\0',id,'\0',name,'\0',desc,'\0',suffix,'\0',0,'\0');
	else
		sprintf(treeString,"%s%c%s%c%s%c%s%c%s%c%d%c",pid,'\0',id,'\0',name,'\0',desc,'\0',suffix,'\0',1,'\0');
		
	addToArray(treeString);
}

void addDoubleCounter(double number, char* id, char* resultString)
{
		sprintf(resultString, "%lf%c",number,'\0');
		addToResultsArray(id, resultString);
}

void addLongCounter(long number, char* id, char* resultString)
{
		sprintf(resultString, "%lu%c",number,'\0');
		addToResultsArray(id, resultString);
}

void addUnsignedCounter(long number, char* id, char* resultString)
{
	sprintf(resultString, "%lu%c",number, '\0');
	addToResultsArray(id, resultString);
}

void getLinuxTree() 
{
	if (VERBOSE == TRUE) printf("*** in getLinuxTree\n");

  	getStatInfo("");
  	getMemInfoTree("");
	getProcessesTree("");
	getNetInfoTree("");
	getMountTree("");
	getSwapTree("");

	if (VERBOSE == TRUE) printf("*** out getLinuxTree\n");
}

void getLinuxResults()
{
	if (VERBOSE == TRUE) printf("*** in getLinuxResults\n");

	getStatResults();
	getMemInfoResults();

	// If we have some filters requested
	if (tableGet(filtersHash, PROC_MAIN) != (XINT64) NULL)
		getProcessesResults();

	getNetInfoResults();	
	getMountResults();
	getSwapResults();
	if (VERBOSE == TRUE) printf("*** out getLinuxResults\n");
}

void expandBuffer()
{
	buflen = buflen*2;
	buff = realloc(buff, sizeof(char)*buflen);
}

int readFromFile(char* filename)
{
	static int file;
	if ((file = open(filename, O_RDONLY, 0)) != -1) 
	{
		memset(buff,'\0',buflen-1);
	   	buff[buflen - 1] = '\0';  /* ensure null termination in buffer */

		while (read(file, buff, buflen - 1) == (buflen - 1))
		{
			expandBuffer();
			lseek(file,0,SEEK_SET);
		}
	   	close(file);
	   	return TRUE;
	}
	else
		printf("Unable to open file %s\n",filename);
	return FALSE;
}

int readSwapInfo()
{
  return readFromFile("/proc/swaps");
}

int readNetDevInfo()
{
	return readFromFile("/proc/net/dev");
}

int readNetWirelessInfo()
{
	return readFromFile("proc/stat");
}

int readStatInfo() 
{
	return readFromFile("/proc/stat");
} 

int readMemInfo() 
{
	return readFromFile("/proc/meminfo");
} 

int readProcInfo(char * fileName) 
{
	return readFromFile(fileName);
}

void getSwapTree(char* parentid)
{
	if (VERBOSE == TRUE) printf("*** in getSwapTree\n");

	if (readSwapInfo())
	{
		char* b;
		char* id = malloc(sizeof(char)*128);
		char* pid = malloc(sizeof(char)*128);
		char* name = malloc(sizeof(char)*128);
		char* type = malloc(sizeof(char)*128);

		// The parent swap node.
		addToTreeArray(parentid, SWAP_PARENT,"${LINUX.AGENT.1}","${LINUX.AGENT.2}","");

		// Cycle through the swaps
	
		b = strchr(buff,'\n');
		b++;

		while (b[0] != '\0')
		{
			sscanf(b, "%s %s %*d %*d %*d",name, type);

			// Add the partition node
			sprintf(pid, "%s_%s%c",SWAP_PART,name,'\0');
			addToTreeArray(SWAP_PARENT,pid, name, type, "");

			// Now add its children
			sprintf(id, "%s_%s%c",SWAP_PUSED,name,'\0');
			addToTreeArray(pid,id,"${LINUX.AGENT.3}","${LINUX.AGENT.4}","");
			sprintf(id, "%s_%s%c",SWAP_PFREE,name,'\0');
			addToTreeArray(pid,id,"${LINUX.AGENT.5}","${LINUX.AGENT.6}","");
			sprintf(id, "%s_%s%c",SWAP_TOTAL,name, '\0');
			addToTreeArray(pid,id,"${LINUX.AGENT.7}","${LINUX.AGENT.8}","");
			sprintf(id, "%s_%s%c",SWAP_USED,name,'\0');
			addToTreeArray(pid,id,"${LINUX.AGENT.9}","${LINUX.AGENT.10}","");
			sprintf(id, "%s_%s%c",SWAP_FREE,name,'\0');
			addToTreeArray(pid,id,"${LINUX.AGENT.11}","${LINUX.AGENT.12}","");

			b = strchr(b,'\n');
			b++;
		}

		b = NULL;
	
	 	free(id);
		free(pid);
		free(name);
		free(type);
	}
	if (VERBOSE == TRUE) printf("*** out getSwapTree\n");
}

void getSwapResults()
{
	if (VERBOSE == TRUE) printf("*** in getSwapResults\n");

	if (tableGet(filtersHash, SWAP_PARENT) != (XINT64) NULL)
	{
		if (readSwapInfo())
		{
			char* b;
			char* id = malloc(sizeof(char)*128);
			char* resultString = malloc(sizeof(char) * 128);
			char* name = malloc(sizeof(char)*128);
			long used, ssize;

			// Cycle through the swaps
	
			b = strchr(buff,'\n');
			b++;

			while (b[0] != '\0')
			{
				sscanf(b, "%s %*s %d %d %*d",name, &ssize, &used);

				// Now add its children
				sprintf(id, "%s_%s%c",SWAP_PUSED,name,'\0');
				if (tableGet(filtersHash, id) != (XINT64) NULL)
					addDoubleCounter(((double) used)/((double)ssize)*100, id,resultString);

				sprintf(id, "%s_%s%c",SWAP_PFREE,name,'\0');
				if (tableGet(filtersHash, id) != (XINT64) NULL)
					addDoubleCounter(((double) ssize-used)/((double)ssize)*100, id,resultString);

				sprintf(id, "%s_%s%c",SWAP_TOTAL,name, '\0');
				if (tableGet(filtersHash, id) != (XINT64) NULL)
					addLongCounter(ssize, id,resultString);

				sprintf(id, "%s_%s%c",SWAP_USED,name,'\0');
				if (tableGet(filtersHash, id) != (XINT64) NULL)
					addDoubleCounter(used, id,resultString);

				sprintf(id, "%s_%s%c",SWAP_FREE,name,'\0');
				if (tableGet(filtersHash, id) != (XINT64) NULL)
					addDoubleCounter(ssize-used, id,resultString);


				b = strchr(b,'\n');
				b++;
			}

			b = NULL;
	
	 		free(id);
			free(resultString);
			free(name);
		}
	}
	if (VERBOSE == TRUE) printf("*** out getSwapTree\n");

}

void addMountCounterTree( char* pid, char* dir)
{
	long bytesize;
	char* id = malloc(sizeof(char) * 128);

	sprintf(id,"%s_%s%c",PART_PERCU,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.13}","${LINUX.AGENT.14}","");
	
	sprintf(id,"%s_%s%c",PART_PERCF,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.15}","${LINUX.AGENT.16}","");
	
	sprintf(id,"%s_%s%c",PART_TOTAL_SIZE,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.17}","${LINUX.AGENT.18}","");
	
	sprintf(id,"%s_%s%c",PART_FREE_SIZE,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.19}","${LINUX.AGENT.20}","");
	
	sprintf(id,"%s_%s%c",PART_AVAIL_SIZE,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.21}","${LINUX.AGENT.22}","");
	
	sprintf(id,"%s_%s%c",PART_USED_SIZE,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.23}","${LINUX.AGENT.24}","");
	
	sprintf(id,"%s_%s%c",PART_TOTAL_BLKS,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.25}","${LINUX.AGENT.26}","");
	
	sprintf(id,"%s_%s%c",PART_USED_BLKS,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.27}","${LINUX.AGENT.28}","");

	sprintf(id,"%s_%s%c",PART_FREE_BLKS,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.29}","${LINUX.AGENT.30}","");
	
	sprintf(id,"%s_%s%c",PART_AVAIL_BLKS,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.31}","${LINUX.AGENT.32}","");
	
	sprintf(id,"%s_%s%c",PART_OPTIMAL,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.33}","${LINUX.AGENT.34}","kb");
	
	sprintf(id,"%s_%s%c",PART_TOTAL_NODES,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.35}","${LINUX.AGENT.36}","");
	
	sprintf(id,"%s_%s%c",PART_TOTAL_USED,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.37}","${LINUX.AGENT.38}","");

	sprintf(id,"%s_%s%c",PART_TOTAL_FREE,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.39}","${LINUX.AGENT.40}","");
	
	sprintf(id,"%s_%s%c",PART_TOTAL_MAXLEN,dir,'\0');
	addToTreeArray(pid, id, "${LINUX.AGENT.41}","${LINUX.AGENT.42}","");
	
	free(id);
}

void getMountTree( char* parentid)
{
	FILE* fp;
	struct mntent* mnt;
	char* id = malloc(sizeof(char) * 128);
	char* name = malloc(sizeof(char) * 128);
	char* desc = malloc(sizeof(char) * 128);

	fp = setmntent("/etc/mtab", "r");
	if (fp != NULL)
	{
		// Lets add the parent node here - only if /etc/mtab was opened succesfully
		addToTreeArray(parentid, PART_PARENT, "${LINUX.AGENT.43}","${LINUX.AGENT.44}","");

		mnt = getmntent(fp);
		while (mnt != NULL)
		{
			sprintf(id, "%s_%s%c",PART_PART,(*mnt).mnt_dir,'\0');
			sprintf(desc, "%s [%s]%c", (*mnt).mnt_type, (*mnt).mnt_dir, '\0');
			addToTreeArray(PART_PARENT, id, (*mnt).mnt_fsname, desc, "");

			addMountCounterTree(id, (*mnt).mnt_dir);

			mnt = getmntent(fp);
		}
	}
	endmntent(fp);

	free(id);
	free(name);
	free(desc);
}

void addMountCounterResults(char* dir)
{
	struct statfs fs;
	char* id = malloc(sizeof(char) * 128);
	char* resultString = malloc(sizeof(char) * 128);

  statfs(dir, &fs);

	sprintf(id,"%s_%s%c",PART_PERCU,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addDoubleCounter(((double) (fs.f_blocks - fs.f_bavail))/((double)fs.f_blocks)*100, id, resultString);
	
	sprintf(id,"%s_%s%c",PART_PERCF,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addDoubleCounter(((double) (fs.f_bavail))/((double)fs.f_blocks)*100, id, resultString);

	sprintf(id,"%s_%s%c",PART_TOTAL_SIZE,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_blocks * fs.f_bsize, id, resultString);

	sprintf(id,"%s_%s%c",PART_FREE_SIZE,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_bfree * fs.f_bsize, id, resultString);

	sprintf(id,"%s_%s%c",PART_AVAIL_SIZE,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_bavail * fs.f_bsize, id, resultString);

	sprintf(id,"%s_%s%c",PART_USED_SIZE,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter((fs.f_blocks - fs.f_bfree)*fs.f_bsize, id, resultString);

	sprintf(id,"%s_%s%c",PART_TOTAL_BLKS,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_blocks, id, resultString);

	sprintf(id,"%s_%s%c",PART_USED_BLKS,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_blocks - fs.f_bfree, id, resultString);

	sprintf(id,"%s_%s%c",PART_FREE_BLKS,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_bfree, id, resultString);

	sprintf(id,"%s_%s%c",PART_AVAIL_BLKS,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_bavail, id, resultString);

	sprintf(id,"%s_%s%c",PART_OPTIMAL,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_bsize, id, resultString);

	sprintf(id,"%s_%s%c",PART_TOTAL_NODES,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_files, id, resultString);

	sprintf(id,"%s_%s%c",PART_TOTAL_USED,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_files - fs.f_ffree, id, resultString);

	sprintf(id,"%s_%s%c",PART_TOTAL_FREE,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_ffree, id, resultString);

	sprintf(id,"%s_%s%c",PART_TOTAL_MAXLEN,dir,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(fs.f_namelen, id, resultString);

	free(id);
	free(resultString);
}

void getMountResults()
{
	if (tableGet(filtersHash, PART_PARENT) != (XINT64) NULL)
	{
		FILE* fp;
		struct mntent *mnt;
		char* id = malloc(sizeof(char) * 128);

		fp = setmntent("/etc/mtab", "r");
		if (fp != NULL)
		{
			mnt = getmntent(fp);
			while (mnt != NULL)
			{
				sprintf(id, "%s_%s%c",PART_PART,(*mnt).mnt_dir,'\0');
				addMountCounterResults((*mnt).mnt_dir);

				mnt = getmntent(fp);
			}
		}
		endmntent(fp);

		free(id);
	}
}

long getProcessCount()
{
  DIR * proc;
	static struct direct * ent;

	long value = 0;
	
 	if ((proc = opendir("/proc")) == NULL) 
		crash("/proc");

	// Read all the entries in the proc directory
	while((ent = readdir(proc))) 
 		if (isdigit(ent->d_name[0])) 
			value++;

 	closedir(proc);

	return value;
}

void getSysStatsInfoTree(char* pid) 
{
	int len;
	char * b = strstr(buff, "cpu ");
  unsigned long l1, l2, l3 ,l4;
	int i;
	char* id = malloc(sizeof(char)*128);
	char* cpuid = malloc(sizeof(char) * 128);
	char* name = malloc(sizeof(char) * 128);
	int counterCount = 0;
	long t;
	
	if (VERBOSE == TRUE) printf("*** in getSysStatsInfoTree\n");

	counterCount = sscanf(buff,"cpu %lu %lu %lu %lu %lu %lu %lu",&t,&t,&t,&t,&t,&t,&t);

	addToTreeArray(pid, STAT_CPU_TOTAL, "${LINUX.AGENT.45}", "${LINUX.AGENT.46}", "");
	addToTreeArray(STAT_CPU_TOTAL, STAT_CPU0_TOTAL, "${LINUX.AGENT.64}", "${LINUX.AGENT.65}","");
	addToTreeArray(STAT_CPU_TOTAL, STAT_CPU1_TOTAL, "${LINUX.AGENT.66}", "${LINUX.AGENT.67}", "");
	addToTreeArray(STAT_CPU_TOTAL, STAT_CPU3_TOTAL, "${LINUX.AGENT.68}", "${LINUX.AGENT.69}", "");
	addToTreeArray(STAT_CPU_TOTAL, STAT_CPU2_TOTAL, "${LINUX.AGENT.70}", "${LINUX.AGENT.71}", "");
	addToTreeArray(STAT_CPU_TOTAL, STAT_CPU4_TOTAL, "${LINUX.AGENT.72}", "${LINUX.AGENT.73}", "");

	if (counterCount == 7)
	{
		addToTreeArray(STAT_CPU_TOTAL, STAT_CPU5_TOTAL, "${LINUX.AGENT.74}", "${LINUX.AGENT.75}", "");
		addToTreeArray(STAT_CPU_TOTAL, STAT_CPU6_TOTAL, "${LINUX.AGENT.76}", "${LINUX.AGENT.77}", "");
		addToTreeArray(STAT_CPU_TOTAL, STAT_CPU7_TOTAL, "${LINUX.AGENT.78}", "${LINUX.AGENT.79}", "");
	}

	// In linux kernel 2.6, there are 7 counters, the above ones PLUS 3 others
	// Check if they are available and then add them.


	for (i =0; i<cpuCount; i++)
	{
		char test[32];
		// We need to check if this is an older kernel rep
		// or a newer one.
		
		sprintf(test, "cpu%d%c",i,'\0');

		if (strstr(buff,test) != NULL)
		{
	
  		// Add the 4 CPU counters
			sprintf(cpuid, "%s_%d%c",STAT_CPU,i,'\0');
			sprintf(name, "CPU_%d%c",i,'\0');
			addToTreeArray(pid, cpuid, name, "${LINUX.AGENT.63}","");

			sprintf(id, "%s_%d%c", STAT_CPU0,i,'\0');
			addToTreeArray(cpuid, id, "${LINUX.AGENT.64}", "${LINUX.AGENT.65}","");
			sprintf(id, "%s_%d%c", STAT_CPU1,i,'\0');
			addToTreeArray(cpuid, id,"${LINUX.AGENT.66}","${LINUX.AGENT.67}","");
			sprintf(id, "%s_%d%c", STAT_CPU3,i,'\0');
			addToTreeArray(cpuid, id,"${LINUX.AGENT.68}","${LINUX.AGENT.69}","");
			sprintf(id, "%s_%d%c", STAT_CPU2,i,'\0');
			addToTreeArray(cpuid, id,"${LINUX.AGENT.70}","${LINUX.AGENT.71}","");
			sprintf(id, "%s_%d%c", STAT_CPU4,i,'\0');
			addToTreeArray(cpuid, id,"${LINUX.AGENT.72}","${LINUX.AGENT.73}","");

			if (counterCount == 7)
			{			
				sprintf(id, "%s_%d%c", STAT_CPU5,i,'\0');
				addToTreeArray(cpuid, id, "${LINUX.AGENT.74}", "${LINUX.AGENT.75}", "");			
				
				sprintf(id, "%s_%d%c", STAT_CPU6,i,'\0');
				addToTreeArray(cpuid, id, "${LINUX.AGENT.76}", "${LINUX.AGENT.77}", "");			
				
				sprintf(id, "%s_%d%c", STAT_CPU7,i,'\0');
				addToTreeArray(cpuid, id, "${LINUX.AGENT.78}", "${LINUX.AGENT.79}", "");

			}
		}
	}

	addToTreeArray(pid, STAT_OTHER, "${LINUX.AGENT.80}","${LINUX.AGENT.81}","");

	if (counterCount != 7)
	{
  		b = strstr(buff, "page ");
		if (b != NULL)
		{
	    		// Add the 2 Page counters
			addToTreeArray(STAT_OTHER, STAT_PAGE1,"${LINUX.AGENT.82}","${LINUX.AGENT.83}","");
			addToTreeArray(STAT_OTHER, STAT_PAGE2,"${LINUX.AGENT.84}","${LINUX.AGENT.85}","");
		}

  		b = strstr(buff, "swap ");
		if (b != NULL)
		{
	  		// Add the 2 swap counters
			addToTreeArray(STAT_OTHER, STAT_SWAP2,"${LINUX.AGENT.86}","${LINUX.AGENT.87}","");
			addToTreeArray(STAT_OTHER, STAT_SWAP1,"${LINUX.AGENT.88}","${LINUX.AGENT.89}","");
		}
	}

  b = strstr(buff, "intr ");
	if (b != NULL)
    // Add the 1 Interrupt counter here
		addToTreeArray(STAT_OTHER, STAT_INTR,"${LINUX.AGENT.90}","${LINUX.AGENT.91}","");

  b = strstr(buff, "ctxt ");
  if (b != NULL)
    // Add the context switch counter
		addToTreeArray(STAT_OTHER, STAT_CTXT,"${LINUX.AGENT.92}","${LINUX.AGENT.93}","");
  
	b = strstr(buff, "btime ");
  if (b != NULL)
		addToTreeArray(STAT_OTHER, STAT_BTIME,"${LINUX.AGENT.94}","${LINUX.AGENT.95}","");

	b = strstr(buff, "processes ");
  if (b != NULL)
		addToTreeArray(STAT_OTHER, STAT_PROC,"${LINUX.AGENT.96}","${LINUX.AGENT.97}","");

	addToTreeArray(STAT_OTHER, STAT_TOTAL_PROC, "${LINUX.AGENT.98}","${LINUX.AGENT.99}","");

	b = NULL;

	if (VERBOSE == TRUE) printf("*** out getSysStatsInfoTree\n");
	free(id);
	free(name);
	free(cpuid);
} 

void addSysCounter( long value, char* id, char* resultString)
{
	long prevValue = (XINT64) tableGet(previousValues, id);

	if (tableGet(filtersHash, id) != (XINT64) NULL)
	{
		if (prevValue == 0)
		{
			if (containsKey(previousValues, id) == TRUE)
				addLongCounter(value-prevValue,id, resultString);
		}
		else
			addLongCounter(value-prevValue,id, resultString);
	}

	tablePut(previousValues, id, (XINT64) value);
}

void addCPUCounter( long value, long prevValue,long total, char* id, char* resultString)
{
	if (tableGet(filtersHash, id) != (XINT64) NULL)
	{
		if (prevValue == 0)
		{
			if (containsKey(previousValues, id) == TRUE)
				addDoubleCounter(((double) (value-prevValue)/ (double) total)*100, id, resultString);
		}
		else
			addDoubleCounter(((double) (value-prevValue)/ (double) total)*100, id, resultString);
	}

	tablePut(previousValues, id, (XINT64) value);
	tablePut(currentValues, id, (XINT64) value-prevValue);

}

void getSysStatsInfoResults() 
{
  // Previous values used for caching of previous result - better than doing hashtable lookups
	char* resultString = malloc(sizeof(char)*128);
	char* cpuid = malloc(sizeof(char) * 128);
	char* cpu = malloc(sizeof(char) * 128);
	char * b;

	long l1, l2,l3, l4, total, l5, l6, l7;
	long pl1, pl2, pl3, pl4,pl5,pl6,pl7;
	int i;
	int counterCount = 0;
	long t;
	
	if (VERBOSE == TRUE) 
		printf("*** in getSysStatsInfoResults\n");


	b = strstr(buff, "cpu ");

	// Deal with the total first
	counterCount = sscanf(b, "cpu  %u %u %u %u %u %u %u", &l1, &l2, &l3, &l4, &l5, &l6, &l7);

	// We ALWAYS do this, because the values are used later on in other calculations
	pl1 = (long) tableGet(previousValues, STAT_CPU1_TOTAL);
	pl2 = (long) tableGet(previousValues, STAT_CPU2_TOTAL);
	pl3 = (long) tableGet(previousValues, STAT_CPU3_TOTAL);
	pl4 = (long) tableGet(previousValues, STAT_CPU4_TOTAL);

	if (counterCount > 4)
	{
		pl5 = (long) tableGet(previousValues, STAT_CPU5_TOTAL);
		pl6 = (long) tableGet(previousValues, STAT_CPU6_TOTAL);
		pl7 = (long) tableGet(previousValues, STAT_CPU7_TOTAL);

		total = (l1-pl1) + (l2-pl2) + (l3-pl3) + (l4-pl4) + (l5 - pl5) + (l6-pl6) + (l7-pl7);
		addCPUCounter((l1+l2+l3+l5+l6+l7), pl1+pl2+pl3+pl5+pl6+pl7,total,STAT_CPU0_TOTAL,resultString);
	}
	else
	{
		total = (l1-pl1) + (l2-pl2) + (l3-pl3) + (l4-pl4);
		addCPUCounter((l1+l2+l3), pl1+pl2+pl3,total,STAT_CPU0_TOTAL,resultString);
	}

	addCPUCounter(l1, pl1, total, STAT_CPU1_TOTAL, resultString);
	addCPUCounter(l2, pl2, total, STAT_CPU2_TOTAL, resultString);
	addCPUCounter(l3, pl3, total, STAT_CPU3_TOTAL, resultString);
	addCPUCounter(l4, pl4, total, STAT_CPU4_TOTAL, resultString);

	if (counterCount > 4)
	{
		addCPUCounter(l5, pl5, total, STAT_CPU5_TOTAL, resultString);
		addCPUCounter(l6, pl6, total, STAT_CPU6_TOTAL, resultString);
		addCPUCounter(l7, pl7, total, STAT_CPU7_TOTAL, resultString);
	}
	
	tablePut(currentValues, STAT_TOTAL, (XINT64) total);

	// Now check for each 'sub' CPU
	for (i=0; i<cpuCount; i++)
	{
		static char cpu0[32];
		static char cpu1[32];
		static char cpu2[32];
		static char cpu3[32];
		static char cpu4[32];
		static char cpu5[32];
		static char cpu6[32];
		static char cpu7[32];

		sprintf(cpu, "cpu%d ", i);
		b = strstr(buff, cpu);
		if (b != NULL)
		{
			sprintf(cpu, "cpu%d",i,'\0');
			strcat(cpu," \%u \%u \%u \%u \%u \%u \%u");
			counterCount = sscanf(b, cpu, &l1, &l2, &l3, &l4, &l5, &l6, &l7);
			sprintf(cpu0, "%s_%d%c", STAT_CPU0,i,'\0');	
			sprintf(cpu1, "%s_%d%c", STAT_CPU1,i,'\0');	
			sprintf(cpu2, "%s_%d%c", STAT_CPU2,i,'\0');	
			sprintf(cpu3, "%s_%d%c", STAT_CPU3,i,'\0');	
			sprintf(cpu4, "%s_%d%c", STAT_CPU4,i,'\0');	
			sprintf(cpu5, "%s_%d%c", STAT_CPU5,i,'\0');	
			sprintf(cpu6, "%s_%d%c", STAT_CPU6,i,'\0');	
			sprintf(cpu7, "%s_%d%c", STAT_CPU7,i,'\0');	
		
			pl1 = (XINT64) tableGet(previousValues, cpu1);
			pl2 = (XINT64) tableGet(previousValues, cpu2);
			pl3 = (XINT64) tableGet(previousValues, cpu3);
			pl4 = (XINT64) tableGet(previousValues, cpu4);							

			if (counterCount > 4)
			{
				pl5 = (XINT64) tableGet(previousValues, cpu5);							
				pl6 = (XINT64) tableGet(previousValues, cpu6);							
				pl7 = (XINT64) tableGet(previousValues, cpu7);							
				total = l1 - pl1 + l2 - pl2 + l3 - pl3 + l4 - pl4 + l5 - pl5 + l6 - pl6 + l7 - pl7;
				addCPUCounter(l1+l2+l3, pl1+pl2+pl3 ,total, cpu0, resultString);
			}
			else
			{
				total = l1 - pl1 + l2 - pl2 + l3 - pl3 + l4 - pl4;
				addCPUCounter(l1+l2+l3+l5+l6+l7, pl1+pl2+pl3+pl5+pl6+pl7 ,total, cpu0, resultString);
			}

  		addCPUCounter(l1, pl1, total, cpu1, resultString);
			addCPUCounter(l2, pl2, total, cpu2, resultString);
			addCPUCounter(l3, pl3, total, cpu3, resultString);
			addCPUCounter(l4, pl4, total, cpu4, resultString);

			if (counterCount > 4)
			{
				addCPUCounter(l5, pl5, total, cpu5, resultString);
				addCPUCounter(l6, pl6, total, cpu6, resultString);
				addCPUCounter(l7, pl7, total, cpu7, resultString);
			}
		}	
	}

	if (counterCount != 7)
	{
		// Page swaps
  		b = strstr(buff, "page ");
	  	sscanf(b, "page %lu %lu", &l1, &l2);

		addSysCounter(l1, STAT_PAGE1, resultString);
		addSysCounter(l2, STAT_PAGE2, resultString);

		// Swap swaps
		b = strstr(buff, "swap ");
  		sscanf(b, "swap %lu %lu", &l1, &l2);
	
		addSysCounter(l1, STAT_SWAP1, resultString);
		addSysCounter(l2, STAT_SWAP2, resultString);
	}
	// Interrupts
  b = strstr(buff, "intr ");
  sscanf(b, "intr %lu", &l1);

	addSysCounter(l1, STAT_INTR, resultString);

	// Context Switches
  b = strstr(buff, "ctxt ");
  sscanf(b, "ctxt %lu", &l1);
	
	addSysCounter(l1, STAT_CTXT, resultString);

	// Boottime 
  b = strstr(buff, "btime ");
  sscanf(b, "btime %lu", &l1);
	
	if (tableGet(filtersHash, STAT_BTIME) != (XINT64) NULL)
		addLongCounter(l1 ,STAT_BTIME, resultString);

	// Processes
  b = strstr(buff, "processes ");
  sscanf(b, "processes %lu", &l1);

	if (tableGet(filtersHash, STAT_PROC) != (XINT64) NULL)
		addDoubleCounter(l1,STAT_PROC, resultString);

	// This call is different, execute code to fetch process count
	if (tableGet(filtersHash, STAT_TOTAL_PROC) != (XINT64) NULL)
	{
		addDoubleCounter(getProcessCount(), STAT_TOTAL_PROC,resultString);
	}
	
	b = NULL;

	free(resultString);
	free(cpuid);
	free(cpu);
	if (VERBOSE == TRUE) printf("*** out getSysStatsInfo\n");
} 


/*************************************************************************************/
// DISK METHODS
// 

void addDiskCounter( long val, char* mainid, char* counterid, char ch, char* resultString)
{
	long diff;
// Below comments remove caching
	sprintf(counterid, "%s%d%c",mainid,(ch-'a'+1),'\0');
	if (tableGet(filtersHash,counterid) != (XINT64)NULL)
	{
//		diff = val - ((XINT64) tableGet(previousValues, counterid));
//		if (diff == val)
//		{
//			if (containsKey(previousValues, counterid)==TRUE)	
//				addLongCounter(diff, counterid, resultString);
//		}
//		else	
//			addLongCounter(diff, counterid, resultString);

	// New line below
		addLongCounter(val, counterid, resultString);
//		tablePut(previousValues, counterid, (XINT64) val);
	}
}								

void addDiskResults( long major, long minor, long noinfo, long r_io, long r_blks, long w_io, long w_blks, char ch)
{
	char* counterid = malloc(sizeof(char)*128);
	char* resultString = malloc(sizeof(char)*128);
	long diff;

	// This populates the disk menu, for the disk with id ch.
	// We must cache previous values, as all are total counts.
	addDiskCounter(r_io, STAT_READ_IO, counterid, ch, resultString);
	addDiskCounter(r_blks, STAT_READ_BLKS, counterid, ch, resultString);
	addDiskCounter(w_io, STAT_WRITE_IO, counterid, ch, resultString);
	addDiskCounter(w_blks, STAT_WRITE_BLKS, counterid, ch, resultString);
	addDiskCounter(noinfo, STAT_NOINFO, counterid, ch, resultString);

  free(counterid);	
	free(resultString);
}

void addNewDiskResults( long major, long minor, char* name,long readno,long rmerge,long rsectors,long rmilli,long writeno,long wmerge,long wsectors,long wmilli,long ioc,long iomilli, long ioweight)
{
	char* id = malloc(sizeof(char)*128);
	char* pid = malloc(sizeof(char)*128);
	char* result = malloc(sizeof(char)*128);

	sprintf(id, "%s_%s%c",NEW_DISK_READNO,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
		addLongCounter(readno, id, result);
	sprintf(id, "%s_%s%c",NEW_DISK_READMERGE,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
	  addLongCounter(rmerge, id, result);
	sprintf(id, "%s_%s%c",NEW_DISK_READSECTORS,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
	  addLongCounter(rsectors, id, result);
	sprintf(id, "%s_%s%c",NEW_DISK_READMILLI,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
	  addLongCounter(rmilli, id, result);
	sprintf(id, "%s_%s%c",NEW_DISK_WRITENO,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
	  addLongCounter(writeno, id, result);
	sprintf(id, "%s_%s%c",NEW_DISK_WRITEMERGE,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
	  addLongCounter(wmerge, id, result);
	sprintf(id, "%s_%s%c",NEW_DISK_WRITESECTORS,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
	  addLongCounter(wsectors, id, result);
	sprintf(id, "%s_%s%c",NEW_DISK_WRITEMILLI,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
	  addLongCounter(wmilli, id, result);
	sprintf(id, "%s_%s%c",NEW_DISK_IOCOUNT,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
	  addLongCounter(ioc, id, result);
	sprintf(id, "%s_%s%c",NEW_DISK_IOMILLI,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
	  addLongCounter(iomilli, id, result);
	sprintf(id, "%s_%s%c",NEW_DISK_WEIGHTED,name,'\0');
	if (tableGet(filtersHash,id) != (XINT64) NULL)
	  addLongCounter(ioweight, id, result);

	free(pid);
	free(id);
	free(result);
}

void addDisk( char* pid, long major, long minor, long noinfo, long r_io, long r_blks, long w_io, long w_blks, char ch)
{
	char* newid = malloc(sizeof(char)*128);
	char* name = malloc(sizeof(char)*128);
	char* desc = malloc(sizeof(char)*128);
	char* childid = malloc(sizeof(char)*128);
	
	sprintf(newid,"%s%d%c",STAT_DISK,ch-'a'+1,'\0');

	// Construct the disk name here
 	sprintf(name, "Disk %d%c",ch-'a'+1,'\0');	
	sprintf(desc, "");

	// Construct the disks description here, eg hd'a' hd'b' and sd'c' sd'd' ... etc..
  if (major == 8)
	  sprintf(desc,"/dev/sd%c (%lu,%lu)%c",ch-1,major,minor,'\0');
	else if (major == 3)
	  sprintf(desc,"/dev/hd%c (%lu,%lu)%c",ch-1,major,minor,'\0');
	else
		sprintf(desc,"%c%c",ch-1,'\0');

  addToTreeArray(pid, newid, name,desc, "");	
	
	// Now add all the child nodes
	sprintf(name, "${LINUX.AGENT.100}%c",'\0');
	sprintf(childid, "%s%d%c",STAT_READ_IO,(ch-'a'+1),'\0');
	addToTreeArray(newid, childid, name, "${LINUX.AGENT.101}", "");
	
	sprintf(name, "Read Blocks%c",'\0');
	sprintf(childid, "%s%d%c",STAT_READ_BLKS,(ch-'a'+1),'\0');
	addToTreeArray(newid, childid, name, "${LINUX.AGENT.103}", "");
	
	sprintf(name, "Write IO Operations%c",'\0');
	sprintf(childid, "%s%d%c",STAT_WRITE_IO,(ch-'a'+1),'\0');
	addToTreeArray(newid, childid, name, "${LINUX.AGENT.105}", "");
	
	sprintf(name, "Write Blocks%c",'\0');
	sprintf(childid, "%s%d%c",STAT_WRITE_BLKS,(ch-'a'+1),'\0');
	addToTreeArray(newid, childid, name, "${LINUX.AGENT.107}", "");
	
	sprintf(name, "No Info%c",'\0');
	sprintf(childid, "%s%d%c",STAT_NOINFO,(ch-'a'+1),'\0');
	addToTreeArray(newid, childid, name, "${LINUX.AGENT.109}", "");

	free(newid);
	free(name);
	free(desc);
	free(childid);
}

void getDiskStatsInfoResults()
{
	if (VERBOSE == TRUE) printf("*** in getDiskStatsInfoResults\n");

	if (tableGet(filtersHash, STAT_PARENT) != (XINT64) NULL)
	{
		char disk[17] = "disk_io ";
		char * b;
		long major=0, minor=0, noinfo=0, read_io_ops=0, read_blks=0, write_io_ops=0, write_blks=0;
		char ch = 'a';
		char* diskid = malloc(sizeof(char)*128);

		if (strstr(buff, "disk_io: ") != NULL)
		{

			b = strstr(buff, "disk_io: ");

		  sscanf(b, "disk_io: (%lu,%lu):(%lu,%lu,%lu,%lu,%lu)",&major,&minor,&noinfo, &read_io_ops, &read_blks, &write_io_ops, &write_blks);

			sprintf(diskid,"%s%d%c",STAT_DISK,(ch-'a'+1),'\0');

			if (tableGet(filtersHash, diskid) != (XINT64)NULL)
				addDiskResults(major, minor, noinfo, read_io_ops, read_blks, write_io_ops, write_blks,ch);

		  ch++;	
			b = strstr(b,") ");

			if (b == NULL)
				return;

			while ((b = strstr(b," ("))!= NULL)
			{
				sscanf(b, " (%lu,%lu):(%lu,%lu,%lu,%lu,%lu)",&major,&minor,&noinfo, &read_io_ops, &read_blks, &write_io_ops, &write_blks);

				sprintf(diskid,"%s%d%c",STAT_DISK,(ch-'a'+1),'\0');

				if (tableGet(filtersHash, diskid) != (XINT64)NULL)
					addDiskResults(major, minor, noinfo, read_io_ops, read_blks, write_io_ops, write_blks,ch);
	
	  		ch++;
			  b = strstr(b,") ");
			}
		}
		else if (strstr(buff,"disk") != NULL)
		{
			long noinfo1, noinfo2, noinfo3, noinfo4;
			long read_io1, read_io2, read_io3, read_io4;
			long write_io1, write_io2, write_io3, write_io4;
			long write_blks1, write_blks2, write_blks3, write_blks4;
			long read_blks1, read_blks2, read_blks3, read_blks4;
		
			// Deal with the older format here
			b = strstr(buff, "disk ");
			sscanf(b,"disk %lu %lu %lu %lu",&noinfo1, &noinfo2, &noinfo3, &noinfo4);
			b = strstr(buff, "disk_rio ");
			sscanf(b,"disk_rio %lu %lu %lu %lu",&read_io1, &read_io2, &read_io3, &read_io4);
			b = strstr(buff, "disk_wio ");
			sscanf(b,"disk_wio %lu %lu %lu %lu",&write_io1, &write_io2, &write_io3, &write_io4);
			b = strstr(buff, "disk_rblk ");
			sscanf(b,"disk_rblk %lu %lu %lu %lu",&read_blks1,&read_blks2,&read_blks3,&read_blks4);
			b = strstr(buff, "disk_wblk ");
			sscanf(b,"disk_wblk %lu %lu %lu %lu",&write_blks1,&write_blks2,&write_blks3,&write_blks4);

			major = 0;
			minor = 0;

			addDiskResults(major, minor, noinfo1, read_io1, read_blks1, write_io1, write_blks1,'a');
			addDiskResults(major, minor, noinfo2, read_io2, read_blks2, write_io2, write_blks2,'b');
			addDiskResults(major, minor, noinfo3, read_io3, read_blks3, write_io3, write_blks3,'c');
  		addDiskResults(major, minor, noinfo4, read_io4, read_blks4, write_io4, write_blks4,'d');

		} 
		else if (readFromFile("/proc/diskstats"))
		{
			long read_no, read_merge, read_sectors, read_milli, write_no, write_sectors, write_milli, iocount, iomilli, weighted, major, minor, write_merge;

			char* name = malloc(sizeof(char)*128);

			b = buff;
			while ((b[0] != '\0') && (b[0] != '\n'))
			{
				sscanf(b,"%u %u %s %u %u %u %u %u %u %u %u %u %u %u",&major,&minor,name,&read_no,&read_merge, &read_sectors, &read_milli, &write_no, &write_merge, &write_sectors, &write_milli, &iocount,&iomilli, &weighted);
				addNewDiskResults(major, minor,name, read_no, read_merge, read_sectors, read_milli, write_no, write_merge,write_sectors, write_milli, iocount, iomilli, weighted);
				b = strchr(b,'\n')+1;
			}

			free(name); 	
		}

	  b = NULL;

		free(diskid);
	}
 
	if (VERBOSE == TRUE) printf("*** out getDiskStatsInfoResults\n");
}

void addNewDisk( char* parent, long major, long minor, char* name)
{
	char* id = malloc(sizeof(char)*128);
	char* pid = malloc(sizeof(char)*128);
	char* dname = malloc(sizeof(char) * 128);

	sprintf(dname, "%s (%u,%u)%c",name,major,minor,'\0');
	
	sprintf(pid,"%s_%s%c",NEW_DISK_PARENT,name,'\0');
	addToTreeArray(parent,pid,dname,"${LINUX.AGENT.110}","");
	sprintf(id, "%s_%s%c",NEW_DISK_READNO,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.111}","${LINUX.AGENT.112}",""); 
	sprintf(id, "%s_%s%c",NEW_DISK_READMERGE,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.113}","${LINUX.AGENT.114}","");
	sprintf(id, "%s_%s%c",NEW_DISK_READSECTORS,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.115}","${LINUX.AGENT.116}","");
	sprintf(id, "%s_%s%c",NEW_DISK_READMILLI,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.117}","${LINUX.AGENT.118}","");
	sprintf(id, "%s_%s%c",NEW_DISK_WRITENO,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.119}","${LINUX.AGENT.120}","");
	sprintf(id, "%s_%s%c",NEW_DISK_WRITEMERGE,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.121}","${LINUX.AGENT.122}","");
	sprintf(id, "%s_%s%c",NEW_DISK_WRITESECTORS,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.123}","${LINUX.AGENT.124}","");
	sprintf(id, "%s_%s%c",NEW_DISK_WRITEMILLI,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.125}","${LINUX.AGENT.126}","");
	sprintf(id, "%s_%s%c",NEW_DISK_IOCOUNT,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.127}","${LINUX.AGENT.128}","");
	sprintf(id, "%s_%s%c",NEW_DISK_IOMILLI,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.129}","${LINUX.AGENT.130}","");
	sprintf(id, "%s_%s%c",NEW_DISK_WEIGHTED,name,'\0');
	addToTreeArray(pid,id,"${LINUX.AGENT.131}","${LINUX.AGENT.132}","");

	free(pid);
	free(id);
	free(dname);
}

void getDiskStatsInfoTree( char* pid) 
{
	char * b;
	long major=0, minor=0, noinfo=0, read_io_ops=0, read_blks=0, write_io_ops=0, write_blks=0;
	char ch = 'a';
	int kver = 0; // Just a value we can switch on later

	addToTreeArray(pid, STAT_PARENT, "${LINUX.AGENT.133}", "${LINUX.AGENT.249}", "");
	// Populate the tree with entries and ids relevant for each disk installed.
	// What we do here is scanf entries from the disk_io stats entry
	// and for each entry we can get we populate the tree
	if (VERBOSE == TRUE) printf("*** in getDiskStatsInfoTree\n");

	// Accomadate for older kernel disk usage here - 
	// check if disk_io is present : if so, then assume ~2.4
	// check if diskstats file exists : if so then assume ~2.6
  // else, assume older disk in stat : k ~2.2	

	if (strstr(buff, "disk_io") != NULL)
	{
		b = strstr(buff, "disk_io: ");

  	sscanf(b, "disk_io: (%lu,%lu):(%lu,%lu,%lu,%lu,%lu)",&major,&minor,&noinfo, &read_io_ops, &read_blks, &write_io_ops, &write_blks);

		addDisk(STAT_PARENT, major, minor, noinfo, read_io_ops, read_blks, write_io_ops, write_blks,ch);

	  ch++;	
		b = strstr(b,") ");

		if (b == NULL)
			return;

		while ((b = strstr(b," ("))!= NULL)
		{
			sscanf(b, " (%lu,%lu):(%lu,%lu,%lu,%lu,%lu)",&major,&minor,&noinfo, &read_io_ops, &read_blks, &write_io_ops, &write_blks);

		  addDisk(STAT_PARENT, major, minor, noinfo, read_io_ops, read_blks, write_io_ops, write_blks,ch);
	  	ch++;
		  b = strstr(b,") ");
		}
	}
	else if (strstr(buff,"disk") != NULL)
	{
		long noinfo1, noinfo2, noinfo3, noinfo4;
		long read_io1, read_io2, read_io3, read_io4;
		long write_io1, write_io2, write_io3, write_io4;
		long write_blks1, write_blks2, write_blks3, write_blks4;
		long read_blks1, read_blks2, read_blks3, read_blks4;
		
		// Deal with the older format here
		b = strstr(buff, "disk ");
		sscanf(b,"disk %lu %lu %lu %lu",&noinfo1, &noinfo2, &noinfo3, &noinfo4);
		b = strstr(buff, "disk_rio ");
		sscanf(b,"disk_rio %lu %lu %lu %lu",&read_io1, &read_io2, &read_io3, &read_io4);
		b = strstr(buff, "disk_wio ");
		sscanf(b,"disk_wio %lu %lu %lu %lu",&write_io1, &write_io2, &write_io3, &write_io4);
		b = strstr(buff, "disk_rblk ");
		sscanf(b,"disk_rblk %lu %lu %lu %lu",&read_blks1,&read_blks2,&read_blks3,&read_blks4);
		b = strstr(buff, "disk_wblk ");
		sscanf(b,"disk_wblk %lu %lu %lu %lu",&write_blks1,&write_blks2,&write_blks3,&write_blks4);

		major = 0;
		minor = 0;

		addDisk(STAT_PARENT, major, minor, noinfo1, read_io1, read_blks1, write_io1, write_blks1,'a');
		addDisk(STAT_PARENT, major, minor, noinfo2, read_io2, read_blks2, write_io2, write_blks2,'b');
		addDisk(STAT_PARENT, major, minor, noinfo3, read_io3, read_blks3, write_io3, write_blks3,'c');
		addDisk(STAT_PARENT, major, minor, noinfo4, read_io4, read_blks4, write_io4, write_blks4,'d');

	}
	else if (readFromFile("/proc/diskstats"))
	{
		long read_no, read_merge, read_sectors, read_milli, write_no, write_sectors, write_milli, iocount, iomilli, weighted, major, minor;

		char* name = malloc(sizeof(char)*128);

		b = buff;
		while ((b[0] != '\0') && (b[0] != '\n'))
		{
			sscanf(b,"%u %u %s %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u",&major,&minor,name);
			addNewDisk(STAT_PARENT, major, minor,name);

			b = strchr(b,'\n')+1;
		}

		free(name); 	
	}

  b = NULL;
 
	if (VERBOSE == TRUE) printf("*** out getDiskStatsInfoTree\n");
} 

// Count the cpu number
int processCpuCount()
{
  char* cpu = malloc(sizeof(char)*16);
	int count = 0;

	// The format of the stats file is cpu#, starting from 0
	// Lets count them up
	
	sprintf(cpu,"cpu%d",count);

	while (strstr(buff, cpu) != NULL)
	{
		count++;
		sprintf(cpu,"cpu%d ",count);
	}

	free(cpu);
	return count;
}

void getStatResults()  
{
	char* newpid = "/proc/stat";

  if (VERBOSE == TRUE) printf("*** in getStatResults\n");

 		if (readStatInfo()) 
		{
			getSysStatsInfoResults();

		  getDiskStatsInfoResults();
		}
		else 
		{
	   	crash("/proc/stat");
	 	} /* end if */
	if (VERBOSE == TRUE) printf("*** out getStatResults\n");
}


void getStatInfo( char* pid)  
{
	char* newpid = "/proc/stat";

  if (VERBOSE == TRUE) printf("*** in getStatInfo\n");

	addToTreeArray(pid, newpid, "${LINUX.AGENT.134}","${LINUX.AGENT.135}", "");	 

 	if (readStatInfo()) 
	{
		cpuCount = processCpuCount();

		getSysStatsInfoTree(newpid);
		getDiskStatsInfoTree(pid);
 	} 
	else 
   	crash("/proc/stat");

	if (VERBOSE == TRUE) printf("*** out getStatInfo\n");
}


/*************************************************************************************/
// MEMINFO STUFF BELOW

void getMemInfoTree(char* parentid) 
{
	if (VERBOSE == TRUE) printf("*** in getMemInfo\n");

	addToTreeArray(parentid, MEM_PARENT, "${LINUX.AGENT.136}","${LINUX.AGENT.137}","");

	if (readMemInfo()) 
	{
			addToTreeArray(MEM_PARENT,MEM_PERC, "${LINUX.AGENT.138}", "${LINUX.AGENT.139}" ,"");
			addToTreeArray(MEM_PARENT,MEM_SPERC, "${LINUX.AGENT.140}", "${LINUX.AGENT.141}" ,"");
			addToTreeArray(MEM_PARENT,MEM_TOTAL, "${LINUX.AGENT.142}","${LINUX.AGENT.143}","");
			addToTreeArray(MEM_PARENT,MEM_FREE, "${LINUX.AGENT.144}","${LINUX.AGENT.145}","");
			addToTreeArray(MEM_PARENT,MEM_USED, "${LINUX.AGENT.146}","${LINUX.AGENT.147}","");
			addToTreeArray(MEM_PARENT,MEM_SWAPT, "${LINUX.AGENT.148}","${LINUX.AGENT.149}","");
			addToTreeArray(MEM_PARENT,MEM_SWAPF, "${LINUX.AGENT.150}","${LINUX.AGENT.151}","");
			addToTreeArray(MEM_PARENT,MEM_SWAPU, "${LINUX.AGENT.152}","${LINUX.AGENT.153}","");
			addToTreeArray(MEM_PARENT,MEM_CACHED, "${LINUX.AGENT.154}","${LINUX.AGENT.155}","");
			addToTreeArray(MEM_PARENT,MEM_BUFFERS, "${LINUX.AGENT.156}","${LINUX.AGENT.157}","");
	} 
	else 
		crash("/proc/meminfo");

	if (VERBOSE == TRUE) printf("*** out getMemInfo\n");
} 

void getMemInfoResults()
{
	if (VERBOSE == TRUE) printf("*** in getMemInfoResults\n");

	if (tableGet(filtersHash, MEM_PARENT) != (XINT64) NULL)
	{
		char* resultString = malloc(sizeof(char) * 128);

		// Just return the memory info from /proc/meminfo - its pretty standard stuff.
		// No need for caching here, as we are interested in the TOTAL :)
		if (readMemInfo()) 
		{
			char* b;
			long total, free;

  	  b = strstr(buff, "MemTotal:    ");
	    sscanf(b, "MemTotal: %lu", &total);
			if (tableGet(filtersHash, MEM_TOTAL) != (XINT64) NULL)
				addLongCounter(total, MEM_TOTAL, resultString);
			// Add the total memory to the currentvalues hash so that we can use it later.
			tablePut(currentValues, MEM_TOTAL, (XINT64) total);

	    b = strstr(buff, "MemFree:    ");
  	  sscanf(b, "MemFree: %lu", &free);
			if (tableGet(filtersHash, MEM_FREE) != (XINT64) NULL)
				addLongCounter(free, MEM_FREE, resultString);

			if (tableGet(filtersHash, MEM_USED) != (XINT64) NULL)
				addLongCounter(total-free, MEM_USED, resultString);

			if (tableGet(filtersHash, MEM_PERC) != (XINT64) NULL)
				addDoubleCounter((((double) (total-free))/((double) total))*100 ,MEM_PERC,resultString);
	
	    b = strstr(buff, "Buffers:  ");
  	  sscanf(b, "Buffers: %u", &total);
			if (tableGet(filtersHash, MEM_BUFFERS) != (XINT64) NULL)
				addLongCounter(total, MEM_BUFFERS, resultString);

	    b = strstr(buff, "Cached:  ");
	    sscanf(b, "Cached: %u", &total);
			if (tableGet(filtersHash, MEM_CACHED) != (XINT64) NULL)
				addLongCounter(total, MEM_CACHED, resultString);
	
	    b = strstr(buff, "SwapTotal:  ");
  	  sscanf(b, "SwapTotal: %lu", &total);
			if (tableGet(filtersHash, MEM_SWAPT) != (XINT64) NULL)
				addLongCounter(total, MEM_SWAPT, resultString);
	
	    b = strstr(buff, "SwapFree:  ");
  	  sscanf(b, "SwapFree: %u", &free);
			if (tableGet(filtersHash, MEM_SWAPF) != (XINT64) NULL)
				addLongCounter(free, MEM_SWAPF, resultString);

			if (tableGet(filtersHash, MEM_SWAPU) != (XINT64) NULL)
				addLongCounter(total-free, MEM_SWAPU,resultString);

			if (tableGet(filtersHash, MEM_SPERC) != (XINT64) NULL)
				addDoubleCounter((((double) (total-free))/((double) total))*100 ,MEM_SPERC,resultString);
																																								     
			b = NULL;
		} 
		else 
			crash("/proc/meminfo");
	
		free(resultString);
	}
	if (VERBOSE == TRUE) printf("*** out getMemInfoResults\n");

}

/*************************************************************************************/
// PROCESS METHODS
// 
void addProcessMemChild( int pid, char* parentid)
{
	char* id = malloc(sizeof(char) * 128);
	char* memid = malloc(sizeof(char) * 128);
	
	sprintf(memid, "%s_%d%c",PROC_MEM,pid,'\0');
	addToTreeArray(parentid, memid, "${LINUX.AGENT.158}", "${LINUX.AGENT.159}","");

	sprintf(id, "%s_%d%c",PROC_MEM_PERC,pid,'\0');
	addToTreeArray(memid, id, "${LINUX.AGENT.160}","${LINUX.AGENT.161}","");

	sprintf(id,"%s_%d%c",PROC_MEM_SIZE,pid,'\0');
	addToTreeArray(memid, id, "${LINUX.AGENT.162}","${LINUX.AGENT.163}","kb");
	
	sprintf(id,"%s_%d%c",PROC_MEM_RESIDENT,pid,'\0');
	addToTreeArray(memid, id, "${LINUX.AGENT.164}","${LINUX.AGENT.165}","kb");

	sprintf(id,"%s_%d%c",PROC_MEM_SWAP,pid,'\0');
	addToTreeArray(memid, id, "${LINUX.AGENT.166}","${LINUX.AGENT.167}","kb");	
	
	sprintf(id,"%s_%d%c",PROC_MEM_SHARE,pid,'\0');
	addToTreeArray(memid, id, "${LINUX.AGENT.168}","${LINUX.AGENT.169}","kb");
	
	sprintf(id,"%s_%d%c",PROC_MEM_TRS,pid,'\0');
	addToTreeArray(memid, id, "${LINUX.AGENT.170}","${LINUX.AGENT.171}","kb");
	
	sprintf(id,"%s_%d%c",PROC_MEM_DRS,pid,'\0');
	addToTreeArray(memid, id, "${LINUX.AGENT.172}","${LINUX.AGENT.173}","kb");
	
	sprintf(id,"%s_%d%c",PROC_MEM_LRS,pid,'\0');
	addToTreeArray(memid, id, "${LINUX.AGENT.174}","${LINUX.AGENT.175}","kb");

	sprintf(id,"%s_%d%c",PROC_MEM_DT,pid,'\0');
	addToTreeArray(memid, id, "${LINUX.AGENT.176}","${LINUX.AGENT.177}","");
	
	sprintf(id, "%s_%d%c",PROC_MEM_MAJFLT,  pid,'\0');
	addToTreeArray(memid, id,"${LINUX.AGENT.178}","${LINUX.AGENT.179}","");

	sprintf(id, "%s_%d%c",PROC_MEM_MINFLT, pid,'\0');
	addToTreeArray(memid, id,"${LINUX.AGENT.180}", "${LINUX.AGENT.181}","");
	
	sprintf(id, "%s_%d%c",PROC_MEM_CMAJFLT, pid,'\0');
	addToTreeArray(memid, id,"${LINUX.AGENT.182}","${LINUX.AGENT.183}","");
	
	sprintf(id, "%s_%d%c",PROC_MEM_CMINFLT,  pid,'\0');
	addToTreeArray(memid, id,"${LINUX.AGENT.184}", "${LINUX.AGENT.185}","");

	sprintf(id, "%s_%d%c",PROC_MEM_NSWAP,  pid,'\0');
	addToTreeArray(memid, id,"${LINUX.AGENT.186}", "${LINUX.AGENT.187}","");

	sprintf(id, "%s_%d%c",PROC_MEM_CNSWAP,  pid,'\0');
	addToTreeArray(memid, id,"${LINUX.AGENT.188}", "${LINUX.AGENT.189}","");

	free(id);
	free(memid);
}

void addProcessOtherChild( int pid, char* parentid)
{
	char* otherid = malloc(sizeof(char) * 128);
	char* id = malloc(sizeof(char) * 128);

	// First, add the Other tree node
	sprintf(otherid, "%s_%d%c",PROC_OTHER,pid,'\0');
	addToTreeArray(parentid, otherid, "${LINUX.AGENT.190}", "${LINUX.AGENT.191}","");
	
	sprintf(id, "%s_%d%c",PROC_OTHER_PID, pid, '\0');
	addToTreeArray(otherid, id,"${LINUX.AGENT.192}", "${LINUX.AGENT.193}","");
	
	sprintf(id, "%s_%d%c",PROC_OTHER_PPID, pid, '\0');
	addToTreeArray(otherid, id,"${LINUX.AGENT.194}", "${LINUX.AGENT.195}","");

	sprintf(id, "%s_%d%c",PROC_OTHER_PROCESSOR, pid, '\0');
	addToTreeArray(otherid, id,"${LINUX.AGENT.196}", "${LINUX.AGENT.197}","");

	free(id);
	free(otherid);

}

void addProcessCpuChild( int pid, char* parentid)
{				
	char* cpuid = malloc(sizeof(char) * 128);
	char* id = malloc(sizeof(char) * 128);

	// First, add the CPU tree node
	sprintf(cpuid, "%s_%d%c",PROC_CPU,pid,'\0');
	addToTreeArray(parentid, cpuid, "${LINUX.AGENT.198}", "${LINUX.AGENT.199}","");

	sprintf(id, "%s_%d%c", PROC_CPU_BOTH, pid, '\0');
	addToTreeArray(cpuid, id, "${LINUX.AGENT.200}", "${LINUX.AGENT.201}","");
	
	sprintf(id, "%s_%d%c",PROC_CPU_TIME, pid, '\0');
	addToTreeArray(cpuid, id,"${LINUX.AGENT.202}", "${LINUX.AGENT.203}","");

	sprintf(id, "%s_%d%c",PROC_CPU_UTIME,   pid,'\0');
	addToTreeArray(cpuid, id,"${LINUX.AGENT.204}", "${LINUX.AGENT.205}","");
	
	sprintf(id, "%s_%d%c",PROC_CPU_STIME,   pid,'\0');
	addToTreeArray(cpuid, id,"${LINUX.AGENT.206}", "${LINUX.AGENT.207}","");
	
	sprintf(id, "%s_%d%c",PROC_CPU_CTIME,   pid,'\0');
	addToTreeArray(cpuid, id,"${LINUX.AGENT.208}", "${LINUX.AGENT.209}","");
	
	sprintf(id, "%s_%d%c",PROC_CPU_CUTIME,  pid,'\0');
	addToTreeArray(cpuid, id,"${LINUX.AGENT.210}", "${LINUX.AGENT.211}","");
	
	sprintf(id, "%s_%d%c",PROC_CPU_CSTIME,   pid,'\0');
	addToTreeArray(cpuid, id,"${LINUX.AGENT.212}", "${LINUX.AGENT.213}","");
	
	free(id);
	free(cpuid);
}

void getProcessesTree( char* parentid)
{
	// return the tree of the processs' stat file, and statm files
	static struct direct * ent;
  static char filename[128];
	static char executeName[128];
	static int pid;
  DIR * proc;
	char* procParentID = malloc(sizeof(char)*128);
	char* procName = malloc(sizeof(char) * 128);
	char* strpid = malloc(sizeof(char)*128);

	if (VERBOSE == TRUE) printf("*** in getProcesses\n");

 	if ((proc = opendir("/proc")) == NULL) 
		crash("/proc");

	// Lets add the process parent element to the resutls tree	
	addToTreeArray(parentid, PROC_MAIN,"${LINUX.AGENT.214}","${LINUX.AGENT.215}","");

	// Read all the entries in the proc directory
	while((ent = readdir(proc))) 
	{
		// Processes must have directories that start with a digit
 		if (isdigit(ent->d_name[0])) 
		{ 
   		sprintf(filename, "/proc/%s/stat", ent->d_name);
   		if (readProcInfo(filename)) 
			{
				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", &pid, executeName);

				executeName[strlen(executeName)-1] = '\0';

				// First, lets deal with the process tree node
				sprintf(procParentID,"%s_%d%c",PROC_PARENT, pid,'\0');
				sprintf(procName, "%s [%d]%c",executeName, pid,'\0');
				sprintf(strpid, "%d%c",pid,'\0');
				
				// Add to the process Hash - this just keeps a record of all the processes that we have populated the tree
				// with, and should be less expensive than processing ALL ids
				tablePut(processHash, strpid,1);
				addToTreeArray(PROC_MAIN, procParentID, procName,"","");
				

				// Now lets deal with the children of the process node
				addProcessCpuChild(pid, procParentID);
   		
				sprintf(filename, "/proc/%s/statm", ent->d_name);
	   		if (readProcInfo(filename)) 
				{								
					sscanf(buff, "%*d %*d %*d %*d %*d %*d %*d");

					addProcessMemChild(pid, procParentID);
				} 
				addProcessOtherChild(pid, procParentID);
			}
		} 
	} 	
 	closedir(proc);

	free(procParentID);
	free(procName);
	free(strpid);

	if (VERBOSE == TRUE) printf("***out getProcessesTree\n");
} 

// Add the other counter results here
void addProcessOtherResults( char* pid,long lpid, long ppid, long processor)
{
	char* id = malloc(sizeof(char)*128);
	char* resultString = malloc(sizeof(char) *  128);

	sprintf(id, "%s_%s%c",PROC_OTHER_PID, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(lpid, id,resultString);
	sprintf(id, "%s_%s%c",PROC_OTHER_PPID, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(ppid, id,resultString);
	sprintf(id, "%s_%s%c",PROC_OTHER_PROCESSOR, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(processor, id,resultString);

	free(resultString);
	free(id);
}


// Add the memopry specific stuff to the results tree for a specific process
void addProcessMemResults(char* pid,long size,long resident,long share,long trs,long drs,long lrs,long dr)
{
	char* id = malloc(sizeof(char) * 128);	
	char* resultString = malloc(sizeof(char) *  128);

	sprintf(id, "%s_%s%c",PROC_MEM_PERC,pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
	{
		long total = (XINT64) tableGet(currentValues, MEM_TOTAL);
		long res = resident*pageSize/1024;
		double perc = ((double) res)/ ((double) total)*100;
		addDoubleCounter(perc, id, resultString);
	}

	sprintf(id, "%s_%s%c",PROC_MEM_SIZE, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(size*pageSize/1024, id,resultString);
	sprintf(id, "%s_%s%c",PROC_MEM_RESIDENT, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(resident*pageSize/1024, id,resultString);
	
	sprintf(id, "%s_%s%c",PROC_MEM_SWAP, pid,'\0'); // SWAP = VIRT - RES = size - resident
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter((size - resident)*pageSize/1024, id,resultString);

	sprintf(id, "%s_%s%c",PROC_MEM_SHARE, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(share*pageSize/1024, id,resultString);
	sprintf(id, "%s_%s%c",PROC_MEM_TRS, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(trs*pageSize/1024, id,resultString);
	sprintf(id, "%s_%s%c",PROC_MEM_DRS, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter((drs+lrs)*pageSize/1024, id,resultString);
	sprintf(id, "%s_%s%c",PROC_MEM_LRS, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(lrs*pageSize/1024, id,resultString);
	sprintf(id, "%s_%s%c",PROC_MEM_DT, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(dr, id,resultString);

	free(id);
	free(resultString);
}

// Add Process Results method - covenience method to add the result children of a process node
// Must check if the counters have been requested, and so much rebuild the specific keys
// for this pid

void addProcessCounter( char* pid, char* id, char* mainid, long current, char* resultString)
{
	// Remove Caching with the comments below...

	sprintf(id, "%s_%s%c",mainid, pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
	{
//		long prev = (long) tableGet(previousValues, id);
//		if (prev == 0)
//		{
//			if (containsKey(previousValues, id) == TRUE)
//				addLongCounter(current-prev, id,resultString);					}						
//		else
//			addLongCounter(current-prev, id,resultString);
//		tablePut(previousValues,id,(XINT64) current);

// New line below
		addLongCounter(current, id, resultString);
	}
}

long getProcessCounter( char* pid, char* idtemp, char* mainid, long current, long ptotal, char* resultString)
{
	long val, prev;
	
	sprintf(idtemp, "%s_%s%c",mainid,   pid,'\0');
	if ((prev = tableGet(previousValues, idtemp)) == (XINT64) NULL) 
		prev = 0;	
	val = ((double) (current-prev)/ (double) ptotal)*100;
	
	if (tableGet(filtersHash, idtemp) != (XINT64) NULL)
	{
		if (prev != 0)
			addDoubleCounter(val, idtemp,resultString);
		else
			if (containsKey(previousValues, idtemp) == TRUE)
				addDoubleCounter(val, idtemp,resultString);
	}

	// return -1 if this value should NOT be used for a CPU aggregate
	if (prev == 0)
		if (containsKey(previousValues, idtemp) == TRUE)
		{
			tablePut(previousValues,idtemp,(XINT64) current);
			return val;
		}
		else
		{
			tablePut(previousValues,idtemp,(XINT64) current);
			return -1;
		}
	tablePut(previousValues,idtemp,(XINT64) current);
	
	return val;
}

void addProcessResults( char* pid,long minflt,long cminflt,long majflt,long cmajflt,long utime,long stime,long cutime,long cstime,long vsize,long rss,long nswap,long cnswap)
{
	char* id = malloc(sizeof(char) * 128);
	char* idtemp = malloc(sizeof(char) * 128);
	char* resultString = malloc(sizeof(char)*128);
	long total = utime+stime;
	long ctotal = cutime + cstime;
	
	addProcessCounter(pid, id, PROC_MEM_MINFLT, minflt, resultString);
	addProcessCounter(pid, id, PROC_MEM_CMINFLT, cminflt, resultString);
	addProcessCounter(pid, id, PROC_MEM_MAJFLT, majflt, resultString);
	addProcessCounter(pid, id, PROC_MEM_CMAJFLT, cmajflt, resultString);

	sprintf(id, "%s_%s%c", PROC_CPU_BOTH, pid, '\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
	{
		long prev, ptotal;
		double val1, val2, val3, val4;

		ptotal = (XINT64) tableGet(currentValues, STAT_TOTAL);

		val1 = getProcessCounter(pid, idtemp, PROC_CPU_UTIME, utime, ptotal, resultString);
		val2 = getProcessCounter(pid, idtemp, PROC_CPU_STIME, stime, ptotal, resultString);
		val3 = getProcessCounter(pid, idtemp, PROC_CPU_CUTIME, cutime, ptotal, resultString);
		val4 = getProcessCounter(pid, idtemp, PROC_CPU_CSTIME, cstime, ptotal, resultString);

		// If the accumulated counters have been requested then just return them below,
		// as we already have computed all the values required.
	  if (!(val1 == -1 || val2 == -1 || val3 == -1 || val4 == -1))
	  {
			sprintf(idtemp, "%s_%s%c", PROC_CPU_TIME, pid, '\0');
			if (tableGet(filtersHash, idtemp) != (XINT64) NULL)
				addDoubleCounter(val1+val2,idtemp, resultString);

			sprintf(idtemp, "%s_%s%c", PROC_CPU_CTIME, pid, '\0');
			if (tableGet(filtersHash, idtemp) != (XINT64) NULL)
				addDoubleCounter(val3+val4,idtemp, resultString);

			addDoubleCounter(val1+val2+val3+val4, id, resultString);
		}
	}
	else
	{

		sprintf(id, "%s_%s%c", PROC_CPU_TIME, pid, '\0');
		if (tableGet(filtersHash, id) != (XINT64) NULL)
		{
			double val1, val2;
			long ptotal = (XINT64) tableGet(currentValues, STAT_TOTAL);

			val1 = getProcessCounter(pid, idtemp, PROC_CPU_UTIME, utime, ptotal, resultString);
			val2 = getProcessCounter(pid, idtemp, PROC_CPU_STIME, stime, ptotal, resultString);

			if (!(val1 == -1 || val2 == -1))
			  addDoubleCounter(val1+val2, id, resultString);
		}
		else
		{
			long ptotal = (XINT64) tableGet(currentValues, STAT_TOTAL);

			getProcessCounter(pid, idtemp, PROC_CPU_UTIME, utime, ptotal, resultString);
			getProcessCounter(pid, idtemp, PROC_CPU_STIME, utime, ptotal, resultString);
		}

		sprintf(id, "%s_%s%c", PROC_CPU_CTIME, pid, '\0');
		if (tableGet(filtersHash, id) != (XINT64) NULL)
		{
			double val1, val2;
			long ptotal = (XINT64) tableGet(currentValues, STAT_TOTAL);

			val1 = getProcessCounter(pid, idtemp, PROC_CPU_CUTIME, utime, ptotal, resultString);
			val2 = getProcessCounter(pid, idtemp, PROC_CPU_CSTIME, stime, ptotal, resultString);

			if (!(val1 == -1 || val2 == -1))
				addDoubleCounter(val1+val2, id, resultString);
		}
		else
		{
			long ptotal = (XINT64) tableGet(currentValues, STAT_TOTAL);

			getProcessCounter(pid, idtemp, PROC_CPU_CUTIME, utime, ptotal, resultString);
			getProcessCounter(pid, idtemp, PROC_CPU_CSTIME, utime, ptotal, resultString);
		}
	}

	sprintf(id, "%s_%s%c",PROC_VSIZE,     pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(vsize, id,resultString);
	sprintf(id, "%s_%s%c",PROC_MEM_RSS,   pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(rss, id,resultString);
	sprintf(id, "%s_%s%c",PROC_MEM_NSWAP,  pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(nswap, id,resultString);
	sprintf(id, "%s_%s%c",PROC_MEM_CNSWAP,  pid,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(cnswap, id,resultString);

	free(id);
	free(idtemp);
	free(resultString);
}

void getProcessesResults()
{
 // Get the results of the requested (if any) processes

	int pSize = 0;
	int pLen = 128;
	char** processes = malloc(sizeof(char*)*pLen);

	if (VERBOSE == TRUE) printf("*** in getProcessesResults\n");

	while (pLen <= (pSize = tableKeysAsList(processHash, processes, pLen)))
	{
		pLen = pLen * 2;
		processes = realloc(processes, sizeof(char*)*pLen);
	}

	if (pSize > 0)
	{
	  static char filename[128];
		static char executeName[128];
		char* procParentID = malloc(sizeof(char)*128);
		char* procName = malloc(sizeof(char) * 128);
		int i;
		long minflt=0,cminflt=0,majflt=0,cmajflt=0,utime=0,stime=0,cutime=0,cstime=0,vsize=0,rss=0,nswap=0,cnswap=0;
		long size, resident, share, trs, drs, lrs, dr, pid, ppid, processor;

		for (i=0; i<pSize; i++)
		{
			// Recreate the process key here,and then check if it has been requested
			sprintf(procParentID,"%s_%s%c",PROC_PARENT, processes[i],'\0');

    	if (tableGet(filtersHash, procParentID) != (XINT64) NULL)
			{
  	 		sprintf(filename, "/proc/%s/stat", processes[i]);
   			if (readProcInfo(filename)) 
				{
					sscanf(buff, "%d %*s %*c %d %*d %*d %*d %*d %*u %lu %lu %lu %lu %lu %lu %lu %lu %*d %*d %*u %*u %*d %lu %lu %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %lu %lu %*d %d",&pid, &ppid, &minflt,&cminflt,&majflt,&cmajflt,&utime,&stime,&cutime,&cstime,&vsize,&rss,&nswap,&cnswap, &processor);

					addProcessResults(processes[i],minflt,cminflt,majflt,cmajflt,utime,stime,cutime,cstime,vsize,rss,nswap,cnswap);
												
					sprintf(filename, "/proc/%s/statm", processes[i]);
	   			if (readProcInfo(filename)) 
					{
						sscanf(buff, "%d %d %d %d %d %d %d",&size,&resident,&share,&trs,&drs,&lrs,&dr);
						addProcessMemResults(processes[i],size,resident,share,trs,drs,lrs,dr);
					}
					addProcessOtherResults(processes[i],pid, ppid, processor);
				}
			} 
		} 	

		free(procParentID);
		free(procName);
	}

	free(processes);

	if (VERBOSE == TRUE) printf("***out getProcesses\n");
} 

/*************************************************************************************/
// NET METHODS

void addNetInterface(char* parentid, char** bstr)
{
	char* b = *bstr;
	char* name = malloc(sizeof(char) * 128);
	char* temp = malloc(sizeof(char) * 128);
	char* interfaceid = malloc(sizeof(char) * 128);
	char* id = malloc(sizeof(char) * 128);
	int i=0;

	while (b[i] != ':')
		i++;

	b[i] = '\0';
	sprintf(temp, "%s%c",b,'\0');
	sscanf(temp, "%s",name);
	b = b+(sizeof(char)*(i+1));

	// Firstly, lets add the interface node
	sprintf(interfaceid,"%s_%s%c",NET_INTERFACE,name,'\0');
	addToTreeArray(parentid, interfaceid, name,"${LINUX.AGENT.216}","");

	sprintf(id,"%s_%s%c",NET_RBYTES,name,'\0');
	addToTreeArray(interfaceid, id, "${MySQL.AGENT.217}","${LINUX.AGENT.218}","");

	sprintf(id,"%s_%s%c",NET_RPACKETS,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.219}","${LINUX.AGENT.220}","");
	
	sprintf(id,"%s_%s%c",NET_RERRS,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.221}","${LINUX.AGENT.222}","");
	
	sprintf(id,"%s_%s%c",NET_RDROP,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.223}","${LINUX.AGENT.224}","");
	
	sprintf(id,"%s_%s%c",NET_RFIFO,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.225}","${LINUX.AGENT.226}","");
	
	sprintf(id,"%s_%s%c",NET_RFRAME,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.227}","${LINUX.AGENT.228}","");
	
	sprintf(id,"%s_%s%c",NET_RCOMPRESSED,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.229}","${LINUX.AGENT.230}","");
	
	sprintf(id,"%s_%s%c",NET_RMULTICAST,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.231}","${LINUX.AGENT.232}","");
	
	sprintf(id,"%s_%s%c",NET_TBYTES,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.233}","${LINUX.AGENT.234}","");
	
	sprintf(id,"%s_%s%c",NET_TPACKETS,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.235}","${LINUX.AGENT.236}","");
	
	sprintf(id,"%s_%s%c",NET_TERRS,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.237}","${LINUX.AGENT.238}","");
	
	sprintf(id,"%s_%s%c",NET_TDROP,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.239}","${LINUX.AGENT.240}","");
	
	sprintf(id,"%s_%s%c",NET_TFIFO,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.241}","${LINUX.AGENT.242}","");
	
	sprintf(id,"%s_%s%c",NET_TCOLLISIONS,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.243}","${LINUX.AGENT.244}","");
	
	sprintf(id,"%s_%s%c",NET_TCARRIER,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.245}","${LINUX.AGENT.246}","");
	
	sprintf(id,"%s_%s%c",NET_TCOMPRESSED,name,'\0');
	addToTreeArray(interfaceid, id, "${LINUX.AGENT.247}","${LINUX.AGENT.248}","");

	free(id);
	free(interfaceid);
	free(temp);
	free(name);
	*bstr = b;
}

void getNetInterfaceResults( char** bstr)
{
	char* b = *bstr;
	char* name = malloc(sizeof(char) * 128);
	char* temp = malloc(sizeof(char) * 128);
	char* id = malloc(sizeof(char) * 128);
	char* resultString = malloc(sizeof(char) * 128);
	long rbytes, rpackets, rerrs, rdrop, rfifo, rframe, rcompressed, rmulticast;
	long tbytes, tpackets, terrs, tdrop, tfifo, tcollisions, tcarrier, tcompressed;
	int i=0;

	while (b[i] != ':')
		i++;

	b[i] = '\0';
	sprintf(temp, "%s%c",b,'\0');
	sscanf(temp, "%s",name);
	b = b+(sizeof(char)*(i+1));

	sscanf(b, "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", &rbytes, &rpackets, &rerrs, &rdrop, &rfifo, &rframe, &rcompressed, &rmulticast, &tbytes, &tpackets, &terrs, &tdrop, &tfifo, &tcollisions, &tcarrier, &tcompressed);

	sprintf(id,"%s_%s%c",NET_RBYTES,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(rbytes,id,resultString);
										
	sprintf(id,"%s_%s%c",NET_RPACKETS,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64) NULL)
		addLongCounter(rpackets,id,resultString);

	sprintf(id,"%s_%s%c",NET_RERRS,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(rerrs,id,resultString);

	sprintf(id,"%s_%s%c",NET_RDROP,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(rdrop,id,resultString);

	sprintf(id,"%s_%s%c",NET_RFIFO,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(rfifo,id,resultString);

	sprintf(id,"%s_%s%c",NET_RFRAME,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(rframe,id,resultString);

	sprintf(id,"%s_%s%c",NET_RCOMPRESSED,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(rcompressed,id,resultString);

	sprintf(id,"%s_%s%c",NET_RMULTICAST,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(rmulticast,id,resultString);

	sprintf(id,"%s_%s%c",NET_TBYTES,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(tbytes,id,resultString);

	sprintf(id,"%s_%s%c",NET_TPACKETS,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(tpackets,id,resultString);

	sprintf(id,"%s_%s%c",NET_TERRS,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(terrs,id,resultString);

	sprintf(id,"%s_%s%c",NET_TDROP,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(tdrop,id,resultString);

	sprintf(id,"%s_%s%c",NET_TFIFO,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(tfifo,id,resultString);

	sprintf(id,"%s_%s%c",NET_TCOLLISIONS,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(tcollisions,id,resultString);

	sprintf(id,"%s_%s%c",NET_TCARRIER,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(tcarrier,id,resultString);

	sprintf(id,"%s_%s%c",NET_TCOMPRESSED,name,'\0');
	if (tableGet(filtersHash, id) != (XINT64)NULL)
		addLongCounter(tcompressed,id,resultString);

	free(id);
	free(temp);
	free(name);
	free(resultString);
	*bstr = b;
}

void getNetInfoResults()
{
	if (VERBOSE == TRUE) printf("*** in getNetInfoResults\n");

	if (readNetDevInfo()) 
	{
		char *b, *btemp = NULL;
		char* name = malloc(sizeof(char)*32);
		int i = 0;

		// Parse the buffer and add each interface to the disk
		// Delete the first two lines - they are headings, and useless
		b = strstr(buff,"\n");
		b++;
		b = strstr(b,"\n");
		b++;
		while (b != NULL && b[0] != '\0')
		{
			if (strchr(b,':') == NULL)
				break;
			getNetInterfaceResults(&b);

			if (b[0] == '\0')
				break;

			b = strchr(b,'\n');
		}
		free(name);
	}	
	else
	  crash("/proc/net");
	
	if (VERBOSE == TRUE) printf("*** out getNetInfoResults\n");
}

void getNetInfoTree( char* parentid)
{
	if (VERBOSE == TRUE) printf("*** in getNetInfoTree\n");

	if (readNetDevInfo()) 
	{
		char *b, *btemp = NULL;
		char* name = malloc(sizeof(char)*32);
		int i = 0;

		addToTreeArray(parentid, "/proc/net", "${LINUX.AGENT.250}","${LINUX.AGENT.251}","");		

		// Parse the buffer and add each interface to the disk
		// Delete the first two lines - they are headings, and useless
		b = strstr(buff,"\n");
		b++;
		b = strstr(b,"\n");
		b++;

		while (b[0] != '\0')
		{
			if (strchr(b,':') == NULL)
				break;

			addNetInterface("/proc/net", &b);
			if (b[0] == '\0')
				break;

			b = strchr(b,'\n');
		}
		free(name);
	}	
	else
	  crash("/proc/net");

	if (VERBOSE == TRUE) printf("*** out getNetInfoTree\n");
}

/*************************************************************************************/

void freeArray()
{
	int i;
	if (max != 0)
	{
//		printf("about to free array : size = %d, max = %d\n",size,max);
		for (i=0;i<size;i++)
			free(results[i]);
		free(results);	
		max = 0;
		size = 0;
		results = NULL;
	}
}

void getResults()
{
	getLinuxResults();
}

void getTree() 
{
	getLinuxTree();
} /* end getStats */


char** DC_CollectionGetTree	(int* numresults)
{
	freeArray();
	getTree();
	*numresults = size;
	max = 0;
	size = 0;
	return results;
}

char** DC_CollectionGetResults (int* numresults)
{
	freeArray();
	getResults();
	*numresults = size;
	return results;
}

int DC_CollectionStartup(HashTable* hasht_variables, HashTable* hasht_filters, HashTable* hasht_tree)
{
	variablesHash = hasht_variables;
	filtersHash = hasht_filters;
	treeHash = hasht_tree;
	previousValues = tableCreate();
	processHash = tableCreate();
	currentValues = tableCreate();

  	pageSize = getpagesize();

	buff = malloc(sizeof(char) * buflen);
								
	return 0;
}

int DC_CollectionShutdown()
{
	tableDelete(previousValues);	
	tableDelete(processHash);
	tableDelete(currentValues);

	free(buff);

	return 0;
}

char* DC_CollectionGetAgentName()
{
	return agent_type;
}
