#!/usr/bin/perl -w
#
# check_usr - nagios plugin 
#
# by Frank Bulk <frnkblk@iname.com> 
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#

use strict;
use Net::SNMP;
use Getopt::Long;
use File::Basename;
&Getopt::Long::config('auto_abbrev');
use IO::Socket;

my $sw_version = "1.0";
my $status;
my $needhelp = '';
my $TIMEOUT = 30;

my %ERRORS = (
	'OK'       => '0',
	'WARNING'  => '1',
	'CRITICAL' => '2',
	'UNKNOWN'  => '3',
);

# default return value is UNKNOWN
my $state = "UNKNOWN";

# time this script was run
my $runtime = time();

# responses from script
my $answer = "";
my $oidmsg = "";
my $error;
my $oidwarn = 0;
my $oidcrit = 0;
my @oid_array;
my $device_num;
my $output_num;
my $index;
my $module_descr;
my $sensor_descr;
my $sensor_num;
my $sensor_oid;
my @sensor_oid_array;
my $failure_count;
my $warning_count;
my $temp;

# external variable declarations
my $hostname;
my $community = "public";
my $port = 161;
my $version = "1";
my @ignorestring;
my $major;
my $minor;
my %alarmstate;
$alarmstate{minor} = 0;
$alarmstate{major} = 0;
my %nmcStatStatus;
$nmcStatStatus{1} = "other";
$nmcStatStatus{2} = "ok";
$nmcStatStatus{3} = "nonCriticalFailure";
my %uchasPowerSupplyOperStatus;
$uchasPowerSupplyOperStatus{1} = "unknown";
$uchasPowerSupplyOperStatus{2} = "bad";
$uchasPowerSupplyOperStatus{3} = "good";
$uchasPowerSupplyOperStatus{4} = "empty";
my %uchasPowerSupplyOutStatus;
$uchasPowerSupplyOutStatus{1} = "unknown";
$uchasPowerSupplyOutStatus{2} = "warning";
$uchasPowerSupplyOutStatus{3} = "good";
my %uchasEnvironStatus;
$uchasEnvironStatus{1} = "unknown";
$uchasEnvironStatus{2} = "bad";
$uchasEnvironStatus{3} = "warning";
$uchasEnvironStatus{4} = "good";
my $response;

# snmp related variables
my $snmpkey;
my $snmpoid;
my $current_oid;
my $next_oid;
my $last_oid;
my %bla;
my $key;

## main program

# Just in case of problems, let's not hang 
$SIG{'ALRM'} = sub {
	print ("ERROR: No snmp response from $hostname (alarm)\n");
	exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);

# we must have -some- arguments
if (scalar(@ARGV) == 0) {
	usage();
} # end if no options

Getopt::Long::Configure("no_ignore_case");
$status = GetOptions(
	"h|help"             => \$needhelp,
	"C|snmpcommunity=s"  => \$community,
	"p|port=i"           => \$port,
	"H|hostname=s"       => \$hostname,
	"v|version=s"        => \$version,
);

if ($status == 0 || $needhelp) {
	usage();
} # end if getting options fails or the user wants help

# check NMC status
$temp = snmp_get_request($hostname, $port, $version, $community, "1.3.6.1.4.1.429.1.2.2.1.0"); 
if ($temp ne "2") {
#print "DEBUG: temp [$temp]\n";
	$oidmsg = $oidmsg . "\nNMC status: $nmcStatStatus{$temp}";
	$alarmstate{minor}++;
}

# check Power Supply
%bla = snmp_get_table($hostname, $port, $version, $community, "1.3.6.1.4.1.429.1.1.4.1.1.3");
foreach my $key (keys %bla) {
	if (($bla{$key} eq 1) || ($bla{$key} eq 2)) {
		@oid_array = split (/\./, $key);
		$device_num = pop(@oid_array);
		$index = "1.3.6.1.4.1.429.1.1.4.1.1.2." . $device_num;
		$module_descr = snmp_get_request($hostname, $port, $version, $community, $index);
		$index = "1.3.6.1.4.1.429.1.1.4.1.1.4." . $device_num;
		$failure_count = snmp_get_request($hostname, $port, $version, $community, $index);
		$oidmsg = $oidmsg . "\nPower supply $device_num ($module_descr) has a status of '$uchasPowerSupplyOperStatus{$bla{$key}}' and has had $failure_count failures";
		$alarmstate{major}++;
	}
}

# check Power Supply Outputs
$current_oid = "1.3.6.1.4.1.429.1.1.4.2.1.3";
($next_oid, $response) = snmp_get_next($hostname, $port, $version, $community, $current_oid);
while ($next_oid ne $current_oid) {
#print "DEBUG: current_oid [$current_oid]\n";
#print "DEBUG: next_oid [$next_oid]\n";
#print "DEBUG: response [$response]\n";
	if ($response eq 2) {
		@oid_array = split (/\./, $next_oid);
		$output_num = pop(@oid_array);
		$device_num = pop(@oid_array);
		$index = "1.3.6.1.4.1.429.1.1.4.1.1.2." . $device_num;
		$module_descr = snmp_get_request($hostname, $port, $version, $community, $index);
		$oidmsg = $oidmsg . "\nPower supply $device_num ($module_descr) output $output_num has a status of '$uchasPowerSupplyOutStatus{$response}'";
		$alarmstate{minor}++;
	}
	$last_oid = $current_oid;
	$current_oid = $next_oid;
	($next_oid, $response) = snmp_get_next($hostname, $port, $version, $community, $current_oid);
}

# check Environmental status
%bla = snmp_get_table($hostname, $port, $version, $community, "1.3.6.1.4.1.429.1.1.5.1.1.3");
foreach my $key (keys %bla) {
	if ($bla{$key} ne 4) {
		@oid_array = split (/\./, $key);
		$device_num = pop(@oid_array);
		$index = "1.3.6.1.4.1.429.1.1.5.1.1.2." . $device_num;
		$sensor_oid = snmp_get_request($hostname, $port, $version, $community, $index);
		@sensor_oid_array = split (/\./, $sensor_oid);
		$sensor_num = pop(@sensor_oid_array);
		if ($sensor_num eq 1) {
			$sensor_descr = "other";
		}
		elsif ($sensor_num eq 2) {
			$sensor_descr = "temperature";
		}
		elsif ($sensor_num eq 3) {
			$sensor_descr = "fans";
		}
		else {
			$sensor_descr = "unknown";
		}
		$index = "1.3.6.1.4.1.429.1.1.5.1.1.4." . $device_num;
		$warning_count = snmp_get_request($hostname, $port, $version, $community, $index);
		$index = "1.3.6.1.4.1.429.1.1.5.1.1.5." . $device_num;
		$failure_count = snmp_get_request($hostname, $port, $version, $community, $index);
		$oidmsg = $oidmsg . "\nSensor \'$sensor_descr\' has a status of \'$uchasEnvironStatus{$bla{$key}}\' and has had $warning_count warning(s) and $failure_count failure(s)";
		if ($failure_count) {	
			$alarmstate{major}++;
		}
		else {
			$alarmstate{minor}++;
		}
	}
}

# figure out what state we're in
if ($alarmstate{major}) {
	$state = "CRITICAL";
} elsif ($alarmstate{minor}) {
	$state = "WARNING";
} else {
	$state = "OK";
} # end if we have warnings or not

# setup final message
$answer = "critical: $alarmstate{major}, warning: $alarmstate{minor}$oidmsg";
print ("$state: $answer\n");
exit $ERRORS{$state};


## subroutines ##




# figure out what state we're in
if ($alarmstate{major}) {
	$state = "CRITICAL";
} elsif ($alarmstate{minor}) {
	$state = "WARNING";
} else {
	$state = "OK";
} # end if we have warnings or not

# setup final message
$answer = "critical: $alarmstate{major}, warning: $alarmstate{minor}$oidmsg";
print ("$state: $answer\n");
exit $ERRORS{$state};


## subroutines ##

# the usage of this program (duh)
sub usage
{
	print <<END;
== check_usr v$sw_version ==
Perl SNMP check U.S. Robotics/3COM TotalControl RAS plugin for Nagios
Frank Bulk <frnkblk\@iname.com>

Usage:
  check_usr (-C|--snmpcommunity) <read_community>
                 (-H|--hostname) <hostname>
                 [-p|--port] <port> 

END
	exit $ERRORS{"UNKNOWN"};
}

sub snmp_get_request {
        my $ip = shift;
	my $port = shift;
        my $version = shift;
	my $community = shift;
        my $sysdescr = shift;

        my $snmp_result = '';

        my ($session, $error) = Net::SNMP->session(
                -hostname => $ip,
                -version => $version,
                -community => $community,
                -port => $port);

        $snmp_result = $session->get_request(
                -varbindlist => [$sysdescr]
                );

        if (!defined($snmp_result)) {
#               print "\nERROR: Trying to obtain $sysdescr from $ip. $session->error.\n";
                sleep 5;
                $snmp_result = $session->get_request(
                        -varbindlist => [$sysdescr]
                );
                if (!defined($snmp_result)) {
                        print "\nERROR: Trying to obtain $sysdescr from $ip. $session->error.\n";
                        $session->close;
                        return 0;
                }
        }

        $session->close;

        return $snmp_result->{$sysdescr};
}

sub snmp_get_table {
        my $ip = shift;
	my $port = shift;
	my $version = shift;
	my $community = shift;
        my $snmp_oid = shift;
#print "DEBUG: snmp_oid [$snmp_oid]\n";

        my ($session, $error) = Net::SNMP->session(
                -hostname => $ip,
                -community => $community,
		-version => $version,
                -timeout => 10,
                -port => $port,
        );

        my $snmp_result = $session->get_table(
                -baseoid => $snmp_oid
        );

        if (!defined($snmp_result)) {
#               print "ERROR: $session->error.\n";
                $session->close;
		return;
#		exit 1;
        }

        $session->close;

        return %{$snmp_result};
}

sub snmp_get_next {
        my $ip = shift;
	my $port = shift;
	my $version = shift;
	my $community = shift;
        my $snmp_oid = shift;

        my $new_oid;
        my $snmp_result;
	my $value;

        my ($session, $error) = Net::SNMP->session(
                -hostname => $ip,
                -community => $community,
                -version => $version,
                -port => $port);

        $snmp_result = $session->get_next_request(
                -varbindlist => [$snmp_oid]
                );

        if (!defined($snmp_result)) {
		return ($snmp_oid, "");
#                print "ERROR: Trying to get $snmp_oid on $ip: '" . $session->error . "'.\n";
#                $session->close;
#                exit 1;
        }

        $session->close;

        return %$snmp_result;
}

