#!/usr/bin/perl -w

# ---

=head1 NAME

check_runningerror.pl - Nagios plugin for checking running errors of eib/knx nodes

=head1 SYNOPSIS

=over 4

=item check_runningerror.pl -U url -E EIB/KNX-address [-v] [-w warning_threshold] [-c critical_threshold]

=item check_runningerror.pl [-h|-V]

=back

=head1 OPTIONS

=over 4

=item -E|--eibaddr=expression

Physical EIB/KNX address e.g. 1.1.1

=item -U| --url=expression

BCU-Connection to EIB/KNX-Bus e.g. ip:127.0.0.1

=item -w|--warning=threshold

threshold can be max (warn if < 0 or > max), min:max (warn if < min or >
max), min: (warn if < min), or @min:max (warn if >= min and <= max). All
values must be integer.

=item -c|--critical=threshold

see --warning for explanation of threshold format

=item -t|--timeout=seconds

timeout after check_runningerror.pl exits.

=item -v|--verbose

increases verbosity, specify twice to see the original output.

=item -V|--version

print version an exit

=item -h|--help

print help message and exit

=back

=cut

use strict;                             # strict syntax usage, predeclared Vars
use warnings;                           # for perl versions lesser than 5.6
use FindBin;                            # find path from this plugin
use lib "$FindBin::Bin/../perl/lib";
use Nagios::Plugin;                     # with const, vars and functions
use Getopt::Long qw(:config no_ignore_case bundling);   # Get options 
                                                        # case-sensitive
                                                        # bundled options
use Pod::Usage;                         # Perl Online Dokumentation (POD)
#use Test::More tests => 6;             # Testing Module for development

### Variables ################################################################
my $np = Nagios::Plugin->new(shortname => "RUNNINGERROR");  # create Nagios Obj
my $warn_threshold = '0:';
my $crit_threshold = '0:';
my $what = '';
my $result = UNKNOWN;
my $version = 'V1.0/2010-07-01';
my $printversion = 0;
my $verbose = 0;
my $help = 0;
my $timeout = 10;  # 10s by default
my $debug = 0;
my $runningerrorflag = 0;
my $url = '';
my $number = 0;
##############################################################################

GetOptions(
   "E|eibaddr=s"	=> \$what,		# =s string type
   "w|warnings=s"	=> \$warn_threshold,
   "c|critical=s"	=> \$crit_threshold,
   "t|timeout=s"	=> \$timeout,
   "h|help"		=> \$help,
   "V|version"		=> \$printversion,
   "v|verbose+"		=> \$verbose,		# Option can set multiple
   "d|debug:+"		=> \$debug,
   "U|url=s"		=> \$url		# e.g. ip:127.0.0.1
) or pod2usage({ -exitval => UNKNOWN,
                 -verbose => 0,
                 -msg     => "*** unknown argument found ***" });

pod2usage(-verbose => 2,
          -exitval => UNKNOWN,
	  -output  => \*STDOUT,
         ) if ( $help );

pod2usage(-msg     => "\n$0 -- version: $version\n",
          -verbose => 0,
          -exitval => UNKNOWN,
         ) if ( $printversion );

pod2usage(-msg     => "*** no eibaddr and/or url specified ***",
          -verbose => 0,
          -exitval => UNKNOWN,
	) unless ($what && $url) ;

if ( $debug >= 2 ) {                               # Debug Information
        print "Plugin options:\n";
        printf "    %-23s %d\n", "verbose:", $verbose;
        printf "    %-23s %s\n", "warning:", $warn_threshold || '';
        printf "    %-23s %s\n", "critical:", $crit_threshold || '';
        printf "    %-23s %s\n", "timeout:", $timeout || '';
        printf "    %-23s %s\n", "eibaddr:", $what || '';
        printf "    %-23s %s\n", "debug:", $debug || '';
        printf "    %-23s %s\n", "url:", $url || '';
        printf "    %-23s %s\n", "version:", $version || '';
}

# set timeout alarm
$SIG{ALRM} = sub { $np->nagios_die("Timeout reached"); }; # Return: UNKNOWN
alarm($timeout);

# allocate thresholds
$np->set_thresholds(
   warning  => $warn_threshold,		# Option -w to warn_threshold
   critical => $crit_threshold		# Option -c to crit_threshold
);

# Debug-Information about threshold values
print "DEBUG: warn= $warn_threshold, crit= $crit_threshold\n" if ($debug);

# The core programm call
open ( OUT, "LANG=C /usr/bin/mread $url $what 10D 1 2>&1 |" ) # open Output
   or $np->nagios_die( "can't start /usr/bin/mread" );	      # LANG=C for Engl	

while (<OUT>) {				# While OUTPUT is there 
   print "$_" if ($verbose);		# if verbose, print current line
   chomp $_;				# Cut current textline $_

   $runningerrorflag = $_;

   if ($_ =~ /^[A-F,0-9][A-F,0-9] $/) 	# If XX is a Hex
   {
      ($number = $_) =~ s/ //i;    	# Delete spaces
      $runningerrorflag = hex($number); # Convert Hex to Dec
      last;
   }
   else 
   {
      $np->nagios_exit( CRITICAL, "cannont read running error");
      last;
   }
}
close (OUT);

# Performance-Data
$np->add_perfdata( label => "errorflag", value => $number, 
                   uom => "", threshold => $np->threshold() # no unit specified
);

# Compare the actual decimal value with the threshold
$result = $np->check_threshold(  $runningerrorflag );

# Reset alarm
alarm(0);

# Return exit-code
$np->nagios_exit( $result, "Errorflag: $runningerrorflag (0x$number)"); 


=head1 EXAMPLES

=head2 Command line example

Check the running error of the EIB/KNX-Bus at an EIB/KNX-Device over IP-Gateway:

$ check_runningerror.pl -E 1.1.1 -U ip:127.0.0.1 

RUNNINGERROR OK - Errorflag 255 (0xFF)

=head2 Nagios configuration example

 define command {
   command_name    check_runningerror
   command_line    $USER1$/check_runningerror.pl --eibaddr $HOSTADDRESS$ --url 
                   $ARG1$ -c $ARG2$
 }

 define service {
   host_name            1.1.1:_Switch
   service_description  RunningError
   check_command        check_runningerror!ip:127.0.0.1!255:255
   use                  generic-service
}

The Values for Warning and Critical are recommanded by the EIB/KNX-Specs, that specified 0xFF (255dec) as "ok", all other values as "error ocours". This is the reason why in the example above there is no warning threshold

 define host {
   use                   generic-node            ; Name of host template
   host_name             1.1.1:_Switch
   alias                 Switch 1.1.1
   address               1.1.1
 }

The pysical Address of the EIB/KNX-Device is defined as regular address.

=head1 NAGIOS PLUGIN NOTES

Nagios plugin reference: http://nagiosplug.sourceforge.net/developer-guidelines.html

This plugin does NOT use Nagios DEFAULT_SOCKET_TIMEOUT (provided by utils.pm as $TIMEOUT) because the path to utils.pm must be specified completely in this program and forces users to edit the source code if their install location is different (if they realize this is the problem). The utils.pm will be deprecated soon and using the Nagios::Plugin from CPAN is recommanded. You can view the default timeout for this module by using the -vv option. 

Other than that, it attempts to follow published guidelines for Nagios plugins.

=head1 AUTHOR

Sebastian Renker, <sebastian.renker@stud.fh-erfurt.de>

=head1 KNOWN ISSUES

none

=head1 BUGS

none

=head1 LICENSE

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
the Free Software Foundation; version 2 of the License (and no
later version).

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

=head1 HISTORY

V1.1/2010-07-01 following nagios plugin development guidelines
V1.0/2010-05-07 inital version for bachelor thesis

=cut
