#!/usr/bin/perl
# ============================================================================
# ============================== INFO ========================================
# ============================================================================
# Version	: 0.1
# Date		: Feb 9 2014
# Author	: Michiel Timmers ( michiel.timmers AT gmx.net)
# Licence 	: GPL - summary below
#
# ============================================================================
# ============================== SUMMARY =====================================
# ============================================================================
#
# Checks card info from MuMuDVB xml file. 
#
# Check the http://exchange.nagios.org website for new versions.
# For comments, questions, problems and patches send me an 
# e-mail (michiel.timmmers AT gmx.net). 
#
# ============================================================================
# ============================== LICENCE =====================================
# ============================================================================
# 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, either version 3 of the License, or
# (at your option) any 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, see <http://www.gnu.org/licenses/>
#
# ============================================================================
# ============================== HELP ========================================
# ============================================================================
# Help : ./check_mumudvb_scrambling.pl --help
#
# ============================================================================

use warnings;
use strict;
use Getopt::Long;
use XML::LibXML;


# ============================================================================
# ============================== NAGIOS VARIABLES ============================
# ============================================================================

my $TIMEOUT 				= 10;	# This is the global script timeout
my %ERRORS				= ('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
my @Nagios_state 			= ("UNKNOWN","OK","WARNING","CRITICAL"); # Nagios states coding


# ============================================================================
# ============================== OID VARIABLES ===============================
# ============================================================================

my $state_location     	= "/monitor/state.xml"; # state.xml location


# ============================================================================
# ============================== GLOBAL VARIABLES ============================
# ============================================================================

my $Version			= '0.1';	# Version number of this script
my $o_host			= undef; 	# Hostname
my $o_port	 		= undef; 	# Port
my $o_help			= undef; 	# Want some help ?
my $o_verb			= undef;	# Verbose mode
my $o_card_uptime_warning	= undef;	# Warning card uptime in hours 
my $o_card_uptime_critical	= undef;	# Critical card uptime in hours 



# ============================================================================
# ============================== SUBROUTINES (FUNCTIONS) =====================
# ============================================================================

# Subroutine: Print version
sub p_version { 
	print "check_mumudvb_card version : $Version\n"; 
}

# Subroutine: Print Usage
sub print_usage {
    print "Usage: $0 [-v] -H <host> -p <port> -w <warning uptime in hours> -c <critical uptime in hours> \n";
}

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

# Subroutine: Set final status
sub set_status { # Return worst status with this order : OK, unknown, warning, critical 
	my $new_status = shift;
	my $cur_status = shift;
	if ($new_status == 1 && $cur_status != 2) {$cur_status = $new_status;}
	if ($new_status == 2) {$cur_status = $new_status;}
	if ($new_status == 3 && $cur_status == 0) {$cur_status = $new_status;}
	return $cur_status;
}


# Subroutine: Print complete help
sub help {
	print "\nMuMuDVB card plugin for Nagios\nVersion: ",$Version,"\n\n";
	print_usage();
	print <<EOT;

Options:
-v, --verbose
   Print extra debugging information 
-h, --help
   Print this help message
-H, --hostname=HOST
   Hostname or IPv4/IPv6 address of host to check
-P, --port=PORT
   http port 
-w,
   Warning threshold uptime in hours
-c,
   Critical threshold uptime in hours
-V, --version
   Prints version number

Notes:
- Check the http://exchange.nagios.org website for new versions.
- For questions, problems and patches send me an e-mail (michiel.timmmers AT gmx.net).

EOT
}

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

# Subroutine: Verbose output
sub check_options {
	Getopt::Long::Configure ("bundling");
	GetOptions(
		'v'	=> \$o_verb,		'verbose'	=> \$o_verb,
	        'h'     => \$o_help,    	'help'        	=> \$o_help,
	        'H:s'   => \$o_host,		'hostname:s'	=> \$o_host,
	        'p:i'   => \$o_port,   		'port:i'	=> \$o_port,
	        				'c:i'       	=> \$o_card_uptime_critical,
	        				'w:i'        	=> \$o_card_uptime_warning
	);

	# Basic checks
	if (defined ($o_help) ) {
		help();
		exit $ERRORS{"UNKNOWN"};
	}

	# check host and filter 
	if ( ! defined($o_host) ) {
		print_usage();
		exit $ERRORS{"UNKNOWN"};
	}

	if ( ! defined($o_port) ) {
		print_usage();
		exit $ERRORS{"UNKNOWN"};
	}

	if ( ! defined($o_card_uptime_warning) ) {
		print_usage();
		exit $ERRORS{"UNKNOWN"};
	}

	if ( ! defined($o_card_uptime_critical) ) {
		print_usage();
		exit $ERRORS{"UNKNOWN"};
	}
}


# ============================================================================
# ============================== MAIN ========================================
# ============================================================================

check_options();

# Check gobal timeout 
if (defined($TIMEOUT)) {
	verb("Alarm at ".$TIMEOUT);
	alarm($TIMEOUT);
}

# Report when the script gets "stuck" in a loop or takes to long
$SIG{'ALRM'} = sub {
	print "CRITICAL: Script timed out\n";
	exit $ERRORS{"CRITICAL"};
};

my $exit_val=undef;

# ============================================================================
# ===================== MuMuDVB - Card status/info  ==========================
# ============================================================================

# Define variables
my $output			= "";	
my $mumudvb_menustring		= "";	
my $final_status		= 0;
my ($num_channels,$num_channels_up,$uptime_day,$uptime_hour,$uptime_minute)	= (0,0,0,0,0);

my $filename = "http://".$o_host.":".$o_port.$state_location;
my $parser = XML::LibXML->new();
my $state    = $parser->parse_file($filename);

# Get MuMuDVB version
my $mumudvb_version = $state->findnodes('/mumudvb/global_version'); 

# Get process PID
my $mumudvb_pid = $state->findnodes('/mumudvb/global_pid'); 

# Set threshold inputs from seconds to hours
$o_card_uptime_warning = $o_card_uptime_warning*60*60;
$o_card_uptime_critical = $o_card_uptime_critical*60*60;
# Get process uptime
my $mumudvb_uptime_seconds = $state->findnodes('/mumudvb/global_uptime'); 
$mumudvb_uptime_seconds = int($mumudvb_uptime_seconds->string_value());
# Critical if uptime if below critical threshold
if($mumudvb_uptime_seconds < $o_card_uptime_critical){$final_status = &set_status(2,$final_status);}
# Warning if uptime if below warning threshold and above critical threshold
if($mumudvb_uptime_seconds < $o_card_uptime_warning && $mumudvb_uptime_seconds > $o_card_uptime_critical){$final_status = &set_status(1,$final_status);}
# Make some calculation for nice output
while ($mumudvb_uptime_seconds >= 86400){$uptime_day++;$mumudvb_uptime_seconds = $mumudvb_uptime_seconds - 86400;}
while ($mumudvb_uptime_seconds >= 3600){$uptime_hour++;$mumudvb_uptime_seconds = $mumudvb_uptime_seconds - 3600;}
while ($mumudvb_uptime_seconds >= 60){$uptime_minute++;$mumudvb_uptime_seconds = $mumudvb_uptime_seconds - 60;}

# Get adapter tuned status
my $mumudvb_tuned = $state->findnodes('/mumudvb/frontend_tuned'); 
$mumudvb_tuned = int($mumudvb_tuned->string_value());
if($mumudvb_tuned == 0){$final_status = &set_status(2,$final_status);}

# Get CAM initialized status
my $mumudvb_cam_initialized = $state->findnodes('/mumudvb/cam_initialized'); 
$mumudvb_cam_initialized = int($mumudvb_cam_initialized->string_value());
if($mumudvb_cam_initialized == 0){
# Uncomment the line bellow if you want an Critical status when the CAM is not initialized
#	$final_status = &set_status(2,$final_status);
}
# When CAM is initialized, Get CAM model
if($mumudvb_cam_initialized == 1){$mumudvb_menustring = $state->findnodes('/mumudvb/cam_menustring'); }

# Check number of channels and if the channels are up
foreach my $channel ($state->findnodes('/mumudvb/channel')) {
	$num_channels++;	
	my $is_up = $channel->findvalue('./@is_up');
	if($is_up == 1){
		$num_channels_up++;
	}
}

# Create the output line
$output = "MuMuDVB ".$mumudvb_version;
$output.= " (PID ".$mumudvb_pid.", uptime ".$uptime_day." days, ".$uptime_hour." hours, ".$uptime_minute." minutes) - ";

if($mumudvb_tuned == 0){$output.= "adapter NOT tuned - ";}
if($mumudvb_tuned == 1){$output.= "adapter tuned - ";}

if($mumudvb_cam_initialized == 0){$output.= "CAM is NOT initialized";}
if($mumudvb_cam_initialized == 1){$output.= "CAM (".$mumudvb_menustring.") is initialized";}
$output.= " - Total channels: ".$num_channels." (".$num_channels_up." up)";

if($num_channels == 0){
	$output = "No channel data found";
	$final_status = &set_status(2,$final_status);
}

# check if all channels are up
if($num_channels > $num_channels_up){
	$final_status = &set_status(2,$final_status);
}

if ($final_status == 3) {
	print $output," : UNKNOWN\n";
	exit $ERRORS{"UNKNOWN"};
}
	
if ($final_status == 2) {
	print $output," : CRITICAL\n";
	exit $ERRORS{"CRITICAL"};
}

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

print $output," : OK\n";
exit $ERRORS{"OK"};


# ============================================================================
# ============================== NO CHECK DEFINED ============================
# ============================================================================

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

