#!/usr/bin/perl -w

# Check CPU Usage via SNMP ( with performance reporting ).
# The following values are reported for performance data:
#   User, System, Idle, Wait
#
# Plugin uses UCD SNMP MIB (1.3.6.1.4.1.2021.11 systemStats).
# Used in net-snmp packages on linux.
#
# Copyright (C) 2009 by Herbert Stadler
# email: hestadler@gmx.at

# License Information:
# 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/>. 
#
#

############################################################################


use POSIX;
use strict;
# if "use warnings" is activated ePN will fail compiling
# use warnings;
use Getopt::Long;

use lib ".";
use lib "/usr/lib/nagios/plugins";
use lib "/usr/lib64/nagios/plugins";
use lib "/usr/local/nagios/libexec";

use utils qw(%ERRORS);

use Net::SNMP qw(oid_lex_sort oid_base_match :debug);

use constant TRANSLATE_OIDs             => 0;

my ($opt_version,$opt_help,$opt_verbose);
my ($opt_timeout,$opt_license);
my ($opt_hostname,$opt_community,$opt_port,$opt_snmpvers);
my ($opt_username,$opt_authpasswd,$opt_authproto);
my ($opt_privpasswd,$opt_privproto);
my ($opt_snmpdebug,$opt_snmptimeout,$opt_warn,$opt_crit);

my ($PROGNAME,$REVISION);
my ($state,$msg);
my ($g_snmpdebug);

use constant DEFAULT_TIMEOUT		=>15;
use constant DEFAULT_PORT    		=>161;
use constant DEFAULT_COMMUNITY  	=>"public";
use constant DEFAULT_SNMPVERS 		=>"2";
use constant DEFAULT_PRIVPROTO		=>"DES";
use constant DEFAULT_AUTHPROTO		=>"MD5";
use constant WAIT_BETWEEN_MEASUREMENT   =>5;

#  UCD SNMP MIB 
my $systemStats 			="1.3.6.1.4.1.2021.11";
my $ssCpuRawUser                        =$systemStats . ".50";
my $ssCpuRawNice                        =$systemStats . ".51";
my $ssCpuRawSystem                      =$systemStats . ".52";
my $ssCpuRawIdle                        =$systemStats . ".53";
my $ssCpuRawWait                        =$systemStats . ".54";
my $ssCpuRawKernel                      =$systemStats . ".55";
my $ssCpuRawInterrupt                   =$systemStats . ".56";
my $ssCpuRawSoftIRQ                     =$systemStats . ".61";

my $kssCpuRawUser                       =$ssCpuRawUser      . ".0";
my $kssCpuRawNice                       =$ssCpuRawNice      . ".0";
my $kssCpuRawSystem                     =$ssCpuRawSystem    . ".0";
my $kssCpuRawIdle                       =$ssCpuRawIdle      . ".0";
my $kssCpuRawWait                       =$ssCpuRawWait      . ".0";
my $kssCpuRawKernel                     =$ssCpuRawKernel    . ".0";
my $kssCpuRawInterrupt                  =$ssCpuRawInterrupt . ".0";
my $kssCpuRawSoftIRQ                    =$ssCpuRawSoftIRQ   . ".0";

my $DEFAULT_SNMPTIMEOUT                 = 2;
my $ticks_per_second			= 100;

$ENV{'PATH'}='';
$ENV{'BASH_ENV'}=''; 
$ENV{'ENV'}='';
$PROGNAME = "check_cpu_ucd";
$REVISION = "1.2";

# checking commandline arguments
my $arg_status = check_args();
if ($arg_status){
  print "ERROR: some arguments wrong\n";
  exit $ERRORS{"UNKNOWN"};
}

if ($opt_snmpdebug) {
  my $module="Net::SNMP";
  printf( "%-20s  Version: %s\n", $module, $module->VERSION );
}

# set alarmhandler for timeout handling
$SIG{'ALRM'} = sub {
  print ("ERROR: plugin timed out after $opt_timeout seconds \n");
  exit $ERRORS{"UNKNOWN"};
};

alarm($opt_timeout);

# get some OID's
my $a_oids=();
push (@{$a_oids},$ssCpuRawUser);
push (@{$a_oids},$ssCpuRawNice);
push (@{$a_oids},$ssCpuRawSystem);
push (@{$a_oids},$ssCpuRawIdle);
push (@{$a_oids},$ssCpuRawWait);
push (@{$a_oids},$ssCpuRawKernel);
push (@{$a_oids},$ssCpuRawInterrupt);
push (@{$a_oids},$ssCpuRawSoftIRQ);

if ( $opt_verbose ) {
  printf("Starting SNMP Session\n");
}

# let's see if the server wants to speak with us
my ($snmp_session,$snmp_error)=open_snmp_session($opt_hostname);
if ( ! defined ($snmp_session)) {
  print "ERROR: Could not open connection: $snmp_error \n";
  exit $ERRORS{'UNKNOWN'};
}

$snmp_session->translate(['-endofmibview'=>0,'-nosuchobject'=>0,'-nosuchinstance'=>0]);

if ( $opt_verbose ) {
  printf("1st Measurement of CPU-Load\n");
}
# get the OID's 1st measurement
my $hValOid1st=get_request($a_oids);

if ( $opt_verbose ) {
  printf("Waiting %d seconds\n",WAIT_BETWEEN_MEASUREMENT);
}

# now we are waiting some seconds 
sleep (WAIT_BETWEEN_MEASUREMENT);

if ( $opt_verbose ) {
  printf("2nd Measurement of CPU-Load\n");
}
# get the OID's 2nd measurement
my $hValOid2nd=get_request($a_oids);

$snmp_session->close;

if ( $opt_verbose ) {
  print_Single_OIDs($hValOid1st);
  print_Single_OIDs($hValOid2nd);
}

# These values can be found under linux in /proc/stat:

# > cat /proc/stat
# cpu  2255 34 2290 22625563 6290 127 456

# The very first "cpu" line aggregates the numbers in all of the 
# other "cpuN" lines.
# These numbers identify the amount of time the CPU has spent performing 
# different kinds of work. Time units are in USER_HZ or Jiffies 
# (typically hundredths of a second).

# The meanings of the columns are as follows, from left to right:
#   user:    normal processes executing in user mode
#   nice:    niced processes executing in user mode
#   system:  processes executing in kernel mode
#   idle:    twiddling thumbs
#   iowait:  waiting for I/O to complete
#   irq:     servicing interrupts
#   softirq: servicing softirqs
#
#   Explanation of system:
#   system = ssCpuRawKernel + ssCpuRawInterrupt + ssCpuRawSoftIRQ
#
# Documentation under: http://www.linuxhowtos.org/System/procstat.htm

my $g_not_numeric_found=0;
my $g_value_not_found=0;

# sum up the OID's
my $hcalc={};
Make_Sums($hcalc,"1st",$hValOid1st);
Make_Sums($hcalc,"2nd",$hValOid2nd);

if ( $g_not_numeric_found == 1 ) {
  printf("ERROR: some/all values not numeric\n");
  exit $ERRORS{'UNKNOWN'};
}
if ( $g_value_not_found == 1 ) {
  printf("ERROR: no/not all CPU values received\n");
  exit $ERRORS{'UNKNOWN'};
}

# now we build the difference between the 2 measuring points
$hcalc->{"us_diff"}   =$hcalc->{"us_2nd"}    - $hcalc->{"us_1st"};
$hcalc->{"sy_diff"}   =$hcalc->{"sy_2nd"}    - $hcalc->{"sy_1st"};
$hcalc->{"id_diff"}   =$hcalc->{"id_2nd"}    - $hcalc->{"id_1st"};
$hcalc->{"wa_diff"}   =$hcalc->{"wa_2nd"}    - $hcalc->{"wa_1st"};
$hcalc->{"total_diff"}=$hcalc->{"total_2nd"} - $hcalc->{"total_1st"};

# Calculation of percentages
my $us_pct=0;
my $sy_pct=0;
my $id_pct=0;
my $wa_pct=0;

if ( $opt_verbose ) {
  if ( $hcalc->{"total_diff"} == 0 ) {
    printf ("\nATTENTION: Total Value == 0\n");
  }
}

if ( $hcalc->{"total_diff"} != 0 ) {
  $us_pct=Round_Number($hcalc->{"us_diff"} * 100 / $hcalc->{"total_diff"},0);
  $sy_pct=Round_Number($hcalc->{"sy_diff"} * 100 / $hcalc->{"total_diff"},0);
  $id_pct=Round_Number($hcalc->{"id_diff"} * 100 / $hcalc->{"total_diff"},0);
  $wa_pct=Round_Number($hcalc->{"wa_diff"} * 100 / $hcalc->{"total_diff"},0);
}

# checking a linux system will show us the same values as "vmstat"
if ( $opt_verbose ) {
  printf ("\nDIFFERENCE VALUES in timeticks and percent:\n");
  printf ("us:    %16d, %4.2f%%\n",$hcalc->{"us_diff"},$us_pct);
  printf ("sy:    %16d, %4.2f%%\n",$hcalc->{"sy_diff"},$sy_pct);
  printf ("id:    %16d, %4.2f%%\n",$hcalc->{"id_diff"},$id_pct);
  printf ("wa:    %16d, %4.2f%%\n",$hcalc->{"wa_diff"},$wa_pct);
  printf ("total: %16d\n",$hcalc->{"total_diff"});
}

# wa_pct & id_pct produces no load on system, therefore we don't add this
my $processor_load=$us_pct + $sy_pct;

# Build performance data line
my $perfdata=sprintf("us=%d%% sy=%d%% id=%d%% wa=%d%%",$us_pct,$sy_pct,$id_pct,$wa_pct);

if ( $processor_load < $opt_warn ) {
  $msg = sprintf("CPU OK - No Problems found (%d%%)",$processor_load);
  $state = $ERRORS{'OK'};
}elsif ( $processor_load < $opt_crit ) {
  $msg = sprintf("CPU WARN - Usage %d%%",$processor_load);
  $state = $ERRORS{'WARNING'};
}else{
  $msg = sprintf("CPU CRIT - Usage %d%%",$processor_load);
  $state = $ERRORS{'CRITICAL'};
}

# attach performance data line
$msg.="|".$perfdata;

# and now "over and out"

print "$msg\n";
exit $state;




#--------------------------------------------------------------------------#
# S U B R O U T I N E S                                                    #
#--------------------------------------------------------------------------#

#--------------------------------------------------------------------------
sub open_snmp_session {
#--------------------------------------------------------------------------
  my ($l_host)=@_;

  my ($snmp_session,$snmp_error);

  # open SNMP Session to Server
  if ( $opt_snmpvers eq "3" ) {
    if ( defined ($opt_authpasswd)) {
      if ( defined ($opt_privpasswd)) {
	($snmp_session,$snmp_error)=Net::SNMP->session(
	    -hostname 		=> 	$l_host,
	    -port		=>	$opt_port,
	    -timeout		=>	$opt_snmptimeout,
	    -retries		=>	2,
            -debug              =>      $g_snmpdebug,
	    -maxmsgsize		=>	16384,
	    -version		=>	$opt_snmpvers,
	    -username		=> 	$opt_username,
	    -authpassword	=> 	$opt_authpasswd,
	    -authprotocol	=> 	$opt_authproto,
	    -privpassword	=> 	$opt_privpasswd,
	    -privprotocol	=> 	$opt_privproto,
	    );
      } else {
	($snmp_session,$snmp_error)=Net::SNMP->session(
	    -hostname 		=> 	$l_host,
	    -port		=>	$opt_port,
	    -timeout		=>	$opt_snmptimeout,
	    -retries		=>	2,
            -debug              =>      $g_snmpdebug,
	    -maxmsgsize		=>	16384,
	    -version		=>	$opt_snmpvers,
	    -username		=> 	$opt_username,
	    -authpassword	=> 	$opt_authpasswd,
	    -authprotocol	=> 	$opt_authproto,
	    );
      } 
    } else {
	($snmp_session,$snmp_error)=Net::SNMP->session(
	    -hostname 		=> 	$l_host,
	    -port		=>	$opt_port,
	    -timeout		=>	$opt_snmptimeout,
	    -retries		=>	2,
            -debug              =>      $g_snmpdebug,
	    -maxmsgsize		=>	16384,
	    -version		=>	$opt_snmpvers,
	    -username		=> 	$opt_username,
	    );
    }
  } else {
    ($snmp_session,$snmp_error)=Net::SNMP->session(
    	-hostname 	=> 	$l_host,
	-community 	=> 	$opt_community,
	-port		=>	$opt_port,
	-timeout	=>	$opt_snmptimeout,
	-retries	=>	2,
        -debug          =>      $g_snmpdebug,
	-maxmsgsize	=>	16384,
	-version	=>	$opt_snmpvers,
	);
  }
  return ($snmp_session,$snmp_error);
}

#--------------------------------------------------------------------------
sub Add_Value {
#--------------------------------------------------------------------------
  my ($hcalc,$hValOid,$key,$kssCpu)=@_;

  if (defined($hValOid->{$kssCpu})) {
    if ($hValOid->{$kssCpu} =~ /^\d+$/ ) {
      $hcalc->{$key}+=$hValOid->{$kssCpu};
    }else{
      $g_not_numeric_found=1;
    }
  }else{
    $g_value_not_found=1;
  }
}

#--------------------------------------------------------------------------
sub Make_Sums {
#--------------------------------------------------------------------------
  my ($hcalc,$key,$hValOid)=@_;

  my $uskey    = "us_".$key;
  my $sykey    = "sy_".$key;
  my $idkey    = "id_".$key;
  my $wakey    = "wa_".$key;
  my $totalkey = "total_".$key;

  $hcalc->{$uskey}   =0;
  $hcalc->{$sykey}   =0;
  $hcalc->{$idkey}   =0;
  $hcalc->{$wakey}   =0;
  $hcalc->{$totalkey}=0;

  Add_Value ($hcalc,$hValOid,$uskey,$kssCpuRawUser);
  Add_Value ($hcalc,$hValOid,$uskey,$kssCpuRawNice);
  Add_Value ($hcalc,$hValOid,$sykey,$kssCpuRawSystem);

  # don't add RawKernel 
  #$hcalc->{$sykey}+=$hValOid->{$kssCpuRawKernel}  if (defined($hValOid->{$kssCpuRawKernel}));

  Add_Value ($hcalc,$hValOid,$idkey,$kssCpuRawIdle);
  Add_Value ($hcalc,$hValOid,$wakey,$kssCpuRawWait);

  $hcalc->{$totalkey}=$hcalc->{$uskey} + $hcalc->{$sykey} + $hcalc->{$idkey} + $hcalc->{$wakey};

  if ( $opt_verbose ) {
    # Calculation of Percentages
    my $us_pct=0;
    my $sy_pct=0;
    my $id_pct=0;
    my $wa_pct=0;

    if ( $hcalc->{$totalkey} != 0 ) {
      $us_pct=Round_Number($hcalc->{$uskey} * 100 / $hcalc->{$totalkey},2);
      $sy_pct=Round_Number($hcalc->{$sykey} * 100 / $hcalc->{$totalkey},2);
      $id_pct=Round_Number($hcalc->{$idkey} * 100 / $hcalc->{$totalkey},2);
      $wa_pct=Round_Number($hcalc->{$wakey} * 100 / $hcalc->{$totalkey},2);
    }

    printf ("\nValues in timeticks and percent for key:%s\n",$key);
    printf ("us:    %16d, %4.2f%%\n",$hcalc->{$uskey},$us_pct);
    printf ("sy:    %16d, %4.2f%%\n",$hcalc->{$sykey},$sy_pct);
    printf ("id:    %16d, %4.2f%%\n",$hcalc->{$idkey},$id_pct);
    printf ("wa:    %16d, %4.2f%%\n",$hcalc->{$wakey},$wa_pct);
    printf ("total: %16d\n",$hcalc->{$totalkey});
  }
}

#--------------------------------------------------------------------------
sub Round_Number {
#--------------------------------------------------------------------------
  my($number,$decimals)=@_;

  my $mult=10 ** $decimals;
  my $result=(int(($number * $mult) + 0.5))/$mult;

  return ($result);
}

#--------------------------------------------------------------------------
sub get_request {
#--------------------------------------------------------------------------
  my ($l_oid)=@_;

  my $l_snmp_result=$snmp_session->get_next_request(
        -varbindlist    =>      $l_oid,
        );

  #if ( ! defined ($l_snmp_result)) {
  if ($snmp_session->error_status != 0) {
    print "ERROR %d get_request: ",$snmp_session->error_status,$snmp_session->error,"\n";
    $snmp_session->close;
    exit $ERRORS{'UNKNOWN'};
  }

  return ($l_snmp_result);
}

#--------------------------------------------------------------------------
sub print_Single_OIDs {
#--------------------------------------------------------------------------
  my ($table)=@_;

  printtable  ("UCDAVIS systemStats OIDs");
  my $translated;
  foreach my $key (oid_lex_sort(keys (%{$table}))) {
    $translated=$key;
    if (TRANSLATE_OIDs) {
      $translated=SNMP::translateObj($translated);
    }

    printtabular($translated, $table->{$key});
  }
}

#--------------------------------------------------------------------------
sub printtable {
#--------------------------------------------------------------------------
  my ($l_head)=@_;

  printf ("\n%-40s\n",$l_head);
  my $len=length($l_head);
  my $line="=" x $len;
  printf ("%-40s\n",$line);
}

#--------------------------------------------------------------------------
sub printtabular {
#--------------------------------------------------------------------------
  my ($l_arg,$l_val)=@_;

  printf ("%-50s: %s\n",$l_arg,$l_val);
}

#--------------------------------------------------------------------------
sub create_msg {
#--------------------------------------------------------------------------
  my ($l_txt,$l_msg)=@_;

  if (! defined $l_txt) {return};

  if (defined $$l_msg) {
    $$l_msg.=", ";
  }
  $$l_msg.=$l_txt;
}

#--------------------------------------------------------------------------
sub check_args {
#--------------------------------------------------------------------------
  Getopt::Long::Configure('bundling');
  GetOptions
	("V"   			=> \$opt_version,
	 "version"   		=> \$opt_version,
	 "L"   			=> \$opt_license, 
	 "license"   		=> \$opt_license, 
	 "v"   			=> \$opt_verbose, 
	 "verbose"   		=> \$opt_verbose, 
         "D"                    => \$opt_snmpdebug,
         "debug"                => \$opt_snmpdebug,
	 "h|?" 			=> \$opt_help,
	 "help"   		=> \$opt_help,
         "T=i"                  => \$opt_snmptimeout,
         "snmptimeout=i"        => \$opt_snmptimeout,
	 "t=i" 			=> \$opt_timeout, 
	 "timeout=i" 		=> \$opt_timeout, 
	 "H=s" 			=> \$opt_hostname, 
	 "hostname=s" 		=> \$opt_hostname, 
	 "C=s" 			=> \$opt_community, 
	 "community=s" 		=> \$opt_community, 
	 "p=i" 			=> \$opt_port, 
	 "port=i" 		=> \$opt_port, 
	 "s=s" 			=> \$opt_snmpvers, 
	 "snmpvers=s" 		=> \$opt_snmpvers, 
         "w=s"                  => \$opt_warn,
         "warn=s"               => \$opt_warn,
         "c=s"                  => \$opt_crit,
         "crit=s"               => \$opt_crit,
         "u=s"       		=> \$opt_username,
         "username=s"       	=> \$opt_username,
         "o=s"   		=> \$opt_authpasswd,
         "authpass=s"   	=> \$opt_authpasswd,
         "r=s"   		=> \$opt_authproto,
         "authprot=s"   	=> \$opt_authproto,
         "O=s"   		=> \$opt_privpasswd,
         "privpass=s"   	=> \$opt_privpasswd,
         "R=s"   		=> \$opt_privproto,
         "privprot=s"   	=> \$opt_privproto,
	 );

  if ($opt_license) {
    print_gpl($PROGNAME,$REVISION);
    exit $ERRORS{'OK'};
  }

  if ($opt_version) {
    print_revision($PROGNAME,$REVISION);
    exit $ERRORS{'OK'};
  }

  if ($opt_help) {
    print_help();
    exit $ERRORS{'OK'};
  }

  if ( ! defined($opt_hostname)){
    print "\nERROR: Hostname not defined\n\n";
    print_usage();
    exit $ERRORS{'UNKNOWN'};
  }

  unless (defined $opt_warn) {
    print "\nERROR: parameter -w <warn> not defined\n\n";
    print_usage();
    exit ($ERRORS{'UNKNOWN'});
  }

  unless (defined $opt_crit) {
    print "\nERROR: parameter -c <crit> not defined\n\n";
    print_usage();
    exit ($ERRORS{'UNKNOWN'});
  }
  if ( $opt_warn > $opt_crit) {
    print "\nERROR: parameter -w <warn> greater than parameter -c\n\n";
    print_usage();
    exit ($ERRORS{'UNKNOWN'});
  }


  unless (defined $opt_snmpvers) {
    $opt_snmpvers = DEFAULT_SNMPVERS;
  }
  if (($opt_snmpvers ne "1") && ($opt_snmpvers ne "2") && ($opt_snmpvers ne "3")) {
    printf ("\nERROR: SNMP Version %s unknown\n",$opt_snmpvers);
    print_usage();
    exit $ERRORS{'UNKNOWN'};
  }

  unless (defined $opt_timeout) {
    $opt_timeout = DEFAULT_TIMEOUT;
  }

  unless (defined $opt_port) {
    $opt_port = DEFAULT_PORT;
  }

  unless (defined $opt_community) {
    $opt_community = DEFAULT_COMMUNITY;
  }

  if (defined $opt_privpasswd) {
    unless (defined $opt_privproto) {
      $opt_privproto = DEFAULT_PRIVPROTO;
    }
  }

  if (defined $opt_authpasswd) {
    unless (defined $opt_authproto) {
      $opt_authproto = DEFAULT_AUTHPROTO;
    }
  }

  if ($opt_snmpvers eq "3") {
    unless (defined $opt_username) {
      printf ("\nERROR: SNMP Version %s: please define username\n",$opt_snmpvers);
      print_usage();
      exit $ERRORS{'UNKNOWN'};
    }
  }

  if ($opt_snmpdebug) {
    $g_snmpdebug = DEBUG_ALL;
  }else{
    $g_snmpdebug = DEBUG_NONE;
  }

  unless (defined $opt_snmptimeout) {
    $opt_snmptimeout = $DEFAULT_SNMPTIMEOUT;
  }

  return $ERRORS{'OK'};
}

#--------------------------------------------------------------------------
sub print_usage {
#--------------------------------------------------------------------------
  print "Usage: $PROGNAME [-h] [-L] [-t timeout] [-T <snmp-timeout>] [-v] [-V] [-C community] [-p port] [-s 1|2|3] -H hostname  -w <warning> -c <critical>\n\n";
  print "SNMP version 3 specific: [-u username] [-o authpass] [-r authprot] [-O privpass] [-R privprot]\n";
}

#--------------------------------------------------------------------------
sub print_help {
#--------------------------------------------------------------------------
  print_revision($PROGNAME,$REVISION);
  printf ("\n");
  print_usage();
  printf ("\n");
  printf ("   Check CPU Load via UCD SNMP MIB with optional performance data\n");
  printf ("         (User, System, Idle, Wait)\n");
  printf ("   e.g: used on linux in net-snmp agent.\n\n");
  printf ("  -t (--timeout)      Timeout in seconds (default = %d)\n",DEFAULT_TIMEOUT);
  printf ("  -T (--snmptimeout) SNMP CallTimeout in seconds (default = %d)\n",$DEFAULT_SNMPTIMEOUT);
  printf ("  -H (--hostname)     Host to monitor\n");
  printf ("  -s (--snmpvers)     SNMP Version [1|2|3] (default = %d)\n",DEFAULT_SNMPVERS);
  printf ("  -C (--community)    SNMP Community (default = %s)\n",DEFAULT_COMMUNITY);
  printf ("  -p (--port)         SNMP Port (default = %d)\n",DEFAULT_PORT);
  printf ("  -w (--warn)         Parameters warning\n");
  printf ("  -c (--crit)         Parameters critical\n");
  printf ("  -h (--help)         Help\n");
  printf ("  -V (--version)      Programm version\n");
  printf ("  -v (--verbose)      Print some useful information\n");
  printf ("  -L (--license)      Print license information\n");
  printf ("\nSNMP version 3 specific arguments:\n");
  printf ("  -u (--username)     Security Name\n");
  printf ("  -o (--authpassword) Authentication password\n");
  printf ("  -r (--authprotocol) Authentication protocol [md5|sha]\n");
  printf ("  -O (--privpassword) Privacy password\n");
  printf ("  -R (--privprotocol) Privacy protocol [des|aes|3des]\n");
  printf ("\nThese are percentages of total CPU time.\n");
  printf ("  us: Time spent running non-kernel code. (user time, including nice time)\n");
  printf ("  sy: Time spent running kernel code. (system time)\n");
  printf ("  id: Time spent idle.\n");
  printf ("  wa: Time spent waiting for IO.\n");

  printf ("\n");
}

#--------------------------------------------------------------------------
sub print_gpl {
#--------------------------------------------------------------------------
  print <<EOD;

  Copyright (C) 2009 by Herbert Stadler
  email: hestadler\@gmx.at

  License Information:
  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/>. 

EOD

}

#--------------------------------------------------------------------------
sub print_revision {
#--------------------------------------------------------------------------
  my ($l_prog,$l_revision)=@_;

  print <<EOD

$l_prog $l_revision, Copyright (C) 2009 Herbert Stadler

This program comes with ABSOLUTELY NO WARRANTY; 
for details type "$l_prog -L".
EOD
}




=head1 NAME

 check_cpu_ucd

=head1 DESCRIPTION

 Check CPU Load via UCD SNMP MIB
 e.g: used on linux in net-snmp agent

 Plugin created for Nagios Monitoring.

=head1 SYNOPSIS

 check_cpu_ucd -H <hostname> -w <warn> -c <crit>

 Plugin collects values (us,sy,id,wa) within 5 seconds and calculates
 an average cpu usage value.

 Output looks like (with performance data)
     CPU OK - No Problems found (32%)|us=24%,sy=8%,id=68%,wa=0%

 for more information concerning this plugin call:
     check_cpu_ucd -h
     perldoc check_cpu_ucd

 more information concerning the configuration of the UCD SNMP Package:
     man snmpd.conf


=head1 AUTHOR

 Herbert Stadler, Austria (hestadler@gmx.at)
 June 2009

 This plugin is a contribution to the nagios community.

=head1 REQUIRED SOFTWARE

 from search.cpan.org
   Net::SNMP Package   	e.g: Net-SNMP-5.2.0.tar.gz

=head1 HOW TO CHECK THE SERVER FUNCTIONALITY

 Example:
   snmpwalk  -Os -c public -v 1 <server_ip> 1.3.6.1.4.1.2021.11

 should return some lines like these:

    ssIndex.0 = INTEGER: 1
    ssErrorName.0 = STRING: systemStats
    ssSwapIn.0 = INTEGER: 0
    ssSwapOut.0 = INTEGER: 0
    ssIOSent.0 = INTEGER: 0
    ssIOReceive.0 = INTEGER: 3
    ssSysInterrupts.0 = INTEGER: 4
    ssSysContext.0 = INTEGER: 5
    ssCpuUser.0 = INTEGER: 1
    ssCpuSystem.0 = INTEGER: 3
    ssCpuIdle.0 = INTEGER: 95
    ssCpuRawUser.0 = Counter32: 8357178
    ssCpuRawNice.0 = Counter32: 587
    ssCpuRawSystem.0 = Counter32: 42816056
    ssCpuRawIdle.0 = Counter32: 646281090
    ssCpuRawWait.0 = Counter32: 29232561
    ssCpuRawKernel.0 = Counter32: 25317769
    ssCpuRawInterrupt.0 = Counter32: 895206
    ssIORawSent.0 = Counter32: 3264259202
    ssIORawReceived.0 = Counter32: 1935288426
    ssRawInterrupts.0 = Counter32: 1961869159
    ssRawContexts.0 = Counter32: 3639542339
    ssCpuRawSoftIRQ.0 = Counter32: 16603081
    ssRawSwapIn.0 = Counter32: 0
    ssRawSwapOut.0 = Counter32: 85

 if not, check:
   - the configuration file (on linux /etc/snmp/snmpd.conf)
   - check net-snmp version if bugs available

=head1 CONFIGURATION IN NAGIOS

 Copy this plugin to the nagios plugin installation directory 
 e.g.: /usr/lib(64)/nagios/plugin

 COMMAND DEFINITION:

 # "check_cpu_ucd" command definition
 define command{
    command_name    check_cpu_ucd
    command_line    $USER1$/check_cpu_ucd -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$
    }


=head1 PLUGIN HISTORY

 Version 1.0 - 2009-06-17	first release
 Version 1.1 - 2010-03-01	Illegal division by zero corrected
 Version 1.2 - 2010-03-24	check error_status of snmp call

=head1 COPYRIGHT AND DISCLAIMER

 Copyright (C) 2009 by Herbert Stadler
 email: hestadler@gmx.at

 License Information:
 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/>. 
 

=cut



