#! perl -w

=head1 NAME

check_perfcnt.pl - Checks Raw Performance Counters.

=head1 VERSION

Version 1.1

=head1 AUTHOR

(c) 2003 Hannes Schulz <mail@hannes-schulz.de>

=head1 SYNOPSIS

Usage: $0 --object <Object> --counter <Counter> [ -w <wlevel> -c <clevel> ] [--interval <sec>]

  <Object>    --  for example NTDS
  <Counter>   --  for example "DRA Inbound Bytes Compressed Since Boot"
  <sec>       --  interval (default: 30*60 seconds)
  <wlevel>    --  warning,  if difference to last value is greater than this
  <clevel>    --  critical, if difference to last value is greater than this

=head1 DESCRIPTION

This is used to read continually rising counters. The return string will
contain a list of day and hour values, where the hour values are resetted in
the interval given. The day values are resetted if the recorded data is from
another day of the month.

Data is stored in files made from hashing the Counter name.

=cut


BEGIN{
	use lib "C:/adm/nagios";
}
use Win32::PerfLib;
use Getopt::Long;
use MD5;
use strict;


my ($level1,$level2,$wlevel,$clevel,$interval);

GetOptions(
  "object=s"  => \$level1,
  "counter=s" => \$level2,
  "interval=i" => \$interval,
  "w|wlevel=i"    => \$wlevel,
  "c|clevel=i"    => \$clevel
);

# set default values
$interval ||= 30*60;
$wlevel ||= 99999999998;
$clevel ||= 99999999999;

# Parameter checks
unless ($level1 and $level2){ printHelp(); }
if(($wlevel and not $clevel) or ($clevel and not $wlevel)){ printHelp(); }
if($wlevel and ($wlevel>$clevel)){ printHelp(); }

# read new value of counter
my $c = readcounter("",$level1,$level2);

# create file name from hash
my $file = "c:/adm/nagios/l" . MD5::md5_hex("$level1 $level2") . ".log";

my $timet = scalar time;

# File does not exist, so write it...
unless (-e $file){
	writefile($file,$timet, $c,$timet,$c);
	nagios(0,0,0);
}

# File does exist, so read it...
my ($coht,$coh,$codt,$cod) = readfile($file);

my ($writed,$writeh) = (0,0);

# Figure out, which values are "outdated".
$writeh=1 if($coht<$timet-$interval);                      # too old
$writed=1 if((localtime($codt))[3] != (localtime($timet))[3]); # different day

# Sort out negative values
if($c-$coh<0){
	$writeh = 1;
	$coh=$c;
};
if($c-$cod<0){
	$writed = 1;
	$cod=$c;
};

# write file.
writefile($file,
  $writeh?$timet:$coht,
  $writeh?$c:$coh,
  $writed?$timet:$codt,
  $writed?$c:$cod
);

# calculate return value for Nagios
my $ret = 0;
if($c-$coh > $wlevel){$ret = 1};  # Warning
if($c-$coh > $clevel){$ret = 2};  # Critical

# Return string and value
nagios(
	$c-$coh,
	$c-$cod,
	$ret
);



### subs

sub nagios{
	print "hour=", shift(), " day=", shift();
	exit(shift()); 
}


sub readfile{

  open(IN,"<". shift()) or die "Could not open $file: $!\n";
  my ($coht,$coh) = split /:/,<IN>;
  my ($codt,$cod) = split /:/,<IN>;

  unless(defined $coht and defined $coh and defined $codt and defined $cod){
    warn "Content error in $file: restarting.";
    writefile($file,scalar time, $c,scalar time,$c);
		nagios(0,0,1);
  }
  close IN;

  return($coht,$coh,$codt,$cod);
}


sub writefile{
	open(OUT,">".shift()) or die "Could not open file for writing: $!\n";
	print OUT shift(),":",shift(),":\n",shift(),":",shift(),":";
}


sub printHelp{
	print<<EOT
Usage: $0 --object <Object> --counter <Counter> [ -w <wlevel> -c <clevel> ] [--interval <sec>]

  <Object>    --  for example NTDS
  <Counter>   --  for example "DRA Inbound Bytes Compressed Since Boot"
  <sec>       --  interval (default: 30*60 seconds)
  <wlevel>    --  warning,  if difference to last value is greater than this
  <clevel>    --  critical, if difference to last value is greater than this

EOT
	;exit 2
}

sub readcounter{
  my $machine = shift();
  my $level1  = shift();
  my $level2  = shift();

  my $perf = new Win32::PerfLib($machine);
  die "Can't open PerfLib of $machine!\n" unless($perf);

  my ($o,$Numerator,$Denominator,$TimeBase);

  my (%nrefs,%objlist); 
  die "Could not get CounterNames!\n" unless (Win32::PerfLib::GetCounterNames($machine,\%nrefs));
  die "Could not get ObjectList!\n"   unless ($perf->GetObjectList($machine, \%objlist));

  $perf->Close();

  my $base = $objlist{Objects};
  my $object = "";
  foreach $o (keys %$base){
    if($nrefs{$base->{$o}->{ObjectNameTitleIndex}} eq $level1){
      $object = $o;
      last
    }
  }

  die "Could not find $level1!\n" unless $object;

  my $counter = "";
  $base = $objlist{Objects}->{$object}->{Counters};
  foreach $o (keys %$base){
    if($nrefs{$base->{$o}->{CounterNameTitleIndex}} eq $level2){
      $counter = $o;
      last
    }
  }
  die "Could not find '$level2' in '$level1'!\n" unless $counter;

  $base = $base->{$counter};

  $Numerator   = $base->{Counter};
  $Denominator = $objlist{PerfTime};
  $TimeBase    = $objlist{PerfFreq};
  return $Numerator;
}
