diff --git a/check_snmp_printer b/check_snmp_printer new file mode 100644 index 0000000000000000000000000000000000000000..6540f2b21df60464f28355ff14a1fac51700d42e --- /dev/null +++ b/check_snmp_printer @@ -0,0 +1,1016 @@ +#!/usr/bin/perl +######################################################### +# # +# # +# SNMP Printer Check Plugin for Icinga # +# Version 1.2.3 (October 14, 2020) # +# by Rob McLoughlin # +# E-mail: rmcloughlin@outlook.com # +# # +# # +# Based on: # +# check_snmp_printer (Perl) # +# Version 1.6 (September 08, 2014) # +# ( by Franky Van Liedekerke # +# E-mail: liedekef@telenet.be ) # +# # +# Which was further based on: # +# check_snmp_printer.sh # +# Version 1.5 (January 15, 2010) # +# ( by Jason Leonard # +# E-mail: jason_leonard@yahoo.com ) # +# # +# Version History # +# - Refer to CHANGELOG.md # +# # +# Like the original, this plugin is distributed # +# under the GNU GPL license. You may re-destribute only # +# according to the terms of the GNU GPL. # +# # +######################################################### +######################################################### +# # +# DEPENDS On # +# Net::SNMP perl module # +# Nagios plugins installed and located in lib64 # +# # +######################################################### + +use strict; +use lib qw( /usr/lib/nagios/plugins /usr/lib64/nagios/plugins ); +use utils qw( %ERRORS $TIMEOUT &print_revision &support &usage ); +use Net::SNMP; +use Getopt::Long; +use Data::Dumper; + + +# globals +use vars qw( + $PROGNAME $VERSION %procs $snmp $errstr $oid + $opt_version $opt_help $opt_timeout $opt_retries $opt_host + $opt_community $opt_snmpver $opt_warning $opt_critical + $opt_messages $opt_model $opt_consum $opt_tray $opt_pagecount + $opt_metric $opt_nofeeder +); +my (@consumables,@status,@trays,@strays,@percentages,@mresults,@message,@measurables); +my ($state,$statuscode,$EXITSTRING); +my ($i,$tcount,$scount,$traynumber,$cnumber,$mnumber,$critcount,$warncount) = 0; + +my %STATUS_CODE = + ( 'UNKNOWN' => '3', 'OK' => '0', 'WARNING' => '1', 'CRITICAL' => '2' ); + +# config +$PROGNAME = $0; +$VERSION = '1.2.3'; + +# init options +$opt_version = undef; +$opt_help = undef; +$opt_timeout = $TIMEOUT; +$opt_retries = 3; +$opt_host = undef; +$opt_community = 'public'; +$opt_snmpver = 1; +$opt_warning = 20; # warning percentage: if lower: warning +$opt_critical = 5; # critical percentage: if lower: critical +$opt_messages = undef; +$opt_model = undef; +$opt_consum = undef; +$opt_tray = undef; +$opt_pagecount = undef; +$opt_metric = undef; + +# get options +Getopt::Long::Configure('bundling'); +GetOptions( + 'V|version' => \$opt_version, + 'h|help' => \$opt_help, + 't|timeout=i' => \$opt_timeout, + 'r|retries=i' => \$opt_retries, + 'H|host=s' => \$opt_host, + 'C|community=s' => \$opt_community, + 'v|snmpver=s' => \$opt_snmpver, + 'w|warning=i' => \$opt_warning, + 'c|critical=i' => \$opt_critical, + 'messages' => \$opt_messages, + 'model' => \$opt_model, + 'consum' => \$opt_consum, + 'trays' => \$opt_tray, + 'pagecount' => \$opt_pagecount, + 'nofeeder' => \$opt_nofeeder, + 'metric' => \$opt_metric +) or do { + print_usage(); + exit($ERRORS{'UNKNOWN'}); +}; + +if($opt_version) { + print_version(); + exit($ERRORS{'UNKNOWN'}); +} + +if($opt_help) { + print_help(); + exit($ERRORS{'UNKNOWN'}); +} + +if(!$opt_host) { + print "Host option not given\n"; + print_usage(); + exit($ERRORS{'UNKNOWN'}); +} + +# only use one of messages|model|consum|tray|pagecount options +my $count=0; +($opt_messages) && ($count++); +($opt_model) && ($count++); +($opt_consum) && ($count++); +(defined($opt_tray)) && ($count++); +($opt_pagecount) && ($count++); +if ($count>1) { + print "Only use one of messages|model|consum|trays|pagecount options\n"; + print_help(); + exit($ERRORS{'UNKNOWN'}); +} +if ($count<1) { + print "Only use one of messages|model|consum|trays|pagecount options\n"; + print_help(); + exit($ERRORS{'UNKNOWN'}); +} + +sub print_usage { + my $tab = ' ' x length($PROGNAME); + print <<EOB +Usage: + $PROGNAME -H host + $tab [-C snmp_community] [-v snmp_version] [-t timeout] + $PROGNAME --version + $PROGNAME --help +EOB +} + +sub print_version { + print_revision($PROGNAME, $VERSION); +} + +sub print_help { + print_version(); + print <<EOB; + +Check a printer through SNMP. + +EOB + + print_usage(); + print <<EOB; + +Required Arguments: + -H, --host=HOST + The name or address of the host running SNMP. + --messages + Print the messages of the printer + --model + Prints the model of the printer + --pagecount + Prints the number of pages printed + --trays + Checks trays for paper status. + --consum + Checks consumables for status. + +Optional Arguments: + -C, --community=STRING + The community string of the SNMP agent. Default: public + -v, --snmpver=STRING + The version of snmp to use. 1 and 2 are supported. Default: 1 + -w, --warning=INTEGER + The warning limit level to alert on. 0 to disable tray alerting. + -c, --critical=INTEGER + The critical limit level to alert on. 0 to disable tray alerting. + -t, --timeout=INTEGER + Number of seconds to wait for a response. + -r, --retries=INTEGER + Number of retries to try before timing out. Default: 3 + --metric + Converts output to metric. Default: imperial + --nofeeder + Disables checking of the manual feeder tray +EOB +} + +sub check_model { + my ($pcheck) = @_; + my ($oid,$result); + my $MODEL="Uknown model"; + my $SERIAL=""; + + if ($pcheck == 1 || $pcheck == 2) { + $oid=".1.3.6.1.2.1.25.3.2.1.3.1"; + $result=$snmp->get_request(-varbindlist => [$oid]); + ($result) && ($MODEL=$result->{$oid}); + if ($pcheck == 2) { return lc $MODEL; } + } + if ($pcheck == 1) { + $oid=".1.3.6.1.2.1.43.5.1.1.17.1"; + $result=$snmp->get_request(-varbindlist => [$oid]); + ($result) && ($SERIAL=$result->{$oid}); + $SERIAL =~ s/\"//g; + + print "$MODEL, Serial # $SERIAL\n"; + } +} + +sub check_messages { + my ($mcheck) = @_; + my ($oid,$result,$model); + my $MESSAGES=""; + + $model = check_model(2); + if ($model =~ m/hp/) { + $oid=".1.3.6.1.4.1.11.2.3.9.1.1.3"; + } else { + $oid=".1.3.6.1.2.1.43.16"; + } + + $result = $snmp->get_entries(-columns => [$oid]); + + foreach my $key (keys(%$result)) { + $result->{$key} =~ s/\"//g; + $result->{$key} =~ s/\n/\!/g; + $MESSAGES .= $result->{$key}."\n"; + } + chomp $MESSAGES; + if ($MESSAGES eq "") { + $MESSAGES= "(Can't determine messages)"; + } + if ($mcheck == 2) { return $MESSAGES; } + my @messages = split('\n',$MESSAGES); + foreach my $message (@messages) { + $message = lc $message; + if ($message =~ m/toner low|wenig toner|cartridge low|niedrig|attention/) { + $state = "WARNING"; + } + elsif ($message =~ m/replace toner|toner ersetzen|error|paper is out/) { + $state = "CRITICAL"; + } else { $state = "OK"; } + push @{ $status[$mnumber] }, $state; + $mnumber++; + } + print "$MESSAGES\n"; +} + +sub check_page_count { + my ($oid,$result,$model,$t_oid,$c_oid,$m_oid, + $m_a3_oid,$m_a4_oid,$c_a3_oid,$c_a4_oid, + $m_a3,$m_a4,$c_a3,$c_a4,$MonoPagecount,$ColorPagecount,$TotalPagecount); + my (%ttmpprs,%ctmpprs,%mtmpprs) = (); + + $model = check_model(2); + if ($model =~ m/hp/) { + $c_oid='.1.3.6.1.4.1.11.2.3.9.4.2.1.4.1.2.7.0'; + $m_oid='.1.3.6.1.4.1.11.2.3.9.4.2.1.4.1.2.6.0'; + } + if ($model =~ m/canon/) { + $t_oid='.1.3.6.1.4.1.1602.1.11.1.3.1.4.101'; + $c_oid='.1.3.6.1.4.1.1602.1.11.1.3.1.4.105'; + $m_oid='.1.3.6.1.4.1.1602.1.11.1.3.1.4.108'; + $m_a3_oid='.1.3.6.1.4.1.1602.1.11.1.3.1.4.112'; + $m_a4_oid='.1.3.6.1.4.1.1602.1.11.1.3.1.4.113'; + $c_a3_oid='.1.3.6.1.4.1.1602.1.11.1.3.1.4.222'; + $c_a4_oid='.1.3.6.1.4.1.1602.1.11.1.3.1.4.223'; + } + if ($model =~ m/xerox/) { + $c_oid='.1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.33'; + $m_oid='.1.3.6.1.4.1.253.8.53.13.2.1.6.1.20.34'; + } + if ($model =~ m/lexmark/) { + $c_oid='.1.3.6.1.4.1.641.6.4.2.2.1.7.1.1'; + $m_oid='.1.3.6.1.4.1.641.6.4.2.2.1.6.1.1'; + } + if ($model =~ m/ricoh/) { + $c_oid='.1.3.6.1.4.1.367.3.2.1.2.19.5.1.9.21'; + $m_oid='.1.3.6.1.4.1.367.3.2.1.2.19.5.1.9.22'; + } + if ($model =~ m/kyocera|ecosys|taskalfa|4200dn/) { + $t_oid='.1.3.6.1.4.1.1347.42.2.1.1.1.6.1'; + $c_oid='.1.3.6.1.4.1.1347.42.2.1.1.1.8.1'; + $m_oid='.1.3.6.1.4.1.1347.42.2.1.1.1.7.1'; + } + + $oid=".1.3.6.1.2.1.43.10.2.1.4.1.1"; + + + if (defined($snmp->get_request(-varbindlist => [$m_a3_oid]))) { $m_a3 = $snmp->get_request(-varbindlist => [$m_a3_oid]) } + if (defined($snmp->get_request(-varbindlist => [$m_a4_oid]))) { $m_a4 = $snmp->get_request(-varbindlist => [$m_a4_oid]) } + if (defined($snmp->get_request(-varbindlist => [$c_a3_oid]))) { $c_a3 = $snmp->get_request(-varbindlist => [$c_a3_oid]) } + if (defined($snmp->get_request(-varbindlist => [$c_a4_oid]))) { $c_a4 = $snmp->get_request(-varbindlist => [$c_a4_oid]) } + + if (($m_a3 || $m_a4) > 0) { + $MonoPagecount = $m_a3 + $m_a4; + } elsif ($model =~ m/kyocera|ecosys|taskalfa|4200dn/) { + my $tresult = $snmp->get_entries(-columns => [$t_oid]); + my $cresult = $snmp->get_entries(-columns => [$c_oid]); + my $mresult = $snmp->get_entries(-columns => [$m_oid]); + foreach my $tkey (keys(%$tresult)) { + my($tindex) = ($tkey =~ /($t_oid\.\d+)/); + $tresult->{$tkey} =~ s/[^\w\s]//g; + $ttmpprs{$tindex}{t_count} = $tresult->{$tkey}; + } + foreach my $tkey (keys(%ttmpprs)) { + my $t_count=$ttmpprs{$tkey}{t_count}; + $TotalPagecount = $TotalPagecount+$t_count; + } + foreach my $ckey (keys(%$cresult)) { + my($cindex) = ($ckey =~ /($c_oid\.\d+)/); + $cresult->{$ckey} =~ s/[^\w\s]//g; + $ctmpprs{$cindex}{c_count} = $cresult->{$ckey}; + } + foreach my $ckey (keys(%ctmpprs)) { + my $c_count=$ctmpprs{$ckey}{c_count}; + $ColorPagecount = $ColorPagecount+$c_count; + } + foreach my $mkey (keys(%$mresult)) { + my($mindex) = ($mkey =~ /($m_oid\.\d+)/); + $mresult->{$mkey} =~ s/[^\w\s]//g; + $mtmpprs{$mindex}{m_count} = $mresult->{$mkey}; + } + foreach my $mkey (keys(%mtmpprs)) { + my $m_count=$mtmpprs{$mkey}{m_count}; + $MonoPagecount = $MonoPagecount+$m_count; + } + } else { + $result=$snmp->get_request(-varbindlist => [$m_oid]); + if((not defined($result)) || ($result->{$m_oid} eq 'noSuchInstance')) { + $result=$snmp->get_request(-varbindlist => [$t_oid]); + if((not defined($result)) || ($result->{$m_oid} eq 'noSuchInstance')) { + $result=$snmp->get_request(-varbindlist => [$oid]); + if ($snmp->error() =~ m/genError/) { + $result = retry_snmp($oid,undef,undef,undef,undef,undef,undef,undef); + } + if(not defined($result)) { + print "CRITICAL - snmp error: " . $snmp->error() . "\n"; + exit($ERRORS{'CRITICAL'}); + } else { $TotalPagecount=$result->{$oid}; } + } else { $TotalPagecount=$result->{$t_oid}; } + } else { $MonoPagecount=$result->{$m_oid}; } + } + if (($c_a3 || $c_a4) > 0) { + $ColorPagecount = $c_a3 + $c_a4; + } else { + $result=$snmp->get_request(-varbindlist => [$c_oid]); + if(not defined($result)) { + } else { $ColorPagecount=$result->{$c_oid}; } + } + if (($TotalPagecount) or (($model =~ m/kyocera|ecosys|taskalfa|4200dn/))) { + $EXITSTRING = "Pagecount is $TotalPagecount"; + if ($model =~ m/kyocera|ecosys|taskalfa|4200dn/) { + $EXITSTRING.= " Total, $MonoPagecount Black-and-White"; + } + } else { $EXITSTRING = "Pagecount is $MonoPagecount Black-and-White"; } + if ($ColorPagecount > 0) { + $EXITSTRING.= ", $ColorPagecount Color"; + } + $EXITSTRING.= "\n"; + if (($TotalPagecount) or ($model =~ m/kyocera|ecosys|taskalfa|4200dn/)) { + $EXITSTRING.= "|Total=$TotalPagecount;;;;"; + if ($model =~ m/kyocera|ecosys|taskalfa|4200dn/) { + $EXITSTRING.= " Black-and-White=$MonoPagecount;;;;"; + } + } else { $EXITSTRING.= "|Black-and-White=$MonoPagecount;;;;"; } + if ($ColorPagecount > 0) { + $EXITSTRING.= " Color=$ColorPagecount;;;;"; + } + +} + +sub get_consumables { + my ($result,$Table,$Names,$CurCap,$MaxCap) = @_; + my %tmpprs = (); + my ($consumable, $curcap_pct); + my ($puncher, $found) = 0; + + foreach my $key (keys(%$result)) { + my($base, $index) = ($key =~ /($Table\.\d+\.\d+)\.(\d+)/); + if($base eq $Names ) { + $result->{$key} =~ s/[^\w\s]//g; + $tmpprs{$index}{name} = $result->{$key}; + } + if($base eq $CurCap) { $tmpprs{$index}{curcap} = $result->{$key}; } + if($base eq $MaxCap) { $tmpprs{$index}{maxcap} = $result->{$key}; } + } + + foreach my $key (keys(%tmpprs)) { + my $name=$tmpprs{$key}{name}; + if ($name =~ m/Imaging Unit|Imaging Kit/) { $consumable = $name; } + else { ($consumable = $name) =~ s/(\w+).*/$1/; } + if ($consumable eq "Canon") { + my @split = split(' ',$consumable = $name); + foreach my $cconsumable (@split) { + if ($cconsumable =~ m/Black|Yellow|Magenta|Cyan/) { $consumable = $cconsumable; } + else { next; } + } + } + if ($consumable eq "Image") { + my @split = split(' ',$consumable = $name); + foreach my $iconsumable (@split) { + if ($iconsumable =~ m/Transfer|Fuser/) { $consumable = $iconsumable. " Kit"; } + else { next; } + } + } + if (check_model(2) =~ m/generic 30c-9/) { + my @split = split(' ',$consumable = $name); + foreach my $gconsumable (@split) { + if ($gconsumable =~ m/Toner/) { + ($consumable) = $name =~ /\((.*)\)/; + } elsif ($gconsumable =~ m/Image|Fusing/) { + $consumable = $name; + } else { + next; + } + } + } + if (check_model(2) =~ m/ricoh/) { + my @split = split(' ',$consumable = $name); + foreach my $rconsumable (@split) { + if ($rconsumable =~ m/Toner/) { + ($consumable) = $name =~ /(?<=Toner )(\w+)/; + } else { + next; + } + } + } + + my $curcap=$tmpprs{$key}{curcap}; + my $maxcap=$tmpprs{$key}{maxcap}; + + if ($name =~ m/Drum|Resttoner|Waste Toner|Belt|Developer/) { + next; + } + + if ($consumable =~ m/Imaging Unit/) { } + elsif ($consumable =~ m/Black|Yellow|Magenta|Cyan/) { $consumable = $consumable." Toner"; } + elsif ($consumable =~ m/Schwarz|Gelb/) { $consumable = $consumable." Toner"; } # German + # Kyocera reports toner as model number so we need to convert that to something human readable + if ($consumable =~ m/TK/) { + if ($consumable =~ /CS$|C$/) { $consumable = "Cyan Toner"; } + elsif ($consumable =~ /MS$|M$/) { $consumable = "Magenta Toner"; } + elsif ($consumable =~ /YS$|Y$/) { $consumable = "Yellow Toner"; } + elsif ($consumable =~ /KS$|K$/) { $consumable = "Black Toner"; } + else { $consumable = "Black Toner"; } + } + if ($consumable eq 'Magneta') { $consumable = "Magenta Toner"; } # New HP OID has a typo + if ($consumable eq 'Clean') { $consumable = $consumable." Rollers"; } + if ($consumable eq 'Document') { $consumable = $consumable." Feeder Kit"; } + if ($consumable eq 'Maintenance') { $consumable = $consumable." Kit"; } + if ($consumable eq 'Transfer') { $consumable = $consumable." Unit"; } + if ($consumable eq 'Stapler') { } + if ($consumable eq 'Staples') { } + if ($consumable eq 'Saddle') { $consumable = $consumable." Staples"; } + if ($consumable eq 'Puncher') { $puncher = 1; $consumable = $consumable. " Waste"; } + + push (@consumables, $consumable); + + $found=1; + if ($puncher == 1) { + if ($curcap > 99) { + $state = "CRITICAL"; + } elsif ($curcap >= 96) { + $state = "WARNING"; + } else { + $state = "OK"; + } + push (@measurables, '1'); + push (@percentages, $curcap); + } else { + if ($maxcap>0 && $curcap>0) { + $curcap_pct=sprintf("%.2f",$curcap*100/$maxcap); + if ($curcap_pct<=$opt_critical) { + # critical messages come first + $state = "CRITICAL"; + } elsif ($curcap_pct<=$opt_warning) { + $state = "WARNING"; + } else { + $state = "OK"; + } + push (@measurables, '1'); + push (@percentages, $curcap_pct); + } elsif ($maxcap == 100 && $curcap == 0) { + $state = "CRITICAL"; + push (@measurables, '1'); + push (@percentages, 0); + } else { + if (check_model(2) =~ m/brother/) { + my ($bresult,$bstatus,$boid); + if ($consumable =~ m/Black|Schwarz/) { + $boid = ".1.3.6.1.4.1.2435.2.3.9.1.1.2.10.1"; + } + if ($consumable =~ m/Cyan/) { + $boid = ".1.3.6.1.4.1.2435.2.3.9.1.1.2.10.2"; + } + if ($consumable =~ m/Magenta/) { + $boid = ".1.3.6.1.4.1.2435.2.3.9.1.1.2.10.3"; + } + if ($consumable =~ m/Yellow|Gelb/) { + $boid = ".1.3.6.1.4.1.2435.2.3.9.1.1.2.10.4"; + } + if (defined($snmp->get_request(-varbindlist => [$boid]))) { + $bstatus = $bresult->{$oid}; + if ($bstatus == 0) { $state = "OK"; push (@measurables, 'b0'); $curcap = 100; } + if ($bstatus == 1) { $state = "WARNING"; push (@measurables, 'b1'); $curcap = 10; } + if ($bstatus == 2) { $state = "CRITICAL"; push (@measurables, 'b2'); $curcap = 0; } + if ($bstatus == 3) { $state = "CRITICAL"; push (@measurables, 'b3'); $curcap = 0; } + } else { ($state,$curcap) = nonmeasurable($curcap,$maxcap,$name); } + } else { + $state = nonmeasurable($curcap,$maxcap,$name); + } + push (@percentages, $curcap); + } + } + $puncher = 0; + push @{ $status[$cnumber] }, $state; + $cnumber++; + } +} + +sub nonmeasurable { + my ($curcap,$maxcap,$name) = @_; + + # Our object is not measurable - it's either FULL or EMPTY (such as a punch dust box) + # Let's report on it's status using appropriate terminology + if (check_model(2) =~ m/brother/) { + if ($curcap == -3) { $state = "OK"; push (@measurables, 'b0'); } + else { + my $smessage = check_messages(2); + my @messages = split('\n',$smessage); + foreach my $message (@messages) { + $message = lc $message; + if ($message =~ m/toner low|wenig toner/) { + $state = "WARNING"; + push (@measurables, 'b1'); + $curcap = 10; + } + elsif ($message =~ m/replace toner|toner ersetzen/) { + $state = "CRITICAL"; + push (@measurables, 'b3'); + $curcap = 0; + } + } + } + push (@measurables, '1'); + return $state, $curcap; + } elsif ($curcap==-3) { + if ($maxcap>0) { $state = "WARNING"; push (@measurables, 'lt'); } + else { $state = "OK"; (@measurables, 'gt'); } + } elsif ($curcap==-2) { + # The value (-2) means unknown + if ($name =~ m/W2020A|W2021A|W2022A|W2023A/) { # HP Color LaserJet Pro M454dw Toner + $state = "CRITICAL"; + push (@measurables, '1'); + } else { $state = "WARNING"; push (@measurables, '0'); } + } elsif ($curcap==0) { + # Something is empty! + $state = "CRITICAL"; + } + return $state; +} + +sub prioritize_results { + my ($metric) = @_; + my ($mcount,$scode); + + if ((scalar @consumables) > 0) { $mcount = (scalar @consumables); } + if ((scalar @strays) > 0) { $mcount = (scalar @strays); } + + $i = 0; + + while ($mcount > 0) { + + if ($status[$i][0] eq 'CRITICAL') { $scode = 1; } + if ($status[$i][0] eq 'WARNING') { $scode = 2; } + if ($status[$i][0] eq 'OK') { $scode = 3; } + + if ($metric eq "consumables") { + push @{ $mresults[$i] }, $scode, $status[$i][0], $consumables[$i], $message[$i]; + } + if ($metric eq "trays") { + push @{ $mresults[$i] }, $scode, $status[$i][0], $strays[$i][0], $message[$i]; + } + $mcount--; + $i++; + } + + @mresults = sort { $a->[0] cmp $b->[0] } @mresults; + + $i = 0; + $mcount = (scalar @mresults); + while ($mcount > 0) { + print "$mresults[$i][1]: $mresults[$i][2]$mresults[$i][3]\n"; + $mcount--; + $i++; + } +} + +sub check_consumables { + my %pr_oids = ( + 'Table' => '.1.3.6.1.2.1.43.11.1.1', + 'Names' => '.1.3.6.1.2.1.43.11.1.1.6.1', + 'CurCap' => '.1.3.6.1.2.1.43.11.1.1.9.1', + 'MaxCap' => '.1.3.6.1.2.1.43.11.1.1.8.1', + 'CTable' => '.1.3.6.1.2.1.43.31.1.1', + 'CNames' => '.1.3.6.1.2.1.43.31.1.1.5.1', + 'CCurCap' => '.1.3.6.1.2.1.43.31.1.1.8.1', + 'CMaxCap' => '.1.3.6.1.2.1.43.31.1.1.7.1' + ); + my ($consumable,$measurable,$perfcount); + my $pct_remaining = ""; + + my $result = $snmp->get_entries(-columns => [$pr_oids{Names}, $pr_oids{CurCap}, $pr_oids{MaxCap}]); + if ($snmp->error() =~ m/genError/) { + $result = retry_snmp($pr_oids{Names}, $pr_oids{CurCap}, $pr_oids{MaxCap},undef,undef,undef,undef,undef); + } + if(not defined($result)) { + print "CRITICAL - snmp error: " . $snmp->error() . "\n"; + exit($ERRORS{'CRITICAL'}); + } + my $cresult = $snmp->get_entries(-columns => [$pr_oids{CNames}, $pr_oids{CCurCap}, $pr_oids{CMaxCap}]); + + get_consumables($result, $pr_oids{Table}, $pr_oids{Names}, $pr_oids{CurCap}, $pr_oids{MaxCap}); + get_consumables($cresult, $pr_oids{CTable}, $pr_oids{CNames}, $pr_oids{CCurCap}, $pr_oids{CMaxCap}); + + $tcount = (scalar @consumables); + if (@percentages != 0 ) { $measurable = 1; } + if ($measurable) { + if ($consumables[0] eq "Puncher Waste") { + $pct_remaining = " is ".$percentages[0]. "% full."; + } elsif ($consumables[0] eq "Stapler") { + $pct_remaining = ""; + } elsif (check_model(2) =~ m/brother/) { + if ($measurables[$i] eq "b0") { + $pct_remaining = " levels are OK."; + } + if ($measurables[$i] eq "b1") { + $pct_remaining = " levels are LOW."; + } + if ($measurables[$i] eq "b2") { + $pct_remaining = " has no toner installed."; + } + if ($measurables[$i] eq "b3") { + $pct_remaining = " levels are EMPTY."; + } + } elsif ($percentages[$i] eq "-2") { + if ($measurables[$i] eq "0") { + $pct_remaining = " levels cannot be measured."; + } else { $pct_remaining = " is at 0% remaining."; } + } else { + $pct_remaining = " is at ".$percentages[0]. "% remaining."; + } + push (@message, $pct_remaining); + } + my $perfcount = $tcount; + if ($tcount > 1) { + $tcount--; + while ($tcount > 0) { + $i++; + if ($consumables[$i] eq "Waste") { + $tcount--; + next; + } + if ($measurable) { + if ($consumables[$i] eq "Puncher Waste") { + $pct_remaining = " is ".$percentages[$i]. "% full."; + } elsif ($consumables[$i] eq "Stapler") { + $pct_remaining = ""; + } elsif (check_model(2) =~ m/brother/) { + if ($measurables[$i] eq "b0") { + $pct_remaining = " levels are OK."; + } + if ($measurables[$i] eq "b1") { + $pct_remaining = " levels are LOW."; + } + if ($measurables[$i] eq "b2") { + $pct_remaining = " has no toner installed."; + } + if ($measurables[$i] eq "b3") { + $pct_remaining = " levels are EMPTY."; + } + } elsif ($percentages[$i] eq "-2") { + if ($measurables[$i] eq "0") { + $pct_remaining = " levels cannot be measured."; + } else { $pct_remaining = " is at 0% remaining."; } + } elsif ($percentages[$i] eq "-3") { + if ($measurables[$i] eq "lt") { + $pct_remaining = " levels are LOW."; + } + if ($measurables[$i] eq "gt") { + $pct_remaining = " levels are OK."; + } + } else { + $pct_remaining = " is at ".$percentages[$i]. "% remaining."; + } + } + push (@message, $pct_remaining); + $tcount--; + } + } + prioritize_results('consumables'); + $i = 0; + $EXITSTRING.= "|"; + while ($perfcount > 0) { + if ($consumables[$i] eq "Waste") { + $i++; + $perfcount--; + next; + } + ($consumable = $consumables[$i]) =~ s/ /_/g; + if ($measurable) { + if ($consumable eq "Stapler") { + if ($status[$i] eq 'CRITICAL') { $EXITSTRING.= $consumable."=0"; } + elsif ($status[$i] eq 'OK') { $EXITSTRING.= $consumable."=100"; } + } elsif ($percentages[$i] eq "-2") { + if ($measurables[$i] eq "0") { } + else { $EXITSTRING.= "$consumable=0"; } + } else { + $EXITSTRING.= $consumable."=".$percentages[$i]; + } + } else { + if ($status[$i] == "CRITICAL") { + $EXITSTRING.= $consumable."=0"; + } else { + $EXITSTRING.= $consumable."=1"; + } + } + $i++; + $perfcount--; + if ($perfcount == 0) { $EXITSTRING.= ";;;;"; } else { $EXITSTRING.=";;;; "; } + } +} + +sub check_paper_trays { + my $found=0; + my %tmpprs = (); + my ($name,$lcname,$feeder,$cap,$tstatus,$traymessage,$maxcap,$feeddim,$xfeeddim,$cap_pct); + my %tray_oids = ( + 'Table' => '.1.3.6.1.2.1.43.8.2.1', + 'Cap' => '.1.3.6.1.2.1.43.8.2.1.10.1', + 'Status' => '.1.3.6.1.2.1.43.8.2.1.11.1', + 'MaxCap' => '.1.3.6.1.2.1.43.8.2.1.9.1', + 'Name' => '.1.3.6.1.2.1.43.8.2.1.13.1', + 'FeedDim' => '.1.3.6.1.2.1.43.8.2.1.4.1', + 'FeedDimUnits' => '.1.3.6.1.2.1.43.8.2.1.2.1', + 'XFeedDim' => '.1.3.6.1.2.1.43.8.2.1.5.1', + 'XFeedDimUnits' => '.1.3.6.1.2.1.43.8.2.1.3.1' + ); + my $result = $snmp->get_entries(-columns => [$tray_oids{Name},$tray_oids{Cap},$tray_oids{MaxCap},$tray_oids{FeedDim},$tray_oids{FeedDimUnits},$tray_oids{XFeedDim},$tray_oids{XFeedDimUnits},$tray_oids{Status}]); + my $model = "Unknown Model"; + my $mresult = $snmp->get_request(-varbindlist => [".1.3.6.1.2.1.25.3.2.1.3.1"]); + ($mresult) && ($model=$mresult->{".1.3.6.1.2.1.25.3.2.1.3.1"}); + + if ($snmp->error() =~ m/genError/) { + $result = retry_snmp($tray_oids{Name},$tray_oids{Cap},$tray_oids{MaxCap},$tray_oids{FeedDim},$tray_oids{FeedDimUnits},$tray_oids{XFeedDim},$tray_oids{XFeedDimUnits},$tray_oids{Status}); + } + + if(not defined($result)) { + print "CRITICAL - snmp error: " . $snmp->error() . "\n"; + exit($ERRORS{'CRITICAL'}); + } + foreach my $key (keys(%$result)) { + my($base, $index) = ($key =~ /($tray_oids{Table}\.\d+\.\d+)\.(\d+)/); + $result->{$key} =~ s/\"//g; + if($base eq $tray_oids{Cap}) { $tmpprs{$index}{cap} = $result->{$key}; } + if($base eq $tray_oids{Status}) { $tmpprs{$index}{tstatus} = $result->{$key}; } + if($base eq $tray_oids{MaxCap}) { $tmpprs{$index}{maxcap} = $result->{$key}; } + if($base eq $tray_oids{Name}) { $tmpprs{$index}{name} = $result->{$key}; } + if($base eq $tray_oids{FeedDim}) { $tmpprs{$index}{feeddim} = $result->{$key}; } + if($base eq $tray_oids{XFeedDim}) { $tmpprs{$index}{xfeeddim} = $result->{$key}; } + } + + foreach my $key (keys(%tmpprs)) { + $name=$tmpprs{$key}{name}; + $cap=$tmpprs{$key}{cap}; + $tstatus=$tmpprs{$key}{tstatus}; + $maxcap=$tmpprs{$key}{maxcap}; + $feeddim=$tmpprs{$key}{feeddim}; + $xfeeddim=$tmpprs{$key}{xfeeddim}; + + # if name is empty, make one with the number + if ($name eq "") { + $name="Tray $key"; + } + if ($name =~ m/(MPT)/) { + $name =~ s/ \(MPT\)//g; + } + if ($name =~ m/Paper Tray/) { + ($name) = $name =~ /[^ ]* (.*)/; + } + $name =~ s/\n/\!/g; + if ($name =~ m/TRAY/) { + if ($name =~ /(?<=TRAY)[0-9]/) { + my @split = split(/(?<=\d)(?=\D)|(?<=\D)(?=\d)/, $name); + $name = @split[0]." ".@split[1]; + } + $name = (ucfirst(lc($name))); + } + $lcname = lc($name); + if (($lcname =~ m/stack bypass|mp tray|manual paper|manual envelope|multi-purpose_tray/) and ($opt_nofeeder)) { $feeder=1; next; } + if (($lcname =~ m/tray 1/) and ($opt_nofeeder) and (scalar(keys(%tmpprs) > 1)) and $feeder != 1) { next; } + $found=1; + push @{ $trays[$traynumber] }, $name, $cap, $maxcap, $feeddim, $xfeeddim, $tstatus; + $traynumber++; + } + + $traynumber = 0; + @strays = sort { $a->[0] cmp $b->[0] } @trays; + $tcount = scalar(@strays); + my $perfcount = $tcount; + + while ($tcount > 0) { + $name = $strays[$i][0]; + $cap = $strays[$i][1]; + $maxcap = $strays[$i][2]; + $feeddim = $strays[$i][3]; + $xfeeddim = $strays[$i][4]; + $tstatus = $strays[$i][5]; + $lcname = lc($name); + + if ($feeddim eq '-2') { $feeddim = "Any"; } + if ($xfeeddim eq '-2') { $xfeeddim = "Any"; } + + $model = check_model(2); + if (($feeddim || $xfeeddim) ne 'Any') { + if ($model =~ m/canon|xerox|ricoh|brother/) { + if ($opt_metric) { + $feeddim = sprintf("%.0f", $feeddim * .001)."mm"; + $xfeeddim = sprintf("%.0f", $xfeeddim * .001)."mm"; + } else { + $feeddim = sprintf("%.2f", (($feeddim / 2.54) * .0001))."in"; + $xfeeddim = sprintf("%.2f", (($xfeeddim / 2.54) * .0001))."in"; + } + } else { + if ($opt_metric) { + $feeddim = sprintf("%.0f", (($feeddim * 2.54) * .001))."mm"; + $xfeeddim = sprintf("%.0f", (($xfeeddim * 2.54) * .001))."mm"; + } else { + $feeddim = sprintf("%.2f", $feeddim * .0001)."in"; + $xfeeddim = sprintf("%.2f", $xfeeddim * .0001)."in"; + } + } + } + + if ($cap == -3) { + # The value (-3) means that the printer knows that at least one unit remains. + if ($model =~ m/lexmark/) { # When -3, Lexmark is really low status. + if (($opt_critical == 0) or ($opt_warning == 0 )) { + $state = "OK"; + } else { + $state = "WARNING"; + } + $traymessage = " is LOW. ($xfeeddim x $feeddim)"; + } else { + $state = "OK"; + $traymessage = " ($xfeeddim x $feeddim)"; + } + } elsif ($cap == -2) { + # The value (-2) means unknown + # so lets check the tray status instead + if ($tstatus eq '0') { + if ($model =~ m/canon|hp|ricoh/) { + $state = "OK"; + $traymessage = " ($xfeeddim x $feeddim)"; + } else { + $state = "WARNING"; + $traymessage = " is in an UNKNOWN state."; + } + if (($lcname =~ m/tray 1|stack bypass|mp tray|manual paper|manual envelope|multi-purpose_tray/) and ($state ne 'WARNING')) { + $traymessage = ""; + } + } elsif ($tstatus eq '4') { + if ($model =~ m/lexmark/) { + $state = "OK"; + $traymessage = " ($xfeeddim x $feeddim)"; + } + } elsif ($tstatus eq '9') { + if ($model =~ m/hp/) { + $state = "OK"; + $traymessage = " ($xfeeddim x $feeddim)"; + } + } else { + # still unknown so we'll mark it warning because we just don't know + $state = "WARNING"; + $traymessage = " is in UNKNOWN status."; + } + } elsif ($cap == 0) { + # 0 means there is no paper left! This is our only critical value. + # first lets check to see if it's a bypass tray, we'll always assume Tray 1 is such. + if ($lcname =~ m/tray 1|stack bypass|mp tray|manual paper|manual envelope|multi-purpose_tray/) { + $state = "CRITICAL"; + if (($xfeeddim || $feeddim) ne 'Any') { + $traymessage = " ($xfeeddim x $feeddim)"; + } else { $traymessage = " is empty."; } + } else { + if ($opt_critical > 0) { + $state = "CRITICAL"; + } else { + $state = "OK"; + } + $traymessage = " ($xfeeddim x $feeddim) is at 0% paper remaining."; + } + $cap_pct=sprintf("%.2f",$cap*100/$maxcap); + } else { + ($maxcap==0) && ($maxcap=1); + $cap_pct=sprintf("%.2f",$cap*100/$maxcap); + if (($cap_pct <= $opt_warning) and ($opt_warning > 0 )) { + $state = "WARNING"; + } else { + $state = "OK"; + } + $traymessage = " ($xfeeddim x $feeddim) is at $cap_pct% paper remaining."; + } + push @{ $status[$traynumber] }, $state, $cap_pct; + push (@message, $traymessage); + $traynumber++; + $tcount--; + $i++; + } + prioritize_results('trays'); + $i = 0; + $EXITSTRING.= "|"; + while ($perfcount > 0) { + (my $tray = $strays[$i][0]) =~ s/ /_/g; + if ($status[$i][0] eq 'CRITICAL') { + if ($status[$i][1] != "") { + $EXITSTRING.= $tray."=$status[$i][1]"; + } else { $EXITSTRING.= $tray."=0"; } + } + if ($status[$i][0] eq 'WARNING') { + if ($status[$i][1] != "") { + $EXITSTRING.= $tray."=$status[$i][1]"; + } else { $EXITSTRING.= $tray."=10"; } + } + if ($status[$i][0] eq 'OK') { + if ($status[$i][1] != "") { + $EXITSTRING.= $tray."=$status[$i][1]"; + } else { $EXITSTRING.= $tray."=100"; } + } + $i++; + $perfcount--; + if ($perfcount == 0) { $EXITSTRING.= ";;;;"; } else { $EXITSTRING.=";;;; "; } + } +} +sub retry_snmp { + my ($sr1,$sr2,$sr3,$sr4,$sr5,$sr6,$sr7,$sr8) = @_; + + if ($sr8) { + return $snmp->get_entries(-columns => [$sr1,$sr2,$sr3,$sr4,$sr5,$sr6,$sr7,$sr8]); + } elsif ($sr2) { + return $snmp->get_entries(-columns => [$sr1,$sr2,$sr3]); + } else { + return $snmp->get_request(-varbindlist => [$sr1]); + } +} + +# set alarm in case we hang +$SIG{ALRM} = sub { + print "CRITICAL - Timeout after $opt_timeout seconds\n"; + exit($ERRORS{'CRITICAL'}); +}; +alarm($opt_timeout*$opt_retries); + +# connect to the snmp server +($snmp, $errstr) = Net::SNMP->session( + -hostname => $opt_host, + -version => $opt_snmpver, + -community => $opt_community, + -timeout => $opt_timeout, + -retries => $opt_retries, +); +if (!$snmp) { + print "Could not create SNMP session: $errstr\n"; + exit($ERRORS{'UNKNOWN'}); +} + +if ($opt_messages) {check_messages();} +if ($opt_model) {check_model(1); exit($ERRORS{'OK'});} +if ($opt_pagecount) {check_page_count();} +if ($opt_consum) {check_consumables();} +if (defined($opt_tray)) {check_paper_trays($opt_tray);} + +$i = 0; +$scount = (scalar @status); +while ($scount > 0) { + if ($status[$i][0] eq "CRITICAL") { $critcount++; } + if (($status[$i][0] eq "WARNING") && ($state ne "CRITICAL")) { $warncount++; } + $scount--; + $i++; +} + +if ($critcount > 0) { $state = "CRITICAL"; } +elsif ($warncount > 0) { $state = "WARNING"; } +else { $state = "OK"; } + +stop($EXITSTRING, $state); +sub stop { + my $result = shift; + my $exit_code = shift; + print $result . "\n"; + exit ( $STATUS_CODE{$exit_code} ); +}