#!/bin/sh
# $Id$
# check_mem - nagios plugin to monitor memory
#   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.3 openbsd support
#   0.2 added support for openbsd
#       elminate dependency on bc
#   0.1 initial release
#
#
# Prerequisites
#
# First try /proc, then try sysctl/vmstat
#
# TODO:
# - hook up the warning and critical values

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

B_PER_MB=$(( 1024 * 1024 ))
KB_PER_MB=1024

usage()
{
    echo "usage: check_mem [-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/meminfo ]; then
  RESULT=`cat /proc/meminfo`
  REAL_TOTAL=$(( `echo $RESULT | sed 's/.*MemTotal: \+\([0-9][0-9]*\) kB.*/\1/'` / KB_PER_MB ))
  REAL_FREE=$(( `echo $RESULT | sed 's/.*MemFree: \+\([0-9][0-9]*\) kB.*/\1/'` / KB_PER_MB ))
  REAL_USED=$(( $REAL_TOTAL - $REAL_FREE ))
  SWAP_TOTAL=$(( `echo $RESULT | sed 's/.*SwapTotal: \+\([0-9][0-9]*\) kB.*/\1/'` / KB_PER_MB ))
  SWAP_FREE=$(( `echo $RESULT | sed 's/.*SwapFree: \+\([0-9][0-9]*\) kB.*/\1/'` / KB_PER_MB ))
  SWAP_USED=$(( $SWAP_TOTAL - $SWAP_FREE ))
  CODE=0
else
  RESULT=`vmstat | tail -1`
  PAGE_FLT=`echo $RESULT | awk '{print $6}'`
  PAGES_IN=`echo $RESULT | awk '{print $8}'`
  PAGES_OUT=`echo $RESULT | awk '{print $9}'`
  REAL_TOTAL=$(( `sysctl -n hw.physmem` / B_PER_MB ))
  REAL_FREE=$(( `echo $RESULT | awk '{print $5}'` / KB_PER_MB ))
  REAL_USED=$(( $REAL_TOTAL - $REAL_FREE ))
  RESULT=`swapctl -s 2>/dev/null`
  if [ "$RESULT" != "" ]; then
    SWAP_TOTAL=$(( `echo $RESULT | awk '{print $2}' | sed 's/\([0-9]*\)k/\1/'` / KB_PER_MB ))
    SWAP_FREE=$(( `echo $RESULT | awk '{print $8}' | sed 's/\([0-9]*\)k/\1/'` / KB_PER_MB ))
    SWAP_USED=$(( $SWAP_TOTAL - $SWAP_FREE ))
  else
    SWAP_TOTAL=0
    SWAP_FREE=0
    SWAP_USED=0
  fi
  CODE=0
fi

REAL_FREE_PCT=$(( 100 * REAL_FREE / REAL_TOTAL ))
REAL_USED_PCT=$(( 100 * REAL_USED / REAL_TOTAL ))
if [ $SWAP_TOTAL -ne 0 ]; then
  SWAP_FREE_PCT=$(( 100 * SWAP_FREE / SWAP_TOTAL ))
  SWAP_USED_PCT=$(( 100 * SWAP_USED / SWAP_TOTAL ))
else
  SWAP_FREE_PCT=0
  SWAP_USED_PCT=0
fi

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

echo "$STATUS - Real Free: ${REAL_FREE}MB (${REAL_FREE_PCT}%); Swap Free: ${SWAP_FREE}MB (${SWAP_FREE_PCT}%) | total=${REAL_TOTAL}MB free=${REAL_FREE}MB swaptot=${SWAP_TOTAL}MB swapfree=${SWAP_FREE}MB pagefaults=${PAGE_FLT} pagesin=${PAGES_IN} pagesout=${PAGES_OUT}"

exit $CODE
