#!perl -w

# RCS information
# enable substitution with:
#   $ svn propset svn:keywords "Id Revision HeadURL Source Date"
#
#   $Id: check_dir 856 2007-10-31 09:34:21Z corti $
#   $Revision: 856 $
#   $HeadURL: https://svn.id.ethz.ch/nagios_plugins/check_dir/check_dir $
#   $Date: 2007-10-31 10:34:21 +0100 (Wed, 31 Oct 2007) $

use strict;
use warnings;

use 5.008;

use Getopt::Long;
use Carp;
use English qw(-no_match_vars);

use File::Slurp;
use Nagios::Plugin;
use Nagios::Plugin::Threshold;
use Net::DNS::Resolver;

use version; our $VERSION = '0.9.5';

# IMPORTANT: Nagios plugins could be executed using embedded perl in this case
#            the main routine would be executed as a subroutine and all the
#            declared subroutines would therefore be inner subroutines
#            This will cause all the global lexical variables not to stay shared
#            in the subroutines!
#
# All variables are therefore declared as package variables...
#
use vars qw(
  $help
  $plugin
  $threshold
  $verbosity
  @procs
);

##############################################################################
# subroutines

##############################################################################
# Usage     : usage( -message => 'some text', -exitval => 1 )
# Purpose   : prints a usage message
# Returns   : n/a
# Arguments : -message : an optional error message
#             -exitval : the exit code (defaults to 0)
# Throws    : n/a
# Comments  : n/a
# See also  : n/a
sub usage {

    my %args = @_;

    my $exitval = 0;
    if ($args{-exitval}) {
        $exitval = $args{-exitval};
    }
    
    if ($args{-message}) {
        print $args{-message};
    }

    print<<'EOT';
check_procs_multi
           --proc name[,warning_min,warning_max,critical_min,critical_max]
           [--verbose]
           [--version|--help]

Mandatory arguments:
 --proc           name[,warning_min,warning_max,critical_min,critical_max]
                            process check definition

Several --proc checks can be specified at the same time
If only the name of the process is specified check_procs_multi assumes ,1,,1,
(i.e., critical if no processes are running)

Options:
 --help,-h,-?               prints the usage
 --version,V                print version number
 --verbose,-v               be more verbose (can be repeated)
EOT

    exit $exitval;
    
}

##############################################################################
# Usage     : print_verbose("some message string", $optional_verbosity_level);
# Purpose   : write a message if the verbosity level is high enough
# Returns   : n/a
# Arguments : message : message string
#             level   : options verbosity level
# Throws    : n/a
# Comments  : n/a
# See also  : n/a
sub print_verbose {

    # arguments
    my $message = shift;
    my $level   = shift;

    if ( !defined $message ) {
        $plugin->nagios_exit( UNKNOWN,
            q{Internal error: not enough parameters for 'print_verbose'} );
    }

    if ( !defined $level ) {
        $level = 0;
    }

    if ( $level < $verbosity ) {
        print $message;
    }

    return;

}

##############################################################################
# main

# initialization
$plugin = Nagios::Plugin->new( shortname => 'CHECK_PROCS_MULTI' );
$verbosity = 0;

Getopt::Long::Configure( 'bundling', 'no_ignore_case' );
my $result = GetOptions(
    'proc|p=s'   => \@procs,
    'help|h|?'   => \$help,
    'verbose|v+' => \$verbosity,
    'version|V'  => sub { print "check_bandwidth version $VERSION\n"; exit 3; },
);

###############
# Sanity checks

# syntax
if ( !$result || $help ) {
    usage(
        -exitval => UNKNOWN,
    );
}

my $critical;
my $warning;

if ( @procs == 0 ) {
    $plugin->nagios_exit( UNKNOWN,
        'Error: at least one process must be specified' );
}

####################
# Perform the checks

for my $proc (@procs) {

    my $name;
    my $wmin;
    my $wmax;
    my $cmin;
    my $cmax;

    # we need 6 fields even if empty
    my @line = split /,/mx, $proc, 5;

    if ( $#line == 0 ) {

        # assume 1,,1,
        $name = $line[0];
        $wmin = 1;
        $cmin = 1;

    }
    else {

        if ( $#line != 4 ) {
            $plugin->nagios_exit( UNKNOWN, "Error parsing @line" );
        }

        $name = $line[0];
        $wmin = $line[1];
        $wmax = $line[2];
        $cmin = $line[3];
        $cmax = $line[4];

        # sanity checks
        if ( $wmin && !$wmin =~ /[0-9]+/mx ) {
            $plugin->nagios_exit( UNKNOWN, "Error: $wmin is not a number" );
        }
        if ( $wmax && !$wmin =~ /[0-9]+/mx ) {
            $plugin->nagios_exit( UNKNOWN, "Error: $wmax is not a number" );
        }

        if ( $cmin && !$wmin =~ /[0-9]+/mx ) {
            $plugin->nagios_exit( UNKNOWN, "Error: $cmin is not a number" );
        }
        if ( $cmax && !$wmin =~ /[0-9]+/mx ) {
            $plugin->nagios_exit( UNKNOWN, "Error: $cmax is not a number" );
        }

        if ( $wmin && $wmax && $wmin > $wmax ) {
            $plugin->nagios_exit( UNKNOWN,
                "Error: $wmin (min) is bigger than $wmax (max)" );
        }
        if ( $cmin && $cmax && $cmin > $cmax ) {
            $plugin->nagios_exit( UNKNOWN,
                "Error: $cmin (min) is bigger than $cmax (max)" );
        }

        if ( $wmin && $cmin && $wmin > $cmin ) {
            $plugin->nagios_exit( UNKNOWN,
                "Error: $wmin (warning) is bigger than $wmin (critical)" );
        }
        if ( $wmax && $cmax && $wmax > $cmax ) {
            $plugin->nagios_exit( UNKNOWN,
                "Error: $wmax (warning) is bigger than $cmax (critical)" );
        }

    }

    my $command = "ps -e -o args | grep $name | grep -v grep";
    my $output;

    print_verbose "Executing \"$command\"\n";

    my $pid = open $output, q{-|}, "$command 2>&1"
      or $plugin->nagios_exit( UNKNOWN, "Cannot execute $command: $OS_ERROR" );

    # read the whole file
    my @lines = read_file($output);

    if ( $verbosity > 0 ) {
        for my $line (@lines) {
            print_verbose "$line", 1;
        }
    }

    if ( !( close $output )
        && ( $OS_ERROR != 0 ) )
    {

        # close to a piped open return false if the command with non-zero
        # status. In this case $! is set to 0
        $plugin->nagios_exit( UNKNOWN,
            "Error while closing pipe to $command: $OS_ERROR" );
    }

    my $count = $#lines;

    if ( $cmin && $count < $cmin ) {
        if ($critical) {
            $critical = $critical . ", $count $name";
        }
        else {
            $critical = "$count $name";
        }
    }
    elsif ( $cmax && $count > $cmax ) {
        if ($critical) {
            $critical = $critical . ", $count $name";
        }
        else {
            $critical = "$count $name";
        }
    }
    elsif ( $wmin && $count < $wmin ) {
        if ($warning) {
            $warning = $warning . ", $count $name";
        }
        else {
            $warning = "$count $name";
        }
    }
    elsif ( $wmax && $count > $wmax ) {
        if ($warning) {
            $warning = $warning . ", $count $name";
        }
        else {
            $warning = "$count $name";
        }
    }

    my $warn_string =
      ( ($wmin) ? "$wmin" : q{} ) . q{:} . ( ($wmax) ? "$wmax" : q{} );
    my $critical_string =
      ( ($cmin) ? "$cmin" : q{} ) . q{:} . ( ($cmax) ? "$cmax" : q{} );

    $threshold = Nagios::Plugin::Threshold->set_thresholds(
        warning  => $warn_string,
        critical => $critical_string,
    );

    $plugin->add_perfdata(
        label     => $name,
        value     => $count,
        threshold => $threshold,
        uom       => q{},
    );

}

if ($critical) {
    $plugin->nagios_exit( CRITICAL, $critical );
}
elsif ($warning) {
    $plugin->nagios_exit( WARNING, $warning );
}
else {
    $plugin->nagios_exit( OK, 'all processes OK' );
}

1;
