#!/usr/bin/perl

###############################################################################
#                                                                             #
# Filename: dmnPFMonitor                                                      #
#                                                                             #
# Description:                                                                #
#                                                                             #
###############################################################################
###############################################################################
#                                                                             #
#  Copyright  2000 - 2001 Intel Corporation.                                 #
#  Intel Corporation All Rights Reserved.                                     #
#                                                                             #
#  The source code contained or described herein and all documents related to #
#  the source code ("Material") are owned by Intel Corporation or its         #
#  suppliers or licensors.  Title to the Material remains with Intel          #
#  Corporation or its suppliers and licensors.  The Material contains trade   #
#  secrets and proprietary and confidential information of Intel or its       #
#  suppliers and licensors.  The Material is protected by worldwide copyright #
#  and trade secret laws and treaty provisions.  No part of the Material may  #
#  be used, copied, reproduced, modified, published, uploaded, posted,        #
#  transmitted, distributed, or disclosed in any way without Intel's prior    #
#  express written permission.                                                #
#                                                                             #
#  No license under any patent, copyright, trade secret or other intellectual #
#  property right is granted to or conferred upon you by disclosure or        #
#  delivery of the Materials, either expressly, by implication, inducement,   #
#  estoppel or otherwise. Any license under such intellectual property rights #
#  must be express and approved by Intel in writing.                          #
#                                                                             #
###############################################################################

use Time::Local;

## Uncomment the debugging you'd like to have occur.
$DEBUG 				= 0;
#$DEBUG 					= 1;

$CAT					=	"/bin/cat";
$LOGGER					=	"/usr/bin/logger";
$SENSORS_CONF			=	"/etc/asm/asm.conf";
$EVENTLOG				= 	"/usr/ins/intel/bin/asm/sysEventLog";
$LS						=   "/bin/ls";
$EMAILALERT				=	"/usr/ins/intel/bin/asm/bakEmailAlert";
$WRITETOSEL				=   "/usr/ins/intel/bin/asm/sysWriteToSEL";
$CLEARTEXT				=	"/usr/ins/intel/bin/asm/sysClearText";
$CLEARICON				=	"/usr/ins/intel/bin/asm/sysClearIcon";

$PF_STATS				= 	"/var/tmp/pfstats.asm";

################### Global Varibles ###################

$initState				= 3;

## Tally variables.
$singlebitTally 		= 0;
$cpuTally 				= 0;
$memTally 				= 0;
@tempTally 	   			= (0,0,0,0);
@voltPlus12Tally 		= (0,0,0,0);
@voltMinus12Tally 		= (0,0,0,0);
@voltPlus5Tally 		= (0,0,0,0);
@voltPlus3Point3Tally	= (0,0,0,0);
@voltCPUTally 			= (0,0,0,0);
@voltIOTally 			= (0,0,0,0);

## Last state variables.
$NORMAL 				= 0;
$LOWER 					= 1;
$TRIGGERED 				= 1;
$LOWER_CRITICAL 		= 2;
$UPPER 					= 3;
$UPPER_CRITICAL 		= 4;

$lastSingleBit 			= $NORMAL;
$lastCPU 				= $NORMAL;
$currentCPU				= $TRIGGERED;
$lastMem 				= $NORMAL;
$currentMem				= $TRIGGERED;
$lastPlus12V 			= $NORMAL;
$lastMinus12V 			= $NORMAL;
$lastPlus5V 			= $NORMAL;
$lastPlus3Point3V 		= $NORMAL;
$lastIOV 				= $NORMAL;
$lastCPUV 				= $NORMAL;
$lastTemp 				= $NORMAL;

#######################################################

($x, $x, $x, $x, $x, $x, $x, $x, $x, $lastModDate,
 $x, $x, $x, $x) = stat($SENSORS_CONF);

ReadParms();
$cpuTimeTrigger			= time() + $CPU_UTILIZATION_DURATION;
$memTimeTrigger			= time() + $MEMORY_UTILIZATION_DURATION;
$sbTimeTrigger			= time() + $SINGLE_BIT_ERROR_DURATION;

$pollTime = time() + $POLL_INTERVAL;
$lastLCD = 0;

while ($initState == 3)
{

	## Tally current CPU and memory usage.
	CheckCPUMemoryUtilization();

	if( ($PF_ENABLED == 1) && (time() >= $pollTime) )
	{
		## Predictive Failure is enabled and we're at our polling interval.
		if($DEBUG) { print "[main] Current Time: ". time() ."\n"};
		$start = time();
		ProcessSEL();
		ProcessCPUMemoryUtilization();
		
		## Dump current stats for use by SNMP.
		open (PF, ">$PF_STATS");
		print PF "$lastSingleBit $lastCPU $lastMem $lastPlus12V $lastMinus12V $lastPlus5V $lastPlus3Point3V $lastIOV $lastCPUV $lastTemp\n";
		close (PF);
		$pollTime = time() + $POLL_INTERVAL;
		
		## See if we should clear the LCD.
	  	if( ($lastLCD != 0)  && ($lastLCD + 60) < time() )
	   	{
			#system("$CLEARTEXT > /dev/null");
		  	#system("$CLEARICON 5 > /dev/null");
		   	$lastLCD = 0;
	  	}
	}

	sleep(5);
	## See if we should reload asm.conf.
	($x, $x, $x, $x, $x, $x, $x, $x, $x, $thisModDate,
 	$x, $x, $x, $x) = stat($SENSORS_CONF);
	if($thisModDate != $lastModDate)
	{
		## Configuration file has changed, so re-read values.
		$oldCPUDuration = $CPU_UTILIZATION_DURATION;
		$oldMemoryDuration = $MEMORY_UTILIZATION_DURATION;
		$oldsbDuration = $SINGLE_BIT_ERROR_DURATION;
		ReadParms();
		if($oldCPUDuration != $CPU_UTILIZIATION_DURATION)
		{
			$cpuTimeTrigger	= time() + $CPU_UTILIZATION_DURATION;
		}
		if($oldMemoryDuration != $MEMORY_UTILIZIATION_DURATION)
		{
			$memTimeTrigger	= time() + $MEMORY_UTILIZATION_DURATION;
		}
		if($oldsbDuration != $SINGLE_BIT_ERROR_DURATION)
		{
			$sbTimeTrigger	= time() + $SINGLE_BIT_ERROR_DURATION;
		}
		$lastModDate = $thisModDate;
	}
}


system("/sbin/init $initState");
exit 0;

##
## [ProcessSEL]
##
## Process System Event Log in both NVRAM and archives.
##
sub ProcessSEL
{
	my $currentTime, $myTime;

	## Reset tally sheet.
	$singlebitTally 		= 0;
	@tempTally 	   			= (0,0,0,0);
	@voltPlus12Tally 		= (0,0,0,0);
	@voltMinus12Tally 		= (0,0,0,0);
	@voltPlus5Tally 		= (0,0,0,0);
	@voltPlus3Point3Tally	= (0,0,0,0);
	@voltCPUTally 			= (0,0,0,0);
	@voltIOTally 			= (0,0,0,0);
	$currentTime = time();

	## Read current entries in NVRAM.
	open(SEL, "$EVENTLOG |");
	Tally(*SEL, $currentTime);
	close SEL;

	## Read archives.
	open( SELLIST, "$LS /var/log/sel*gz -1 2>/dev/null |");
	while( <SELLIST> ) 
	{
		open( SEL, "$EVENTLOG $_ |");
		Tally(*SEL, $currentTime);
		close(SEL);
	}
	close(SELLIST);


	## Check our tallies against occurances for this duration.
	if(time() >= $sbTimeTrigger)
	{
		## Time to see if we've changed.
		$current = ($singlebitTally >= $SINGLE_BIT_ERROR_OCCURANCE) 
					? $TRIGGERED : $NORMAL;

		## See what we've changed to.
		if( $current == $TRIGGERED)
		{
			## We've triggered.
			if($DEBUG)		{print "Single-bit error triggered\n"};
			PerformActions('Single-bit', 'Single-bit error Trigger', 'xxx', '2', 
								$PF_SINGLE_BIT_ERROR_ACTIONS, "PFSingle-bit");
		}else{
			## Normal to flush the LCD.
			if($DEBUG)		{print "Single-bit error normal\n"};
			PerformActions("Single-bit", "", "xxx", "1", "", "");
		}
	}	
	
	## Check Temperature.
  	if($DEBUG)		{print "\n[ProcessSEL] Checking Temperature...\n"}
	$lastTemp = Check4Level($lastTemp, \@tempTally, 
				$TEMP_UPPER_CRITICAL_OCCURANCE,
				$TEMP_UPPER_OCCURANCE, $TEMP_LOWER_OCCURANCE, 
				$TEMP_LOWER_CRITICAL_OCCURANCE, 
				"CPUTemp", "CPU Temperature", "xxx", 
				$PF_TEMP_UPPER_CRITICAL_ACTIONS, $PF_TEMP_UPPER_ACTIONS,
				$PF_TEMP_LOWER_ACTIONS, $PF_TEMP_LOWER_CRITICAL_ACTIONS,
				"PFCPUTemp");
  	if($DEBUG)		{print "[ProcessSEL] Temperature Status: $lastTemp\n"}

	## Check +12V.
  	if($DEBUG)		{print "\n[ProcessSEL] Checking +12V...\n"}
	$lastPlus12V = Check4Level($lastPlus12V, \@voltPlus12Tally, 
				$VOLT_UPPER_CRITICAL_OCCURANCE,
				$VOLT_UPPER_OCCURANCE, $VOLT_LOWER_OCCURANCE, 
				$VOLT_LOWER_CRITICAL_OCCURANCE, 
				"+12v", "+12v", "xxx", 
				$PF_VOLT_UPPER_CRITICAL_ACTIONS, $PF_VOLT_UPPER_ACTIONS,
				$PF_VOLT_LOWER_ACTIONS, $PF_VOLT_LOWER_CRITICAL_ACTIONS,
				"PF+12v");
  	if($DEBUG)		{print "[ProcessSEL] +12V Status: $lastPlus12V\n"}

	## Check -12V.
  	if($DEBUG)		{print "\n[ProcessSEL] Checking -12V...\n"}
	$lastMinus12V = Check4Level($lastMinus12V, \@voltMinus12Tally, 
				$VOLT_UPPER_CRITICAL_OCCURANCE,
				$VOLT_UPPER_OCCURANCE, $VOLT_LOWER_OCCURANCE, 
				$VOLT_LOWER_CRITICAL_OCCURANCE, 
				"-12v", "-12v", "xxx", 
				$PF_VOLT_UPPER_CRITICAL_ACTIONS, $PF_VOLT_UPPER_ACTIONS,
				$PF_VOLT_LOWER_ACTIONS, $PF_VOLT_LOWER_CRITICAL_ACTIONS,
				"PF-12v");
  	if($DEBUG)		{print "[ProcessSEL] -12V Status: $lastMinus12V\n"}

	## Check +5V.
  	if($DEBUG)		{print "\n[ProcessSEL] Checking +5V...\n"}
	$lastPlus5V = Check4Level($lastPlus5V, \@voltPlus5Tally, 
				$VOLT_UPPER_CRITICAL_OCCURANCE,
				$VOLT_UPPER_OCCURANCE, $VOLT_LOWER_OCCURANCE, 
				$VOLT_LOWER_CRITICAL_OCCURANCE, 
				"+5v", "+5v", "xxx", 
				$PF_VOLT_UPPER_CRITICAL_ACTIONS, $PF_VOLT_UPPER_ACTIONS,
				$PF_VOLT_LOWER_ACTIONS, $PF_VOLT_LOWER_CRITICAL_ACTIONS,
				"PF+5v");
  	if($DEBUG)		{print "[ProcessSEL] +5V Status: $lastPlus5V\n"}

	## Check 3.3V.\
  	if($DEBUG)		{print "\n[ProcessSEL] Checking +3.3...\n"}
	$lastPlus3Point3V = Check4Level($lastPlus3Point3V, \@voltPlus3Point3Tally, 
				$VOLT_UPPER_CRITICAL_OCCURANCE,
				$VOLT_UPPER_OCCURANCE, $VOLT_LOWER_OCCURANCE, 
				$VOLT_LOWER_CRITICAL_OCCURANCE, 
				"+3.3v", "+3.3v", "xxx", 
				$PF_VOLT_UPPER_CRITICAL_ACTIONS, $PF_VOLT_UPPER_ACTIONS,
				$PF_VOLT_LOWER_ACTIONS, $PF_VOLT_LOWER_CRITICAL_ACTIONS,
				"PF+3.3v");
  	if($DEBUG)		{print "[ProcessSEL] +3.3V Status: $lastPlus3Point3V\n"}


	## Check CPU V.
  	if($DEBUG)		{print "\n[ProcessSEL] Checking CPU V...\n"}
	$lastCPUV = Check4Level($lastCPUV, \@voltCPUTally, 
				$VOLT_UPPER_CRITICAL_OCCURANCE,
				$VOLT_UPPER_OCCURANCE, $VOLT_LOWER_OCCURANCE, 
				$VOLT_LOWER_CRITICAL_OCCURANCE, 
				"+Vcore", "+Vcore", "xxx", 
				$PF_VOLT_UPPER_CRITICAL_ACTIONS, $PF_VOLT_UPPER_ACTIONS,
				$PF_VOLT_LOWER_ACTIONS, $PF_VOLT_LOWER_CRITICAL_ACTIONS,
				"PF+Vcore");
  	if($DEBUG)		{print "[ProcessSEL] CPU Voltage Status: $lastCPUV\n"}

	## Check I/O V.
  	if($DEBUG)		{print "\n[ProcessSEL] Checking I/O V...\n"}
	$lastIOV = Check4Level($lastIOV, \@voltIOTally, 
				$VOLT_UPPER_CRITICAL_OCCURANCE,
				$VOLT_UPPER_OCCURANCE, $VOLT_LOWER_OCCURANCE, 
				$VOLT_LOWER_CRITICAL_OCCURANCE, 
				"+Vio", "+Vio", "xxx", 
				$PF_VOLT_UPPER_CRITICAL_ACTIONS, $PF_VOLT_UPPER_ACTIONS,
				$PF_VOLT_LOWER_ACTIONS, $PF_VOLT_LOWER_CRITICAL_ACTIONS,
				"PF+Vio");
  	if($DEBUG)		{print "[ProcessSEL] I/O Voltage Status: $lastIOV\n"}

}


##
## [Tally]
##
## Process our tally sheet of variables according to the specified type.
##
sub Tally
{
	my ($handle, $currentTime) = @_;

	while( <$handle> )
	{
		($type, $length, $date, $time, $ext) = split( " ", $_);
		
		## Ignore non-numeric garbage.
		next if( !($type =~ /^[0-9]*$/) );
		next if( length($ext) > 8);
		@timeStuff = split(":", $time);
		@dateStuff = split("/", $date);
		## Check for bogus values that will punt us out if passed to 
		## timelocal().
		next if( !($timeStuff[0] =~ /^[0-9]*$/) || ($timeStuff[0] > 23));
		next if( !($timeStuff[1] =~ /^[0-9]*$/) || ($timeStuff[1] > 59));
		next if( !($timeStuff[2] =~ /^[0-9]*$/) || ($timeStuff[2] > 59));
		next if( !($dateStuff[0] =~ /^[0-9]*$/) || ($dateStuff[0] > 12));
		next if( !($dateStuff[1] =~ /^[0-9]*$/) || ($dateStuff[1] < 1) || 
														($dateStuff[1] > 31));
		$myTime = timelocal($timeStuff[2], $timeStuff[1], $timeStuff[0], 
	  			$dateStuff[1], $dateStuff[0] - 1, 2000 + $dateStuff[2]);
		next if($myTime > $currentTime);	## Safety for bogus entries.

		## Figure out and tally what we have.
		if($type =~ 10)
   		{
			## Classed entry.
	  		if( !(substr($ext, 0, 4) =~ "ffff") )
	   		{
		 		## Real-event sensor. 
		  		$event = substr($ext, 0, 2);
		   		$sensor = substr($ext, 6, 2);
				
				if( $sensor eq "05")
				{
					## +12 V.
					TallyCalc($myTime, $currentTime, $event, \@voltPlus12Tally,
								$VOLT_UPPER_CRITICAL_DURATION,
								$VOLT_UPPER_DURATION, $VOLT_LOWER_DURATION,
								$VOLT_LOWER_CRITICAL_DURATION);
				}
				if( $sensor eq "06")
				{
					## -12 V.
					TallyCalc($myTime, $currentTime, $event, \@voltMinus12Tally,
								$VOLT_UPPER_CRITICAL_DURATION,
								$VOLT_UPPER_DURATION, $VOLT_LOWER_DURATION,
								$VOLT_LOWER_CRITICAL_DURATION);
				}
				if( $sensor eq "03")
				{
					## +5 V.
					TallyCalc($myTime, $currentTime, $event, \@voltPlus5Tally,
								$VOLT_UPPER_CRITICAL_DURATION,
								$VOLT_UPPER_DURATION, $VOLT_LOWER_DURATION,
								$VOLT_LOWER_CRITICAL_DURATION);
				}
				if( $sensor eq "02")
				{
					## +3.3 V.
					TallyCalc($myTime, $currentTime, $event, \@voltPlus3Point3Tally,
								$VOLT_UPPER_CRITICAL_DURATION,
								$VOLT_UPPER_DURATION, $VOLT_LOWER_DURATION,
								$VOLT_LOWER_CRITICAL_DURATION);
				}
				if( $sensor eq "01")
				{
					## I/O V.
					TallyCalc($myTime, $currentTime, $event, \@voltIOTally,
								$VOLT_UPPER_CRITICAL_DURATION,
								$VOLT_UPPER_DURATION, $VOLT_LOWER_DURATION,
								$VOLT_LOWER_CRITICAL_DURATION);
				}
				if( $sensor eq "00")
				{
					## CPU V.
					TallyCalc($myTime, $currentTime, $event, \@voltCPUTally,
								$VOLT_UPPER_CRITICAL_DURATION,
								$VOLT_UPPER_DURATION, $VOLT_LOWER_DURATION,
								$VOLT_LOWER_CRITICAL_DURATION);
				}
				if($sensor eq "10")
		 		{
					## Temperature
					TallyCalc($myTime, $currentTime, $event, \@tempTally,
								$TEMP_UPPER_CRITICAL_DURATION,
								$TEMP_UPPER_DURATION, $TEMP_LOWER_DURATION,
								$TEMP_LOWER_CRITICAL_DURATION);
		 		}
   		}
		}elsif($type eq "1")
		{
   			## Single bit error.
			$singlebitTally += 
					TallyCalcTrigger($myTime, $currentTime, $SINGLE_BIT_ERROR_DURATION);
  		}

	}
}

##
## [TallyCalc]
##
## Calculate tally based on event.
##
sub TallyCalc
{

	my ($myTime, $currentTime, $event, $tally, 
				$upper_critical, $upper, $lower, $lower_critical) = @_;

	if($DEBUG == 255)		{print "[TallyCalc] "};
  	if($event eq "80")
  	{
   		## Upper critical.
		if($DEBUG == 255)		{print "Upper critical\n"};
		@$tally[0] = @$tally[0] +
			   	TallyCalcTrigger($myTime, $currentTime, $upper_critical);
	}elsif($event eq "c0")
  	{
		## Upper warning.
		if($DEBUG == 255)		{print "Upper warning\n"};
		@$tally[1] = @$tally[1] +
			  	TallyCalcTrigger($myTime, $currentTime, $upper);
  	}elsif($event eq "a0")
	{
	  	## Lower critical.
		if($DEBUG == 255)		{print "Lower critical\n"};
		@$tally[2] = @$tally[2] +
			 	TallyCalcTrigger($myTime, $currentTime, $lower_critical);
   	}elsif($event eq "e0")
   	{
   		## Lower warning.
		if($DEBUG == 255)		{print "Lower warning\n"};
	  	@$tally[3] = @$tally[3] +
			  	TallyCalcTrigger($myTime, $currentTime, $lower);
	}
	
}

##
## [TallyCalcTrigger]
##
## Determine whether the entry should be counted toward the sensor's tally
## by comparing it's time against the sensor's duration range.
##
sub TallyCalcTrigger
{
	my ($myTime, $currentTime, $duration) = @_; 

	if($DEBUG == 255)		{print "[TallyCalcTrigger] "};

	if($myTime >= ($currentTime - $duration) )
	{
		## Inside duration.
		if($DEBUG == 255)	{print "Triggered\n"};
		return 1;
	}else{
		## Outside duration.
		if($DEBUG == 255)	{print "Not Triggered\n"};
		return 0;
	}
}

##
## [ProcessCPUMemoryUtilization]
##
## Process CPU and Memory Utilization
##
sub ProcessCPUMemoryUtilization
{
	if($DEBUG)		{print "[ProcessCPUMemoryUtilization] "};

	## CPU Utilization.
	if(time() >= $cpuTimeTrigger)
	{
		## Time to see if we've changed.
		$currentCPU = ($cpuTally > 0) ? $TRIGGERED : $NORMAL;
		
	  	if( $currentCPU == $TRIGGERED)
	  	{
			## We've triggered.
		  	if($DEBUG)		{print "CPU Utilization triggered\n"};
		   	PerformActions('CPUUtil', 'CPU Utilization Trigger', 'xxx', '2', 
									  $PF_CPU_UTILIZATION_ACTIONS,"PFCPUUtil");
	  	}else{
			## We're normal.
		   	if($DEBUG)		{print "CPU Utilization normal\n"};
		   	PerformActions('CPUUtil', "", 'xxx', '1', "", "");
		}
	 	$lastCPU = $currentCPU;
		$cpuTimeTrigger = time() + $CPU_UTILIZATION_DURATION;
	}
  	if($DEBUG)		{print "CPU Utilization: $lastCPU\n"};

	## Memory Utilization.
	$current = ($memTally > 0) ? $TRIGGERED : $NORMAL;
	if(time() >= $memTimeTrigger)
	{
		## Time to see if we've changed.
		$currentMem = ($memTally > 0) ? $TRIGGERED : $NORMAL;
		
	  	if( $currentMem == $TRIGGERED)
	   	{
			## We've triggered.
		  	if($DEBUG)		{print "Memory Utilization triggered\n"};
		  	PerformActions('MemUtil', 'Memory Utilization Trigger', 'xxx', '2', 
								  $PF_MEMORY_UTILIZATION_ACTIONS, "PFMemUtil");
	   	}else{
		 	## We''re normal.
		  	if($DEBUG)		{print "Memory Utilization normal\n"};
		 	PerformActions('MemUtil', "", 'xxx', '1', "", "");
		}
	 	$lastMem = $currentMem;
		$memTimeTrigger = time() + $MEMORY_UTILIZATION_DURATION;
	}
  	if($DEBUG)		{print "Memory Utilization: $lastMem\n"};
}

##
## [CheckCPUMemoryUtilization]
##
## Check the current CPU and memory utilization and update our tally if
## the current usage surpases the current percent thresholds.  If for any
## reason the threshold drops, turn the tally to 0.
##
sub CheckCPUMemoryUtilization 
{
	
	open (STAT, "/proc/stat");
	my $line = <STAT>;
	close (STAT);

	my @cpuarray = split (/ /, $line);
	my ($user_ticks, $nice_ticks, $systim_ticks, $idle_ticks) = @cpuarray[2..5];

	my ($user_diff, $nice_diff, $system_diff, $idle_diff) =
		($user_ticks - $old_user_ticks,
		$nice_ticks - $old_nice_ticks,
		$system_ticks - $old_system_ticks,
		$idle_ticks - $old_idle_ticks);

	# Calculate CPU usage
	my $CPUUsage = ( ($user_diff + $nice_diff + $system_diff) / 
		($idle_diff + $user_diff + $nice_diff + $system_diff) )
		* 100;

	if($CPUUsage >= $CPU_UTILIZATION_OCCURANCE)
	{
		## Still in same range.
		$cpuTally++;
	}else{
		## Under the range.
		$cpuTally = 0;
	}

	# Save current values for next calculation
	($old_user_ticks, $old_nice_ticks, $old_system_ticks, $old_idle_ticks) = ($user_ticks, $nice_ticks, $system_ticks, $idle_ticks);

	open (MEMFILE, "/proc/meminfo");
	<MEMFILE>;		# Throw away the first line
	$line = <MEMFILE>;
	$swapline = <MEMFILE>;
	close (MEMFILE);

	my @memarray = split (' ', $line);
	my $real_total = $memarray[1];
	my $real_used  = $memarray[2]-$memarray[5]-$memarray[6];
	my @swaparray = split (' ', $swapline);
	my $swap_total = $swaparray[1];
	my $swap_used = $swaparray[2];

	my $MemoryUsage = ( ($real_used + $swap_used) / ($real_total + $swap_total) ) * 100;

	if($MemoryUsage >= $MEMORY_UTILIZATION_OCCURANCE)
	{
		## Inside the range.
		$memTally++;
	}else{
		## Outside the range.
		$memTally = 0;
	}

}

##
## [Check4Level]
##
## Check stats.
##
sub Check4Level
{
	my ($last, $tally, $upper_critical, $upper, $lower, $lower_critical,
		$id, $desc, $xxx, $upper_critical_actions, $upper_actions,
		$lower_actions, $lower_critical_actions, $SELCode) = @_;

	if($DEBUG)		{print "[Check4Level] "};

	$current = $last;
	if( ($last != $UPPER_CRITICAL) && (@$tally[0] >= $upper_critical) )
	{
		if($DEBUG)		{print "Upper Critical, Tally=@$tally[0], Occurance=$upper_critical\n"};
		$current = $UPPER_CRITICAL;
	}
	if( ($last != $UPPER) && ( @$tally[1] >= $upper) )
	{
		if($DEBUG)		{print "Upper, Tally=@$tally[1], Occurance=$upper\n"};
		$current = $UPPER;
	}
	if( ($last != $LOWER) && ( @$tally[3] >= $lower) )
	{
		if($DEBUG)		{print "Lower, Tally=@$tally[3], Occurance=$lower\n"};
		$current = $LOWER;
	}
	if( ($last != $LOWER_CRITICAL) && (@$tally[2] >= $lower_critical) )
	{
		if($DEBUG)		{print "Lower Critical, Tally=@$tally[2], Occurance=$lower_critical\n"};
		$current = $LOWER_CRITICAL;
	}
	
	if( ($last != $NORMAL) && @$tally[0] == 0 && @$tally[1] == 0 &&
							  @$tally[2] == 0 && @$tally[3] == 0)
	{
		$current = $NORMAL;
		if($DEBUG)		{print "Normal\n";}
	}
	if($current == $last)
	{
		if($DEBUG)		{print "Same as last time\n";}
	}

	if($DEBUG)		{print "[Check4Level] "};
	if ($current != $last)
	{
 		if ($current == $LOWER)
  		{
			if($DEBUG)		{print "Perform Lower Action\n"};
			PerformActions( $id, "$desc crossed warning threshold",
							$xxx, "5", $lower_actions, $SELCode);
 		}elsif ($current == $LOWER_CRITICAL)
  		{
			if($DEBUG)		{print "Perform Lower-critical Action\n"};
			PerformActions( $id, "$desc crossed critical threshold", 
							$xxx, "4", $lower_critical_actions, $SELCode);
  		}elsif ($current == $UPPER)
  		{
			if($DEBUG)		{print "Perform Upper Action\n"};
	 		PerformActions( $id, "$desc crossed warning threshold",
							$xxx, "3", $upper_actions, $SELCode);
  		}elsif ($current == $UPPER_CRITICAL)
  		{
			if($DEBUG)		{print "Perform Upper-critical Action\n"};
			PerformActions( $id, "$desc crossed critical threshold",
							$xxx, "2", $upper_critical_actions, $SELCode);
  		}elsif ($current == $NORMAL)
  		{
			if($DEBUG)		{print "Perform NormalAction\n"};
			PerformActions( $id, "", $xxx, "1", "", "");
  		}
	}else{
  		if($DEBUG)		{print "No change\n"};
	}
	
	return $current;
}

##
## [PerformActions]
##
## Perform actions based on alert conditions.
##
sub PerformActions
{
	my ($sensor, $description, $LCDCode, $type, $actions, $SELCode) = @_;

	if($DEBUG)		{print "[PerformActions] $actions\n"};

	if ($type == 1)
	{
		## Normal is only used to clear LCD.
		#system("$CLEARTEXT > /dev/null");
		#system("$CLEARICON 5 > /dev/null");
		return;
	}
	system("$WRITETOSEL \"$SELCode\" $type > /dev/null");
	system("$LOGGER -- \"$description$SELCode\" > /dev/null");

	@ouractions = split(",", $actions);
	
	$action = pop(@ouractions);
	while($action)
	{
		if($action eq "Beep")
		{
			if($DEBUG)		{print "Beep "};
	 		system("/usr/ins/intel/bin/asm/sysBeep > /dev/null");
		}
		elsif($action eq "LANAlert")
		{
			if($DEBUG)		{print "LANAlert "};
	 		system("/usr/ins/intel/bin/asm/sysLANAlert \"$SELCode\" $type > /dev/null");
		}
		elsif($action eq "WriteToLCD")
		{
	   		if($DEBUG)		{print "WriteToLCD "};
			system("/usr/ins/intel/bin/asm/sysPFWriteToLCD \"$sensor\" $type > /dev/null");
			$lastLCD = time();
		}
		elsif($action eq "Shutdown")
		{
			if($DEBUG)		{print "Shutdown "};
			$initState = 0;
		}
		elsif($action eq "Reboot")
		{
			if($DEBUG)		{print "Reboot "};
			$initState = 6;
		}
		elsif($action eq "Page")
		{
			if($DEBUG)		{print "Page "};
  			SendPage($sensor, $type);
		}
		elsif($action eq "Email")
		{
	 		system("$EMAILALERT PF $sensor $type > /dev/null");
		}
	    elsif( ($action eq 'SNMP')  &&
		      ( -e "/usr/ins/intel/bin/asm/bakSNMPTrap") )
		{
			system("/usr/ins/intel/bin/asm/bakSNMPTrap PF$sensor $type $SNMP_DESTINATION > /dev/null");
		}
		$action = pop(@ouractions);
	}
	if($DEBUG)		{print "\n"};

}

sub SendPage
{
	my ($sensor, $type) = @_;
	my (%scode_map, $scode);
	my ($callnumber, $sendnumber);
	
	my %scode_map=(	"CPUUtil",	7,
			"MemUtil",	7,
			"Single-bit", 	7);
	$scode = $scode_map{$sensor};
	$level = ($PAGER_FORCE_IMMEDIATE eq "Yes") ? 0 : 1;
	$sendnumber = "$PAGER_STRING" . $scode . $type;
	
	system("/usr/ins/intel/bin/asm/sysSendTonePage -n -l $level -p $PAGER_NUMBER $sendnumber > /dev/null &");

}

##
## [ReadParms]
##
## Read our global variables from the configuration file.
##
sub ReadParms
{
	($PF_ENABLED, $PF_POLLING_TIME, 
 	 $PF_CPU_UTILIZATION_TRIGGER, $PF_CPU_UTILIZATION_ACTIONS,
 	 $PF_MEMORY_UTILIZATION_TRIGGER, $PF_MEMORY_UTILIZATION_ACTIONS,
 	 $PF_SINGLE_BIT_ERROR_TRIGGER, $PF_SINGLE_BIT_ERROR_ACTIONS,
 	 $PF_TEMP_UPPER_CRITICAL_TRIGGER, $PF_TEMP_UPPER_CRITICAL_ACTIONS,
 	 $PF_TEMP_UPPER_TRIGGER, $PF_TEMP_UPPER_ACTIONS,
 	 $PF_TEMP_LOWER_TRIGGER, $PF_TEMP_LOWER_ACTIONS,
 	 $PF_TEMP_LOWER_CRITICAL_TRIGGER, $PF_TEMP_LOWER_CRITICAL_ACTIONS,
 	 $PF_VOLT_UPPER_CRITICAL_TRIGGER, $PF_VOLT_UPPER_CRITICAL_ACTIONS,
 	 $PF_VOLT_UPPER_TRIGGER, $PF_VOLT_UPPER_ACTIONS,
 	 $PF_VOLT_LOWER_TRIGGER, $PF_VOLT_LOWER_ACTIONS,
 	 $PF_VOLT_LOWER_CRITICAL_TRIGGER, $PF_VOLT_LOWER_CRITICAL_ACTIONS,
	 $PAGER_NUMBER, $PAGER_STRING, $PAGER_FORCE_IMMEDIATE,
	 $SNMP_DESTINATION
 		) = ReadSensorParameters( 
			"PF_ENABLED", 
			"PF_POLLING_TIME",
			"PF_CPU_UTILIZATION_TRIGGER", "PF_CPU_UTILIZATION_ACTIONS",
			"PF_MEMORY_UTILIZATION_TRIGGER", "PF_MEMORY_UTILIZATION_ACTIONS",
			"PF_SINGLE-BIT_ERROR_TRIGGER", "PF_SINGLE-BIT_ERROR_ACTIONS",
			"PF_TEMP_UPPER_CRITICAL_TRIGGER", "PF_TEMP_UPPER_CRITICAL_ACTIONS",
			"PF_TEMP_UPPER_TRIGGER", "PF_TEMP_UPPER_ACTIONS",
			"PF_TEMP_LOWER_TRIGGER", "PF_TEMP_LOWER_ACTIONS",
			"PF_TEMP_LOWER_CRITICAL_TRIGGER", "PF_TEMP_LOWER_CRITICAL_ACTIONS",
			"PF_VOLT_UPPER_CRITICAL_TRIGGER", "PF_VOLT_UPPER_CRITICAL_ACTIONS",
			"PF_VOLT_UPPER_TRIGGER", "PF_VOLT_UPPER_ACTIONS",
			"PF_VOLT_LOWER_TRIGGER", "PF_VOLT_LOWER_ACTIONS",
			"PF_VOLT_LOWER_CRITICAL_TRIGGER", "PF_VOLT_LOWER_CRITICAL_ACTIONS",
			"PAGER_NUMBER", "PAGER_STRING", "PAGER_FORCE_IMMEDIATE",
			"SNMP_DESTINATION"
			);
	
	$POLL_INTERVAL = $PF_POLLING_TIME / 1000;
	if($POLL_INTERVAL > 2)
	{
		$POLL_INTERVAL = $POLL_INTERVAL - 1;
	}
	
	## Split tiggers into occurance and duration values.
	($CPU_UTILIZATION_OCCURANCE, $CPU_UTILIZATION_DURATION) =
								split(",", $PF_CPU_UTILIZATION_TRIGGER);
	($MEMORY_UTILIZATION_OCCURANCE, $MEMORY_UTILIZATION_DURATION) =
								split(",", $PF_MEMORY_UTILIZATION_TRIGGER);
	($SINGLE_BIT_ERROR_OCCURANCE, $SINGLE_BIT_ERROR_DURATION) =
								split(",", $PF_SINGLE_BIT_ERROR_TRIGGER);
	($TEMP_UPPER_CRITICAL_OCCURANCE, $TEMP_UPPER_CRITICAL_DURATION) =
								split(",", $PF_TEMP_UPPER_CRITICAL_TRIGGER);
	($TEMP_UPPER_OCCURANCE, $TEMP_UPPER_DURATION) =
								split(",", $PF_TEMP_UPPER_TRIGGER);
	($TEMP_LOWER_OCCURANCE, $TEMP_LOWER_DURATION) =
								split(",", $PF_TEMP_LOWER_TRIGGER);
	($TEMP_LOWER_CRITICAL_OCCURANCE, $TEMP_LOWER_CRITICAL_DURATION) =
								split(",", $PF_TEMP_LOWER_CRITICAL_TRIGGER);
	($VOLT_UPPER_CRITICAL_OCCURANCE, $VOLT_UPPER_CRITICAL_DURATION) =
								split(",", $PF_VOLT_UPPER_CRITICAL_TRIGGER);
	($VOLT_UPPER_OCCURANCE, $VOLT_UPPER_DURATION) =
								split(",", $PF_VOLT_UPPER_TRIGGER);
	($VOLT_LOWER_OCCURANCE, $VOLT_LOWER_DURATION) =
								split(",", $PF_VOLT_LOWER_TRIGGER);
	($VOLT_LOWER_CRITICAL_OCCURANCE, $VOLT_LOWER_CRITICAL_DURATION) =
								split(",", $PF_VOLT_LOWER_CRITICAL_TRIGGER);
}

##
## [ReadSensorParameters]
##
## Read and return a list of parameters from sensor configuration file.
##
sub ReadSensorParameters
{	
	return ReadParametersEngine($SENSORS_CONF, "", @_);
}

##
## [ReadParametersEngine]
##
## Read and return a list of parameters from sensor configuration file
##
sub ReadParametersEngine
{	
	my ($baseFile, $tempConfFile, @parameters) = @_;
	my $tempfile, $param_count, $at_least_one_array, $file, $i;
	my $got_it, $sep, $cmd, $params_left;
    my @return_list, @seperators;

	@separators = ("=", "_TEMP=");
	$at_least_one_array = 0;

	## See if temp file exists.
	$tempfile = ( ($tempConfFile != "") && (-e $tempConfFile ) ) ? 1 : 0;

	## Count number of parameters.
	for($param_count = 0; 
	    length($parameters[$param_count]) != ""; 
		$param_count++)
	{
		if( ref(@parameters[$param_count]) =~ "ARRAY")
		{
			$at_least_one_array = 1;		
			push(@return_list, []);
		}else{
			push(@return_list, "");
		}
	}
	
	## We read the following files:
	## 1. If temp file exists, we'll read through it first, then live conf.
	## 2. If temp file does not exist, only read live conf.
	for($file = 0; $file < ($tempfile ? 2 : 1); $file++)
	{
        if (open(fh,"< $baseFile") == 0)
		{
			print "Error opening $baseFile!\n";
			return false;
		}		
		
		$cmd = "";
		while( <fh> )
		{
			$line = $_;
			chomp($line);
			## Ignore comments.
			next if( $line =~ "/^#/" );
			
			for($i = 0; $i < $param_count; $i++)
			{
				## This is a non-array value that we already have,
				next if( !(ref(@parameters[$i]) =~ "ARRAY") &&
				    	 ($parameters[$i] eq "") );
			    
				## Loop through this line as many times as required for
				## our separators.  When reading the conf file, our command
				## separator is just "=".  For temp file reading, it can be
				## either "=" or "_TEMP=".
				$got_it = 0;
				for( $sep = 0; $sep < ($tempfile ? 2 : 1); $sep++)
				{
#					print "$sep: $parameters[$i]\n";
					## Get the command to compare.
					$cmd = ( ref(@parameters[$i]) =~ "ARRAY"
							 ? $parameters["$i"][0]
							 : $parameters[$i] ) .
							 $separators[$sep];
				  
				  	## Compare command with read line
					if(substr($line, 0, length($cmd) ) =~ "$cmd")
					{
						$got_it = 1;
						## Found it.  Add to proper place in return array.
						if( ref(@parameters[$i]) =~ "ARRAY" )
						{
							# Add to sub-array.
							($cmd, $value) = split("=", $line, 2);
							$list = @return_list[$i];
							push(@list, $value);
							$return_list[$i] = @list;
						}else{
							($cmd, $return_list[$i]) = split("=", $line, 2);
						}
					}
					last if( $got_it);
				}
			}
		 	if( !$at_least_one_array)
			{
				## If no arrays, see if we're done with all parameters.
				$params_left = 0;
				for($i = 0; $i < $param_count; $i++)
				{
					next if( !(ref(@parameters[$i]) =~ "ARRAY") &&
				    	 	 ($parameters[$i] eq "") );
					$params_left = 1;
				}
				last if( !$params_left);
			}
		}
		
		close fh;
		
	}

	return @return_list;
}
