#!/usr/local/bin/perl 
#
# check snmp readable temperature sensors 
# 
# by Doke Scott, doke@udel.edu, 23 Jun 2003

use Socket;
use Getopt::Std;

$ENV{PATH} .= "/usr/local/bin:/usr/local/net-snmp/bin";

$warning_temp = 50;  # celcius
$critical_temp = 65;  # celcius


sub usage { 
    die "Usage: $0 [-w <warn_temp>] [-c <critical_temp>] -C <community> -H <host> [-v]\n";
    }

# v = verbose
getopts( 'w:c:H:C:v' );

$warning_temp = $opt_w if ( $opt_w );
$critical_temp = $opt_c if ( $opt_c );
&usage() if ( ! $opt_H );
&usage() if ( ! $opt_C );
$host = $opt_H;
$community = $opt_C;



if ( $host =~ m/^[\d\.]+$/ ) { 
    $hostip = $host;
    $hostname = &ip2name( $host );
    }
else {
    ($a,$b,$c,$d) = unpack('C4',gethostbyname( $host ));
    $hostip = "$a.$b.$c.$d";
    $hostname = $host;
    }


&get_system( $hostip, $community ); 
if ( $sysDescr =~ m/Cisco Internetwork Operating System .* Version 12\./ ) { 
    $use_snmpv2 = 1;
    }
elsif ( $sysDescr =~ m/Cisco Catalyst Operating System.* Version 6\./ ) { 
    $use_snmpv2 = 1;
    }

&get_temp_info( $hostip, $community ); 

exit 0;

#
# end of main 
##########################




sub snmpwalk { 
    my( $fH, $host, $community, $oid ) = @_;

    if ( $use_snmpv2 ) { 
	$cmd = "snmpbulkwalk -v 2c -Oq -c $community $host $oid |";
	}
    else { 
	$cmd = "snmpwalk -v 1 -Oq -c $community $host $oid |";
	}
    $opt_v && print "cmd = '$cmd'\n";
    open( $fH, $cmd ) || die "can't snmpwalk: $!\n";
    }






# get host's system info
sub get_system { 
    my( $host, $community ) = @_;

    # why does cisco put cr/lf in the sysDescr???
    &snmpwalk( fH,  $host, $community, "system.sysDescr" );
    while ( <fH> ) { 
	chomp;
	s/\s+$/ /;
	if ( m/sysDescr\.0 (.*)/ ) { 
	    $sysDescr = $1;
	    }
	else { 
	    $sysDescr .= $_;
	    }
	}
    close fH;
    $opt_v && print "sysDescr = $sysDescr\n";

    &snmpwalk( fH,  $host, $community, "system.sysName" );
    while ( <fH> ) { 
	if ( m/sysName\.0 (.*)/ ) { 
	    $sysName = $1;
	    $opt_v && print "sysName = $sysName\n";
	    }
	}
    close fH;
    }

    





sub get_temp_info { 
    my( $host, $community ) = @_;
    my $sensorcount, $critical_exit, $warn_exit, $worst_temp, $worst_temp_desc; 

    $sensorcount = 0;
    $critical_exit = 0;
    $warn_exit = 0;
    $worst_temp = 0;
    $worst_temp_desc = "";

    # try the ciscoEnvMonMIB
    # works on 7206s, and chp-br4
    # works on 3648, but only get status, not temperature value 
    #
    &snmpwalk( fH,  $host, $community, "1.3.6.1.4.1.9.9.13.1.3.1" );
    while ( <fH> ) { 
	next unless ( m/13.1.3.1.(\d+)\.(\d+) (.+)/ );
	$col = $1;
	$row = $2;
	$val = $3;
	$envmon_mib{ $row }{ $col } = $val;
	}
    close fH;

    foreach $row ( sort { $a <=> $b } keys %envmon_mib ) { 
	if ( defined( $envmon_mib{ $row }{ 3 } ) ) { 
	    $temp = $envmon_mib{ $row }{ 3 };
	    if ( $temp > $critical_temp ) { 
		$opt_v && printf "TEMP CRITICAL - %s = %d C\n", 
		    $envmon_mib{ $row }{ 2 }, $temp;
		$critical_exit = 2;
		}
	    elsif ( $temp > $warning_temp ) { 
		$opt_v && printf "TEMP WARNING - %s = %d C\n", 
		    $envmon_mib{ $row }{ 2 }, $temp;
		$warn_exit = 1;
		}
	    else { 
		$opt_v && printf "TEMP OK - %s = %d C\n", 
		    $envmon_mib{ $row }{ 2 }, $temp;
		}
	    if ( $temp > $worst_temp ) { 
		$worst_temp = $temp;
		$worst_temp_desc = $envmon_mib{ $row }{ 2 };
		}
	    $sensor_count++;
	    }
	elsif ( defined( $envmon_mib{ $row }{ 6 } ) ) {
	    $state = $envmon_mib{ $row }{ 6 };
	    # snmp values: 1 ok, 2 warning, 3 critical, 4 shutdown, 
	    #     5 not present, 6 not functioning
	    # nagios return codes: -1 unknown, 0 ok, 1 warning, 2 critical
	    if ( $state == 3 ) { 
		$opt_v && printf "TEMP CRITICAL - %s\n", 
		    $envmon_mib{ $row }{ 2 };
		$critical_exit = 2;
		}
	    elsif ( $state == 2 ) { 
		$opt_v && printf "TEMP WARNING - %s\n", 
		    $envmon_mib{ $row }{ 2 };
		$warn_exit = 1;
		}
	    else { 
		$opt_v && printf "TEMP OK - %s\n", $envmon_mib{ $row }{ 2 };
		}
	    if ( $temp >= $worst_temp ) { 
		$worst_temp = "";
		$worst_temp_desc = $envmon_mib{ $row }{ 2 };
		}
	    $sensor_count++;
	    }
	}



    # pull entityMIB.entityMIBObjects.entityPhysical.entPhysicalTable
    # for names of sensors
    &snmpwalk( fH,  $host, $community, "1.3.6.1.2.1.47.1.1.1.1.2" );
    while ( <fH> ) { 
	next unless ( m/\.(\d+) (.+)/ );
	$col = "entPhysicalDescr";
	$row = $1;
	$val = $2;
	$entPhysicalDescr{ $row } = $val;
	}
    close fH;



    # try the entitySensorMIB
    # this works on catalyst 6509
    &snmpwalk( fH,  $host, $community, "1.3.6.1.4.1.9.9.91.1.1" );
    while ( <fH> ) { 
	next unless ( m/91.1.1.1.1.(\d+)\.(\d+) (.+)/ );
	$col = $1;
	$row = $2;
	$val = $3;
	$sensor_mib{ $row }{ $col } = $val;
	}
    close fH;

    foreach $row ( sort { $a <=> $b } keys %sensor_mib ) { 
	if ( $sensor_mib{ $row }{ 1 } == 8   # type celsius
		&& $sensor_mib{ $row }{ 5 } == 1  )  {  # sensor status ok
	    $temp = $sensor_mib{ $row }{ 4 };
	    if ( $temp > $critical_temp ) { 
		$opt_v && printf "TEMP CRITICAL - %s = %d C\n", 
		    $entPhysicalDescr{ $row }, $temp;
		$critical_exit = 2;
		}
	    elsif ( $temp > $warning_temp ) { 
		$opt_v && printf "TEMP WARNING - %s = %d C\n", 
		    $entPhysicalDescr{ $row }, $temp;
		$warn_exit = 1;
		}
	    else { 
		$opt_v && printf "TEMP OK - %s = %d C\n", 
		    $entPhysicalDescr{ $row }, $temp;
		$good++;
		}
	    if ( $temp > $worst_temp ) { 
		$worst_temp = $temp;
		$worst_temp_desc = $entPhysicalDescr{ $row };
		}
	    $sensor_count++;
	    }
	}

    if ( $critical_exit ) { 
	printf "TEMP CRITICAL - %s = %d C\n", $worst_temp_desc, $worst_temp;
	exit 2;   # nagios critical exit code
	}
    elsif ( $warn_exit ) { 
	printf "TEMP Warning - %s = %d C\n", $worst_temp_desc, $worst_temp;
	exit 1;   # nagios warn exit code
	}
    elsif ( ! $sensor_count ) { 
	printf "TEMP UNKNOWN - no temperature sensors found\n";
	exit -1;
	}
    else { 
	printf "TEMP OK - %s = %d C\n", $worst_temp_desc, $worst_temp;
	}
    }





sub ip2name { 
    my( $ipaddr ) = @_;
    $ippat = '(\d+)\.' x 3 . '(\d+)';
    $ipaddr =~ m/$ippat/o;
    $themaddr = pack( "C4", $1, $2, $3, $4 );
    $host = gethostbyaddr( $themaddr, &AF_INET );
    $host = "unknown" if ! $host;
    return $host;
    }
    









