#!/bin/sh
# $Id$
# check_cpu - nagios plugin to monitor cpu
#   by Matthew Wall
#
# Copyright (c) 2009 Matthew Wall, all rights reserved
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
#
# Revision History
#   0.2 added support for openbsd
#   0.1 initial release
#
#
# Prerequisites
#
# First try to use /proc, if that fails use ?
#
# TODO:
# - put the units into perfdata
# - put the warn/crit values into the perfdata
# - accept ranges for warn/crit
# - deal with different number of drives in vmstat output

STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3

usage()
{
    echo "usage: check_cpu [-w value] [-c value]"
    echo
    exit $STATE_OK
}

while getopts c:h:p:w: OPTNAME; do
    case "$OPTNAME" in
    w)
        WARNVAL="$OPTARG"
        ;;
    c)
        CRITVAL="$OPTARG"
        ;;
    *)
        usage
        ;;
    esac
done

if [ "$WARNVAL" != "" -a "`echo $WARNVAL | grep '^[0-9][0-9]*$'`" = "" ]; then
    echo "Error: warning_value must be a positive integer!"
    exit $STATE_UNKNOWN
fi

if [ "$CRITVAL" != "" -a "`echo $CRITVAL | grep '^[0-9][0-9]*$'`" = "" ]; then
    echo "Error: critical_value must be a positive integer!"
    exit $STATE_UNKNOWN
fi

if [ "$WARNVAL" != "" -a "$CRITVAL" != "" ]; then
    if [ $WARNVAL -ge $CRITVAL ]; then
        echo "Error: warning_value must be less than critical_value!"
        exit $STATE_UNKNOWN
    fi
fi

if [ -f /proc/stat ]; then
  RESULT=`/usr/bin/head -n 1 /proc/stat`
  USER=`echo $RESULT | sed 's/^cpu \+\([0-9][0-9]*\) .*/\1/'`
  NICE=`echo $RESULT | sed 's/^cpu \+[0-9][0-9]* \([0-9][0-9]*\) .*/\1/'`
  SYS=`echo $RESULT | sed 's/^cpu \+[0-9][0-9]* [0-9][0-9]* \([0-9][0-9]*\) .*/\1/'`
  IDLE=`echo $RESULT | sed 's/^cpu \+[0-9][0-9]* [0-9][0-9]* [0-9][0-9]* \([0-9][0-9]*\) .*/\1/'`
else
  RESULT=`vmstat | tail -1`
  USER=`echo RESULT | awk '{print 17}'`
  NICE=0
  SYS=`echo RESULT | awk '{print 18}'`
  IDLE=`echo RESULT | awk '{print 19}'`
fi

CODE=0

TOTAL=`expr $USER + $NICE + $SYS + $IDLE`

# precise numbers for perfdata
PUSER=$(( 100 * $USER / $TOTAL ))
PNICE=$(( 100 * $NICE / $TOTAL ))
PSYS=$(( 100 * $SYS / $TOTAL ))
PIDLE=$(( 100 * $IDLE / $TOTAL ))

# round numbers for human-readable
RUSER=`echo $PUSER | sed 's/\..*//'`
RNICE=`echo $PNICE | sed 's/\..*//'`
RSYS=`echo $PSYS | sed 's/\..*//'`
RIDLE=`echo $PIDLE | sed 's/\..*//'`

if [ "$RUSER" = "" ]; then
    RUSER=0
fi
if [ "$RNICE" = "" ]; then
    RNICE=0
fi
if [ "$RSYS" = "" ]; then
    RSYS=0
fi
if [ "$RIDLE" = "" ]; then
    RIDLE=0
fi

case $CODE in
0)
    STATUS=OK
    ;;
1)
    STATUS=WARNING
    ;;
2)
    STATUS=CRITICAL
    ;;
esac

echo "$STATUS - User: ${RUSER}%, Nice: ${RNICE}%; System: ${RSYS}%, Idle: ${RIDLE}% | user=${PUSER}% nice=${PNICE}% sys=${PSYS}% idle=${PIDLE}%"

exit $CODE
