]> git.uio.no Git - check_openmanage.git/blobdiff - check_openmanage
3.7.2
[check_openmanage.git] / check_openmanage
index 38094afc90aad6f494c6e762b64907ab7716ee21..5a1e30971fb4f5d07f3eb885d503d6029b42a8c6 100755 (executable)
@@ -7,7 +7,7 @@
 #
 # $Id$
 #
-# Copyright (C) 2010 Trond H. Amundsen
+# Copyright (C) 2008-2011 Trond H. Amundsen
 #
 # 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
@@ -51,7 +51,7 @@ $SIG{__WARN__} = sub { push @perl_warnings, [@_]; };
 
 # Version and similar info
 $NAME    = 'check_openmanage';
-$VERSION = '3.6.1';
+$VERSION = '3.7.2';
 $AUTHOR  = 'Trond H. Amundsen';
 $CONTACT = 't.h.amundsen@usit.uio.no';
 
@@ -74,37 +74,42 @@ $HELP = <<'END_HELP';
 
 GENERAL OPTIONS:
 
-   -p, --perfdata      Output performance data [no]
-   -t, --timeout       Plugin timeout in seconds [30]
-   -c, --critical      Customise temperature critical limits
-   -w, --warning       Customise temperature warning limits
-   -d, --debug         Debug output, reports everything
-   -h, --help          Display this help text
-   -V, --version       Display version info
+   -f, --config         Specify configuration file
+   -p, --perfdata       Output performance data [default=no]
+   -t, --timeout        Plugin timeout in seconds [default=30]
+   -c, --critical       Custom temperature critical limits
+   -w, --warning        Custom temperature warning limits
+   -F, --fahrenheit     Use Fahrenheit as temperature unit
+   -d, --debug          Debug output, reports everything
+   -h, --help           Display this help text
+   -V, --version        Display version info
 
 SNMP OPTIONS:
 
-   -H, --hostname      Hostname or IP (required for SNMP)
-   -C, --community     SNMP community string [public]
-   -P, --protocol      SNMP protocol version [2]
-   --port              SNMP port number [161]
+   -H, --hostname       Hostname or IP (required for SNMP)
+   -C, --community      SNMP community string [default=public]
+   -P, --protocol       SNMP protocol version [default=2]
+   --port               SNMP port number [default=161]
+   -6, --ipv6           Use IPv6 instead of IPv4 [default=no]
+   --tcp                Use TCP instead of UDP [default=no]
 
 OUTPUT OPTIONS:
 
-   -i, --info          Prefix any alerts with the service tag
-   -e, --extinfo       Append system info to alerts
-   -s, --state         Prefix alerts with alert state
-   -S, --short-state   Prefix alerts with alert state (abbreviated)
-   -o, --okinfo        Verbosity when check result is OK
-   -I, --htmlinfo      HTML output with clickable links
+   -i, --info           Prefix any alerts with the service tag
+   -e, --extinfo        Append system info to alerts
+   -s, --state          Prefix alerts with alert state
+   -S, --short-state    Prefix alerts with alert state abbreviated
+   -o, --okinfo         Verbosity when check result is OK
+   -B, --show-blacklist Show blacklistings in OK output
+   -I, --htmlinfo       HTML output with clickable links
 
 CHECK CONTROL AND BLACKLISTING:
 
-   -a, --all           Check everything, even log content
-   -b, --blacklist     Blacklist missing and/or failed components
-   --only              Only check a certain component or alert type
-   --check             Fine-tune which components are checked
-   --no-storage        Don't check storage (alias for "--check storage=0")
+   -a, --all            Check everything, even log content
+   -b, --blacklist      Blacklist missing and/or failed components
+   --only               Only check a certain component or alert type
+   --check              Fine-tune which components are checked
+   --no-storage         Don't check storage
 
 For more information and advanced options, see the manual page or URL:
   http://folk.uio.no/trondham/software/check_openmanage.html
@@ -113,7 +118,7 @@ END_HELP
 # Version and license text
 $LICENSE = <<"END_LICENSE";
 $NAME $VERSION
-Copyright (C) 2010 $AUTHOR
+Copyright (C) 2008-2011 $AUTHOR
 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
@@ -126,10 +131,14 @@ END_LICENSE
         'check'             => [],       # check control
         'critical'          => [],       # temperature critical limits
         'warning'           => [],       # temperature warning limits
+         'tempunit'          => 'C',      # temperature unit
+        'fahrenheit'        => 0,        # Use fahrenheit
+         'configfile'        => undef,    # configuration file
         'timeout'           => 30,       # default timeout is 30 seconds
         'debug'             => 0,        # debugging / verbose output
         'help'              => 0,        # display help output
         'perfdata'          => undef,    # output performance data
+        'legacy_perfdata'   => 0,        # legacy performance data output
         'info'              => 0,        # display servicetag
         'extinfo'           => 0,        # display extra info
         'htmlinfo'          => undef,    # html tags in output
@@ -137,6 +146,7 @@ END_LICENSE
         'state'             => 0,        # display alert type
         'short-state'       => 0,        # display alert type (short)
         'okinfo'            => 0,        # default "ok" output level
+        'show_blacklist'    => 0,        # show blacklisted components
         'linebreak'         => undef,    # specify linebreak
         'version'           => 0,        # plugin version info
          'all'               => 0,        # check everything
@@ -147,6 +157,8 @@ END_LICENSE
         'hostname'          => undef,    # hostname or IP
         'community'         => 'public', # SMNP v1 or v2c
         'protocol'          => 2,        # default SNMP protocol 2c
+        'ipv6'              => 0,        # default is IPv4
+        'tcp'               => 0,        # default is UDP
         'username'          => undef,    # SMNP v3
         'authpassword'      => undef,    # SMNP v3
         'authkey'           => undef,    # SMNP v3
@@ -155,6 +167,7 @@ END_LICENSE
         'privkey'           => undef,    # SMNP v3
         'privprotocol'      => undef,    # SMNP v3
          'use_get_table'     => 0,        # hack for SNMPv3 on Windows with net-snmp
+        'hide_servicetag'   => 0,        # hidden servicetag
        );
 
 # Get options
@@ -162,11 +175,15 @@ GetOptions('b|blacklist=s'      => \@{ $opt{blacklist} },
           'check=s'            => \@{ $opt{check} },
           'c|critical=s'       => \@{ $opt{critical} },
           'w|warning=s'        => \@{ $opt{warning} },
+          'tempunit=s'         => \$opt{tempunit},
+          'F|fahrenheit'       => \$opt{fahrenheit},
+           'f|configfile=s'     => \$opt{configfile},
           't|timeout=i'        => \$opt{timeout},
           'd|debug'            => \$opt{debug},
           'h|help'             => \$opt{help},
           'V|version'          => \$opt{version},
           'p|perfdata:s'       => \$opt{perfdata},
+          'legacy-perfdata'    => \$opt{legacy_perfdata},
           'i|info'             => \$opt{info},
           'e|extinfo'          => \$opt{extinfo},
           'I|htmlinfo:s'       => \$opt{htmlinfo},
@@ -174,6 +191,7 @@ GetOptions('b|blacklist=s'      => \@{ $opt{blacklist} },
           's|state'            => \$opt{state},
           'S|short-state'      => \$opt{shortstate},
           'o|ok-info=i'        => \$opt{okinfo},
+          'B|show-blacklist'   => \$opt{show_blacklist},
           'linebreak=s'        => \$opt{linebreak},
           'a|all'              => \$opt{all},
           'only=s'             => \$opt{only},
@@ -183,6 +201,8 @@ GetOptions('b|blacklist=s'      => \@{ $opt{blacklist} },
           'H|hostname=s'       => \$opt{hostname},
           'C|community=s'      => \$opt{community},
           'P|protocol=i'       => \$opt{protocol},
+          '6|ipv6'             => \$opt{ipv6},
+          'tcp'                => \$opt{tcp},
           'U|username=s'       => \$opt{username},
           'authpassword=s'     => \$opt{authpassword},
           'authkey=s'          => \$opt{authkey},
@@ -191,36 +211,23 @@ GetOptions('b|blacklist=s'      => \@{ $opt{blacklist} },
           'privkey=s'          => \$opt{privkey},
           'privprotocol=s'     => \$opt{privprotocol},
            'use-get_table'      => \$opt{use_get_table},
+          'hide-servicetag'    => \$opt{hide_servicetag},
          ) or do { print $USAGE; exit $E_UNKNOWN };
 
 # If user requested help
 if ($opt{help}) {
     print $USAGE, $HELP;
-    exit $E_OK;
+    exit $E_UNKNOWN;
 }
 
 # If user requested version info
 if ($opt{version}) {
     print $LICENSE;
-    exit $E_OK;
-}
-
-# Setting timeout
-$SIG{ALRM} = sub {
-    print "PLUGIN TIMEOUT: $NAME timed out after $opt{timeout} seconds\n";
     exit $E_UNKNOWN;
-};
-alarm $opt{timeout};
-
-# If we're using SNMP
-$snmp = defined $opt{hostname} ? 1 : 0;
-
-# SNMP session variables
-$snmp_session = undef;
-$snmp_error   = undef;
+}
 
-# The omreport command
-$omreport = undef;
+# Initialize blacklist
+%blacklist = ();
 
 # Check flags, override available with the --check option
 %check = ( 'storage'     => 1,   # check storage subsystem
@@ -239,6 +246,31 @@ $omreport = undef;
           'esmhealth'   => 1,   # check the ESM log overall health
         );
 
+# Messages
+@report_storage = ();  # messages with associated nagios level (storage)
+@report_chassis = ();  # messages with associated nagios level (chassis)
+@report_other   = ();  # messages with associated nagios level (other)
+
+# Read config file
+parse_configfile() if defined $opt{configfile};
+
+# Setting timeout
+$SIG{ALRM} = sub {
+    print "PLUGIN TIMEOUT: $NAME timed out after $opt{timeout} seconds\n";
+    exit $E_UNKNOWN;
+};
+alarm $opt{timeout};
+
+# If we're using SNMP
+$snmp = defined $opt{hostname} ? 1 : 0;
+
+# SNMP session variables
+$snmp_session = undef;
+$snmp_error   = undef;
+
+# The omreport command
+$omreport = undef;
+
 # Default line break
 $linebreak = isatty(*STDOUT) ? "\n" : '<br/>';
 
@@ -266,11 +298,6 @@ if (!$snmp && -f $FW_LOCK) {
 @enclosures  = ();  # enclosures
 %snmp_enclosure   = ();  # enclosures
 
-# Messages
-@report_storage = ();  # messages with associated nagios level (storage)
-@report_chassis = ();  # messages with associated nagios level (chassis)
-@report_other   = ();  # messages with associated nagios level (other)
-
 # Counters for everything
 %count
   = (
@@ -389,7 +416,7 @@ $globalstatus   = $E_OK;  # default global health status is "OK"
 adjust_checks() if defined $opt{check};
 
 # Blacklisted components
-%blacklist = defined $opt{blacklist} ? %{ get_blacklist() } : ();
+set_blacklist($opt{blacklist}) if defined $opt{blacklist};
 
 # If blacklisting is in effect, don't check global health status
 if (scalar keys %blacklist > 0) {
@@ -415,11 +442,357 @@ else {
     check_omreport_options();
 }
 
+# Temperature unit
+if ($opt{fahrenheit}) {
+    $opt{tempunit} = 'F';
+}
+
+# Check tempunit syntax
+if ($opt{tempunit} !~ m{\A C|F|K|R \z}xms) {
+    print "ERROR: Unknown temperature unit '$opt{tempunit}'\n";
+    exit $E_UNKNOWN;
+}
 
 #---------------------------------------------------------------------
 # Helper functions
 #---------------------------------------------------------------------
 
+# Make a regex from a glob pattern. Shamelessly stolen from Perl
+# Cookbook chapter 6.9
+sub glob2regex {
+    my $globstr = shift;
+    my %patmap
+      = ( '*' => '.*',
+          '?' => '.',
+          '[' => '[',
+          ']' => ']',
+        );
+    $globstr =~ s{(.)} { $patmap{$1} || "\Q$1" }ge;
+    return '\A' . $globstr . '\z';
+}
+
+#
+# Read config file
+#
+sub parse_configfile {
+    our $tiny = undef;
+
+    # Regexp for boolean values
+    our $off = qr{\A (0|off|false) \s* \z}ixms;
+    our $on  = qr{\A (1|on|true) \s* \z}ixms;
+
+    # Mapping between command line options and the corresponding
+    # config file options
+    our %opt2config
+      = ( 'info'            => 'output_servicetag',
+         'extinfo'         => 'output_sysinfo',
+         'postmsg'         => 'output_post_message',
+         'state'           => 'output_servicestate',
+         'shortstate'      => 'output_servicestate_abbr',
+         'show_blacklist'  => 'output_blacklist',
+          'hide_servicetag' => 'output_hide_servicetag',
+         'htmlinfo'        => 'output_html',
+         'okinfo'          => 'output_ok_verbosity',
+         'protocol'        => 'snmp_version',
+         'community'       => 'snmp_community',
+         'port'            => 'snmp_port',
+         'ipv6'            => 'snmp_use_ipv6',
+         'tcp'             => 'snmp_use_tcp',
+         'warning'         => 'temp_threshold_warning',
+         'critical'        => 'temp_threshold_critical',
+         'all'             => 'check_everything',
+         'perfdata'        => 'performance_data',
+         'tempunit'        => 'temperature_unit',
+         'timeout'         => 'timeout',
+         'blacklist'       => 'blacklist',
+         'legacy_perfdata' => 'legacy_performance_data',
+       );
+
+    # Load the perl module
+    if ( eval { require Config::Tiny; 1 } ) {
+       $tiny = Config::Tiny->new();
+    }
+    else {
+       print "ERROR: Required perl module 'Config::Tiny' not found\n";
+       exit $E_UNKNOWN;
+    }
+
+    # Read the config file
+    $tiny = Config::Tiny->read($opt{configfile})
+      or do { report('other', (sprintf q{Couldn't read configuration file: %s}, Config::Tiny->errstr()), $E_UNKNOWN);
+             return; };
+
+    # Syntax check
+    foreach my $section (keys %{ $tiny }) {
+      KEYWORD:
+       foreach my $keyword (keys %{ $tiny->{$section} }) {
+           next KEYWORD if $keyword eq 'check_everything';
+           if ($keyword =~ m{\A check_(.+)}xms) {
+               my $c = $1;
+               foreach my $cl (keys %check) {
+                   next KEYWORD if $c eq $cl;
+               }
+           }
+           else {
+             LEGAL:
+               foreach my $legal (keys %opt2config) {
+                   next KEYWORD if $keyword eq $opt2config{$legal};
+               }
+           }
+           if ($section eq '_') {
+               report('other', qq{CONFIG ERROR: In the global section: Unknown statement "$keyword"}, $E_UNKNOWN);
+           }
+           else {
+               report('other', qq{CONFIG ERROR: Unknown statement "$keyword" in section "$section"}, $E_UNKNOWN);
+           }
+       }
+    }
+
+    # Adjust checks according to statements in the configuration file
+    sub configfile_adjust_checks {
+       my $keyword = shift;
+      CHECK_CONFIG:
+       foreach my $key (keys %check) {
+           my $copt = join '_', 'check', $key;
+           next CHECK_CONFIG if !defined $tiny->{$keyword}->{$copt} or $tiny->{$keyword}->{$copt} eq q{};
+           if ($tiny->{$keyword}->{$copt} =~ m{$on}ixms) {
+               $check{$key} = 1;
+           }
+           elsif ($tiny->{$keyword}->{$copt} =~ m{$off}ixms) {
+               $check{$key} = 0;
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for '$copt' must be boolean (True/False)", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
+    # Set blacklist according to statements in the configuration file
+    sub configfile_set_blacklist {
+       my $keyword = shift;
+       if (defined $tiny->{$keyword}->{blacklist} and $tiny->{$keyword}->{blacklist} ne q{}) {
+           # set_blacklist() takes an array ref
+           set_blacklist([$tiny->{$keyword}->{blacklist}]);
+       }
+       return;
+    }
+
+    # Set timeout according to statements in the configuration file
+    sub configfile_set_timeout {
+       my $keyword = shift;
+       if (defined $tiny->{$keyword}->{timeout} and $tiny->{$keyword}->{timeout} ne q{}) {
+           if ($tiny->{$keyword}->{timeout} =~ m{\A \d+ \z}xms) { # integer
+               $opt{timeout} = $tiny->{$keyword}->{timeout};
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for 'timeout' must be a positive integer", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
+    # Set a boolean option
+    sub configfile_set_boolean {
+       my ($keyword, $bool) = @_;
+       my $cbool = $opt2config{$bool};
+       if (defined $tiny->{$keyword}->{$cbool} and $tiny->{$keyword}->{$cbool} ne q{}) {
+           if ($tiny->{$keyword}->{$cbool} =~ m{$on}ixms) {
+               $opt{$bool} = 1;
+           }
+           elsif ($tiny->{$keyword}->{$cbool} =~ m{$off}ixms) {
+               $opt{$bool} = 0;
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for '$cbool' must be boolean (True/False)", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
+    # Set htmlinfo option from config file
+    sub configfile_set_htmlinfo {
+       my $keyword = shift;
+       my $conf = $opt2config{htmlinfo};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           if ($tiny->{$keyword}->{$conf} =~ m{$on}ixms) {
+               $opt{htmlinfo} = 1;
+           }
+           elsif ($tiny->{$keyword}->{$conf} =~ m{$off}ixms) {
+               $opt{htmlinfo} = undef;
+           }
+           else {
+               $opt{htmlinfo} = $tiny->{$keyword}->{$conf};
+           }
+       }
+       return;
+    }
+
+    # Set OK output verbosity
+    sub configfile_set_ok_verbosity {
+       my $keyword = shift;
+       my $conf = $opt2config{okinfo};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           if ($tiny->{$keyword}->{$conf} =~ m{\A \d+ \z}xms) {
+               $opt{okinfo} = $tiny->{$keyword}->{$conf};
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for '$conf' must be a positive integer", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
+    # Set SNMP protocol version from config file
+    sub configfile_set_snmp_version {
+       my $keyword = shift;
+       my $conf = $opt2config{protocol};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           if ($tiny->{$keyword}->{$conf} =~ m{\A 1|2|3 \z}xms) {
+               $opt{protocol} = $tiny->{$keyword}->{$conf};
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for '$conf' must be '1', '2' or '3'", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
+    # Set SNMP community name from config file
+    sub configfile_set_snmp_community {
+       my $keyword = shift;
+       my $conf = $opt2config{community};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           $opt{community} = $tiny->{$keyword}->{$conf};
+       }
+       return;
+    }
+
+    # Set SNMP port number from config file
+    sub configfile_set_snmp_port {
+       my $keyword = shift;
+       my $conf = $opt2config{port};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           if ($tiny->{$keyword}->{$conf} =~ m{\A \d+ \z}xms) { # integer
+               $opt{port} = $tiny->{$keyword}->{$conf};
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for '$conf' must be a positive integer", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
+    # Set temperature threshold from config file
+    sub configfile_set_temp_threshold {
+       my $keyword = shift;
+       my $level = shift;
+       my $conf = $opt2config{$level};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           $opt{$level} = [$tiny->{$keyword}->{$conf}]; # array ref
+       }
+       return;
+    }
+
+    # Set perfdata from config file
+    sub configfile_set_perfdata {
+       my $keyword = shift;
+       my $conf = $opt2config{perfdata};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           if ($tiny->{$keyword}->{$conf} =~ m{$on}ixms) {
+               $opt{perfdata} = 1;
+           }
+           elsif ($tiny->{$keyword}->{$conf} =~ m{$off}ixms) {
+               $opt{perfdata} = undef;
+           }
+           elsif ($tiny->{$keyword}->{$conf} =~ m{\A minimal|multiline \z}xms) {
+               $opt{perfdata} = $tiny->{$keyword}->{$conf};
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for '$conf' must be either boolean, 'minimal' or 'multiline'", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
+    # Set temp unit from config file
+    sub configfile_set_tempunit {
+       my $keyword = shift;
+       my $conf = $opt2config{tempunit};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           if ($tiny->{$keyword}->{$conf} =~ m{\A C|F|K|R \z}ixms) {
+               $opt{tempunit} = $tiny->{$keyword}->{$conf};
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for '$conf' must one of C/F/K/R", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
+    # Set postmsg string from config file
+    sub configfile_set_postmsg {
+       my $keyword = shift;
+       my $conf = $opt2config{postmsg};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           $opt{postmsg} = $tiny->{$keyword}->{$conf}; # array ref
+       }
+       return;
+    }
+
+    # Sections in the config file to check for statements
+    my @sections = ();
+
+    # First: Populate the sections array with the global section
+    @sections = ('_');
+
+    # Second: Populate the sections array with host glob pattern (but
+    # not exact match)
+  PATTERN:
+    foreach my $glob (sort keys %{ $tiny }) {
+       next PATTERN if $glob eq '_';            # global section
+        next PATTERN if $glob eq $opt{hostname}; # exact match
+       my $regex = glob2regex($glob);           # make regexp
+       if ($opt{hostname} =~ m{$regex}) {
+           push @sections, $glob;
+       }
+    }
+
+    # Third: Populate the sections array with exact hostname
+    if (defined $tiny->{$opt{hostname}}) {
+       push @sections, $opt{hostname};
+    }
+
+    # Loop through the sections array and get options
+    foreach my $sect (@sections) {
+       configfile_adjust_checks($sect);
+       configfile_set_blacklist($sect);
+       configfile_set_timeout($sect);
+       configfile_set_htmlinfo($sect);
+        configfile_set_ok_verbosity($sect);
+       configfile_set_boolean($sect, 'all');
+       configfile_set_boolean($sect, 'info');
+       configfile_set_boolean($sect, 'extinfo');
+       configfile_set_boolean($sect, 'state');
+       configfile_set_boolean($sect, 'shortstate');
+       configfile_set_boolean($sect, 'show_blacklist');
+       configfile_set_boolean($sect, 'ipv6');
+       configfile_set_boolean($sect, 'tcp');
+       configfile_set_boolean($sect, 'legacy_perfdata');
+       configfile_set_boolean($sect, 'hide_servicetag');
+       configfile_set_snmp_version($sect);
+       configfile_set_snmp_community($sect);
+       configfile_set_snmp_port($sect);
+       configfile_set_temp_threshold($sect, 'warning');
+       configfile_set_temp_threshold($sect, 'critical');
+       configfile_set_perfdata($sect);
+       configfile_set_tempunit($sect);
+       configfile_set_postmsg($sect);
+    }
+
+    return;
+}
+
 #
 # Store a message in one of the message arrays
 #
@@ -437,7 +810,6 @@ sub report {
     return push @{ $type2array{$type} }, [ $msg, $exval, $id ];
 }
 
-
 #
 # Run command, put resulting output lines in an array and return a
 # pointer to that array
@@ -488,6 +860,11 @@ sub snmp_initialize {
         '-version'  => $opt{protocol},
        );
 
+    # Setting the domain (IP version and transport protocol)
+    my $transport = $opt{tcp} ? 'tcp' : 'udp';
+    my $ipversion = $opt{ipv6} ? 'ipv6' : 'ipv4';
+    $param{'-domain'} = "$transport/$ipversion";
+
     # Parameters for SNMP v3
     if ($opt{protocol} == 3) {
 
@@ -594,14 +971,23 @@ sub snmp_check {
 # Detecting blade via SNMP
 #
 sub snmp_detect_blade {
-    my $DellBaseBoardType = '1.3.6.1.4.1.674.10892.1.300.80.1.7.1.1';
-    my $result = $snmp_session->get_request(-varbindlist => [$DellBaseBoardType]);
+    # In some setups, the IDs for the blade and interconnect
+    # board are mixed up, so we need to check both.
+    my $DellBaseBoardType1 = '1.3.6.1.4.1.674.10892.1.300.80.1.7.1.1';
+    my $DellBaseBoardType2 = '1.3.6.1.4.1.674.10892.1.300.80.1.7.1.2';
+    my $result1 = $snmp_session->get_request(-varbindlist => [$DellBaseBoardType1]);
+    my $result2 = $snmp_session->get_request(-varbindlist => [$DellBaseBoardType2]);
 
     # Identify blade. Older models (4th and 5th gen models) and/or old
     # OMSA (4.x) don't have this OID. If we get "noSuchInstance" or
     # similar, we assume that this isn't a blade
-    if (exists $result->{$DellBaseBoardType} && $result->{$DellBaseBoardType} eq '3') {
+    if (exists $result1->{$DellBaseBoardType1} && $result1->{$DellBaseBoardType1} eq '3') {
+       $blade = 1;
+       return;
+    }
+    if (exists $result2->{$DellBaseBoardType2} && $result2->{$DellBaseBoardType2} eq '3') {
        $blade = 1;
+       return;
     }
     return;
 }
@@ -677,12 +1063,12 @@ sub check_omreport_options {
 # Read the blacklist option and return a hash containing the
 # blacklisted components
 #
-sub get_blacklist {
+sub set_blacklist {
+    my $foo = shift;
     my @bl = ();
-    my %blacklist = ();
 
-    if (scalar @{ $opt{blacklist} } >= 0) {
-       foreach my $black (@{ $opt{blacklist} }) {
+    if (scalar @{ $foo } >= 0) {
+       foreach my $black (@{ $foo }) {
            my $tmp = q{};
            if (-f $black) {
                open my $BL, '<', $black
@@ -707,11 +1093,11 @@ sub get_blacklist {
            next if $c !~ m/=/xms;
            my ($key, $val) = split /=/xms, $c;
            my @vals = split /,/xms, $val;
-           $blacklist{$key} = \@vals;
+           push @{ $blacklist{$key} }, @vals;
        }
     }
 
-    return \%blacklist;
+    return;
 }
 
 #
@@ -761,7 +1147,7 @@ sub adjust_checks {
 
        # adjust the check hash
        if ($opt{only} eq 'chassis') {
-           map { $check{$_} = 1 } qw(memory fans power temp cpu voltage
+           map { $check{$_} = 1 } qw(memory fans power temp cpu voltage sdcard
                                      batteries amperage intrusion esmhealth);
        }
        else {
@@ -835,7 +1221,8 @@ sub run_omreport {
           | No\sbattery\sprobes\sfound\son\sthis\ssystem               # No battery probes
           | Invalid\scommand:\spwrmonitoring                           # Old hardware
           | Hardware\sor\sfeature\snot\spresent\.                      # SD cards
-          | Invalid\scommand:\sremovableflashmedia                      # SD cards with old OMSA
+          | Invalid\scommand:\sremovableflashmedia                     # SD cards with old OMSA
+          | Error\sCorrection;                                         # Memory stuff. Not really an error (new in OMSA 6.4)
 #          | Current\sprobes\snot\sfound                                # OMSA + RHEL5.4 bug
 #          | No\scontrollers\sfound                                     # No RAID controller
         }xms;
@@ -853,6 +1240,13 @@ sub run_omreport {
     # Workaround for Openmanage BUG introduced in OMSA 5.5.0
     $rawtext =~ s{\n;}{;}gxms if $command eq 'storage controller';
 
+    # Workaround for logical connectors where there are extra
+    # information that isn't possible to parse consistently. Remove
+    # everything after and including "Path Health"
+    if ($command =~ m{\A storage\sconnector}xms) {
+       $rawtext =~ s{Path\sHealth.*}{}xms;
+    }
+
     # Report if no controllers found
     if ($command eq 'storage controller' and $rawtext =~ m{No\scontrollers\sfound}xms) {
        report('storage', 'Storage Error! No controllers found', $E_UNKNOWN);
@@ -1078,11 +1472,51 @@ sub warranty_url {
 # This helper function returns the corresponding value of a hash key,
 # but takes into account that the key may not exist
 sub get_hashval {
-    my $key  = shift || return undef;
+    my $key  = shift || return;
     my $hash = shift;
-    return exists $hash->{$key} ? $hash->{$key} : "Undefined value $key";
+    return defined $hash->{$key} ? $hash->{$key} : "Undefined value $key";
+}
+
+# Find component status from hash
+sub get_snmp_status {
+    my $key  = shift || return 'Unknown';
+    return exists $snmp_status{$key} ? $snmp_status{$key} : 'Unknown';
+}
+
+# Find component status from hash
+sub get_snmp_probestatus {
+    my $key  = shift || return 'Unknown';
+    return exists $snmp_probestatus{$key} ? $snmp_probestatus{$key} : 'Unknown';
 }
 
+# Check that a hash entry is defined and not an empty string. Return a
+# chosen string (parameter) if these conditions are not met
+sub get_nonempty_string {
+    my $key  = shift;  # key to check
+    my $hash = shift;  # hash where the key belongs
+    my $alt  = shift;  # alternate return value
+    if (defined $hash->{$key} and $hash->{$key} ne q{}) {
+       return $hash->{$key};
+    }
+    return $alt;
+}
+
+# Converts from Celsius to something else
+sub temp_from_celsius {
+    my $x  = shift;
+    my $to = shift;
+
+    if ($to eq 'F') {
+       return sprintf '%.1f', ($x * 9/5 + 32);
+    }
+    elsif ($to eq 'K') {
+       return sprintf '%.1f', ($x + 273.15);
+    }
+    elsif ($to eq 'R') {
+       return sprintf '%.1f', ($x * 9/5 + 32 + 459.67);
+    }
+    return $x;
+}
 
 
 #---------------------------------------------------------------------
@@ -1105,7 +1539,7 @@ sub check_global {
            printf "SNMP ERROR [global]: %s\n", $snmp_error;
            exit $E_UNKNOWN;
        }
-       $health = $status2nagios{$snmp_status{$result->{$systemStateGlobalSystemStatus}}};
+       $health = $status2nagios{get_snmp_status($result->{$systemStateGlobalSystemStatus})};
     }
     else {
        #
@@ -1130,8 +1564,6 @@ sub check_global {
 # STORAGE: Check controllers
 #-----------------------------------------
 sub check_controllers {
-    return if blacklisted('ctrl', 'all');
-
     my $nexus    = undef;
     my $name     = undef;
     my $state    = undef;
@@ -1190,28 +1622,22 @@ sub check_controllers {
   CTRL:
     foreach my $out (@output) {
        if ($snmp) {
-           $name     = $out->{controllerName};
-           $state    = get_hashval($out->{controllerState}, \%ctrl_state);
-           $status   = $snmp_status{$out->{controllerComponentStatus}};
-           $minfw    = exists $out->{controllerMinFWVersion}
-             ? $out->{controllerMinFWVersion} : undef;
-           $mindr    = exists $out->{controllerMinDriverVersion}
-             ? $out->{controllerMinDriverVersion} : undef;
-           $firmware = exists $out->{controllerFWVersion}
-             ? $out->{controllerFWVersion} : 'N/A';
-           $driver   = exists $out->{controllerDriverVersion}
-             ? $out->{controllerDriverVersion} : 'N/A';
-           $minstdr  = exists $out->{'controllerMinRequiredStorportVer'}
-             ? $out->{controllerMinRequiredStorportVer} : undef;
-           $stdr     = exists $out->{controllerStorportDriverVersion}
-             ? $out->{controllerStorportDriverVersion} : undef;
-           $nexus    = convert_nexus($out->{controllerNexusID});
+           $name     = $out->{controllerName} || 'Unknown controller';
+           $state    = get_hashval($out->{controllerState}, \%ctrl_state) || 'Unknown state';
+           $status   = get_snmp_status($out->{controllerComponentStatus});
+           $minfw    = $out->{controllerMinFWVersion} || undef;
+           $mindr    = $out->{controllerMinDriverVersion} || undef;
+           $firmware = $out->{controllerFWVersion} || 'N/A';
+           $driver   = $out->{controllerDriverVersion} || 'N/A';
+           $minstdr  = $out->{'controllerMinRequiredStorportVer'} || undef;
+           $stdr     = $out->{controllerStorportDriverVersion} || undef;
+           $nexus    = convert_nexus(($out->{controllerNexusID} || 9999));
        }
        else {
-           $nexus    = $out->{ID};
-           $name     = $out->{Name};
-           $state    = $out->{State};
-           $status   = $out->{Status};
+           $nexus    = get_nonempty_string('ID', $out, '9999');
+           $name     = get_nonempty_string('Name', $out, 'Unknown controller');
+           $state    = get_nonempty_string('State', $out, 'Unknown state');
+           $status   = get_nonempty_string('Status', $out, 'Unknown');
            $minfw    = $out->{'Minimum Required Firmware Version'} ne 'Not Applicable'
              ? $out->{'Minimum Required Firmware Version'} : undef;
            $mindr    = $out->{'Minimum Required Driver Version'} ne 'Not Applicable'
@@ -1289,7 +1715,6 @@ sub check_controllers {
 #-----------------------------------------
 sub check_physical_disks {
     return if $#controllers == -1;
-    return if blacklisted('pdisk', 'all');
 
     my $nexus    = undef;
     my $name     = undef;
@@ -1304,6 +1729,7 @@ sub check_physical_disks {
     my $media    = undef;  # media type (e.g. HDD, SSD)
     my $bus      = undef;  # bus protocol (e.g. SAS, SATA)
     my $spare    = undef;  # spare state (e.g. global hotspare)
+    my $cert     = undef;  # if drive is certified or not
     my @output  = ();
 
     if ($snmp) {
@@ -1323,6 +1749,7 @@ sub check_physical_disks {
             '1.3.6.1.4.1.674.10893.1.20.130.4.1.26' => 'arrayDiskNexusID',
             '1.3.6.1.4.1.674.10893.1.20.130.4.1.31' => 'arrayDiskSmartAlertIndication',
             '1.3.6.1.4.1.674.10893.1.20.130.4.1.35' => 'arrayDiskMediaType',
+            '1.3.6.1.4.1.674.10893.1.20.130.4.1.36' => 'arrayDiskDellCertified',
             '1.3.6.1.4.1.674.10893.1.20.130.5.1.7'  => 'arrayDiskEnclosureConnectionControllerNumber',
             '1.3.6.1.4.1.674.10893.1.20.130.6.1.7'  => 'arrayDiskChannelConnectionControllerNumber',
            );
@@ -1420,22 +1847,19 @@ sub check_physical_disks {
   PDISK:
     foreach my $out (@output) {
        if ($snmp) {
-           $name   = $out->{arrayDiskName};
-           $state    = get_hashval($out->{arrayDiskState}, \%pdisk_state);
-           $status   = $snmp_status{$out->{arrayDiskComponentStatus}};
-           $fpred    = exists $out->{arrayDiskSmartAlertIndication}
+           $name     = $out->{arrayDiskName} || 'Unknown disk';
+           $state    = get_hashval($out->{arrayDiskState}, \%pdisk_state) || 'Unknown state';
+           $status   = get_snmp_status($out->{arrayDiskComponentStatus});
+           $fpred    = defined $out->{arrayDiskSmartAlertIndication}
              && $out->{arrayDiskSmartAlertIndication} == 2 ? 1 : 0;
            $progr    = q{};
-           $nexus    = convert_nexus($out->{arrayDiskNexusID});
-           $vendor   = exists $out->{arrayDiskVendor}
-             ? $out->{arrayDiskVendor} : 'Unknown Vendor';
-           $product  = exists $out->{arrayDiskProductID}
-             ? $out->{arrayDiskProductID} : 'Unknown Product ID';
-           $spare    = get_hashval($out->{arrayDiskSpareState}, \%spare_state);
-           $bus      = exists $out->{arrayDiskBusType}
-             ? get_hashval($out->{arrayDiskBusType}, \%bus_type) : undef;
-           $media    = exists $out->{arrayDiskMediaType}
-             ? get_hashval($out->{arrayDiskMediaType}, \%media_type) : undef;
+           $nexus    = convert_nexus(($out->{arrayDiskNexusID} || 9999));
+           $vendor   = $out->{arrayDiskVendor} || 'Unknown vendor';
+           $product  = $out->{arrayDiskProductID} || 'Unknown product ID';
+           $spare    = get_hashval($out->{arrayDiskSpareState}, \%spare_state) || q{};
+           $bus      = get_hashval($out->{arrayDiskBusType}, \%bus_type);
+           $media    = get_hashval($out->{arrayDiskMediaType}, \%media_type);
+           $cert     = defined $out->{arrayDiskDellCertified} ? $out->{arrayDiskDellCertified} : 1;
            $capacity = exists $out->{arrayDiskLengthInMB}
              ? $out->{arrayDiskLengthInMB} * 1024**2 : -1;
 
@@ -1455,27 +1879,34 @@ sub check_physical_disks {
            }
        }
        else {
-           $name     = $out->{'Name'};
-           $state    = $out->{'State'};
-           $status   = $out->{'Status'};
-           $fpred    = lc($out->{'Failure Predicted'}) eq 'yes' ? 1 : 0;
-           $progr    = ' [' . $out->{'Progress'} . ']';
-           $ctrl     = $out->{'ctrl'};
+           $name     = get_nonempty_string('Name', $out, 'Unknown disk');
+           $state    = get_nonempty_string('State', $out, 'Unknown state');
+           $status   = get_nonempty_string('Status', $out, 'Unknown');
+           $fpred    = lc(get_nonempty_string('Failure Predicted', $out, q{})) eq 'yes' ? 1 : 0;
+           $progr    = ' [' . get_nonempty_string('Progress', $out, q{}) . ']';
            $nexus    = join q{:}, $out->{ctrl}, $out->{'ID'};
-           $vendor   = $out->{'Vendor ID'} ne q{} ? $out->{'Vendor ID'} : 'Unknown Vendor';
-           $product  = $out->{'Product ID'} ne q{} ? $out->{'Product ID'} : 'Unknown Product ID';
-           $media    = $out->{'Media'};
-           $spare    = $out->{'Hot Spare'};
-           $bus      = $out->{'Bus Protocol'};
-           $capacity = $out->{'Capacity'};
+           $vendor   = get_nonempty_string('Vendor ID', $out, 'Unknown Vendor');
+           $product  = get_nonempty_string('Product ID', $out, 'Unknown Product ID');
+           $media    = get_nonempty_string('Media', $out, undef);
+           $bus      = get_nonempty_string('Bus Protocol', $out, undef);
+           $spare    = get_nonempty_string('Hot Spare', $out, q{});
+            $cert     = get_nonempty_string('Certified', $out, 1);
+           $ctrl     = $out->{ctrl};
+           $capacity = get_nonempty_string('Capacity', $out, q{});
            $capacity =~ s{\A .*? \((\d+) \s bytes\) \z}{$1}xms;
            if ($capacity eq 'Unavailable') {
                $capacity = -1;
            }
+           if ($cert eq 'Yes' or $cert eq 'Not Applicable') {
+               $cert = 1;
+           }
+           else {
+               $cert = 0;
+           }
        }
 
-       next PDISK if blacklisted('pdisk', $nexus);
        $count{pdisk}++;
+       next PDISK if blacklisted('pdisk', $nexus);
 
         $vendor  =~ s{\s+\z}{}xms; # remove trailing whitespace
         $product =~ s{\s+\z}{}xms; # remove trailing whitespace
@@ -1529,6 +1960,26 @@ sub check_physical_disks {
              $name, $vendor, $product, $capacity, $ctrl, $state, $progr;
            report('storage', $msg, $E_WARNING, $nexus);
        }
+       # Special case: Uncertified disk
+       elsif ($status eq 'Non-Critical' and !$cert) {
+           if (blacklisted('pdisk_cert', $nexus)) {
+               my $msg = sprintf '%s [%s %s, %s] on ctrl %d is %s, Not Certified',
+                 $name, $vendor, $product, $capacity, $ctrl, $state;
+               report('storage', $msg, $E_OK, $nexus);
+           }
+           else {
+               my $msg = sprintf '%s [%s %s, %s] on ctrl %d is Not Certified',
+                 $name, $vendor, $product, $capacity, $ctrl;
+               report('storage', $msg, $E_WARNING, $nexus);
+           }
+       }
+       # Special case: Foreign disk
+       elsif ($status eq 'Non-Critical' and $state eq 'Foreign'
+             and blacklisted('pdisk_foreign', $nexus)) {
+           my $msg = sprintf '%s [%s %s, %s] on ctrl %d is %s',
+             $name, $vendor, $product, $capacity, $ctrl, $state;
+           report('storage', $msg, $E_OK, $nexus);
+       }
        # Default
        elsif ($status ne 'Ok') {
            my $msg =  sprintf '%s [%s %s, %s] on ctrl %d needs attention: %s',
@@ -1552,7 +2003,6 @@ sub check_physical_disks {
 #-----------------------------------------
 sub check_virtual_disks {
     return if $#controllers == -1;
-    return if blacklisted('vdisk', 'all');
 
     my $name   = undef;
     my $nexus  = undef;
@@ -1621,40 +2071,54 @@ sub check_virtual_disks {
         1  => 'Concatenated',
         2  => 'RAID-0',
         3  => 'RAID-1',
+        4  => 'UNSUPPORTED:raid-2',
+        5  => 'UNSUPPORTED:raid-3',
+        6  => 'UNSUPPORTED:raid-4',
         7  => 'RAID-5',
         8  => 'RAID-6',
+        9  => 'UNSUPPORTED:raid-7',
         10 => 'RAID-10',
+        11 => 'UNSUPPORTED:raid-30',
         12 => 'RAID-50',
+        13 => 'UNSUPPORTED:addSpares',
+        14 => 'UNSUPPORTED:deleteLogical',
+        15 => 'UNSUPPORTED:transformLogical',
+        18 => 'UNSUPPORTED:raid-0-plus-1',
         19 => 'Concatenated RAID-1',
+        20 => 'UNSUPPORTED:concatRaid-5',
+        21 => 'UNSUPPORTED:noRaid',
+        22 => 'UNSUPPORTED:volume',
+        23 => 'UNSUPPORTED:raidMorph',
         24 => 'RAID-60',
+         25 => 'CacheCade',
        );
 
     # Check virtual disks on each of the controllers
   VDISK:
     foreach my $out (@output) {
        if ($snmp) {
-           $dev    = $out->{virtualDiskDeviceName};
-           $state  = get_hashval($out->{virtualDiskState}, \%vdisk_state);
-           $layout = get_hashval($out->{virtualDiskLayout}, \%vdisk_layout);
-           $status = $snmp_status{$out->{virtualDiskComponentStatus}};
-           $size   = sprintf '%.2f GB', $out->{virtualDiskLengthInMB} / 1024;
-           $progr  = q{};  # can't get this from SNMP(?)
-           $nexus  = convert_nexus($out->{virtualDiskNexusID});
+           $dev    = $out->{virtualDiskDeviceName} || 'Unknown device';
+           $state  = get_hashval($out->{virtualDiskState}, \%vdisk_state) || 'Unknown state';
+           $layout = get_hashval($out->{virtualDiskLayout}, \%vdisk_layout) || 'Unknown layout';
+           $status = get_snmp_status($out->{virtualDiskComponentStatus});
+           $size   = sprintf '%.2f GB', ($out->{virtualDiskLengthInMB} || 0) / 1024;
+           $progr  = q{};  # not available via SNMP
+           $nexus  = convert_nexus(($out->{virtualDiskNexusID} || 9999));
        }
        else {
-           $dev    = $out->{'Device Name'};
-           $state  = $out->{State};
-           $status = $out->{Status};
-           $layout = $out->{Layout};
-           $size   = $out->{Size};
-           $progr  = ' [' . $out->{Progress} . ']';
+           $dev    = get_nonempty_string('Device Name', $out, 'Unknown device');
+           $state  = get_nonempty_string('State', $out, 'Unknown state');
+           $status = get_nonempty_string('Status', $out, 'Unknown');
+           $layout = get_nonempty_string('Layout', $out, 'Unknown layout');
+           $size   = get_nonempty_string('Size', $out, 'Unavailable');
            $size   =~ s{\A (.*GB).* \z}{$1}xms;
-           $nexus  = join q{:}, $out->{ctrl}, $out->{ID};
+           $progr  = ' [' . get_nonempty_string('Progress', $out, q{}) . ']';
            $ctrl   = $out->{ctrl};
+           $nexus  = join q{:}, $ctrl, get_nonempty_string('ID', $out, '9999');
        }
 
-       next VDISK if blacklisted('vdisk', $nexus);
        $count{vdisk}++;
+       next VDISK if blacklisted('vdisk', $nexus);
 
        # The device name is undefined sometimes
        $dev = q{} if !defined $dev;
@@ -1687,7 +2151,6 @@ sub check_virtual_disks {
 #-----------------------------------------
 sub check_cache_battery {
     return if $#controllers == -1;
-    return if blacklisted('bat', 'all');
 
     my $id     = undef;
     my $nexus  = undef;
@@ -1773,21 +2236,21 @@ sub check_cache_battery {
   BATTERY:
     foreach my $out (@output) {
        if ($snmp) {
-           $status = $snmp_status{$out->{batteryComponentStatus}};
-           $state  = get_hashval($out->{batteryState}, \%bat_state);
-           $learn  = get_hashval($out->{batteryLearnState}, \%bat_learn_state);
-           $pred   = get_hashval($out->{batteryPredictedCapacity}, \%bat_pred_cap);
-           $ctrl   = $out->{batteryConnectionControllerNumber} - 1;
-           $nexus  = convert_nexus($out->{batteryNexusID});
+           $status = get_snmp_status($out->{batteryComponentStatus});
+           $state  = get_hashval($out->{batteryState}, \%bat_state) || 'Unknown state';
+           $learn  = get_hashval($out->{batteryLearnState}, \%bat_learn_state) || 'Unknown learn state';
+           $pred   = get_hashval($out->{batteryPredictedCapacity}, \%bat_pred_cap) || 'Unknown predicted capacity status';
+           $ctrl   = $snmp_controller{$out->{batteryConnectionControllerNumber}};
+           $nexus  = convert_nexus(($out->{batteryNexusID} || 9999));
            $id     = $nexus;
            $id     =~ s{\A \d+:(\d+) \z}{$1}xms;
        }
        else {
-           $id     = $out->{'ID'};
-           $state  = $out->{'State'};
-           $status = $out->{'Status'};
-           $learn  = $out->{'Learn State'};
-           $pred   = $out->{'Predicted Capacity Status'};
+           $id     = get_nonempty_string('ID', $out, 9999);
+           $state  = get_nonempty_string('State', $out, 'Unknown state');
+           $status = get_nonempty_string('Status', $out, 'Unknown');
+           $learn  = get_nonempty_string('Learn State', $out, 'Unknown learn state');
+           $pred   = get_nonempty_string('Predicted Capacity Status', $out, 'Unknown predicted capacity status');
            $ctrl   = $out->{'ctrl'};
            $nexus  = join q{:}, $out->{ctrl}, $id;
        }
@@ -1837,16 +2300,10 @@ sub check_cache_battery {
            report('storage', $msg, $E_WARNING, $nexus);
        }
        # Default
-       elsif ($status ne 'Ok') {
-           my $msg = sprintf 'Cache Battery %d in controller %d needs attention: %s (%s)',
-             $id, $ctrl, $state, $status;
-           report('storage', $msg, $status2nagios{$status}, $nexus);
-       }
-       # Ok
        else {
            my $msg = sprintf 'Cache Battery %d in controller %d is %s',
              $id, $ctrl, $state;
-           report('storage', $msg, $E_OK, $nexus);
+           report('storage', $msg, $status2nagios{$status}, $nexus);
        }
     }
     return;
@@ -1858,7 +2315,6 @@ sub check_cache_battery {
 #-----------------------------------------
 sub check_connectors {
     return if $#controllers == -1;
-    return if blacklisted('conn', 'all');
 
     my $nexus  = undef;
     my $name   = undef;
@@ -1926,21 +2382,19 @@ sub check_connectors {
   CHANNEL:
     foreach my $out (@output) {
         if ($snmp) {
-            $name   = $out->{channelName};
-            $status = $snmp_status{$out->{channelComponentStatus}};
-            $state  = get_hashval($out->{channelState}, \%conn_state);
-            $type   = get_hashval($out->{channelBusType}, \%conn_bustype);
-           $nexus  = convert_nexus($out->{channelNexusID});
+            $name   = $out->{channelName} || 'Unknown channel';
+            $status = get_snmp_status($out->{channelComponentStatus});
+            $state  = get_hashval($out->{channelState}, \%conn_state) || 'Unknown state';
+            $type   = get_hashval($out->{channelBusType}, \%conn_bustype) || 'Unknown type';
+           $nexus  = convert_nexus(($out->{channelNexusID} || 9999));
            $ctrl   = $nexus;
            $ctrl   =~ s{(\d+):\d+}{$1}xms;
-           # workaround for ancient OMSA versions
-           if (! defined $type) { $type = 'n/a'; }
         }
         else {
-            $name   = $out->{'Name'};
-            $state  = $out->{'State'};
-            $status = $out->{'Status'};
-            $type   = $out->{'Connector Type'};
+            $name   = get_nonempty_string('Name', $out, 'Unknown channel');
+            $state  = get_nonempty_string('State', $out, 'Unknown state');
+           $status = get_nonempty_string('Status', $out, 'Unknown');
+            $type   = get_nonempty_string('Connector Type', $out, 'Unknown type');
            $ctrl   = $out->{ctrl};
            $nexus  = join q{:}, $out->{ctrl}, $out->{'ID'};
         }
@@ -1959,8 +2413,6 @@ sub check_connectors {
 # STORAGE: Check enclosures
 #-----------------------------------------
 sub check_enclosures {
-    return if blacklisted('encl', 'all');
-
     my $id       = undef;
     my $nexus    = undef;
     my $name     = undef;
@@ -2019,30 +2471,29 @@ sub check_enclosures {
   ENCLOSURE:
     foreach my $out (@output) {
         if ($snmp) {
-            $id       = $out->{enclosureNumber} - 1;
-            $name     = $out->{enclosureName};
-            $state    = get_hashval($out->{enclosureState}, \%encl_state);
-            $status   = $snmp_status{$out->{enclosureComponentStatus}};
-           $firmware = exists $out->{enclosureFirmwareVersion}
-             ? $out->{enclosureFirmwareVersion} : 'N/A';
-           $nexus    = convert_nexus($out->{enclosureNexusID});
+            $id       = ($out->{enclosureNumber} || 10000) - 1;
+            $name     = $out->{enclosureName} || 'Unknown enclosure';
+            $state    = get_hashval($out->{enclosureState}, \%encl_state) || 'Unknown state';
+            $status   = get_snmp_status($out->{enclosureComponentStatus});
+           $firmware = $out->{enclosureFirmwareVersion} || 'N/A';
+           $nexus    = convert_nexus(($out->{enclosureNexusID} || 9999));
            $ctrl     = $nexus;
            $ctrl     =~ s{\A (\d+):.* \z}{$1}xms;
            # for the next two, a value of 9999 means feature not available
-           $occupied_slots = exists $out->{enclosureOccupiedSlotCount}
+           $occupied_slots = defined $out->{enclosureOccupiedSlotCount}
              && $out->{enclosureOccupiedSlotCount} != 9999
                ? $out->{enclosureOccupiedSlotCount} : undef;
-           $total_slots    = exists $out->{enclosureTotalSlots}
+           $total_slots    = defined $out->{enclosureTotalSlots}
              && $out->{enclosureTotalSlots} != 9999
                ? $out->{enclosureTotalSlots} : undef;
         }
         else {
-            $id       = $out->{ID};
-            $name     = $out->{Name};
-            $state    = $out->{State};
-            $status   = $out->{Status};
-           $firmware = $out->{'Firmware Version'} ne 'Not Applicable'
-             ? $out->{'Firmware Version'} : 'N/A';
+            $id       = get_nonempty_string('ID', $out, 9999);
+            $name     = get_nonempty_string('Name', $out, 'Unknown enclosure');
+            $state    = get_nonempty_string('State', $out, 'Unknown state');
+           $status   = get_nonempty_string('Status', $out, 'Unknown');
+           $firmware = get_nonempty_string('Firmware Version', $out, 'N/A');
+           $firmware =~ s{Not\sApplicable}{N/A}xms;
            $nexus    = join q{:}, $out->{ctrl}, $id;
            $ctrl     = $out->{ctrl};
         }
@@ -2089,7 +2540,6 @@ sub check_enclosures {
 #-----------------------------------------
 sub check_enclosure_fans {
     return if $#controllers == -1;
-    return if blacklisted('encl_fan', 'all');
 
     my $nexus     = undef;
     my $name      = undef;
@@ -2156,22 +2606,22 @@ sub check_enclosure_fans {
   FAN:
     foreach my $out (@output) {
        if ($snmp) {
-           $name      = $out->{fanName};
-           $state     = get_hashval($out->{fanState}, \%fan_state);
-           $status    = $snmp_status{$out->{fanComponentStatus}};
-           $speed     = $out->{fanProbeCurrValue};
-           $encl_name = $out->{fanConnectionEnclosureName};
+           $name      = $out->{fanName} || 'Unknown fan';
+           $state     = get_hashval($out->{fanState}, \%fan_state) || 'Unknown state';
+           $status    = get_snmp_status($out->{fanComponentStatus});
+           $speed     = $out->{fanProbeCurrValue} || 'N/A';
+           $encl_name = $out->{fanConnectionEnclosureName} || 'Unknown enclosure';
            $encl_id   = $snmp_enclosure{$out->{fanConnectionEnclosureNumber}}{nexus};
-           $nexus     = convert_nexus($out->{fanNexusID});
+           $nexus     = convert_nexus(($out->{fanNexusID} || 9999));
        }
        else {
-           $name      = $out->{'Name'};
-           $state     = $out->{'State'};
-           $status    = $out->{'Status'};
-           $speed     = $out->{'Speed'};
+           $name      = get_nonempty_string('Name', $out, 'Unknown fan');
+           $state     = get_nonempty_string('State', $out, 'Unknown state');
+           $status    = get_nonempty_string('Status', $out, 'Unknown');
+           $speed     = get_nonempty_string('Speed', $out, 'N/A');
            $encl_id   = join q{:}, $out->{ctrl}, $out->{'encl_id'};
            $encl_name = $out->{encl_name};
-           $nexus     = join q{:}, $out->{ctrl}, $out->{'encl_id'}, $out->{'ID'};
+           $nexus     = join q{:}, $out->{ctrl}, $out->{'encl_id'}, get_nonempty_string('ID', $out, '9999');
        }
 
        next FAN if blacklisted('encl_fan', $nexus);
@@ -2198,7 +2648,6 @@ sub check_enclosure_fans {
 #-----------------------------------------
 sub check_enclosure_pwr {
     return if $#controllers == -1;
-    return if blacklisted('encl_ps', 'all');
 
     my $nexus     = undef;
     my $name      = undef;
@@ -2263,20 +2712,20 @@ sub check_enclosure_pwr {
   PS:
     foreach my $out (@output) {
        if ($snmp) {
-           $name      = $out->{powerSupplyName};
-           $state     = get_hashval($out->{powerSupplyState}, \%ps_state);
-           $status    = $snmp_status{$out->{powerSupplyComponentStatus}};
+           $name      = $out->{powerSupplyName} || 'Unknown PSU';
+           $state     = get_hashval($out->{powerSupplyState}, \%ps_state) || 'Unknown state';
+           $status    = get_snmp_status($out->{powerSupplyComponentStatus});
            $encl_id   = $snmp_enclosure{$out->{powerSupplyConnectionEnclosureNumber}}{nexus};
-           $encl_name = $out->{powerSupplyConnectionEnclosureName};
-           $nexus     = convert_nexus($out->{powerSupplyNexusID});
+           $encl_name = $out->{powerSupplyConnectionEnclosureName} || 'Unknown enclosure';
+           $nexus     = convert_nexus(($out->{powerSupplyNexusID} || 9999));
        }
        else {
-           $name      = $out->{'Name'};
-           $state     = $out->{'State'};
-           $status    = $out->{'Status'};
+           $name      = get_nonempty_string('Name', $out, 'Unknown PSU');
+           $state     = get_nonempty_string('State', $out, 'Unknown state');
+           $status    = get_nonempty_string('Status', $out, 'Unknown');
            $encl_id   = join q{:}, $out->{ctrl}, $out->{'encl_id'};
            $encl_name = $out->{encl_name};
-           $nexus     = join q{:}, $out->{ctrl}, $out->{'encl_id'}, $out->{'ID'};
+           $nexus     = join q{:}, $out->{ctrl}, $out->{'encl_id'}, get_nonempty_string('ID', $out, '9999');
        }
 
        next PS if blacklisted('encl_ps', $nexus);
@@ -2303,7 +2752,6 @@ sub check_enclosure_pwr {
 #-----------------------------------------
 sub check_enclosure_temp {
     return if $#controllers == -1;
-    return if blacklisted('encl_temp', 'all');
 
     my $nexus     = undef;
     my $name      = undef;
@@ -2380,37 +2828,32 @@ sub check_enclosure_temp {
   TEMP:
     foreach my $out (@output) {
        if ($snmp) {
-           $name      = $out->{temperatureProbeName};
-           $state     = get_hashval($out->{temperatureProbeState}, \%temp_state);
-           $status    = $snmp_status{$out->{temperatureProbeComponentStatus}};
-           $unit      = $out->{temperatureProbeUnit};
-           $reading   = exists $out->{temperatureProbeCurValue}
-             ? $out->{temperatureProbeCurValue} : '[N/A]';
-           $max_warn  = exists $out->{temperatureProbeMaxWarning}
-             ? $out->{temperatureProbeMaxWarning} : '[N/A]';
-           $max_crit  = exists $out->{temperatureProbeMaxCritical}
-             ? $out->{temperatureProbeMaxCritical} : '[N/A]';
-           $min_warn  = exists $out->{temperatureProbeMinWarning}
-             ? $out->{temperatureProbeMinWarning} : '[N/A]';
-           $min_crit  = exists $out->{temperatureProbeMinCritical}
-             ? $out->{temperatureProbeMinCritical} : '[N/A]';
+           $name      = $out->{temperatureProbeName} || 'Unknown temp probe';
+           $state     = get_hashval($out->{temperatureProbeState}, \%temp_state) || 'Unknown state';
+           $status    = get_snmp_probestatus($out->{temperatureProbeComponentStatus});
+           $unit      = $out->{temperatureProbeUnit} || 'Unknown unit';
+           $reading   = $out->{temperatureProbeCurValue} || '[N/A]';
+           $max_warn  = $out->{temperatureProbeMaxWarning} || '[N/A]';
+           $max_crit  = $out->{temperatureProbeMaxCritical} || '[N/A]';
+           $min_warn  = $out->{temperatureProbeMinWarning} || '[N/A]';
+           $min_crit  = $out->{temperatureProbeMinCritical} || '[N/A]';
            $encl_id   = $snmp_enclosure{$out->{temperatureConnectionEnclosureNumber}}{nexus};
-           $encl_name = $out->{temperatureConnectionEnclosureName};
-           $nexus     = convert_nexus($out->{temperatureProbeNexusID});
+           $encl_name = $out->{temperatureConnectionEnclosureName} || 'Unknown enclosure';
+           $nexus     = convert_nexus(($out->{temperatureProbeNexusID} || 9999));
        }
        else {
-           $name      = $out->{'Name'};
-           $state     = $out->{'State'};
-           $status    = $out->{'Status'};
+           $name      = get_nonempty_string('Name', $out, 'Unknown temp probe');
+           $state     = get_nonempty_string('State', $out, 'Unknown state');
+           $status    = get_nonempty_string('Status', $out, 'Unknown');
            $unit      = 'FIXME';
-           $reading   = $out->{'Reading'};
-           $max_warn  = $out->{'Maximum Warning Threshold'};
-           $max_crit  = $out->{'Maximum Failure Threshold'};
-           $min_warn  = $out->{'Minimum Warning Threshold'};
-           $min_crit  = $out->{'Minimum Failure Threshold'};
+           $reading   = get_nonempty_string('Reading', $out, '[N/A]');
+           $max_warn  = get_nonempty_string('Maximum Warning Threshold', $out, '[N/A]');
+           $max_crit  = get_nonempty_string('Maximum Failure Threshold', $out, '[N/A]');
+           $min_warn  = get_nonempty_string('Minimum Warning Threshold', $out, '[N/A]');
+           $min_crit  = get_nonempty_string('Minimum Failure Threshold', $out, '[N/A]');
            $encl_id   = join q{:}, $out->{ctrl}, $out->{'encl_id'};
            $encl_name = $out->{encl_name};
-           $nexus     = join q{:}, $out->{ctrl}, $out->{'encl_id'}, $out->{'ID'};
+           $nexus     = join q{:}, $out->{ctrl}, $out->{'encl_id'}, get_nonempty_string('ID', $out, '9999');
        }
 
        next TEMP if blacklisted('encl_temp', $nexus);
@@ -2422,6 +2865,15 @@ sub check_enclosure_temp {
        $min_warn =~ s{\A \s* (-?\d+) \s* C? \s* \z}{$1}xms or $min_warn = '[N/A]';
        $min_crit =~ s{\A \s* (-?\d+) \s* C? \s* \z}{$1}xms or $min_crit = '[N/A]';
 
+       # Convert temp units
+       if ($opt{tempunit} ne 'C') {
+           $reading  = temp_from_celsius($reading,  $opt{tempunit});
+           $max_warn = temp_from_celsius($max_warn, $opt{tempunit});
+           $max_crit = temp_from_celsius($max_crit, $opt{tempunit});
+           $min_warn = temp_from_celsius($min_warn, $opt{tempunit});
+           $min_crit = temp_from_celsius($min_crit, $opt{tempunit});
+       }
+
        # Inactive temp probes
        if ($status eq 'Unknown' and $state eq 'Inactive') {
            my $msg = sprintf '%s in enclosure %s [%s] is %s',
@@ -2429,26 +2881,26 @@ sub check_enclosure_temp {
            report('storage', $msg, $E_OK, $nexus);
        }
        elsif ($status ne 'Ok' and $max_crit ne '[N/A]' and $reading > $max_crit) {
-           my $msg = sprintf '%s in enclosure %s [%s] is critically high at %d C',
-             $name, $encl_id, $encl_name, $reading;
+           my $msg = sprintf '%s in enclosure %s [%s] is critically high at %s %s',
+             $name, $encl_id, $encl_name, $reading, $opt{tempunit};
            my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
            report('chassis', $msg, $err, $nexus);
        }
        elsif ($status ne 'Ok' and $max_warn ne '[N/A]' and $reading > $max_warn) {
-           my $msg = sprintf '%s in enclosure %s [%s] is too high at %d C',
-             $name, $encl_id, $encl_name, $reading;
+           my $msg = sprintf '%s in enclosure %s [%s] is too high at %s %s',
+             $name, $encl_id, $encl_name, $reading, $opt{tempunit};
            my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
            report('chassis', $msg, $err, $nexus);
        }
        elsif ($status ne 'Ok' and $min_crit ne '[N/A]' and $reading < $min_crit) {
-           my $msg = sprintf '%s in enclosure %s [%s] is critically low at %d C',
-             $name, $encl_id, $encl_name, $reading;
+           my $msg = sprintf '%s in enclosure %s [%s] is critically low at %s %s',
+             $name, $encl_id, $encl_name, $reading, $opt{tempunit};
            my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
            report('chassis', $msg, $err, $nexus);
        }
        elsif ($status ne 'Ok' and $min_warn ne '[N/A]' and $reading < $min_warn) {
-           my $msg = sprintf '%s in enclosure %s [%s] is too low at %d C',
-             $name, $encl_id, $encl_name, $reading;
+           my $msg = sprintf '%s in enclosure %s [%s] is too low at %s %s',
+             $name, $encl_id, $encl_name, $reading, $opt{tempunit};
            my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
            report('chassis', $msg, $err, $nexus);
        }
@@ -2459,7 +2911,7 @@ sub check_enclosure_temp {
            if (defined $reading && $reading =~ m{\A -?\d+ \z}xms) {
                # take into account that with certain states the
                # reading doesn't exist or is not an integer
-               $msg .= sprintf ' at %s C', $reading;
+               $msg .= sprintf ' at %s %s', $reading, $opt{tempunit};
                if ($min_warn eq '[N/A]' or $min_crit eq '[N/A]') {
                    $msg .= sprintf ' (max=%s/%s)', $max_warn, $max_crit;
                }
@@ -2478,7 +2930,7 @@ sub check_enclosure_temp {
            if (defined $reading && $reading ne '[N/A]') {
                # take into account that with certain states the
                # reading doesn't exist or is not an integer
-               $msg .= sprintf ' reads %d C', $reading;
+               $msg .= sprintf ' reads %s %s', $reading, $opt{tempunit};
                if ($min_warn eq '[N/A]' or $min_crit eq '[N/A]') {
                    $msg .= sprintf ' (max=%s/%s)', $max_warn, $max_crit;
                }
@@ -2495,16 +2947,23 @@ sub check_enclosure_temp {
 
        # Collect performance data
        if (defined $opt{perfdata} && $reading ne '[N/A]') {
-           $name =~ s{\A Temperature\sProbe\s(\d+) \z}{temp_$1}gxms;
-           my $label = "enclosure_${encl_id}_${name}";
-           my $mini = $label;
-           $mini =~ s{enclosure_(.+?)_temp_(.+?)}{e$1t$2}xms;
+           my $index = $name;
+           $index =~ s{\A Temperature\sProbe\s(\d+) \z}{$1}gxms;
+           my $legacy_name = $name;
+           $legacy_name =~ s{\A Temperature\sProbe\s(\d+) \z}{temp_$1}gxms;
+           my $legacy_label = lc "enclosure_${encl_id}_${legacy_name}";
+           my $legacy_mini = $legacy_label;
+            $legacy_mini =~ s{enclosure_(.+?)_temp_(.+?)}{e$1t$2}xms;
            push @perfdata, {
-                            label => $label,
-                            mini  => $mini,
-                            value => $reading,
-                            warn  => $max_warn,
-                            crit  => $max_crit,
+                            type   => 'E',
+                            id     => $opt{perfdata} eq 'minimal' ? "${encl_id}_t${index}" : "${encl_id}_temp_${index}",
+                            unit   => $opt{tempunit},
+                            label  => q{},
+                            legacy => $legacy_label,
+                            mini   => $legacy_mini,
+                            value  => $reading,
+                            warn   => $max_warn,
+                            crit   => $max_crit,
                            };
        }
     }
@@ -2517,7 +2976,6 @@ sub check_enclosure_temp {
 #-----------------------------------------
 sub check_enclosure_emms {
     return if $#controllers == -1;
-    return if blacklisted('encl_emm', 'all');
 
     my $nexus     = undef;
     my $name      = undef;
@@ -2583,20 +3041,20 @@ sub check_enclosure_emms {
   EMM:
     foreach my $out (@output) {
        if ($snmp) {
-           $name      = $out->{enclosureManagementModuleName};
-           $state     = get_hashval($out->{enclosureManagementModuleState}, \%emms_state);
-           $status    = $snmp_status{$out->{enclosureManagementModuleComponentStatus}};
+           $name      = $out->{enclosureManagementModuleName} || 'Unknown EMM';
+           $state     = get_hashval($out->{enclosureManagementModuleState}, \%emms_state) || 'Unknown state';
+           $status    = get_snmp_status($out->{enclosureManagementModuleComponentStatus});
            $encl_id   = $snmp_enclosure{$out->{enclosureManagementModuleConnectionEnclosureNumber}}{nexus};
-           $encl_name = $out->{enclosureManagementModuleConnectionEnclosureName};
-           $nexus     = convert_nexus($out->{enclosureManagementModuleNexusID});
+           $encl_name = $out->{enclosureManagementModuleConnectionEnclosureName} || 'Unknown enclosure';
+           $nexus     = convert_nexus(($out->{enclosureManagementModuleNexusID} || 9999));
        }
        else {
-           $name      = $out->{'Name'};
-           $state     = $out->{'State'};
-           $status    = $out->{'Status'};
+           $name      = get_nonempty_string('Name', $out, 'Unknown EMM');
+           $state     = get_nonempty_string('State', $out, 'Unknown state');
+           $status    = get_nonempty_string('Status', $out, 'Unknown');
            $encl_id   = join q{:}, $out->{ctrl}, $out->{'encl_id'};
            $encl_name = $out->{encl_name};
-           $nexus     = join q{:}, $out->{ctrl}, $out->{'encl_id'}, $out->{'ID'};
+           $nexus     = join q{:}, $out->{ctrl}, $out->{'encl_id'}, get_nonempty_string('ID', $out, '9999');
        }
 
        next EMM if blacklisted('encl_emm', $nexus);
@@ -2628,8 +3086,6 @@ sub check_enclosure_emms {
 # CHASSIS: Check memory modules
 #-----------------------------------------
 sub check_memory {
-    return if blacklisted('dimm', 'all');
-
     my $index    = undef;
     my $status   = undef;
     my $location = undef;
@@ -2683,22 +3139,26 @@ sub check_memory {
     foreach my $out (@output) {
        @failures = ();  # Initialize
        if ($snmp) {
-           $index    = $out->{memoryDeviceIndex};
-           $status   = $snmp_status{$out->{memoryDeviceStatus}};
-           $location = $out->{memoryDeviceLocationName};
-           $size     = sprintf '%d MB', $out->{memoryDeviceSize}/1024;
-           $modes    = $out->{memoryDeviceFailureModes};
+           $index    = ($out->{memoryDeviceIndex} || 10000) - 1;
+           $status   = get_snmp_status($out->{memoryDeviceStatus});
+           $location = $out->{memoryDeviceLocationName} || 'Unknown location';
+           $size     = sprintf '%d MB', ($out->{memoryDeviceSize} || 0)/1024;
+           $modes    = $out->{memoryDeviceFailureModes} || -9999;
            if ($modes > 0) {
                foreach my $mask (sort keys %failure_mode) {
                    if (($modes & $mask) != 0) { push @failures, $failure_mode{$mask}; }
                }
            }
+           elsif ($modes == -9999) {
+               push @failures, q{ERROR: Failure modes not available via SNMP};
+           }
        }
        else {
-           $index    = $out->{'Type'} eq '[Not Occupied]' ? undef : $out->{'Index'};
-           $status   = $out->{'Status'};
-           $location = $out->{'Connector Name'};
-           $size     = $out->{'Size'};
+           my $type  = get_nonempty_string('Type', $out, q{});
+           $index    = $type eq '[Not Occupied]' ? undef : get_nonempty_string('Index', $out, 9999);
+           $status   = get_nonempty_string('Status', $out, 'Unknown');
+           $location = get_nonempty_string('Connector Name', $out, 'Unknown location');
+           $size     = get_nonempty_string('Size', $out, 0);
            if (defined $size) {
                $size =~ s{\s\s}{ }gxms;
            }
@@ -2719,11 +3179,11 @@ sub check_memory {
        $msize =~ s{\A (\d+) \s MB}{$1}xms;
        $count{mem} += $msize;
 
-       next DIMM if blacklisted('dimm', $index);
-
        # Ignore empty memory slots
        next DIMM if !defined $index;
+
        $count{dimm}++;
+       next DIMM if blacklisted('dimm', $index);
 
        if ($status ne 'Ok') {
            my $msg = undef;
@@ -2753,8 +3213,6 @@ sub check_memory {
 # CHASSIS: Check fans
 #-----------------------------------------
 sub check_fans {
-    return if blacklisted('fan', 'all');
-
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -2800,55 +3258,53 @@ sub check_fans {
   FAN:
     foreach my $out (@output) {
        if ($snmp) {
-           $index    = $out->{coolingDeviceIndex};
-           $status   = $snmp_probestatus{$out->{coolingDeviceStatus}};
-           $reading  = $out->{coolingDeviceReading};
-           $location = $out->{coolingDeviceLocationName};
-           $max_crit = exists $out->{coolingDeviceUpperCriticalThreshold}
-             ? $out->{coolingDeviceUpperCriticalThreshold} : 0;
-           $max_warn = exists $out->{coolingDeviceUpperNonCriticalThreshold}
-             ? $out->{coolingDeviceUpperNonCriticalThreshold} : 0;
+           $index    = ($out->{coolingDeviceIndex} || 10000) - 1;
+           $status   = get_snmp_probestatus($out->{coolingDeviceStatus});
+           $reading  = $out->{coolingDeviceReading} || 0;
+           $location = $out->{coolingDeviceLocationName} || 'Unknown location';
+           $max_crit = $out->{coolingDeviceUpperCriticalThreshold} || 0;
+           $max_warn = $out->{coolingDeviceUpperNonCriticalThreshold} || 0;
        }
        else {
-           $index    = $out->{'Index'};
-           $status   = $out->{'Status'};
-           $reading  = $out->{'Reading'};
-           $location = $out->{'Probe Name'};
-           $max_crit = $out->{'Maximum Failure Threshold'} ne '[N/A]'
-             ? $out->{'Maximum Failure Threshold'} : 0;
-           $max_warn = $out->{'Maximum Warning Threshold'} ne '[N/A]'
-             ? $out->{'Maximum Warning Threshold'} : 0;
+           $index    = get_nonempty_string('Index', $out, 9999);
+           $status   = get_nonempty_string('Status', $out, 'Unknown');
+           $reading  = get_nonempty_string('Reading', $out, 0);
+           $location = get_nonempty_string('Probe Name', $out, 'Unknown location');
+           $max_crit = get_nonempty_string('Maximum Failure Threshold', $out, 0);
+           $max_warn = get_nonempty_string('Maximum Warning Threshold', $out, 0);
+           if ($max_crit eq '[N/A]') { $max_crit = 0; }
+           if ($max_warn eq '[N/A]') { $max_warn = 0; }
            $reading  =~ s{\A (\d+).* \z}{$1}xms;
            $max_warn =~ s{\A (\d+).* \z}{$1}xms;
            $max_crit =~ s{\A (\d+).* \z}{$1}xms;
        }
 
-       next FAN if blacklisted('fan', $index);
        $count{fan}++;
+       next FAN if blacklisted('fan', $index);
 
-       if ($status ne 'Ok') {
-           my $msg = sprintf 'Chassis fan %d [%s] needs attention: %s',
-             $index, $location, $status;
-           my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
-           report('chassis', $msg, $err, $index);
-       }
-       else {
-           my $msg = sprintf 'Chassis fan %d [%s]: %s',
-             $index, $location, $reading;
-           report('chassis', $msg, $E_OK, $index);
-       }
+       # Default
+       my $msg = sprintf 'Chassis fan %d [%s] reading: %s RPM',
+         $index, $location, $reading;
+       my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
+       report('chassis', $msg, $err, $index);
 
        # Collect performance data
        if (defined $opt{perfdata}) {
-           my $pname = lc $location;
+           my $pname = $location;
            $pname =~ s{\s}{_}gxms;
            $pname =~ s{proc_}{cpu#}xms;
+           my $legacy_pname = $pname;
+           $pname =~ s{_rpm\z}{}ixms;
            push @perfdata, {
-                            label => "fan_${index}_${pname}",
-                            mini  => "f$index",
-                            value => $reading,
-                            warn  => $max_warn,
-                            crit  => $max_crit,
+                            type   => 'F',
+                            id     => $index,
+                            unit   => 'rpm',
+                            label  => $pname,
+                            legacy => lc "fan_${index}_${legacy_pname}",
+                             mini   => "f$index",
+                            value  => $reading,
+                            warn   => $max_warn,
+                            crit   => $max_crit,
                            };
        }
     }
@@ -2860,8 +3316,6 @@ sub check_fans {
 # CHASSIS: Check power supplies
 #-----------------------------------------
 sub check_powersupplies {
-    return if blacklisted('ps', 'all');
-
     my $index    = undef;
     my $status   = undef;
     my $type     = undef;
@@ -2935,15 +3389,15 @@ sub check_powersupplies {
        if ($snmp) {
            @states = ();  # contains states for the PS
 
-           $index    = $out->{powerSupplyIndex} - 1;
-           $status   = $snmp_status{$out->{powerSupplyStatus}};
-           $type     = get_hashval($out->{powerSupplyType}, \%ps_type);
-           $err_type = defined $out->{powerSupplyConfigurationErrorType}
-             ? $ps_config_error_type{$out->{powerSupplyConfigurationErrorType}} : undef;
+           $index    = ($out->{powerSupplyIndex} || 10000) - 1;
+           $status   = get_snmp_status($out->{powerSupplyStatus});
+           $type     = get_hashval($out->{powerSupplyType}, \%ps_type) || 'Unknown type';
+           $err_type = get_hashval($out->{powerSupplyConfigurationErrorType}, \%ps_config_error_type);
 
            # get the combined state from the StatusReading OID
+           my $raw_state = $out->{powerSupplySensorState} || 0;
            foreach my $mask (sort keys %ps_state) {
-               if (($out->{powerSupplySensorState} & $mask) != 0) {
+               if (($raw_state & $mask) != 0) {
                    push @states, $ps_state{$mask};
                }
            }
@@ -2957,14 +3411,14 @@ sub check_powersupplies {
            $state = join q{, }, @states;
        }
        else {
-           $index  = $out->{'Index'};
-           $status = $out->{'Status'};
-           $type   = $out->{'Type'};
-           $state  = $out->{'Online Status'};
+           $index  = get_nonempty_string('Index', $out, 9999);
+           $status = get_nonempty_string('Status', $out, 'Unknown');
+           $type   = get_nonempty_string('Type', $out, 'Unknown type');
+           $state  = get_nonempty_string('Online Status', $out, 'Unknown state');
        }
 
-       next PS if blacklisted('ps', $index);
        $count{power}++;
+       next PS if blacklisted('ps', $index);
 
        if ($status ne 'Ok') {
            my $msg = sprintf 'Power Supply %d [%s] needs attention: %s',
@@ -2985,8 +3439,6 @@ sub check_powersupplies {
 # CHASSIS: Check temperatures
 #-----------------------------------------
 sub check_temperatures {
-    return if blacklisted('temp', 'all');
-
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -3047,42 +3499,61 @@ sub check_temperatures {
   TEMP:
     foreach my $out (@output) {
        if ($snmp) {
-           $index    = $out->{temperatureProbeIndex} - 1;
-           $status   = $snmp_probestatus{$out->{temperatureProbeStatus}};
-           $location = $out->{temperatureProbeLocationName};
-           $reading  = exists $out->{temperatureProbeReading}
-             ? $out->{temperatureProbeReading} / 10 : '[N/A]';
-           $max_crit = exists $out->{temperatureProbeUpperCriticalThreshold}
-             ? $out->{temperatureProbeUpperCriticalThreshold} / 10 : '[N/A]';
-           $max_warn = exists $out->{temperatureProbeUpperNonCriticalThreshold}
-             ? $out->{temperatureProbeUpperNonCriticalThreshold} / 10 : '[N/A]';
-           $min_crit = exists $out->{temperatureProbeLowerCriticalThreshold}
-             ? $out->{temperatureProbeLowerCriticalThreshold} / 10 : '[N/A]';
-           $min_warn = exists $out->{temperatureProbeLowerNonCriticalThreshold}
-             ? $out->{temperatureProbeLowerNonCriticalThreshold} / 10 : '[N/A]';
+           $index    = ($out->{temperatureProbeIndex} || 10000) - 1;
+           $status   = get_snmp_probestatus($out->{temperatureProbeStatus});
+           $location = $out->{temperatureProbeLocationName} || 'Unknown location';
            $type     = get_hashval($out->{temperatureProbeType}, \%probe_type);
-           $discrete = exists $out->{temperatureProbeDiscreteReading}
-             ? $out->{temperatureProbeDiscreteReading} : '[N/A]';
+           $reading  = $out->{temperatureProbeReading} || '[N/A]';
+           $max_crit = $out->{temperatureProbeUpperCriticalThreshold} || '[N/A]';
+           $max_warn = $out->{temperatureProbeUpperNonCriticalThreshold} || '[N/A]';
+           $min_crit = $out->{temperatureProbeLowerCriticalThreshold} || '[N/A]';
+           $min_warn = $out->{temperatureProbeLowerNonCriticalThreshold} || '[N/A]';
+           $discrete = $out->{temperatureProbeDiscreteReading} || '[N/A]';
+
+           # If numeric values, i.e. not discrete
+           $reading  /= 10 if $reading  =~ m{\A \d+ \z}xms;
+           $max_crit /= 10 if $max_crit =~ m{\A \d+ \z}xms;
+           $max_warn /= 10 if $max_warn =~ m{\A \d+ \z}xms;
+           $min_crit /= 10 if $min_crit =~ m{\A \d+ \z}xms;
+           $min_warn /= 10 if $min_warn =~ m{\A \d+ \z}xms;
+
            # workaround for bad temp probes
            if ($type eq 'AmbientESM' and $reading !~ m{\A \d+(\.\d+)? \z}xms) {
                $type = 'Discrete';
            }
        }
        else {
-           $index    = $out->{'Index'};
-           $status   = $out->{'Status'};
-           $reading  = $out->{'Reading'}; $reading =~ s{\.0\s+C}{}xms;
-           $location = $out->{'Probe Name'};
-           $max_crit = $out->{'Maximum Failure Threshold'}; $max_crit =~ s{\.0\s+C}{}xms;
-           $max_warn = $out->{'Maximum Warning Threshold'}; $max_warn =~ s{\.0\s+C}{}xms;
-           $min_crit = $out->{'Minimum Failure Threshold'}; $min_crit =~ s{\.0\s+C}{}xms;
-           $min_warn = $out->{'Minimum Warning Threshold'}; $min_warn =~ s{\.0\s+C}{}xms;
+           $index    = get_nonempty_string('Index', $out, 9999);
+           $status   = get_nonempty_string('Status', $out, 'Unknown');
+           $location = get_nonempty_string('Probe Name', $out, 'Unknown location');
+           $reading  = get_nonempty_string('Reading', $out, '[N/A]');
+           $max_crit = get_nonempty_string('Maximum Failure Threshold', $out, '[N/A]');
+           $max_warn = get_nonempty_string('Maximum Warning Threshold', $out, '[N/A]');
+           $min_crit = get_nonempty_string('Minimum Failure Threshold', $out, '[N/A]');
+           $min_warn = get_nonempty_string('Minimum Warning Threshold', $out, '[N/A]');
+
+           # Cleaning the temp readings
+           $reading =~ s{\.0\s+C}{}xms;
+           $max_crit =~ s{\.0\s+C}{}xms;
+           $max_warn =~ s{\.0\s+C}{}xms;
+           $min_crit =~ s{\.0\s+C}{}xms;
+           $min_warn =~ s{\.0\s+C}{}xms;
+
            $type     = $reading =~ m{\A\d+\z}xms ? 'AmbientESM' : 'Discrete';
            $discrete = $reading;
        }
 
-       next TEMP if blacklisted('temp', $index);
        $count{temp}++;
+       next TEMP if blacklisted('temp', $index);
+
+       # Convert temp units
+       if ($opt{tempunit} ne 'C') {
+           $reading  = temp_from_celsius($reading,  $opt{tempunit});
+           $max_warn = temp_from_celsius($max_warn, $opt{tempunit});
+           $max_crit = temp_from_celsius($max_crit, $opt{tempunit});
+           $min_warn = temp_from_celsius($min_warn, $opt{tempunit});
+           $min_crit = temp_from_celsius($min_crit, $opt{tempunit});
+       }
 
        if ($type eq 'Discrete') {
            my $msg = sprintf 'Temperature probe %d [%s] is %s',
@@ -3094,56 +3565,56 @@ sub check_temperatures {
            # First check according to custom thresholds
            if (exists $crit_threshold{$index}{max} and $reading > $crit_threshold{$index}{max}) {
                # Custom critical MAX
-               my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom max=%d)',
-                 $index, $location, $reading, $crit_threshold{$index}{max};
+               my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom max=%s)',
+                 $index, $location, $reading, $opt{tempunit}, $crit_threshold{$index}{max};
                report('chassis', $msg, $E_CRITICAL, $index);
            }
            elsif (exists $warn_threshold{$index}{max} and $reading > $warn_threshold{$index}{max}) {
                # Custom warning MAX
-               my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom max=%d)',
-                 $index, $location, $reading, $warn_threshold{$index}{max};
+               my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom max=%s)',
+                 $index, $location, $reading, $opt{tempunit}, $warn_threshold{$index}{max};
                report('chassis', $msg, $E_WARNING, $index);
            }
            elsif (exists $crit_threshold{$index}{min} and $reading < $crit_threshold{$index}{min}) {
                # Custom critical MIN
-               my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom min=%d)',
-                 $index, $location, $reading, $crit_threshold{$index}{min};
+               my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom min=%s)',
+                 $index, $location, $reading, $opt{tempunit}, $crit_threshold{$index}{min};
                report('chassis', $msg, $E_CRITICAL, $index);
            }
            elsif (exists $warn_threshold{$index}{min} and $reading < $warn_threshold{$index}{min}) {
                # Custom warning MIN
-               my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom min=%d)',
-                 $index, $location, $reading, $warn_threshold{$index}{min};
+               my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom min=%s)',
+                 $index, $location, $reading, $opt{tempunit}, $warn_threshold{$index}{min};
                report('chassis', $msg, $E_WARNING, $index);
            }
            elsif ($status ne 'Ok' and $max_crit ne '[N/A]' and $reading > $max_crit) {
-               my $msg = sprintf 'Temperature Probe %d [%s] is critically high at %d C',
-                 $index, $location, $reading;
+               my $msg = sprintf 'Temperature Probe %d [%s] is critically high at %s %s',
+                 $index, $location, $reading, $opt{tempunit};
                my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
                report('chassis', $msg, $err, $index);
            }
            elsif ($status ne 'Ok' and $max_warn ne '[N/A]' and $reading > $max_warn) {
-               my $msg = sprintf 'Temperature Probe %d [%s] is too high at %d C',
-                 $index, $location, $reading;
+               my $msg = sprintf 'Temperature Probe %d [%s] is too high at %s %s',
+                 $index, $location, $reading, $opt{tempunit};
                my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
                report('chassis', $msg, $err, $index);
            }
            elsif ($status ne 'Ok' and $min_crit ne '[N/A]' and $reading < $min_crit) {
-               my $msg = sprintf 'Temperature Probe %d [%s] is critically low at %d C',
-                 $index, $location, $reading;
+               my $msg = sprintf 'Temperature Probe %d [%s] is critically low at %s %s',
+                 $index, $location, $reading, $opt{tempunit};
                my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
                report('chassis', $msg, $err, $index);
            }
            elsif ($status ne 'Ok' and $min_warn ne '[N/A]' and $reading < $min_warn) {
-               my $msg = sprintf 'Temperature Probe %d [%s] is too low at %d C',
-                 $index, $location, $reading;
+               my $msg = sprintf 'Temperature Probe %d [%s] is too low at %s %s',
+                 $index, $location, $reading, $opt{tempunit};
                my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
                report('chassis', $msg, $err, $index);
            }
            # Ok
            else {
-               my $msg = sprintf 'Temperature Probe %d [%s] reads %d C',
-                 $index, $location, $reading;
+               my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s',
+                 $index, $location, $reading, $opt{tempunit};
                if ($min_warn eq '[N/A]' and $min_crit eq '[N/A]') {
                    $msg .= sprintf ' (max=%s/%s)', $max_warn, $max_crit;
                }
@@ -3157,16 +3628,20 @@ sub check_temperatures {
 
            # Collect performance data
            if (defined $opt{perfdata}) {
-               my $pname = lc $location;
+               my $pname = $location;
                $pname =~ s{\s}{_}gxms;
-               $pname =~ s{_temp\z}{}xms;
+               $pname =~ s{_temp\z}{}ixms;
                $pname =~ s{proc_}{cpu#}xms;
                push @perfdata, {
-                                label => "temp_${index}_${pname}",
-                                mini  => "t$index",
-                                value => $reading,
-                                warn  => $max_warn,
-                                crit  => $max_crit,
+                                type   => 'T',
+                                id     => $index,
+                                unit   => $opt{tempunit},
+                                label  => $pname,
+                                legacy => lc "temp_${index}_${pname}",
+                                 mini   => "t$index",
+                                value  => $reading,
+                                warn   => $max_warn,
+                                crit   => $max_crit,
                                };
            }
        }
@@ -3179,8 +3654,6 @@ sub check_temperatures {
 # CHASSIS: Check processors
 #-----------------------------------------
 sub check_processors {
-    return if blacklisted('cpu', 'all');
-
     my $index   = undef;
     my $status  = undef;
     my $state   = undef;
@@ -3391,12 +3864,12 @@ sub check_processors {
     foreach my $out (@output) {
        if ($snmp) {
            $index  = exists $out->{processorDeviceStatusIndex}
-             ? $out->{processorDeviceStatusIndex} - 1
-               : $out->{processorDeviceIndex} - 1;
+             ? ($out->{processorDeviceStatusIndex} || 10000) - 1
+               : ($out->{processorDeviceIndex} || 10000) - 1;
            $status = exists $out->{processorDeviceStatusStatus}
-             ? $snmp_status{$out->{processorDeviceStatusStatus}}
-               : $snmp_status{$out->{processorDeviceStatus}};
-           if (exists $out->{processorDeviceStatusReading}) {
+             ? get_snmp_status($out->{processorDeviceStatusStatus})
+               : get_snmp_status($out->{processorDeviceStatus});
+           if (defined $out->{processorDeviceStatusReading}) {
                my @states  = ();  # contains states for the CPU
 
                # get the combined state from the StatusReading OID
@@ -3410,39 +3883,38 @@ sub check_processors {
                $state = join q{, }, @states;
            }
            else {
-               $state  = get_hashval($out->{processorDeviceStatusState}, \%cpu_state);
+               $state  = get_hashval($out->{processorDeviceStatusState}, \%cpu_state) || 'Unknown state';
            }
-           $man    = $out->{processorDeviceManufacturerName};
-           $family = (exists $out->{processorDeviceFamily}
-                      and exists $cpu_family{$out->{processorDeviceFamily}})
+           $man    = $out->{processorDeviceManufacturerName} || undef;
+           $family = (defined $out->{processorDeviceFamily}
+                      and defined $cpu_family{$out->{processorDeviceFamily}})
              ? $cpu_family{$out->{processorDeviceFamily}} : undef;
-           $speed  = $out->{processorDeviceCurrentSpeed};
-           $brand  = $out->{processorDeviceBrandName};
+           $speed  = $out->{processorDeviceCurrentSpeed} || undef;
+           $brand  = $out->{processorDeviceBrandName} || undef;
        }
        else {
-           $index  = $out->{'Index'};
-           $status = $out->{'Status'};
-           $state  = $out->{'State'};
-           $brand  = exists $out->{'Processor Brand'} ? $out->{'Processor Brand'} : undef;
-           $family = exists $out->{'Processor Family'} ? $out->{'Processor Family'} : undef;
-           $man    = exists $out->{'Processor Manufacturer'} ? $out->{'Processor Manufacturer'} : undef;
-           $speed  = exists $out->{'Current Speed'} ? $out->{'Current Speed'} : undef;
+           $index  = get_nonempty_string('Index', $out, 9999);
+           $status = get_nonempty_string('Status', $out, 'Unknown');
+           $state  = get_nonempty_string('State', $out, 'Unknown state');
+           $brand  = get_nonempty_string('Processor Brand', $out, undef);
+           $family = get_nonempty_string('Processor Family',  $out, undef);
+           $man    = get_nonempty_string('Processor Manufacturer', $out, undef);
+           $speed  = get_nonempty_string('Current Speed', $out, undef);
        }
 
-       next CPU if blacklisted('cpu', $index);
-
        # Ignore unoccupied CPU slots (omreport)
        next CPU if (defined $out->{'Processor Manufacturer'}
                     and $out->{'Processor Manufacturer'} eq '[Not Occupied]')
          or (defined $out->{'Processor Brand'} and $out->{'Processor Brand'} eq '[Not Occupied]');
 
        # Ignore unoccupied CPU slots (snmp)
-       if ($snmp and exists $out->{processorDeviceStatusReading}
+       if ($snmp and defined $out->{processorDeviceStatusReading}
            and $out->{processorDeviceStatusReading} == 0) {
            next CPU;
        }
 
        $count{cpu}++;
+       next CPU if blacklisted('cpu', $index);
 
        if (defined $brand) {
            $brand =~ s{\s\s+}{ }gxms;
@@ -3479,12 +3951,12 @@ sub check_processors {
 # CHASSIS: Check voltage probes
 #-----------------------------------------
 sub check_volts {
-    return if blacklisted('volt', 'all');
-
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
     my $location = undef;
+    my $max_crit = undef;
+    my $max_warn = undef;
     my @output = ();
 
     if ($snmp) {
@@ -3521,27 +3993,52 @@ sub check_volts {
   VOLT:
     foreach my $out (@output) {
        if ($snmp) {
-           $index    = $out->{voltageProbeIndex} - 1;
-           $status   = $snmp_probestatus{$out->{voltageProbeStatus}};
-           $reading  = exists $out->{voltageProbeReading}
+           $index    = ($out->{voltageProbeIndex} || 10000) - 1;
+           $status   = get_snmp_probestatus($out->{voltageProbeStatus});
+           $reading  = defined $out->{voltageProbeReading}
              ? sprintf('%.3f V', $out->{voltageProbeReading}/1000)
-                : get_hashval($out->{voltageProbeDiscreteReading}, \%volt_discrete_reading);
-           $location = $out->{voltageProbeLocationName};
+                : (get_hashval($out->{voltageProbeDiscreteReading}, \%volt_discrete_reading) || 'Unknown reading');
+           $location = $out->{voltageProbeLocationName} || 'Unknown location';
+           $max_crit = $out->{voltageProbeUpperCriticalThreshold} || 0;
+           $max_warn = $out->{voltageProbeUpperNonCriticalThreshold} || 0;
        }
        else {
-           $index    = $out->{'Index'};
-           $status   = $out->{'Status'};
-           $reading  = $out->{'Reading'};
-           $location = $out->{'Probe Name'};
+           $index    = get_nonempty_string('Index', $out, 9999);
+           $status   = get_nonempty_string('Status', $out, 'Unknown');
+           $reading  = get_nonempty_string('Reading', $out, 'Unknown reading');
+           $location = get_nonempty_string('Probe Name', $out, 'Unknown location');
+           $max_crit = get_nonempty_string('Maximum Failure Threshold', $out, 0);
+           $max_warn = get_nonempty_string('Maximum Warning Threshold', $out, 0);
+
+           $max_crit = 0 if $max_crit eq '[N/A]';
+           $max_warn = 0 if $max_warn eq '[N/A]';
        }
 
-       next VOLT if blacklisted('volt', $index);
        $count{volt}++;
+       next VOLT if blacklisted('volt', $index);
 
        my $msg = sprintf 'Voltage sensor %d [%s] is %s',
          $index, $location, $reading;
        my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
        report('chassis', $msg, $err, $index);
+
+       # Collect performance data
+       if (defined $opt{perfdata} and !$opt{legacy_perfdata}) {
+           $reading =~ s{\s+V\z}{}xms;  # remove unit
+           $reading =~ s{\.000\z}{}xms; # if integer
+           next VOLT if $reading !~ m{\A \d+(\.\d+)? \z}xms; # discrete reading (not number)
+           my $label = join q{_}, $location;
+           $label =~ s{\s}{_}gxms;
+           push @perfdata, {
+                            type   => 'V',
+                            id     => $index,
+                            unit   => 'V',
+                            label  => $label,
+                            value  => $reading,
+                            warn   => 0,
+                            crit   => 0,
+                           };
+       }
     }
     return;
 }
@@ -3551,8 +4048,6 @@ sub check_volts {
 # CHASSIS: Check batteries
 #-----------------------------------------
 sub check_batteries {
-    return if blacklisted('bp', 'all');
-
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -3595,20 +4090,20 @@ sub check_batteries {
   BATTERY:
     foreach my $out (@output) {
        if ($snmp) {
-           $index    = $out->{batteryIndex} - 1;
-           $status   = $snmp_status{$out->{batteryStatus}};
-           $reading  = get_hashval($out->{batteryReading}, \%bat_reading);
-           $location = $out->{batteryLocationName};
+           $index    = ($out->{batteryIndex} || 10000) - 1;
+           $status   = get_snmp_status($out->{batteryStatus});
+           $reading  = get_hashval($out->{batteryReading}, \%bat_reading) || 'Unknown reading';
+           $location = $out->{batteryLocationName} || 'Unknown location';
        }
        else {
-           $index    = $out->{'Index'};
-           $status   = $out->{'Status'};
-           $reading  = $out->{'Reading'};
-           $location = $out->{'Probe Name'};
+           $index    = get_nonempty_string('Index', $out, 9999);
+           $status   = get_nonempty_string('Status', $out, 'Unknown');
+           $reading  = get_nonempty_string('Reading', $out, 'Unknown reading');
+           $location = get_nonempty_string('Probe Name', $out, 'Unknown location');
        }
 
-       next BATTERY if blacklisted('bp', $index);
        $count{bat}++;
+       next BATTERY if blacklisted('bp', $index);
 
        my $msg = sprintf 'Battery probe %d [%s] is %s',
          $index, $location, $reading;
@@ -3622,8 +4117,6 @@ sub check_batteries {
 # CHASSIS: Check amperage probes (power monitoring)
 #-----------------------------------------
 sub check_pwrmonitoring {
-    return if blacklisted('amp', 'all');
-
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -3706,27 +4199,18 @@ sub check_pwrmonitoring {
   AMP:
     foreach my $out (@output) {
        if ($snmp) {
-           $index    = $out->{amperageProbeIndex} - 1;
-           $status   = $snmp_status{$out->{amperageProbeStatus}};
+           $index    = ($out->{amperageProbeIndex} || 10000) - 1;
+           $status   = get_snmp_probestatus($out->{amperageProbeStatus});
            $type     = get_hashval($out->{amperageProbeType}, \%amp_type);
            $reading  = $type eq 'amperageProbeTypeIsDiscrete'
              ? get_hashval($out->{amperageProbeDiscreteReading}, \%amp_discrete)
-               : $out->{amperageProbeReading};
-           $location = $out->{amperageProbeLocationName};
-           $max_crit = exists $out->{amperageProbeUpperCriticalThreshold}
-             ? $out->{amperageProbeUpperCriticalThreshold} : 0;
-           $max_warn = exists $out->{amperageProbeUpperNonCriticalThreshold}
-             ? $out->{amperageProbeUpperNonCriticalThreshold} : 0;
+               : ($out->{amperageProbeReading} || 0);
+           $location = $out->{amperageProbeLocationName} || 'Unknown location';
+           $max_crit = $out->{amperageProbeUpperCriticalThreshold} || 0;
+           $max_warn = $out->{amperageProbeUpperNonCriticalThreshold} || 0;
            $unit     = exists $amp_unit{$amp_type{$out->{amperageProbeType}}}
              ? $amp_unit{$amp_type{$out->{amperageProbeType}}} : 'mA';
 
-           # workaround for broken probes
-           if (!defined $reading) {
-               $type = 'amperageProbeTypeIsDiscrete';
-               $reading = '[N/A]';
-               $unit = q{};
-           }
-
            # calculate proper values and set unit for ampere probes
            if ($unit eq 'hA' and $type ne 'amperageProbeTypeIsDiscrete') {
                $reading  /= 10;
@@ -3734,24 +4218,30 @@ sub check_pwrmonitoring {
                $max_warn /= 10;
                $unit      = 'A';
            }
+           if ($unit eq 'mA' and $type ne 'amperageProbeTypeIsDiscrete') {
+               $reading  /= 1000;
+               $max_crit /= 1000;
+               $max_warn /= 1000;
+               $unit      = 'A';
+           }
        }
        else {
-           $index    = $out->{'Index'};
-           next AMP if (!defined $index || $index !~ m/^\d+$/x);
-           $status   = $out->{'Status'};
-           $reading  = $out->{'Reading'};
-           $location = $out->{'Probe Name'};
-           $max_crit = $out->{'Failure Threshold'} ne '[N/A]'
-             ? $out->{'Failure Threshold'} : 0;
-           $max_warn = $out->{'Warning Threshold'} ne '[N/A]'
-             ? $out->{'Warning Threshold'} : 0;
+           $index    = get_nonempty_string('Index', $out, 9999);
+           $status   = get_nonempty_string('Status', $out, 'Unknown');
+           $reading  = get_nonempty_string('Reading', $out, 'Unknown reading');
+           $location = get_nonempty_string('Probe Name', $out, 'Unknown location');
+           $max_crit = get_nonempty_string('Failure Threshold', $out, 0);
+           $max_warn = get_nonempty_string('Warning Threshold', $out, 0);
+
+           $max_crit = 0 if $max_crit eq '[N/A]';
+           $max_warn = 0 if $max_warn eq '[N/A]';
+
            $reading  =~ s{\A (\d+.*?)\s+([a-zA-Z]+) \s*\z}{$1}xms;
-           $unit     = $2;
+           $unit     = $2 || 'unknown';
            $max_warn =~ s{\A (\d+.*?)\s+[a-zA-Z]+ \s*\z}{$1}xms;
            $max_crit =~ s{\A (\d+.*?)\s+[a-zA-Z]+ \s*\z}{$1}xms;
        }
 
-       next AMP if blacklisted('amp', $index);
        next AMP if $index !~ m{\A \d+ \z}xms;
 
        # Special case: Probe is present but unknown. This happens via
@@ -3759,36 +4249,43 @@ sub check_pwrmonitoring {
        # disabled due to non-redundant and/or non-instrumented power
        # supplies.
         # E.g. R410 with newer BMC firmware and 1 power supply
-       if ($snmp && $status eq 'Unknown' && $reading eq '[N/A]') {
+       if ($snmp && $status eq 'Unknown' && $reading == 0) {
            next AMP;
        }
 
        $count{amp}++;
+       next AMP if blacklisted('amp', $index);
 
        # Special case: Discrete reading
        if (defined $type and $type eq 'amperageProbeTypeIsDiscrete') {
            my $msg = sprintf 'Amperage probe %d [%s] is %s',
              $index, $location, $reading;
-           report('chassis', $msg, $status2nagios{$status}, $index);
+           my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
+           report('chassis', $msg, $err, $index);
        }
        # Default
        else {
            my $msg = sprintf 'Amperage probe %d [%s] reads %s %s',
              $index, $location, $reading, $unit;
-           report('chassis', $msg, $status2nagios{$status}, $index);
+           my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
+           report('chassis', $msg, $err, $index);
        }
 
        # Collect performance data
        if (defined $opt{perfdata}) {
            next AMP if $reading !~ m{\A \d+(\.\d+)? \z}xms; # discrete reading (not number)
-           my $label = join q{_}, 'pwr_mon', $index, lc $location;
+           my $label = join q{_},  $location;
            $label =~ s{\s}{_}gxms;
            push @perfdata, {
-                            label => $label,
-                            mini  => "p${index}" . lc $unit,
-                            value => $reading,
-                            warn  => $max_warn,
-                            crit  => $max_crit,
+                            type   => $unit,
+                            id     => $index,
+                            unit   => $unit,
+                            label  => $label,
+                            legacy => (join q{_}, 'pwr_mon', $index, lc $label),
+                             mini   => "p${index}" . lc $unit,
+                            value  => $reading,
+                            warn   => $max_warn,
+                            crit   => $max_crit,
                            };
        }
     }
@@ -3802,7 +4299,7 @@ sub check_pwrmonitoring {
 
        # find used indexes
        foreach (@perfdata) {
-           if ($_->{label} =~ m/\A pwr_mon_(\d+)/xms) {
+           if ($_->{label} =~ m/\A [WA](\d+)/xms) {
                $used{$1} = 1;
            }
        }
@@ -3810,7 +4307,7 @@ sub check_pwrmonitoring {
       AMP2:
        foreach my $line (@{ run_command("$omreport $omopt_chassis pwrmonitoring -fmt ssv") }) {
            chop $line;
-           if ($line eq 'Location;Reading') {
+           if ($line eq 'Location;Reading' or $line eq 'Amperage') {
                $found = 1;
                next AMP2;
            }
@@ -3818,20 +4315,25 @@ sub check_pwrmonitoring {
                $found = 0;
                next AMP2;
            }
-           if ($found and $line =~ m/\A ([^;]+?) ; (\d*\.\d+) \s [AW] \z/xms) {
-               my $aname = lc $1;
-               my $aval = $2;
+           if ($found and $line =~ m/\A ([^;]+?) ; (\d*\.\d+) \s ([AW]) \z/xms) {
+               my $aname = $1;
+               my $aval  = $2;
+               my $aunit = $3;
                $aname =~ s{\s}{_}gxms;
 
                # don't use an existing index
                while (exists $used{$index}) { ++$index; }
 
                push @perfdata, {
-                                label => "pwr_mon_${index}_${aname}",
-                                mini  => "p${index}a",
-                                value => $aval,
-                                warn  => 0,
-                                crit  => 0,
+                                type   => $aunit,
+                                id     => $index,
+                                unit   => $aunit,
+                                label  => $aname,
+                                legacy => "pwr_mon_${index}_${aname}",
+                                 mini   => "p${index}a",
+                                value  => $aval,
+                                warn   => 0,
+                                crit   => 0,
                                };
                ++$index;
            }
@@ -3846,8 +4348,6 @@ sub check_pwrmonitoring {
 # CHASSIS: Check intrusion
 #-----------------------------------------
 sub check_intrusion {
-    return if blacklisted('intr', 'all');
-
     my $index    = undef;
     my $status   = undef;
     my $reading  = undef;
@@ -3889,18 +4389,18 @@ sub check_intrusion {
   INTRUSION:
     foreach my $out (@output) {
        if ($snmp) {
-           $index    = $out->{intrusionIndex} - 1;
-           $status   = $snmp_status{$out->{intrusionStatus}};
-           $reading  = get_hashval($out->{intrusionReading}, \%int_reading);
+           $index    = ($out->{intrusionIndex} || 10000) - 1;
+           $status   = get_snmp_status($out->{intrusionStatus});
+           $reading  = get_hashval($out->{intrusionReading}, \%int_reading) || 'Unknown reading';
        }
        else {
-           $index    = $out->{'Index'};
-           $status   = $out->{'Status'};
-           $reading  = $out->{'State'};
+           $index    = get_nonempty_string('Index', $out, 9999);
+           $status   = get_nonempty_string('Status', $out, 'Unknown');
+           $reading  = get_nonempty_string('State', $out, 'Unknown reading');
        }
 
-       next INTRUSION if blacklisted('intr', $index);
        $count{intr}++;
+       next INTRUSION if blacklisted('intr', $index);
 
        if ($status ne 'Ok') {
            my $msg = sprintf 'Chassis intrusion %d detected: %s',
@@ -3922,8 +4422,6 @@ sub check_intrusion {
 # CHASSIS: Check SD Card Device
 #-----------------------------------------
 sub check_sdcard {
-    return if blacklisted('sdcard', 'all');
-
     my $index    = undef;
     my $status   = undef;
     my $state    = undef;
@@ -3980,10 +4478,10 @@ sub check_sdcard {
   SDCARD:
     foreach my $out (@output) {
        if ($snmp) {
-           $index    = $out->{sdCardDeviceIndex} - 1;
-           $status   = $snmp_status{$out->{sdCardDeviceStatus}};
+           $index    = ($out->{sdCardDeviceIndex} || 10000) - 1;
+           $status   = get_snmp_status($out->{sdCardDeviceStatus});
 
-           if (exists $out->{sdCardDeviceCardState}) {
+           if (defined $out->{sdCardDeviceCardState}) {
                my @states  = ();  # contains states SD card
 
                # get the combined state from the Device Status OID
@@ -4002,20 +4500,21 @@ sub check_sdcard {
                }
            }
 
-           $location = $out->{sdCardDeviceLocationName};
-           $capacity = sprintf '%s MB', $out->{sdCardDeviceCardStorageSize};
+           $location = $out->{sdCardDeviceLocationName} || 'Unknown location';
+           $capacity = sprintf '%s MB', ($out->{sdCardDeviceCardStorageSize} || 'Unknown size');
        }
        else {
            $index    = $c++;
-           $status   = defined $out->{'Status'} ? $out->{'Status'} : 'Ok';
-           $state    = $out->{'State'};
-           $location = $out->{'Connector Name'};
-           $capacity = $out->{'Storage Size'} ne '[Not Available]'
-             ? $out->{'Storage Size'} : 'Unknown Size';
+           $status   = get_nonempty_string('Status', $out, 'Ok');
+           $state    = get_nonempty_string('State', $out, 'Unknown state');
+           $location = get_nonempty_string('Connector Name', $out, 'Unknown location');
+           $capacity = get_nonempty_string('Storage Size', $out, 'Unknown size');
+
+           $capacity =~ s{\[Not Available\]}{Unknown Size};
        }
 
-       next SDCARD if blacklisted('sd', $index);
        $count{sd}++ if $state ne 'Absent';
+       next SDCARD if blacklisted('sd', $index);
 
        if ($status ne 'Ok') {
            my $msg = sprintf 'SD Card %d needs attention: %s',
@@ -4076,7 +4575,7 @@ sub check_esmlog_health {
              $snmp_session->error;
            report('other', $msg, $E_UNKNOWN);
        }
-       $health = $snmp_status{$result->{$systemStateEventLogStatus}};
+       $health = get_snmp_status($result->{$systemStateEventLogStatus});
     }
     else {
        foreach (@{ run_command("$omreport $omopt_system esmlog -fmt ssv") }) {
@@ -4186,7 +4685,7 @@ sub get_omreport_chassis_info {
                $sysinfo{model}  = $val;
            }
            if ($key eq 'Chassis Service Tag' or $key eq 'Service Tag') {
-               $sysinfo{serial} = $val;
+               $sysinfo{serial} = $opt{hide_servicetag} ? 'XXXXXXX' : $val;
            }
            if ($key eq 'System Revision') {
                $sysinfo{rev} = q{ } . $val;
@@ -4276,7 +4775,7 @@ sub get_snmp_chassis_info {
                $sysinfo{model} =~ s{\s+\z}{}xms; # remove trailing whitespace
            }
            elsif (exists $chassis_oid{$oid} and $chassis_oid{$oid} eq 'chassisServiceTagName') {
-               $sysinfo{serial} = $result->{$oid};
+               $sysinfo{serial} = $opt{hide_servicetag} ? 'XXXXXXX' : $result->{$oid};
            }
            elsif (exists $chassis_oid{$oid} and $chassis_oid{$oid} eq 'chassisSystemRevisionName') {
                $sysinfo{rev} = q{ } . $result->{$oid};
@@ -4475,7 +4974,9 @@ sub get_firmware_info {
         14 => 'secondaryBackPlane',                 # Secondary Backplane for ESM 2 systems
         15 => 'secondaryBackPlaneESM3And4',         # Secondary Backplane for ESM 3 and 4 systems
         16 => 'rac',                                # Remote Access Controller
-        17 => 'imc'                                 # Integrated Management Controller
+        17 => 'iDRAC',                              # Integrated Dell Remote Access Controller
+        19 => 'unifiedServerConfigurator',          # Unified Server Configurator
+        20 => 'lifecycleController',                # Lifecycle Controller
        );
 
 
@@ -4485,7 +4986,7 @@ sub get_firmware_info {
                $sysinfo{'bmc'} = 1;
                $sysinfo{'bmc_fw'} = $out->{firmwareVersionName};
            }
-           elsif ($fw_type{$out->{firmwareType}} =~ m{\A rac|imc \z}xms) {
+           elsif ($fw_type{$out->{firmwareType}} =~ m{\A rac|iDRAC \z}xms) {
                my $name = $out->{firmwareTypeName}; $name =~ s/\s//gxms;
                $sysinfo{'rac'} = 1;
                $sysinfo{'rac_name'} = $name;
@@ -4569,11 +5070,21 @@ if ($snmp) {
 
 # Print messages
 if ($opt{debug}) {
-    print "   System:      $sysinfo{model}$sysinfo{rev}\n";
+    # finding the mode of operation
+    my $mode = 'local';
+    if ($snmp) {
+       # Setting the domain (IP version and transport protocol)
+       my $transport = $opt{tcp} ? 'TCP' : 'UDP';
+       my $ipversion = $opt{ipv6} ? 'IPv6' : 'IPv4';
+       $mode = "SNMPv$opt{protocol} $transport/$ipversion";
+    }
+
+    print "   System:      $sysinfo{model}$sysinfo{rev}";
+    print q{ } x (25 - length "$sysinfo{model}$sysinfo{rev}"), "OMSA version:    $sysinfo{om}\n";
     print "   ServiceTag:  $sysinfo{serial}";
-    print q{ } x (25 - length $sysinfo{serial}), "OMSA version:    $sysinfo{om}\n";
+    print q{ } x (25 - length $sysinfo{serial}), "Plugin version:  $VERSION\n";
     print "   BIOS/date:   $sysinfo{bios} $sysinfo{biosdate}";
-    print q{ } x (25 - length "$sysinfo{bios} $sysinfo{biosdate}"), "Plugin version:  $VERSION\n";
+    print q{ } x (25 - length "$sysinfo{bios} $sysinfo{biosdate}"), "Checking mode:   $mode\n";
     if ($#report_storage >= 0) {
        print "-----------------------------------------------------------------------------\n";
        print "   Storage Components                                                        \n";
@@ -4632,8 +5143,8 @@ else {
 
        # Prefix with service tag if specified with option '-i|--info'
        if ($opt{info}) {
-           if (defined $opt{htmlinfo}) {
-               $msg = '[<a href="' . warranty_url($sysinfo{serial})
+           if (defined $opt{htmlinfo} and !$opt{hide_servicetag}) {
+               $msg = '[<a target="_blank" href="' . warranty_url($sysinfo{serial})
                  . "\">$sysinfo{serial}</a>] " . $msg;
            }
            else {
@@ -4688,13 +5199,28 @@ if ($exit_code == $E_OK && defined $opt{only} && $opt{only} !~ m{\A critical|war
        );
 
     print $okmsg{$opt{only}};
+
+    # show blacklisted components
+    if ($opt{show_blacklist} and %blacklist) {
+       my @blstr = ();
+       foreach (keys %blacklist) {
+           push @blstr, "$_=" . join ',', @{ $blacklist{$_} };
+       }
+       print $linebreak;
+       print "----- BLACKLISTED: " . join '/', @blstr;
+    }
 }
 elsif ($exit_code == $E_OK && !$opt{debug}) {
-    if (defined $opt{htmlinfo}) {
-       printf q{OK - System: '<a href="%s">%s%s</a>', SN: '<a href="%s">%s</a>'},
+    if (defined $opt{htmlinfo} and !$opt{hide_servicetag}) {
+       printf q{OK - System: '<a target="_blank" href="%s">%s%s</a>', SN: '<a target="_blank" href="%s">%s</a>'},
          documentation_url($sysinfo{model}), $sysinfo{model}, $sysinfo{rev},
            warranty_url($sysinfo{serial}), $sysinfo{serial};
     }
+    if (defined $opt{htmlinfo} and $opt{hide_servicetag}) {
+       printf q{OK - System: '<a target="_blank" href="%s">%s%s</a>', SN: '%s'},
+         documentation_url($sysinfo{model}), $sysinfo{model}, $sysinfo{rev},
+           $sysinfo{serial};
+    }
     else {
        printf q{OK - System: '%s%s', SN: '%s'},
          $sysinfo{model}, $sysinfo{rev}, $sysinfo{serial};
@@ -4720,6 +5246,16 @@ elsif ($exit_code == $E_OK && !$opt{debug}) {
        print ', not checking storage';
     }
 
+    # show blacklisted components
+    if ($opt{show_blacklist} and %blacklist) {
+       my @blstr = ();
+       foreach (keys %blacklist) {
+           push @blstr, "$_=" . join ',', @{ $blacklist{$_} };
+       }
+       print $linebreak;
+       print "----- BLACKLISTED: " . join '/', @blstr;
+    }
+
     if ($opt{okinfo} >= 1) {
        print $linebreak;
        printf q{----- BIOS='%s %s'}, $sysinfo{bios}, $sysinfo{biosdate};
@@ -4766,11 +5302,16 @@ elsif ($exit_code == $E_OK && !$opt{debug}) {
 else {
     if ($opt{extinfo}) {
        print $linebreak;
-       if (defined $opt{htmlinfo}) {
-           printf '------ SYSTEM: <a href="%s">%s%s</a>, SN: <a href="%s">%s</a>',
+       if (defined $opt{htmlinfo} && !$opt{hide_servicetag}) {
+           printf '------ SYSTEM: <a target="_blank" href="%s">%s%s</a>, SN: <a target="_blank" href="%s">%s</a>',
              documentation_url($sysinfo{model}), $sysinfo{model}, $sysinfo{rev},
                warranty_url($sysinfo{serial}), $sysinfo{serial};
        }
+       elsif (defined $opt{htmlinfo} && $opt{hide_servicetag}) {
+           printf '------ SYSTEM: <a target="_blank" href="%s">%s%s</a>, SN: %s',
+             documentation_url($sysinfo{model}), $sysinfo{model}, $sysinfo{rev},
+               $sysinfo{serial};
+       }
        else {
            printf '------ SYSTEM: %s%s, SN: %s',
              $sysinfo{model}, $sysinfo{rev}, $sysinfo{serial};
@@ -4826,18 +5367,50 @@ if (defined $opt{perfdata} && !$opt{debug} && @perfdata) {
 
     # Sort routine for performance data
     sub perfsort {
+       my %order = ( 'T' => 0, 'W' => 1, 'A' => 2, 'V' => 3, 'F' => 4, 'E' => 5, );
+
+       # sort in this order:
+       #  1. the type according to the hash "order" above
+       #  2. the id (index) numerically
+       #  3. the id (index) alphabetically
+       #  4. the label
+       return $order{$a->{type}} cmp $order{$b->{type}} ||
+         ($a->{id} =~ m{\A\d+\z}xms and $a->{id} <=> $b->{id}) ||
+           ($a->{id} !~ m{\A\d+\z}xms and $a->{id} cmp $b->{id}) ||
+             $a->{label} cmp $b->{label};
+    }
+
+    # LEGACY sort routine for performance data
+    sub perfsort_legacy {
        my %order = ( fan => 0, pwr => 1, tem => 2, enc => 3, );
-       return ($order{(substr $a->{label}, 0, 3)} cmp $order{(substr $b->{label}, 0, 3)}) ||
-         $a->{label} cmp $b->{label};
+       return ($order{(substr $a->{legacy}, 0, 3)} cmp $order{(substr $b->{legacy}, 0, 3)}) ||
+         $a->{legacy} cmp $b->{legacy};
     }
 
     # Print performance data sorted
-    my $type = $opt{perfdata} eq 'minimal' ? 'mini' : 'label';
-    print join $lb, map { "$_->{$type}=$_->{value};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
+    if ($opt{legacy_perfdata}) {
+       my $type = $opt{perfdata} eq 'minimal' ? 'mini' : 'legacy';
+       print join $lb, map { "$_->{$type}=$_->{value};$_->{warn};$_->{crit}" } sort perfsort_legacy @perfdata;
+    }
+    else {
+       if ($opt{perfdata} eq 'minimal') {
+           print join $lb, map { "$_->{type}$_->{id}=$_->{value}$_->{unit};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
+       }
+       else {
+           print join $lb, map { "$_->{type}$_->{id}_$_->{label}=$_->{value}$_->{unit};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
+       }
+    }
 }
 
-# Print a linebreak at the end
-print "\n" if !$opt{debug};
+# Wrapping up and finishing
+if ($opt{debug}) {
+   # Exit with value 3 (unknown) if debug
+    exit $E_UNKNOWN;
+}
+else {
+    # Print a linebreak at the end if we have a TTY
+    isatty(*STDOUT) && print "\n";
 
-# Exit with proper exit code
-exit $exit_code;
+    # Exit with proper exit code
+    exit $exit_code;
+}