#!/usr/bin/perl -w 
############################## check_snmp_env #################
# Version : 1.3
# Date : May 24 2007
# Author  : Patrick Proy ( patrick at proy.org)
# Help : http://www.manubulon.com/nagios/
# License : GPL - http://www.fsf.org/licenses/gpl.txt
# Changelog :
# Contributors : Fredrik Vocks
#################################################################
#
# Help : ./check_snmp_env.pl -h
#

use strict;
use Net::SNMP;
use Getopt::Long;

# Icinga specific
my $TIMEOUT = 15;
my %ERRORS = ('OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'UNKNOWN' => 3, 'DEPENDENT' => 4);

my @Nagios_state = ("UNKNOWN", "OK", "WARNING", "CRITICAL");    # Nagios states coding

# SNMP Datas

# CISCO-ENVMON-MIB
my $ciscoEnvMonMIB = "1.3.6.1.4.1.9.9.13";    # Cisco env base table
my %CiscoEnvMonState
    = (1, "normal", 2, "warning", 3, "critical", 4, "shutdown", 5, "notPresent", 6, "notFunctioning");    # Cisco states
my %CiscoEnvMonNagios
    = (1, 1, 2, 2, 3, 3, 4, 3, 5, 0, 6, 3);    # Nagios states returned for CIsco states (coded see @Nagios_state).
my $ciscoVoltageTable      = $ciscoEnvMonMIB . ".1.2.1";    # Cisco voltage table
my $ciscoVoltageTableIndex = $ciscoVoltageTable . ".1";     #Index table
my $ciscoVoltageTableDesc  = $ciscoVoltageTable . ".2";     #Description
my $ciscoVoltageTableValue = $ciscoVoltageTable . ".3";     #Value
my $ciscoVoltageTableState = $ciscoVoltageTable . ".7";     #Status

# CiscoEnvMonVoltageStatusEntry ::=
# 1 ciscoEnvMonVoltageStatusIndex   Integer32 (0..2147483647),
# 2 ciscoEnvMonVoltageStatusDescr   DisplayString,
# 3 ciscoEnvMonVoltageStatusValue   CiscoSignedGauge,
# 4 ciscoEnvMonVoltageThresholdLow  Integer32,
# 5 ciscoEnvMonVoltageThresholdHigh Integer32,
# 6 ciscoEnvMonVoltageLastShutdown  Integer32,
# 7 ciscoEnvMonVoltageState         CiscoEnvMonState
my $ciscoTempTable      = $ciscoEnvMonMIB . ".1.3.1";    # Cisco temprature table
my $ciscoTempTableIndex = $ciscoTempTable . ".1";        #Index table
my $ciscoTempTableDesc  = $ciscoTempTable . ".2";        #Description
my $ciscoTempTableValue = $ciscoTempTable . ".3";        #Value
my $ciscoTempTableState = $ciscoTempTable . ".6";        #Status

# CiscoEnvMonTemperatureStatusEntry ::=
# ciscoEnvMonTemperatureStatusIndex       Integer32 (0..2147483647),
# ciscoEnvMonTemperatureStatusDescr       DisplayString,
# ciscoEnvMonTemperatureStatusValue       Gauge32,
# ciscoEnvMonTemperatureThreshold         Integer32,
# ciscoEnvMonTemperatureLastShutdown      Integer32,
# ciscoEnvMonTemperatureState             CiscoEnvMonState
my $ciscoFanTable      = $ciscoEnvMonMIB . ".1.4.1";    # Cisco fan table
my $ciscoFanTableIndex = $ciscoFanTable . ".1";         #Index table
my $ciscoFanTableDesc  = $ciscoFanTable . ".2";         #Description
my $ciscoFanTableState = $ciscoFanTable . ".3";         #Status

# CiscoEnvMonFanStatusEntry ::=
# ciscoEnvMonFanStatusIndex       Integer32 (0..2147483647),
# ciscoEnvMonFanStatusDescr       DisplayString,
# ciscoEnvMonFanState             CiscoEnvMonState
my $ciscoPSTable      = $ciscoEnvMonMIB . ".1.5.1";    # Cisco power supply table
my $ciscoPSTableIndex = $ciscoPSTable . ".1";          #Index table
my $ciscoPSTableDesc  = $ciscoPSTable . ".2";          #Description
my $ciscoPSTableState = $ciscoPSTable . ".3";          #Status

# CiscoEnvMonSupplyStatusEntry ::=
# ciscoEnvMonSupplyStatusIndex    Integer32 (0..2147483647),
# ciscoEnvMonSupplyStatusDescr    DisplayString,
# ciscoEnvMonSupplyState          CiscoEnvMonState,
# ciscoEnvMonSupplySource         INTEGER

# Nokia env mib
my $nokia_temp_tbl   = "1.3.6.1.4.1.94.1.21.1.1.5";
my $nokia_temp       = "1.3.6.1.4.1.94.1.21.1.1.5.0";
my $nokia_fan_table  = "1.3.6.1.4.1.94.1.21.1.2";
my $nokia_fan_status = "1.3.6.1.4.1.94.1.21.1.2.1.1.2";
my $nokia_ps_table   = "1.3.6.1.4.1.94.1.21.1.3";
my $nokia_ps_temp    = "1.3.6.1.4.1.94.1.21.1.3.1.1.2";
my $nokia_ps_status  = "1.3.6.1.4.1.94.1.21.1.3.1.1.3";

# Bluecoat env mib
my @bc_SensorCode = (
    "",                        "ok",                   "unknown",                  "not-installed",
    "voltage-low-warning",     "voltage-low-critical", "no-power",                 "voltage-high-warning",
    "voltage-high-critical",   "voltage-high-severe",  "temperature-high-warning", "temperature-high-critical",
    "temperature-high-severe", "fan-slow-warning",     "fan-slow-critical",        "fan-stopped"
);    # BC element status returned by MIB
my @bc_status_nagios = (3, 0, 3, 3, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2);    # nagios status equivallent to BC status
my @bc_SensorStatus = ("", "ok", "unavailable", "nonoperational");          # ok(1),unavailable(2),nonoperational(3)
my @bc_mesure = ("", "", "", "Enum", "volts", "celsius", "rpm");

my @bc_DiskStatus
    = ("", "present", "initializing", "inserted", "offline", "removed", "not-present", "empty", "bad", "unknown");
my @bc_dsk_status_nagios = (3, 0, 0, 1, 1, 1, 2, 2, 2, 3);

my $bc_sensor_table  = "1.3.6.1.4.1.3417.2.1.1.1.1.1";                      # sensor table
my $bc_sensor_units  = "1.3.6.1.4.1.3417.2.1.1.1.1.1.3";                    # cf bc_mesure
my $bc_sensor_Scale  = "1.3.6.1.4.1.3417.2.1.1.1.1.1.4";                    # * 10^value
my $bc_sensor_Value  = "1.3.6.1.4.1.3417.2.1.1.1.1.1.5";                    # value
my $bc_sensor_Code   = "1.3.6.1.4.1.3417.2.1.1.1.1.1.6";                    # bc_SensorCode
my $bc_sensor_Status = "1.3.6.1.4.1.3417.2.1.1.1.1.1.7";                    # bc_SensorStatus
my $bc_sensor_Name   = "1.3.6.1.4.1.3417.2.1.1.1.1.1.9";                    # name

my $bc_dsk_table  = "1.3.6.1.4.1.3417.2.2.1.1.1.1";                         #disk table
my $bc_dsk_status = "1.3.6.1.4.1.3417.2.2.1.1.1.1.3";                       # cf 	bc_DiskStatus
my $bc_dsk_vendor = "1.3.6.1.4.1.3417.2.2.1.1.1.1.5";                       # cf 	bc_DiskStatus
my $bc_dsk_serial = "1.3.6.1.4.1.3417.2.2.1.1.1.1.8";                       # cf 	bc_DiskStatus

# Ironport env mib

my $iron_ps_table  = "1.3.6.1.4.1.15497.1.1.1.8";                           # ps table
my $iron_ps_status = "1.3.6.1.4.1.15497.1.1.1.8.1.2";                       # ps status

#powerSupplyNotInstalled(1), powerSupplyHealthy(2), powerSupplyNoAC(3), powerSupplyFaulty(4)
my @iron_ps_status_name = ("", "powerSupplyNotInstalled", "powerSupplyHealthy", "powerSupplyNoAC", "powerSupplyFaulty");
my @iron_ps_status_nagios = (3, 3, 0, 2, 2);
my $iron_ps_ha            = "1.3.6.1.4.1.15497.1.1.1.8.1.3";                # ps redundancy status

#powerSupplyRedundancyOK(1), powerSupplyRedundancyLost(2)
my @iron_ps_ha_name = ("", "powerSupplyRedundancyOK", "powerSupplyRedundancyLost");
my @iron_ps_ha_nagios = (3, 0, 1);
my $iron_ps_name = "1.3.6.1.4.1.15497.1.1.1.8.1.4";                         # ps name

my $iron_tmp_table   = "1.3.6.1.4.1.15497.1.1.1.9";                         # temp table
my $iron_tmp_celcius = "1.3.6.1.4.1.15497.1.1.1.9.1.2";                     # temp in celcius
my $iron_tmp_name    = "1.3.6.1.4.1.15497.1.1.1.9.1.3";                     # name

my $iron_fan_table = "1.3.6.1.4.1.15497.1.1.1.10";                          # fan table
my $iron_fan_rpm   = "1.3.6.1.4.1.15497.1.1.1.10.1.2";                      # fan speed in RPM
my $iron_fan_name  = "1.3.6.1.4.1.15497.1.1.1.10.1.3";                      # fan name

# Foundry BigIron Router Switch (FOUNDRY-SN-AGENT-MIB)

my $foundry_temp       = "1.3.6.1.4.1.1991.1.1.1.1.18.0";                   # Chassis temperature in Deg C *2
my $foundry_temp_warn  = "1.3.6.1.4.1.1991.1.1.1.1.19.0";                   # Chassis warn temperature in Deg C *2
my $foundry_temp_crit  = "1.3.6.1.4.1.1991.1.1.1.1.20.0";                   # Chassis warn temperature in Deg C *2
my $foundry_ps_table   = "1.3.6.1.4.1.1991.1.1.1.2.1";                      # PS table
my $foundry_ps_desc    = "1.3.6.1.4.1.1991.1.1.1.2.1.1.2";                  # PS desc
my $foundry_ps_status  = "1.3.6.1.4.1.1991.1.1.1.2.1.1.3";                  # PS status
my $foundry_fan_table  = "1.3.6.1.4.1.1991.1.1.1.3.1";                      # FAN table
my $foundry_fan_desc   = "1.3.6.1.4.1.1991.1.1.1.3.1.1.2";                  # FAN desc
my $foundry_fan_status = "1.3.6.1.4.1.1991.1.1.1.3.1.1.3";                  # FAN status

my @foundry_status = (3, 0, 2);    # oper status : 1:other, 2: Normal, 3: Failure

# Linux Net-SNMP with LM-SENSORS
my $linux_temp       = "1.3.6.1.4.1.2021.13.16.2.1";      # temperature table
my $linux_temp_descr = "1.3.6.1.4.1.2021.13.16.2.1.2";    # temperature entry description
my $linux_temp_value = "1.3.6.1.4.1.2021.13.16.2.1.3";    # temperature entry value (mC)
my $linux_fan        = "1.3.6.1.4.1.2021.13.16.3.1";      # fan table
my $linux_fan_descr  = "1.3.6.1.4.1.2021.13.16.3.1.2";    # fan entry description
my $linux_fan_value  = "1.3.6.1.4.1.2021.13.16.3.1.3";    # fan entry value (RPM)
my $linux_volt       = "1.3.6.1.4.1.2021.13.16.4.1";      # voltage table
my $linux_volt_descr = "1.3.6.1.4.1.2021.13.16.4.1.2";    # voltage entry description
my $linux_volt_value = "1.3.6.1.4.1.2021.13.16.4.1.3";    # voltage entry value (mV)
my $linux_misc       = "1.3.6.1.4.1.2021.13.16.4.1";      # misc table
my $linux_misc_descr = "1.3.6.1.4.1.2021.13.16.4.1.2";    # misc entry description
my $linux_misc_value = "1.3.6.1.4.1.2021.13.16.4.1.3";    # misc entry value

# Globals

my $VERSION = "2.1.0";

my $o_host      = undef;                                  # hostname
my $o_community = undef;                                  # community
my $o_port      = 161;                                    # port
my $o_help      = undef;                                  # wan't some help ?
my $o_verb      = undef;                                  # verbose mode
my $o_version   = undef;                                  # print version
my $o_timeout   = undef;                                  # Timeout (Default 5)
my $o_perf      = undef;                                  # Output performance data
my $o_version2  = undef;                                  # use snmp v2c

# check type
my $o_check_type = "cisco";                                                # default Cisco
my @valid_types  = ("cisco", "nokia", "bc", "iron", "foundry", "linux");
my $o_temp       = undef;                                                  # max temp
my $o_fan        = undef;                                                  # min fan speed

# SNMPv3 specific
my $o_login     = undef;                                                   # Login for snmpv3
my $o_passwd    = undef;                                                   # Pass for snmpv3
my $v3protocols = undef;                                                   # V3 protocol list.
my $o_authproto = 'md5';                                                   # Auth protocol
my $o_privproto = 'des';                                                   # Priv protocol
my $o_privpass  = undef;                                                   # priv password

# functions

sub p_version { print "check_snmp_env version : $VERSION\n"; }

sub print_usage {
    print
"Usage: $0 [-v] -H <host> -C <snmp_community> [-2] | (-l login -x passwd [-X pass -L <authp>,<privp>])  [-p <port>] -T (cisco|nokia|bc|iron|foundry|linux) [-F <rpm>] [-c <celcius>] [-f] [-t <timeout>] [-V]\n";
}

sub isnnum {                                                               # Return true if arg is not a number
    my $num = shift;
    if ($num =~ /^(\d+\.?\d*)|(^\.\d+)$/) { return 0; }
    return 1;
}

sub set_status {    # return worst status with this order : OK, unknwonw, warning, critical
    my $new_status = shift;
    my $cur_status = shift;
    if (($cur_status == 0) || ($new_status == $cur_status)) { return $new_status; }
    if ($new_status == 3)          { return $cur_status; }
    if ($new_status > $cur_status) { return $new_status; }
    return $cur_status;
}

sub help {
    print "\nSNMP environmental Monitor for Icinga/Nagios/Naemon/Shinken, Version ", $VERSION, "\n";
    print "GPL License, (c)2006-2007 Patrick Proy\n\n";
    print_usage();
    print <<EOT;
-v, --verbose
   print extra debugging information 
-h, --help
   print this help message
-H, --hostname=HOST
   name or IP address of host to check
-C, --community=COMMUNITY NAME
   community name for the host's SNMP agent (implies v1 protocol)
-2, --v2c
   Use snmp v2c
-l, --login=LOGIN ; -x, --passwd=PASSWD
   Login and auth password for snmpv3 authentication 
   If no priv password exists, implies AuthNoPriv 
-X, --privpass=PASSWD
   Priv password for snmpv3 (AuthPriv protocol)
-L, --protocols=<authproto>,<privproto>
   <authproto> : Authentication protocol (md5|sha : default md5)
   <privproto> : Priv protocole (des|aes : default des) 
-P, --port=PORT
   SNMP port (Default 161)
-T, --type=cisco|nokia|bc|iron|foundry
   Environemental check : 
	cisco : All Cisco equipements : voltage,temp,fan,power supply
	        (will try to check everything in the env mib)
	nokia : Nokia IP platforms : fan and power supply
	bc : BlueCoat platforms : fans, power supply, voltage, disks
	iron : IronPort platforms : fans, power supply, temp
	foundry : Foundry Network platforms : power supply, temp
	linux : Net-SNMP with LM-SENSORS : temp, fan, volt, misc
-F, --fan=<rpm>
   Minimum fan rpm value (only needed for 'iron' & 'linux')
-c, --celcius=<celcius>
   Maximum temp in degree celcius (only needed for 'iron' & 'linux')
-f, --perfparse
   Perfparse compatible output
-t, --timeout=INTEGER
   timeout for SNMP in seconds (Default: 5)
-V, --version
   prints version number
EOT
}

# For verbose output
sub verb { my $t = shift; print $t, "\n" if defined($o_verb); }

sub check_options {
    Getopt::Long::Configure("bundling");
    GetOptions(
        'v'           => \$o_verb,
        'verbose'     => \$o_verb,
        'h'           => \$o_help,
        'help'        => \$o_help,
        'H:s'         => \$o_host,
        'hostname:s'  => \$o_host,
        'p:i'         => \$o_port,
        'port:i'      => \$o_port,
        'C:s'         => \$o_community,
        'community:s' => \$o_community,
        'l:s'         => \$o_login,
        'login:s'     => \$o_login,
        'x:s'         => \$o_passwd,
        'passwd:s'    => \$o_passwd,
        'X:s'         => \$o_privpass,
        'privpass:s'  => \$o_privpass,
        'L:s'         => \$v3protocols,
        'protocols:s' => \$v3protocols,
        't:i'         => \$o_timeout,
        'timeout:i'   => \$o_timeout,
        'V'           => \$o_version,
        'version'     => \$o_version,

        '2'         => \$o_version2,
        'v2c'       => \$o_version2,
        'f'         => \$o_perf,
        'perfparse' => \$o_perf,
        'T:s'       => \$o_check_type,
        'type:s'    => \$o_check_type,
        'F:i'       => \$o_fan,
        'fan:i'     => \$o_fan,
        'c:i'       => \$o_temp,
        'celcius:i' => \$o_temp
    );

    # check the -T option
    my $T_option_valid = 0;
    foreach (@valid_types) {
        if ($_ eq $o_check_type) { $T_option_valid = 1 }
    }
    if ($T_option_valid == 0) { print "Invalid check type (-T)!\n"; print_usage(); exit $ERRORS{"UNKNOWN"} }

    # Basic checks
    if (defined($o_timeout) && (isnnum($o_timeout) || ($o_timeout < 2) || ($o_timeout > 60))) {
        print "Timeout must be >1 and <60 !\n";
        print_usage();
        exit $ERRORS{"UNKNOWN"};
    }
    if (!defined($o_timeout)) { $o_timeout = 5; }
    if (defined($o_help))    { help();      exit $ERRORS{"UNKNOWN"} }
    if (defined($o_version)) { p_version(); exit $ERRORS{"UNKNOWN"} }
    if (!defined($o_host))    # check host and filter
    {
        print_usage();
        exit $ERRORS{"UNKNOWN"};
    }

    # check snmp information
    if (!defined($o_community) && (!defined($o_login) || !defined($o_passwd))) {
        print "Put snmp login info!\n";
        print_usage();
        exit $ERRORS{"UNKNOWN"};
    }
    if ((defined($o_login) || defined($o_passwd)) && (defined($o_community) || defined($o_version2))) {
        print "Can't mix snmp v1,2c,3 protocols!\n";
        print_usage();
        exit $ERRORS{"UNKNOWN"};
    }
    if (defined($v3protocols)) {
        if (!defined($o_login)) {
            print "Put snmp V3 login info with protocols!\n";
            print_usage();
            exit $ERRORS{"UNKNOWN"};
        }
        my @v3proto = split(/,/, $v3protocols);
        if ((defined($v3proto[0])) && ($v3proto[0] ne "")) { $o_authproto = $v3proto[0]; }    # Auth protocol
        if (defined($v3proto[1])) { $o_privproto = $v3proto[1]; }                             # Priv  protocol
        if ((defined($v3proto[1])) && (!defined($o_privpass))) {
            print "Put snmp V3 priv login info with priv protocols!\n";
            print_usage();
            exit $ERRORS{"UNKNOWN"};
        }
    }
}

########## MAIN #######

check_options();

# Check gobal timeout if snmp screws up
if (defined($TIMEOUT)) {
    verb("Alarm at $TIMEOUT + 5");
    alarm($TIMEOUT + 5);
} else {
    verb("no global timeout defined : $o_timeout + 10");
    alarm($o_timeout + 10);
}

$SIG{'ALRM'} = sub {
    print "No answer from host\n";
    exit $ERRORS{"UNKNOWN"};
};

# Connect to host
my ($session, $error);
if (defined($o_login) && defined($o_passwd)) {

    # SNMPv3 login
    verb("SNMPv3 login");
    if (!defined($o_privpass)) {
        verb("SNMPv3 AuthNoPriv login : $o_login, $o_authproto");
        ($session, $error) = Net::SNMP->session(
            -hostname     => $o_host,
            -port         => $o_port,
            -version      => '3',
            -username     => $o_login,
            -authpassword => $o_passwd,
            -authprotocol => $o_authproto,
            -timeout      => $o_timeout
        );
    } else {
        verb("SNMPv3 AuthPriv login : $o_login, $o_authproto, $o_privproto");
        ($session, $error) = Net::SNMP->session(
            -hostname     => $o_host,
            -port         => $o_port,
            -version      => '3',
            -username     => $o_login,
            -authpassword => $o_passwd,
            -authprotocol => $o_authproto,
            -privpassword => $o_privpass,
            -privprotocol => $o_privproto,
            -timeout      => $o_timeout
        );
    }
} else {
    if (defined($o_version2)) {

        # SNMPv2 Login
        verb("SNMP v2c login");
        ($session, $error) = Net::SNMP->session(
            -hostname  => $o_host,
            -version   => 2,
            -community => $o_community,
            -port      => $o_port,
            -timeout   => $o_timeout
        );
    } else {

        # SNMPV1 login
        verb("SNMP v1 login");
        ($session, $error) = Net::SNMP->session(
            -hostname  => $o_host,
            -community => $o_community,
            -port      => $o_port,
            -timeout   => $o_timeout
        );
    }
}
if (!defined($session)) {
    printf("ERROR opening session: %s.\n", $error);
    exit $ERRORS{"UNKNOWN"};
}

my $exit_val = undef;
########### Cisco env checks ##############

if ($o_check_type eq "cisco") {

    verb("Checking cisco env");

    # Get load table
    my $resultat
        = (version->parse(Net::SNMP->VERSION) < 4)
        ? $session->get_table($ciscoEnvMonMIB)
        : $session->get_table(Baseoid => $ciscoEnvMonMIB);

    if (!defined($resultat)) {
        printf("ERROR: Description table : %s.\n", $session->error);
        $session->close;
        exit $ERRORS{"UNKNOWN"};
    }
    $session->close;

    # Get env data index
    my (@voltindex, @tempindex, @fanindex, @psindex) = (undef, undef, undef, undef);
    my ($voltexist, $tempexist, $fanexist, $psexist) = (0,     0,     0,     0);
    my @oid = undef;
    foreach my $key (keys %$resultat) {
        verb("OID : $key, Desc : $$resultat{$key}");
        if ($key =~ /$ciscoVoltageTableDesc/) {
            @oid = split(/\./, $key);
            $voltindex[$voltexist++] = pop(@oid);
        }
        if ($key =~ /$ciscoTempTableDesc/) {
            @oid = split(/\./, $key);
            $tempindex[$tempexist++] = pop(@oid);
        }
        if ($key =~ /$ciscoFanTableDesc/) {
            @oid = split(/\./, $key);
            $fanindex[$fanexist++] = pop(@oid);
        }
        if ($key =~ /$ciscoPSTableDesc/) {
            @oid = split(/\./, $key);
            $psindex[$psexist++] = pop(@oid);
        }
    }

    if (($voltexist == 0) && ($tempexist == 0) && ($fanexist == 0) && ($psexist == 0)) {
        print "No Environemental data found : UNKNOWN";
        exit $ERRORS{"UNKNOWN"};
    }

    my $perf_output = "";

    # Get the data
    my ($i, $cur_status) = (undef, undef);

    my $volt_global = 0;
    my %volt_status;
    if ($fanexist != 0) {
        for ($i = 0; $i < $voltexist; $i++) {
            $cur_status = $$resultat{ $ciscoVoltageTableState . "." . $voltindex[$i] };
            verb($$resultat{ $ciscoVoltageTableDesc . "." . $voltindex[$i] });
            verb($cur_status);
            if (!defined($cur_status)) {    ### Error TODO
                $volt_global = 1;
            }
            if (defined($$resultat{ $ciscoVoltageTableValue . "." . $voltindex[$i] })) {
                $perf_output .= " '" . $$resultat{ $ciscoVoltageTableDesc . "." . $voltindex[$i] } . "'=";
                $perf_output .= $$resultat{ $ciscoVoltageTableValue . "." . $voltindex[$i] };
            }
            if ($Nagios_state[$CiscoEnvMonNagios{$cur_status}] ne "OK") {
                $volt_global = 1;
                $volt_status{ $$resultat{ $ciscoVoltageTableDesc . "." . $voltindex[$i] } } = $cur_status;
            }
        }
    }

    my $temp_global = 0;
    my %temp_status;
    if ($tempexist != 0) {
        for ($i = 0; $i < $tempexist; $i++) {
            $cur_status = $$resultat{ $ciscoTempTableState . "." . $tempindex[$i] };
            verb($$resultat{ $ciscoTempTableDesc . "." . $tempindex[$i] });
            verb($cur_status);
            if (!defined($cur_status)) {    ### Error TODO
                $temp_global = 1;
            }
            if (defined($$resultat{ $ciscoTempTableValue . "." . $tempindex[$i] })) {
                $perf_output .= " '" . $$resultat{ $ciscoTempTableDesc . "." . $tempindex[$i] } . "'=";
                $perf_output .= $$resultat{ $ciscoTempTableValue . "." . $tempindex[$i] };
            }
            if ($Nagios_state[$CiscoEnvMonNagios{$cur_status}] ne "OK") {
                $temp_global = 1;
                $temp_status{ $$resultat{ $ciscoTempTableDesc . "." . $tempindex[$i] } } = $cur_status;
            }
        }
    }

    my $fan_global = 0;
    my %fan_status;
    if ($fanexist != 0) {
        for ($i = 0; $i < $fanexist; $i++) {
            $cur_status = $$resultat{ $ciscoFanTableState . "." . $fanindex[$i] };
            verb($$resultat{ $ciscoFanTableDesc . "." . $fanindex[$i] });
            verb($cur_status);
            if (!defined($cur_status)) {    ### Error TODO
                $fan_global = 1;
            }
            if ($Nagios_state[$CiscoEnvMonNagios{$cur_status}] ne "OK") {
                $fan_global = 1;
                $fan_status{ $$resultat{ $ciscoFanTableDesc . "." . $fanindex[$i] } } = $cur_status;
            }
        }
    }

    my $ps_global = 0;
    my %ps_status;
    if ($psexist != 0) {
        for ($i = 0; $i < $psexist; $i++) {
            $cur_status = $$resultat{ $ciscoPSTableState . "." . $psindex[$i] };
            if (!defined($cur_status)) {    ### Error TODO
                $fan_global = 1;
            }
            if ($Nagios_state[$CiscoEnvMonNagios{$cur_status}] ne "OK") {
                $ps_global = 1;
                $ps_status{ $$resultat{ $ciscoPSTableDesc . "." . $psindex[$i] } } = $cur_status;
            }
        }
    }

    my $global_state = 0;
    my $output       = "";

    if ($fanexist != 0) {
        if ($fan_global == 0) {
            $output .= $fanexist . " Fan OK";
            $global_state = 1 if ($global_state == 0);
        } else {
            foreach (keys %fan_status) {
                $output .= "Fan " . $_ . ":" . $CiscoEnvMonState{ $fan_status{$_} } . " ";
                if ($global_state < $CiscoEnvMonNagios{ $fan_status{$_} }) {
                    $global_state = $CiscoEnvMonNagios{ $fan_status{$_} };
                }
            }
        }
    }

    if ($psexist != 0) {
        $output .= ", " if ($output ne "");
        if ($ps_global == 0) {
            $output .= $psexist . " ps OK";
            $global_state = 1 if ($global_state == 0);
        } else {
            foreach (keys %ps_status) {
                $output .= "ps " . $_ . ":" . $CiscoEnvMonState{ $ps_status{$_} } . " ";
                if ($global_state < $CiscoEnvMonNagios{ $ps_status{$_} }) {
                    $global_state = $CiscoEnvMonNagios{ $ps_status{$_} };
                }
            }
        }
    }

    if ($voltexist != 0) {
        $output .= ", " if ($output ne "");
        if ($volt_global == 0) {
            $output .= $voltexist . " volt OK";
            $global_state = 1 if ($global_state == 0);
        } else {
            foreach (keys %volt_status) {
                $output .= "volt " . $_ . ":" . $CiscoEnvMonState{ $volt_status{$_} } . " ";
                if ($global_state < $CiscoEnvMonNagios{ $volt_status{$_} }) {
                    $global_state = $CiscoEnvMonNagios{ $volt_status{$_} };
                }
            }
        }
    }

    if ($tempexist != 0) {
        $output .= ", " if ($output ne "");
        if ($temp_global == 0) {
            $output .= $tempexist . " temp OK";
            $global_state = 1 if ($global_state == 0);
        } else {
            foreach (keys %temp_status) {
                $output .= "temp " . $_ . ":" . $CiscoEnvMonState{ $temp_status{$_} } . " ";
                if ($global_state < $CiscoEnvMonNagios{ $temp_status{$_} }) {
                    $global_state = $CiscoEnvMonNagios{ $temp_status{$_} };
                }
            }
        }
    }

    #print $output," : ",$Nagios_state[$global_state]," | ",$perf_output,"\n";
    print $output, " : ", $Nagios_state[$global_state], "\n";
    $exit_val = $ERRORS{ $Nagios_state[$global_state] };

    exit $exit_val;

}

############# Nokia checks
if ($o_check_type eq "nokia") {

    verb("Checking nokia env");

    my $resultat;

    # status : 0=ok, 1=nok, 2=temp prb
    my ($fan_status, $ps_status, $temp_status) = (0, 0, 0);
    my ($fan_exist,  $ps_exist,  $temp_exist)  = (0, 0, 0);
    my ($num_fan,     $num_ps)     = (0, 0);
    my ($num_fan_nok, $num_ps_nok) = (0, 0);
    my $global_status = 0;
    my $output        = "";

    # get temp
    $resultat
        = (version->parse(Net::SNMP->VERSION) < 4)
        ? $session->get_table($nokia_temp_tbl)
        : $session->get_table(Baseoid => $nokia_temp_tbl);
    if (defined($resultat)) {
        verb("temp found");
        $temp_exist = 1;
        if ($$resultat{$nokia_temp} != 1) {
            $temp_status   = 2;
            $global_status = 1;
            $output        = "Temp CRITICAL ";
        } else {
            $output = "Temp OK ";
        }
    }

    # Get fan table
    $resultat
        = (version->parse(Net::SNMP->VERSION) < 4)
        ? $session->get_table($nokia_fan_table)
        : $session->get_table(Baseoid => $nokia_fan_table);

    if (defined($resultat)) {
        $fan_exist = 1;
        foreach my $key (keys %$resultat) {
            verb("OID : $key, Desc : $$resultat{$key}");
            if ($key =~ /$nokia_fan_status/) {
                if ($$resultat{$key} != 1) { $fan_status = 1; $num_fan_nok++ }
                $num_fan++;
            }
        }
        if ($fan_status == 0) {
            $output .= ", " . $num_fan . " fan OK";
        } else {
            $output .= ", " . $num_fan_nok . "/" . $num_fan . " fan CRITICAL";
            $global_status = 2;
        }
    }

    # Get ps table
    $resultat
        = (version->parse(Net::SNMP->VERSION) < 4)
        ? $session->get_table($nokia_ps_table)
        : $session->get_table(Baseoid => $nokia_ps_table);

    if (defined($resultat)) {
        $ps_exist = 1;
        foreach my $key (keys %$resultat) {
            verb("OID : $key, Desc : $$resultat{$key}");
            if ($key =~ /$nokia_ps_status/) {
                if ($$resultat{$key} != 1) { $ps_status = 1; $num_ps_nok++; }
                $num_ps++;
            }
            if ($key =~ /$nokia_ps_temp/) {
                if ($$resultat{$key} != 1) {
                    if ($ps_status == 0) { $ps_status = 2; $num_ps_nok++; }
                }
            }
        }
        if ($ps_status == 0) {
            $output .= ", " . $num_ps . " ps OK";
        } elsif ($ps_status == 2) {
            $output .= ", " . $num_ps_nok . "/" . $num_ps . " ps WARNING (temp)";
            if ($global_status != 2) { $global_status = 1; }
        } else {
            $output .= ", " . $num_ps_nok . "/" . $num_ps . " ps CRITICAL";
            $global_status = 2;
        }
    }

    $session->close;

    verb("status : $global_status");

    if (($fan_exist + $ps_exist + $temp_exist) == 0) {
        print "No environemental informations found : UNKNOWN\n";
        exit $ERRORS{"UNKNOWN"};
    }

    if ($global_status == 0) {
        print $output. " : all OK\n";
        exit $ERRORS{"OK"};
    }

    if ($global_status == 1) {
        print $output. " : WARNING\n";
        exit $ERRORS{"WARNING"};
    }

    if ($global_status == 2) {
        print $output. " : CRITICAL\n";
        exit $ERRORS{"CRITICAL"};
    }
}

############# Bluecoat checks
if ($o_check_type eq "bc") {

    verb("Checking bluecoat env");

    my $resultat;
    my $global_status = 0;
    my ($num_fan,    $num_other,    $num_volt,    $num_temp,    $num_disk)    = (0, 0, 0, 0, 0);
    my ($num_fan_ok, $num_other_ok, $num_volt_ok, $num_temp_ok, $num_disk_ok) = (0, 0, 0, 0, 0);
    my $output      = "";
    my $output_perf = "";

    # get sensor table
    $resultat
        = (version->parse(Net::SNMP->VERSION) < 4)
        ? $session->get_table($bc_sensor_table)
        : $session->get_table(Baseoid => $bc_sensor_table);
    if (defined($resultat)) {
        verb("sensor table found");
        my ($sens_name, $sens_status, $sens_value, $sens_unit) = (undef, undef, undef, undef);
        foreach my $key (keys %$resultat) {
            if ($key =~ /$bc_sensor_Name/) {
                $sens_name = $$resultat{$key};
                $key =~ s/$bc_sensor_Name//;
                $sens_unit = $$resultat{ $bc_sensor_units . $key };
                if ($$resultat{ $bc_sensor_Status . $key } != 1) {    # sensor not operating : output and status unknown
                    if ($output ne "") { $output .= ", "; }
                    $output .= $sens_name . " sensor " . $bc_SensorStatus[$$resultat{ $bc_sensor_Status . $key }];
                    if ($global_status == 0) { $global_status = 3; }
                } else {                                              # Get status
                    $sens_status = $bc_status_nagios[$$resultat{ $bc_sensor_Code . $key }];
                    if ($sens_status != 0) {                          # warn/critical/unknown : output
                        if ($output ne "") { $output .= ", "; }
                        $output .= $sens_name . ":" . $bc_SensorCode[$sens_status];
                        set_status($sens_status, $global_status);
                    }
                }
                if (defined($o_perf)) {
                    if ($output_perf ne "") { $output_perf .= " "; }
                    $output_perf .= "'" . $sens_name . "'=";
                    my $perf_value = $$resultat{ $bc_sensor_Value . $key } * 10**$$resultat{ $bc_sensor_Scale . $key };
                    $output_perf .= $perf_value;
                }
                ### FAN
                if ($bc_mesure[$sens_unit] eq "rpm") {
                    $num_fan++;
                    if ($sens_status == 0) { $num_fan_ok++; }
                } elsif ($bc_mesure[$sens_unit] eq "celsius") {
                    $num_fan++;
                    if ($sens_status == 0) { $num_temp_ok++; }
                } elsif ($bc_mesure[$sens_unit] eq "volts") {
                    $num_volt++;
                    if ($sens_status == 0) { $num_volt_ok++; }
                } else {
                    $num_other++;
                    if ($sens_status == 0) { $num_other_ok++; }
                }
            }
        }
    }

    # Get disk table
    $resultat
        = (version->parse(Net::SNMP->VERSION) < 4)
        ? $session->get_table($bc_dsk_table)
        : $session->get_table(Baseoid => $bc_dsk_table);

    if (defined($resultat)) {
        foreach my $key (keys %$resultat) {
            verb("OID : $key, Desc : $$resultat{$key}");
            my ($dsk_name, $dsk_status) = (undef, undef, undef);
            if ($key =~ /$bc_dsk_status/) {
                $num_disk++;
                $dsk_status = $bc_dsk_status_nagios[$$resultat{$key}];
                if ($dsk_status != 0) {
                    $key =~ s/$bc_dsk_status//;
                    $dsk_name = $$resultat{ $bc_dsk_vendor . $key } . "(" . $$resultat{ $bc_dsk_serial . $key } . ")";
                    if ($output ne "") { $output .= ", "; }
                    $output .= $dsk_name . ":" . $bc_DiskStatus[$$resultat{ $bc_dsk_status . $key }];
                    set_status($dsk_status, $global_status);
                } else {
                    $num_disk_ok++;
                }
            }
        }
    }

    if ($num_fan + $num_other + $num_volt + $num_temp + $num_disk == 0) {
        print "No information found : UNKNOWN\n";
        exit $ERRORS{"UNKNOWN"};
    }

    if ($output ne "")      { $output .= ", "; }
    if ($num_fan_ok != 0)   { $output .= $num_fan_ok . " fan OK "; }
    if ($num_other_ok != 0) { $output .= $num_other_ok . " other OK "; }
    if ($num_volt_ok != 0)  { $output .= $num_volt_ok . " voltage OK "; }
    if ($num_temp_ok != 0)  { $output .= $num_temp_ok . " temp OK "; }
    if ($num_disk_ok != 0)  { $output .= $num_disk_ok . " disk OK "; }

    if (defined($o_perf)) { $output_perf = " | " . $output_perf; }
    if ($global_status == 3) {
        print $output, " : UNKNOWN", $output_perf, "\n";
        exit $ERRORS{"UNKNOWN"};
    }
    if ($global_status == 2) {
        print $output, " : CRITICAL", $output_perf, "\n";
        exit $ERRORS{"CRITICAL"};
    }
    if ($global_status == 1) {
        print $output, " : WARNING", $output_perf, "\n";
        exit $ERRORS{"WARNING"};
    }
    print $output, " : OK", $output_perf, "\n";
    exit $ERRORS{"OK"};

}

############# Ironport checks
if ($o_check_type eq "iron") {

    verb("Checking Ironport env");

    my $resultat;

    # status : 0=ok, 1=warn, 2=crit
    my ($fan_status,  $ps_status,  $temp_status)  = (0, 0, 0);
    my ($fan_exist,   $ps_exist,   $temp_exist)   = (0, 0, 0);
    my ($num_fan,     $num_ps,     $num_temp)     = (0, 0, 0);
    my ($num_fan_nok, $num_ps_nok, $num_temp_nok) = (0, 0, 0);
    my $global_status = 0;
    my $output        = "";

    # get temp if $o_temp is defined
    if (defined($o_temp)) {
        verb("Checking temp < $o_temp");
        $resultat
            = (version->parse(Net::SNMP->VERSION) < 4)
            ? $session->get_table($iron_tmp_table)
            : $session->get_table(Baseoid => $iron_tmp_table);
        if (defined($resultat)) {
            verb("temp found");
            $temp_exist = 1;
            foreach my $key (keys %$resultat) {
                verb("OID : $key, Desc : $$resultat{$key}");
                if ($key =~ /$iron_tmp_celcius/) {
                    verb("Status : $$resultat{$key}");
                    if ($$resultat{$key} > $o_temp) {
                        my @index_oid = split(/\./, $key);
                        my $index_oid_key = pop(@index_oid);
                        $output
                            .= ",Temp : "
                            . $$resultat{ $iron_tmp_name . "." . $index_oid_key } . " : "
                            . $$resultat{$key} . " C";
                        $temp_status = 2;
                        $num_temp_nok++;
                    }
                    $num_temp++;
                }
            }
            if ($temp_status == 0) {
                $output .= ", " . $num_temp . " temp < " . $o_temp . " OK";
            } else {
                $output .= ", " . $num_temp_nok . "/" . $num_temp . " temp probes CRITICAL";
                $global_status = 2;
            }
        }
    }

    # Get fan status if $o_fan is defined
    if (defined($o_fan)) {
        verb("Checking fan > $o_fan");
        $resultat
            = (version->parse(Net::SNMP->VERSION) < 4)
            ? $session->get_table($iron_fan_table)
            : $session->get_table(Baseoid => $iron_fan_table);
        if (defined($resultat)) {
            verb("fan found");
            $fan_exist = 1;
            foreach my $key (keys %$resultat) {
                verb("OID : $key, Desc : $$resultat{$key}");
                if ($key =~ /$iron_fan_rpm/) {
                    verb("Status : $$resultat{$key}");
                    if ($$resultat{$key} < $o_fan) {
                        my @index_oid = split(/\./, $key);
                        my $index_oid_key = pop(@index_oid);
                        $output
                            .= ",Fan "
                            . $$resultat{ $iron_fan_name . "." . $index_oid_key } . " : "
                            . $$resultat{$key} . " RPM";
                        $fan_status = 2;
                        $num_fan_nok++;
                    }
                    $num_fan++;
                }
            }
            if ($fan_status == 0) {
                $output .= ", " . $num_fan . " fan > " . $o_fan . " OK";
            } else {
                $output .= ", " . $num_fan_nok . "/" . $num_fan . " fans CRITICAL";
                $global_status = 2;
            }
        }
    }

    # Get power supply status
    verb("Checking PS");
    $resultat
        = (version->parse(Net::SNMP->VERSION) < 4)
        ? $session->get_table($iron_ps_table)
        : $session->get_table(Baseoid => $iron_ps_table);
    if (defined($resultat)) {
        verb("ps found");
        $ps_exist = 1;
        foreach my $key (keys %$resultat) {
            verb("OID : $key, Desc : $$resultat{$key}");
            if ($key =~ /$iron_ps_status/) {
                verb("Status : $iron_ps_status_name[$$resultat{$key}]");
                if ($iron_ps_status_nagios[$$resultat{$key}] != 0) {
                    my @index_oid = split(/\./, $key);
                    my $index_oid_key = pop(@index_oid);
                    $output
                        .= ",PS "
                        . $$resultat{ $iron_ps_name . "." . $index_oid_key } . " : "
                        . $iron_ps_status_name[$$resultat{$key}];
                    $ps_status = 2;
                    $num_ps_nok++;
                }
                $num_ps++;
            }
        }
        if ($ps_status == 0) {
            $output .= ", " . $num_ps . " ps OK";
        } else {
            $output .= ", " . $num_ps_nok . "/" . $num_ps . " ps CRITICAL";
            $global_status = 2;
        }
    }

    $session->close;

    verb("status : $global_status");

    if (($fan_exist + $ps_exist + $temp_exist) == 0) {
        print "No environemental informations found : UNKNOWN\n";
        exit $ERRORS{"UNKNOWN"};
    }

    $output =~ s/^,//;

    if ($global_status == 0) {
        print $output. " : all OK\n";
        exit $ERRORS{"OK"};
    }

    if ($global_status == 1) {
        print $output. " : WARNING\n";
        exit $ERRORS{"WARNING"};
    }

    if ($global_status == 2) {
        print $output. " : CRITICAL\n";
        exit $ERRORS{"CRITICAL"};
    }
}

########### Foundry env checks ##############

if ($o_check_type eq "foundry") {

    verb("Checking foundry env");

    my $global_status = 0;    # status to UNKNOWN
    my $output        = "";

    # Get temperature

    my @foundry_temp_oid = ($foundry_temp, $foundry_temp_warn, $foundry_temp_crit);

    my $result_temp = $session->get_request(Varbindlist => \@foundry_temp_oid);

    my $temp_found = 0;
    if (defined($result_temp)) {
        $temp_found = 1;

        #Temp found
        $output = "Temp : " . $$result_temp{$foundry_temp} / 2;
        if ($$result_temp{$foundry_temp} > $$result_temp{$foundry_temp_crit}) {    # Temp above critical
            $output .= " > " . $$result_temp{$foundry_temp_crit} / 2 . " : CRITICAL";
            $global_status = 3;
        } elsif ($$result_temp{$foundry_temp} > $$result_temp{$foundry_temp_warn}) {    # Temp above warning
            $output .= " > " . $$result_temp{$foundry_temp_warn} / 2 . " : WARNING";
            $global_status = 2;
        } else {
            $output .= " < " . $$result_temp{$foundry_temp_warn} / 2 . " : OK";
            $global_status = 1;
        }
    }

    # Get PS table (TODO : Bug in FAN table, see with Foundry).

    my $result_ps
        = (version->parse(Net::SNMP->VERSION) < 4)
        ? $session->get_table($foundry_ps_table)
        : $session->get_table(Baseoid => $foundry_ps_table);

    my $ps_num = 0;
    if (defined($result_ps)) {
        $output .= ", " if defined($output);
        foreach my $key (keys %$result_ps) {
            verb("OID : $key, Desc : $$result_ps{$key}");
            if ($$result_ps{$key} =~ /$foundry_ps_desc/) {
                $ps_num++;
                my @oid_list = split(/\./, $key);
                my $index_ps = pop(@oid_list);
                $index_ps = $foundry_ps_status . "." . $index_ps;
                if (defined($$result_ps{$index_ps})) {
                    if ($$result_ps{$index_ps} == 3) {
                        $output .= "PS " . $$result_ps{$key} . " : FAILURE";
                        $global_status = 3;
                    } elsif ($$result_ps{$index_ps} == 2) {
                        $global_status = 1 if ($global_status == 0);
                    } else {
                        $output .= "ps " . $$result_ps{$key} . " : OTHER";
                    }
                } else {
                    $output .= "ps " . $$result_ps{$key} . " : UNDEFINED STATUS";
                }
            }
        }
    }

    $session->close;

    if (($ps_num + $temp_found) == 0) {
        print "No data found : UNKNOWN\n";
        exit $ERRORS{"UNKNOWN"};
    }

    if ($global_status == 1) {
        print $output. " : all OK\n";
        exit $ERRORS{"OK"};
    }

    if ($global_status == 2) {
        print $output. " : WARNING\n";
        exit $ERRORS{"WARNING"};
    }

    if ($global_status == 3) {
        print $output. " : CRITICAL\n";
        exit $ERRORS{"CRITICAL"};
    }

    print $output. " : UNKNOWN\n";
    exit $ERRORS{"UNKNOWN"};

}

########### Cisco env checks ##############
if ($o_check_type eq "linux") {

    verb("Checking linux env");

    print "Not implemented yet : UNKNOWN\n";
    exit $ERRORS{"UNKNOWN"};
}

print "Unknown check type : UNKNOWN\n";
exit $ERRORS{"UNKNOWN"};
