#!/usr/bin/perl

# V2.0 A Munro 20 Oct 2011
#
# Get stats out of /proc/meminfo. This is designed to be a generic script. Thus it
# returns anything you want in meminfo, including anything they add in the future.
# You can simply use it to return perf data (my original requirement) by NOT defining 
# the c or w tags. Otherwise you can add c or w thresholds, and the w or c will be
# returned with the highest status noted.
#
# V1.0 was a quick hack script to just get the perf data.

# Format of -k (key); warning and critical levels are optional: 
#
# -k '<meminfo-key>[;c:<crit-val>][;w:<warn-val>],<meminfo-key>[;c:<crit-val>][;w:<warn-val>]'
# eg -k "HighTotal;c:60600;w:303030,CommitLimit;c:102020;w:5000"

use Data::Dumper;
use Getopt::Std;
use File::Basename;

sub usage() {

  print "\nNagios nrpe plugin: Get anything from /proc/meminfo\n";
  print "(including setting Warning and Critical thresholds).\n\n";
  print "usage:\n";

  print " ".basename($0)." [-h] [-k \'<meminfo-key>[;c:<crit-val>][;w:<warn-val>],<meminfo-key>[;c:<crit-val>][;w:<warn-val>]\...'] \n\n";
  exit 0;

}

my %mem;

# nrpe exit status's:
#
my $s_ok=0;      # Ok
my $s_warn=1;    # Warning
my $s_crit=2;    # Critical
my $s_unknown=3; # Unknown

getopts('k:h');

if (defined $opt_h or ! defined $opt_k) { &usage }

my @key;

# Parse -k and store
#
foreach (split(",",$opt_k)) {
  my @subarg=split(";");
  my $sev, $val, $k;

  foreach (@subarg) {
     if (!/:/) { $k=$_; push(@key,$k) }
     if (/:/)  { ($sev,$val)=split(":"); $sev=lc($sev); $mem{$k."_".$sev}=$val }
  }
}

my @m=`/bin/cat /proc/meminfo`;

# Load variables/values into a hash
#
foreach (@m) {
   my @v=split; 
   chop $v[0]; # remove the colon
   $mem{$v[0]}=$v[1] * 1024; # Convert kb to bytes
}

my $pl="";
my $sl="";
my $exit_s=$s_ok;
my $percent;

# Process the data loaded and match to what was requested
#
foreach (@key) { 
   $pl.="'$_'=".$mem{$_}." ";

#  Always report the highest severity; thus if a warn comes after a crit, the crit is the severity status returned.
#  The warn is still reported.
#

   if (defined $mem{$_."_c"} and $mem{$_} >= $mem{$_."_c"}) { 
      $exit_s=$s_crit;
      $sl.="Critical ".$_.": ".$mem{$_}." (threshold: ".$mem{$_."_c"}.");";
   }  else {
      if (defined $mem{$_."_w"} and $mem{$_} >= $mem{$_."_w"}) { 
         if ($exit_s == $s_ok or $exit_s != $s_crit) { $exit_s=$s_warn }; # change status if its ok or not critical
	 $sl.="Warning ".$_.": ".$mem{$_}." (threshold: ".$mem{$_."_w"}.");";
      }
   }

}

chop $l; # remove extra space

if ($sl eq "") { $sl="OK;" };

print $sl."|".$pl."\n";

exit $exit_s;
