package SNMPstat;

use strict;
use vars qw($session @ISA @EXPORT);

require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(getDiskStats getMemStats getLoadStats getProcStats getSysInfo);

use SNMP;
my $session=new SNMP::Session();

# We can either use the dotted decimal notation or
# the named notation. I'm using the decimal notation here
# when it is more compact.

# System info MIB
my %sys=(
	"system.sysContact"  => "sysContact",
        "system.sysDescr"    => "sysDescription",
        "system.sysName"     => "sysName",

# 	This is actually the snmpd uptime.
#        "system.sysUpTime"   => "sysUpTime",

#	This is the system uptime, in TimeTicks (100 per second).
	"host.hrSystem.hrSystemUptime" => "sysUpTime",

        "system.sysLocation" => "sysLocation"
        );

# Disk Usage MIB
my %disk=(
	".1.3.6.1.4.1.2021.9.1.1" => "disk.Index",
	".1.3.6.1.4.1.2021.9.1.2" => "disk.Path",
	".1.3.6.1.4.1.2021.9.1.3" => "disk.Device",
	".1.3.6.1.4.1.2021.9.1.4" => "disk.RedLimit",
	".1.3.6.1.4.1.2021.9.1.5" => "disk.RedLimitPct",
	".1.3.6.1.4.1.2021.9.1.6" => "disk.Total",
	".1.3.6.1.4.1.2021.9.1.7" => "disk.Avail",
	".1.3.6.1.4.1.2021.9.1.8" => "disk.Used",
	".1.3.6.1.4.1.2021.9.1.9" => "disk.UsedPct"
	);

# Load Average MIB
my %load=(
        ".1.3.6.1.4.1.2021.10.1.6" => "load.LoadFloat",
        ".1.3.6.1.4.1.2021.10.1.4" => "load.RedLimit",
        ".1.3.6.1.4.1.2021.10.1.3" => "load.Load",
        ".1.3.6.1.4.1.2021.10.1.1" => "load.Index",
        ".1.3.6.1.4.1.2021.10.1.5" => "load.LoadInt",
        ".1.3.6.1.4.1.2021.10.1.2" => "load.Name",
            );

# Memory MIB
my %memory=(
        ".1.3.6.1.4.1.2021.4.11" => "mem.TotalFree",
        ".1.3.6.1.4.1.2021.4.12" => "mem.MinimumSwap",
        ".1.3.6.1.4.1.2021.4.3"  => "mem.TotalSwap",
        ".1.3.6.1.4.1.2021.4.5"  => "mem.TotalReal",
        ".1.3.6.1.4.1.2021.4.4"  => "mem.AvailSwap",
        ".1.3.6.1.4.1.2021.4.1"  => "mem.Index",
        ".1.3.6.1.4.1.2021.4.6"  => "mem.AvailReal",
        ".1.3.6.1.4.1.2021.4.2"  => "mem.ErrorName"
            );

# Process MIB
my %process=(
        ".1.3.6.1.4.1.2021.2.1.1" => "proc.Index",
        ".1.3.6.1.4.1.2021.2.1.2" => "proc.Name",
        ".1.3.6.1.4.1.2021.2.1.3" => "proc.MinCount",
        ".1.3.6.1.4.1.2021.2.1.4" => "proc.MaxCount",
        ".1.3.6.1.4.1.2021.2.1.5" => "proc.Count",
            );

sub getMemStats {
  my %memdata;
  my $memlist=new SNMP::VarList();

  # Build up the VarList
  map {
    push @{$memlist}, ( [ $_, 0 ] );
  } keys %memory;

  # Retrieve data
  # varlist is a X by 4 2D array, each row is a SNMP::VarBind array
  $session->get($memlist);

  die $session->{ErrorStr} if($session->{ErrorStr});

  # Make a hash keyed by the values of the lookup hash
  foreach my $n (0 .. scalar(@{$memlist}-1)) {
    $memdata{$memory{$memlist->[$n][0]}}=$memlist->[$n][2];
  }

  return \%memdata;
}

sub getLoadStats {
  my @loaddata;
  my $loadlist=new SNMP::VarList();

  # Build up the VarList
  for my $d (1 .. 3) { # 0, 5, 15 minute load averages
    map {
      push @{$loadlist}, ( [ $_, $d ] );
    } keys %load;
  }

  # Retrieve data
  $session->get($loadlist);

  die $session->{ErrorStr} if($session->{ErrorStr});

  # Make an arrays of hashes keyed by the values of the load hash
  foreach my $n (0 .. scalar(@{$loadlist}-1)) {
    $loaddata[$loadlist->[$n][1]]->{$load{$loadlist->[$n][0]}}=$loadlist->[$n][2];
  }

  return \@loaddata;
}

sub getProcStats {
  my @procdata;
  my $proclist=new SNMP::VarList();

  # first determine how many procs entries by walking the sub-tree.
  # the only way to do it!
  my $entries=0;
  do {
    $session->get(new SNMP::VarList([".1.3.6.1.4.1.2021.2.1.1",++$entries]));
  } until($session->{ErrorNum});

  --$entries;

  # Build up the VarList
  for my $d (1 .. $entries) {
    map {
      push @{$proclist}, ( [ $_, $d ] );
    } keys %process;
  }

  # Retrieve data
  $session->get($proclist);

  die $session->{ErrorStr} if($session->{ErrorStr});

  # Make an arrays of hashes keyed by the values of the process hash
  foreach my $n (0 .. scalar(@{$proclist}-1)) {
    $procdata[$proclist->[$n][1]]->{$process{$proclist->[$n][0]}}=$proclist->[$n][2];
  }

  return \@procdata;
}

sub getDiskStats {
  my @diskdata;
  my $disklist=new SNMP::VarList();

  # first determine how many disk entries by walking the sub-tree.
  # the only way to do it!
  my $entries=0;
  do {
    $session->get(new SNMP::VarList([".1.3.6.1.4.1.2021.9.1.1",++$entries]));
  } until($session->{ErrorNum});

  --$entries;


  # Build up the VarList
  for my $d (1 .. $entries) {
    map {
      push @{$disklist}, ( [ $_, $d ] );
    } keys %disk;
  }

  # Retrieve data
  $session->get($disklist);

  die $session->{ErrorStr} if($session->{ErrorStr});

  # Make an arrays of hashes keyed by the values of the disk hash
  foreach my $n (0 .. scalar(@{$disklist}-1)) {
    $diskdata[$disklist->[$n][1]]->{$disk{$disklist->[$n][0]}}=$disklist->[$n][2];
  }

  return \@diskdata;
}

sub getSysInfo {
  my %sysdata;
  # Basic system info
  my $syslist=new SNMP::VarList();

  map {
    push @{$syslist}, ( [ $_, 0 ] );
  } keys %sys;
	
  $session->get($syslist);

  die $session->{ErrorStr} if($session->{ErrorStr});

  foreach my $n (0 .. scalar(@{$syslist}-1)) {
    $sysdata{$sys{$syslist->[$n][0]}}=$syslist->[$n][2];
  }

  return \%sysdata;
}