=================================================================== RCS file: /cvs/nagios/check_hw_sensors/check_hw_sensors,v retrieving revision 1.22 retrieving revision 1.39 diff -u -r1.22 -r1.39 --- nagios/check_hw_sensors/check_hw_sensors 2007/01/06 03:16:41 1.22 +++ nagios/check_hw_sensors/check_hw_sensors 2009/11/11 18:14:00 1.39 @@ -1,519 +1,493 @@ #!/usr/bin/perl -T -# $RedRiver: check_hw_sensors,v 1.21 2006/12/05 16:26:27 andrew Exp $ +# $RedRiver: check_hw_sensors,v 1.38 2009/11/11 18:08:41 andrew Exp $ ######################################################################## -# check_hw_sensors *** A nagios check for OpenBSD hw.sensors -# -# 2006.05.01 #*#*# andrew fresh +# check_hw_sensors *** A nagios check for OpenBSD sysctl hw.sensors +# +# 2006.05.01 #*#*# andrew fresh ######################################################################## -# TODO: -# Really need real documentation. -######################################################################## use strict; use warnings; -%ENV = (); +local %ENV = (); -use constant NAGIOS_OUTPUT => 0; +my $NAGIOS_OUTPUT = 1; +my $LICENSE = <<'EOL'; +Copyright (c) 2009 Andrew Fresh +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +EOL + use POSIX; use Config; -use lib "/usr/local/libexec/nagios"; -use utils qw($TIMEOUT %ERRORS &print_revision &support); +my $PREFIX; +BEGIN { + ## no critic 'warnings' + no warnings 'uninitialized'; + $PREFIX = "${PREFIX}" || '/usr/local'; # Magic for OpenBSD ports tree +} +use lib $PREFIX . '/libexec/nagios'; +use utils qw($TIMEOUT %ERRORS &support); use Getopt::Long; Getopt::Long::Configure('bundling'); -my $PROGNAME = "check_hw_sensors"; +my $PROGNAME = 'check_hw_sensors'; -my $SYSCTL = '/sbin/sysctl'; -my $GETCAP = '/usr/bin/getcap'; -my $BASE = 'hw.sensors'; +my $SYSCTL = '/sbin/sysctl'; +my $GETCAP = '/usr/bin/getcap'; +my $BASE = 'hw.sensors'; my $DEFAULT_CONFIG = '/etc/sensorsd.conf'; -my $OSVer = $Config{'osvers'} || 0; +my $OSVer = $Config{'osvers'} || 0; -my $state = 'UNKNOWN'; # tells whether the it is warning, critical, or OK -my %states; # This stores the count of states; -my $filename; -my $ignore_status; -my $sensor; -my $warning; -my $critical; -my $opt_h; +my $state = 'UNKNOWN'; # tells whether the it is warning, critical, or OK my $opt_V; +my $opt_h; +my $IGNORE_STATUS; +my $FILENAME; +my $SENSOR; +my $WARNING; +my $CRITICAL; -my $CHECK_SENSOR = $BASE; -my %CHECKS; -my %SENSORS; - #Option checking -my $status = GetOptions( - "version|V" => \$opt_V, - "filename|f:s" => \$filename, - "ignore-status|i" => \$ignore_status, - "sensor|s=s" => \$sensor, - "warning|w=s" => \$warning, - "critical|c=s" => \$critical, +my $getopt_status = GetOptions( + 'version|V' => \$opt_V, + 'help|h' => \$opt_h, + 'ignore-status|i' => \$IGNORE_STATUS, + 'filename|f:s' => \$FILENAME, + 'sensor|s=s' => \$SENSOR, + 'warning|w=s' => \$WARNING, + 'critical|c=s' => \$CRITICAL, ); -# set the default this way so it only happens if someone typed -f or --filename -$filename = $DEFAULT_CONFIG if (defined $filename && $filename eq ''); - -# Stuff is output in this file by print_sensor() -# http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/sysctl/sysctl.c -my @Type_Map = ( - { - type => 'temp', - regex => qr/\sdegC$/, - }, - { - type => 'fanrpm', - regex => qr/\sRPM$/, - }, - { - type => 'volts_dc', - regex => qr/\sV\sDC$/, - }, - { - type => 'amps', - regex => qr/\sA$/, - }, - { - type => 'watthour', - regex => qr/\sWh$/, - }, - { - type => 'amphour', - regex => qr/\sAh$/, - }, - { - type => 'indicator', - regex => qr/^(On|Off)$/, - }, - { - type => 'integer', - regex => qr/\sraw$/, - }, - { - type => 'percent', - regex => qr/\s\%$/, - }, - { - type => 'lux', - regex => qr/\slx$/, - }, - { - type => 'drive', - regex => qr/^drive\s/, - }, - { - type => 'timedelta', - regex => qr/\ssecs$/, - }, -); - -if ($status == 0) { - print_help() ; - exit $ERRORS{'OK'}; +if ( $getopt_status == 0 ) { + print_help(); + exit $ERRORS{'OK'}; } if ($opt_V) { - print_revision($PROGNAME,'$Revision: 1.22 $ '); - exit $ERRORS{'OK'}; + print_revision( $PROGNAME, '$Revision: 1.39 $ ' ); + exit $ERRORS{'OK'}; } -unless ( - ( - defined $filename || - (not defined $ignore_status) || - (defined $sensor && ($warning || $critical)) - ) && - ( (!defined $filename) || (!defined $sensor) ) -) { - print_help(); - exit $ERRORS{'OK'}; +if ($opt_h) { + print_help(); + exit $ERRORS{'OK'}; } +# set the default this way so it only happens if someone typed -f or --filename +$FILENAME = $DEFAULT_CONFIG if ( defined $FILENAME && $FILENAME eq q{} ); -if (defined $sensor) { - if ($sensor !~ /^$BASE/) { - $sensor = $BASE . '.' . $sensor; - } - $CHECK_SENSOR = $sensor; +# Stuff is output in this file by print_sensor() +# http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/sysctl/sysctl.c +my @TYPE_MAP = ( + { type => 'temp', + regex => qr/\sdegC$/xms, + }, + { type => 'fanrpm', + regex => qr/\sRPM$/xms, + }, + { type => 'volts_dc', + regex => qr/\sV\sDC$/xms, + }, + { type => 'amps', + regex => qr/\sA$/xms, + }, + { type => 'watthour', + regex => qr/\sWh$/xms, + }, + { type => 'amphour', + regex => qr/\sAh$/xms, + }, + { type => 'indicator', + regex => qr/^(On|Off)$/xms, + }, + { type => 'integer', + regex => qr/\sraw$/xms, + }, + { type => 'percent', + regex => qr/\s\%$/xms, + }, + { type => 'lux', + regex => qr/\slx$/xms, + }, + { type => 'drive', + regex => qr/^drive\s/xms, + }, + { type => 'timedelta', + regex => qr/\ssecs$/xms, + }, +); - $CHECKS{$sensor}{'warn'} = $warning if defined $warning; - $CHECKS{$sensor}{'crit'} = $critical if defined $critical; +my $CHECK_SENSOR = $BASE; +my %CHECKS; +if ( defined $SENSOR ) { + if ( $SENSOR !~ /^$BASE/xms ) { + $SENSOR = join q{.}, $BASE, $SENSOR; + } + $CHECK_SENSOR = $SENSOR; -} elsif (defined $filename) { - %CHECKS = parse_file($filename); + $CHECKS{$SENSOR}{'warn'} = $WARNING if $WARNING; + $CHECKS{$SENSOR}{'crit'} = $CRITICAL if $CRITICAL; } +elsif ( defined $FILENAME ) { + %CHECKS = read_file($FILENAME); +} -open my $sysctl, "-|", $SYSCTL, $CHECK_SENSOR - or die "Couldn't open sysctl: $!"; -while (<$sysctl>) { -#while (<>) { - chomp; - my ($id, $output) = split /=/; - my @s = split /\./, $id; - my @o = split /,\s*/, $output; +my @SENSORS = read_sensors($CHECK_SENSOR); +my %STATES = check_sensors( \@SENSORS, \%CHECKS, + { IGNORE_STATUS => $IGNORE_STATUS } ); - my ($type, $source, $descr, $data, $status); +my $have_results = 0; +$state = 'OK'; +foreach + my $error ( reverse sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS ) +{ + if ( exists $STATES{$error} ) { + $have_results++; + $state = $error if $ERRORS{$state} < $ERRORS{$error}; - $source = $o[0]; - $descr = $o[1]; + if ($NAGIOS_OUTPUT) { + print $error . ' (' . scalar( @{ $STATES{$error} } ) . ')'; + if ( $error ne 'OK' ) { + print '
'; + print map { " - $_
" } @{ $STATES{$error} }; + } + } + else { + print $error . ' (' . scalar( @{ $STATES{$error} } ) . "):\n"; + foreach ( @{ $STATES{$error} } ) { + print " $_\n"; + } + } + } +} +if ( $have_results == 0 ) { + print "No results found\n"; +} +exit $ERRORS{$state}; - if (@s == 4) { # XXX This mebbe needs to end up $OSVer >= 4.1 - $data = $o[0]; - $descr =~ s/^\(|\)$//g; - $status = $o[2]; - ($source, $type) = $id =~ /([^\.]+)\.([^\.]+)\d+$/; - } elsif ($OSVer >= 4.0) { - $data = $o[2]; - $status = $o[3]; - foreach my $t (@Type_Map) { - if ($data =~ /$t->{'regex'}/) { - $type = $t->{'type'}; - last; - } - } - } else { - $data = $o[-1]; - $status = $o[2] if @o == 5; - $type = $o[-2]; - } +sub read_sensors { + my ($sensor) = @_; + my @S; + open my $sysctl, '-|', $SYSCTL, $sensor + or die "Couldn't open sysctl: $!\n"; + while (<$sysctl>) { + chomp; + push @S, parse_sensor($_); + } + ## no critic 'die' + close $sysctl + or die $! + ? "Error closing sysctl pipe: $!\n" + : "Exit status $? from sysctl\n"; - $type ||= 'unknown'; - - $SENSORS{$id} = { - id => $id, - output => $output, - source => $source, - description => $descr, - status => $status, - type => $type, - data => $data, - }; - + return @S; } -close $sysctl; -sub as_if_numeric { - my $_a = $a; - my $_b = $b; - $_a =~ s/\D//g; - $_b =~ s/\D//g; - $_a <=> $_b; -} +sub parse_sensor { + my ($sensor) = @_; -foreach my $s (sort as_if_numeric keys %SENSORS) { - my ($r, $data); - if (exists $CHECKS{$s}) { - $r = check_sensor($SENSORS{$s}, $CHECKS{$s}); - $data = $s . '=' . $SENSORS{$s}{'output'}; - } elsif (not $ignore_status) { - $r = check_sensor($SENSORS{$s}); - $data = $s . '=' . $SENSORS{$s}{'output'}; - } else { - # ignore this sensor - } - next unless defined $r; - push @{ $states{ $r } }, $data; -} + my ( $id, $output ) = split /=/xms, $sensor; + my @s = split /\./xms, $id; + my @o = split /,\s*/xms, $output; -$state = 'OK'; -my $have_results = 0; -foreach my $error (sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS) { - if (exists $states{$error}) { - $have_results++; - $state = $error; - } -} -foreach my $error (sort { $ERRORS{$b} <=> $ERRORS{$a} } keys %ERRORS) { - if (exists $states{$error}) { - if (NAGIOS_OUTPUT) { - print "$error (" . scalar(@{ $states{ $error } }) . ")"; - unless ($error eq 'OK') { - print '
'; - print map {" - $_
"} @{ $states{ $error } }; - } - } else { - print "$error (" . scalar(@{ $states{ $error } }) . "):\n"; - foreach (@{ $states{ $error } }) { - print " $_\n"; - } - } - } -} -if ($have_results == 0) { - print "No results found\n"; -} -exit $ERRORS{$state}; + my ( $type, $source, $descr, $data, $status ); + $source = $o[0]; + $descr = $o[1]; -sub parse_file { - my $filename = shift; - my %contents; - - die "file '$filename' does not exist." unless -e $filename; + if ( $OSVer >= 4.1 ) { + $data = $o[0]; + if ( $data =~ s/\s+\((.*)\).*$//xms ) { + $descr = $1; + } + $status = $o[1]; + ( $source, $type ) = $id =~ /([^\.]+)\.([^\.]+?)\d+$/xms; + } + elsif ( $OSVer >= 4.0 ) { + $data = $o[2]; + $status = $o[3]; + foreach my $t (@TYPE_MAP) { + if ( $data =~ /$t->{'regex'}/xms ) { + $type = $t->{'type'}; + last; + } + } + } + else { + $data = $o[-1]; + $status = $o[2] if @o == 5; + $type = $o[-2]; + } - open my $fh, '-|', $GETCAP, '-a', '-f', $filename - or die "Couldn't open FILE '$GETCAP -a -f $filename': $!"; - LINE: while (<$fh>) { - chomp; - my ($key, @c) = split /\:/; - foreach (@c) { - my ($k, $v) = split /\=/; - if (lc($k) eq 'ignore') { - $contents{$key}{'IGNORE'} = 1; - } elsif (lc($k) eq 'status') { - $contents{$key}{'STATUS'} = 1; - } else { - $contents{$key}{$k} = $v; - } - } - } - close $fh; + $type ||= 'unknown'; - return %contents; + return { + id => $id, + output => $output, + source => $source, + description => $descr, + status => $status, + type => $type, + data => $data, + }; } -sub parse_check { - my $type = shift; - my $check = shift; +sub read_file { + my $filename = shift; + my %contents; - return undef unless $check; - return undef if $check->{'STATUS'}; - return 'IGNORE' if $check->{'IGNORE'}; + die "file '$filename' does not exist.\n" unless -e $filename; - foreach my $code ('crit', 'warn') { - if (defined $check->{$code} && $check->{$code} =~ /:/) { - if (my ($low, $high) = split /:/, $check->{$code}) { - $check->{$code . '.low'} = $low; - $check->{$code . '.high'} = $high; - } - delete $check->{$code}; - } + open my $fh, '-|', $GETCAP, '-a', '-f', $filename + or die "Couldn't open '$GETCAP -a -f $filename': $!\n"; + while (<$fh>) { + chomp; + my ( $s, @c ) = split /\:/xms; + $contents{$s} = parse_line(@c); + } + ## no critic 'die' + close $fh + or die $! + ? "Error closing getcap pipe: $!\n" + : "Exit status $? from getcap\n"; - foreach my $severity ('low', 'high') { - if (defined $check->{$severity}) { - $check->{ $code . '.' . $severity } = $check->{$severity} - unless defined $check->{ $code . '.' . $severity }; - } - } - no warnings 'uninitialized'; - $check->{$code} = [ split /,\s*/, $check->{$code} ]; - } + return %contents; +} - return $check; +sub parse_line { + my (@c) = @_; + my %c; + foreach (@c) { + my ( $k, $v ) = split /\=/xms; + if ( lc($k) eq 'ignore' ) { $c{'IGNORE'} = 1; } + elsif ( lc($k) eq 'status' ) { $c{'STATUS'} = 1; } + else { $c{$k} = $v; } + } + return \%c; } -sub check_sensor { - my $sensor = shift; - my $check = shift; - my $result = 'UNKNOWN'; - my %errors = ( - 'warn' => 'WARNING', - 'crit' => 'CRITICAL', - ); +sub parse_check { + my $check = shift; - return $result unless ref $sensor eq 'HASH'; - $check = parse_check($sensor->{'type'}, $check) if $check; + return unless $check; + return 'STATUS' if $check->{'STATUS'}; + return 'IGNORE' if $check->{'IGNORE'}; - # It looks like doing this should be safe, from - # src/sbin/sysctl/sysctl.c - return $sensor->{'status'} unless $check; + foreach my $code ( 'crit', 'warn' ) { + if ( defined $check->{$code} && $check->{$code} =~ /:/xms ) { + if ( my ( $low, $high ) = split /:/xms, $check->{$code} ) { + $check->{ $code . '.low' } = $low if length $low; + $check->{ $code . '.high' } = $high if length $high; + } + delete $check->{$code}; + } - return undef if $check eq 'IGNORE'; + foreach my $direction ( 'low', 'high' ) { + my $c = $code . '.' . $direction; + if ( defined $check->{$direction} ) { + $check->{$c} ||= $check->{$direction}; + } - $result = 'OK'; - foreach my $code ('warn', 'crit') { - if ( - $sensor->{'type'} eq 'fanrpm' || - $sensor->{'type'} eq 'volt' || - $sensor->{'type'} eq 'volts_dc' || - $sensor->{'type'} eq 'amps' || - $sensor->{'type'} eq 'watthour' || - $sensor->{'type'} eq 'amphour' || - $sensor->{'type'} eq 'integer' || - $sensor->{'type'} eq 'raw' || - $sensor->{'type'} eq 'percent' || - $sensor->{'type'} eq 'lux' || - $sensor->{'type'} eq 'timedelta' - ) { - my $data = $sensor->{'data'}; - $data =~ s/[^\d\.]//g; - unless (length $data) { - warn "INVALID DATA ($sensor->{'data'}) for '$sensor->{'id'}'"; - next; - } + if ( defined $check->{$c} ) { + my $old = $check->{$c}; + $check->{$c} =~ s/[^\d\.]//gxms; + if ( !length $check->{$c} ) { + warn "INVALID CHECK ($old)\n"; + delete $check->{$c}; + } + } + } - if ( - defined $check->{$code . ".low"} || - defined $check->{$code . ".high"} - ) { - if (defined $check->{$code . ".low"}) { - my $c = $check->{$code . ".low"}; - $c =~ s/[^\d\.]//g; - - unless (length $c) { - warn "INVALID CHECK (" . $check->{$code . ".low"} . - ") for '$sensor->{'id'}:$code.low'"; - next; - } + if ( defined $check->{$code} ) { + $check->{$code} = [ split /,\s*/xms, $check->{$code} ]; + } + else { + $check->{$code} = []; + } + } - $result = $errors{$code} - if ($c >= $data); - } - if (defined $check->{$code . ".high"}) { - my $c = $check->{$code . ".high"}; - $c =~ s/[^\d\.]//g; - unless (length $c) { - warn "INVALID CHECK (" . $check->{$code . ".high"} . - ") for '$sensor->{'id'}:$code.high'"; - next; - } + return $check; +} - $result = $errors{$code} - if ($c <= $data); - } - } elsif (@{ $check->{$code} }) { - my $matched = 0; - foreach my $c (@{ $check->{$code} }) { - $c =~ s/[^\d\.]//g; - unless (length $c) { - warn "INVALID CHECK (" . $c . - ") for '$sensor->{'id'}:$code'"; - next; - } +sub check_sensors { + my ( $S, $C, $O ) = @_; - if ($c eq $data) { - $matched = 1; - last; - } - } - $result = $errors{$code} unless $matched; - } + my %states; + foreach my $sensor ( @{$S} ) { + my ( $r, $data ); + if ( exists $C->{ $sensor->{id} } ) { + $r = check_sensor( $sensor, $C->{ $sensor->{id} } ); + $data = $sensor->{id} . '=' . $sensor->{output}; + } + elsif ( $sensor->{status} && !$O->{IGNORE_STATUS} ) { + $r = check_sensor( $sensor, { STATUS => 1 } ); + $data = $sensor->{id} . '=' . $sensor->{output}; + } + else { - } elsif ($sensor->{'type'} eq 'temp') { - my ($degC, $degF) = split /\//, $sensor->{'data'}; - $degC =~ s/[^\d\.]//g; - $degF ||= $degC * 9 / 5 + 32; - $degF =~ s/[^\d\.]//g; - if ( - defined $check->{$code . ".low"} || - defined $check->{$code . ".high"} - ) { - if (defined $check->{$code . ".low"}) { - my $c = $check->{$code . ".low"}; - my $data = $degC; + # ignore this sensor, theoretically you could do the check and + # that would show unknown sensors. + } + if ( defined $r ) { + push @{ $states{$r} }, $data; + } + } - $data = $degF if ($c =~ /F/i); - unless (length $data) { - warn "INVALID DATA (" . $sensor->{'data'} . - ") for '$sensor->{'id'}'"; - next; - } + return %states; +} - $c =~ s/[^\d\.]//g; - unless (length $c) { - warn "INVALID CHECK (" . $check->{$code . ".low"} . - ") for '$sensor->{'id'}':$code.low"; - next; - } +sub check_sensor { + my ( $sensor, $check ) = @_; + my $result = 'UNKNOWN'; - $result = $errors{$code} - if ($c >= $data); - } - if (defined $check->{$code . ".high"}) { - my $c = $check->{$code . ".high"}; + return $result unless ref $sensor eq 'HASH'; + $check = parse_check($check) if $check; - my $data = $degC; - $data = $degF if ($c =~ /F/i); - unless (length $data) { - warn "INVALID DATA (" . $sensor->{'data'} . - ") for '$sensor->{'id'}'"; - next; - } + if ( !$check ) { return $result; } + elsif ( $check eq 'STATUS' ) { - $c =~ s/[^\d\.]//g; - unless (length $c) { - warn "INVALID CHECK (" . $check->{$code . ".high"} . - ") for '$sensor->{'id'}:$code.high'"; - next; - } + # It looks like returning $sensor->{status} should be safe, from + # src/sbin/sysctl/sysctl.c + return ( $sensor->{'status'} || $result ); + } + elsif ( $check eq 'IGNORE' ) { return; } - $result = $errors{$code} - if ($c <= $data); - } - } elsif (@{ $check->{$code} }) { + my $type = $sensor->{'type'}; + if (grep { $type eq $_ } + qw( + fan fanrpm + volt volts_dc + amps watthour amphour + integer raw percent + lux temp timedelta + ) + ) + { + $result = check_sensor_numeric( $sensor->{'data'}, $check ); + } + elsif ( grep { $type eq $_ } qw( drive indicator ) ) { + my $data = $sensor->{'data'}; + $data =~ s/^drive\s+//xms; + $result = check_sensor_list( $data, $check ); + } + else { + warn 'Unknown Sensor Type: ', $sensor->{'id'}, '=', $type, "\n"; + } - my $matched = 0; - foreach my $c (@{ $check->{$code} }) { - my $data = $degC; + return $result; +} - $data = $degF if ($c =~ /F/i); - unless (length $data) { - warn "INVALID DATA (" . $sensor->{'data'} . - ") for '$sensor->{'id'}'"; - next; - } +sub check_sensor_numeric { + my ( $data, $check ) = @_; - $c =~ s/[^\d\.]//g; - unless (length $c) { - warn "INVALID CHECK (" . $c . - ") for '$sensor->{'id'}':$code"; - next; - } + my $result = 'UNKNOWN'; + my %errors = ( + 'warn' => 'WARNING', + 'crit' => 'CRITICAL', + ); - if ($c eq $data) { - $matched = 1; - last; - } - } - $result = $errors{$code} unless $matched; - } + $data =~ s/[^\d\.]//gxms; + if ( !length $data ) { + warn "INVALID DATA ($data)\n"; + return $result; + } - } elsif ( - $sensor->{'type'} eq 'drive' || - $sensor->{'type'} eq 'indicator' - ) { - $sensor->{'data'} =~ s/^drive\s+//; - if (@{ $check->{$code} }) { - my $matched = 0; - foreach (@{ $check->{$code} }) { - if ($_ eq $sensor->{'data'}) { - $matched = 1; - last; - } - } - $result = $errors{$code} unless $matched; - } + foreach my $code ( 'warn', 'crit' ) { + if ( defined $check->{ $code . '.low' } + || defined $check->{ $code . '.high' } ) + { + if (( defined $check->{ $code . '.low' } + && $check->{ $code . '.low' } >= $data + ) + || ( defined $check->{ $code . '.high' } + && $check->{ $code . '.high' } <= $data ) + ) + { + $result = $errors{$code}; + } + $result = 'OK' if $result eq 'UNKNOWN'; + } + elsif ( @{ $check->{$code} } ) { + my $matched = 0; + NUMERIC_CHECK: foreach ( @{ $check->{$code} } ) { + my $c = $_; + $c =~ s/[^\d\.]//gxms; + if ( !length $c ) { + warn "INVALID CHECK ($_) for '$code'\n"; + next; + } - } else { - print STDERR 'Unknown Sensor Type: ', - $sensor->{'id'}, - '=', - $sensor->{'type'}, - "\n"; - $result = 'UNKNOWN'; - } + if ( $c eq $data ) { + $matched = 1; + last NUMERIC_CHECK; + } + } + if ($matched) { + $result = 'OK' if $result eq 'UNKNOWN'; + } + else { + $result = $errors{$code}; + } + } + } - } + return $result; +} - return $result; +sub check_sensor_list { + my ( $data, $check ) = @_; + + my $result = 'UNKNOWN'; + my %errors = ( + 'warn' => 'WARNING', + 'crit' => 'CRITICAL', + ); + + foreach my $code ( 'warn', 'crit' ) { + if ( @{ $check->{$code} } ) { + my $matched = 0; + LIST_CHECK: foreach ( @{ $check->{$code} } ) { + if ( $_ eq $data ) { + $matched = 1; + last LIST_CHECK; + } + } + if ($matched) { + $result = 'OK' if $result eq 'UNKNOWN'; + } + else { + $result = $errors{$code}; + } + } + } + + return $result; } sub print_help { - print <]|(-s [-w limit] [-c limit])) + print <<"EOL"; +$PROGNAME - monitors sysctl hw.sensors on OpenBSD + $PROGNAME [-i] [-f []|(-s [-w limit] [-c limit])] Usage: -i, --ignore-status - Don't check the status of sensors that report it. + Don't automatically check the status of sensors that report it. -f, --filename=FILE FILE to load checks from (defaults to /etc/sensorsd.conf) -s, --sensor=ID - ID of a single sensor. "-s 0" means hw.sensors.0. + ID of a single sensor. "-s kate0.temp0" means hw.sensors.kate0.temp0 + Overrides --filename. -w, --warning=RANGE or single ENTRY Exit with WARNING status if outside of RANGE or if != ENTRY -c, --critical=RANGE or single ENTRY @@ -521,7 +495,8 @@ FILE is in the same format as sensorsd.conf(5) plus some additional entries. These additional entries in the file are ignored by -sensorsd(8). +sensorsd(8). This means you can use the same config file for $PROGNAME +as well as sensorsd(8). $PROGNAME understands the following entries: @@ -532,14 +507,11 @@ can be used when appropriate, or you can use the following: fanrpm, volts_dc, amps, watthour, amphour, integer (raw), percent, - lux or timedelta - Anything that includes digits. Both the value of - the check and the value of the sensor response that are not either a - digit or period are stripped and then the two resultant values are - compared. + lux, temp or timedelta - Anything that includes digits. Both the + value of the check and the value of the sensor response that are not + either a digit or period are stripped and then the two resultant + values are compared. - temp - Can be as above, but if the entry has an F in it, - it compares farenheit, otherwise it uses celcius. - indicator or drive - does a case sensitive match of each entry in the comma separated list and if it does not match any of the entries, it sets the status. @@ -552,7 +524,7 @@ A RANGE is a low ENTRY and a high ENTRY separated by a colon (:). It can also be low: or :high with the other side left blank to only -make the single check.. +make the single check. An entry marked "ignore" will cause that sensor to be skipped. Generally used with state checking of all sensors to ignore sensors you @@ -563,6 +535,19 @@ EOL - print_revision($PROGNAME, '$Revision: 1.22 $'); + print_revision( $PROGNAME, '$Revision: 1.39 $' ); + + print $LICENSE; + + return; +} + +sub print_revision { + my ( $prog, $rev ) = @_; + $rev =~ s/^\D+([\d\.]+)\D+$/v$1/xms; + + print "$prog $rev\n"; + + return; }