#!/bin/sh
# $Id$
# check_apcupsd - nagios plugin to monitor APC Smart-UPSes using apcupsd.
#
# Copyright (c) 2008 Martin Toft <mt@martintoft.dk>
#   with modifications by mwall, Fabio Milano
#
# 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 (since mwall started hacking on it)
# 1.5 feb11 mwall
#   work with ups models other than just smartups
# 1.2 dec09 mwall
#   miscellaneous fixes
#   better handling of warn/crit
# Modified by Fabio Milano
#   ADDED APC STATUS
#
#
# Example configuration
#
# commands.cfg:
#
# define command {
#         command_name check_apcupsd
#         command_line $USER1$/check_apcupsd -w $ARG2$ -c $ARG3$ $ARG1$
#         }
# 
# define command {
#         command_name check_apcupsd_no_notify
#         command_line $USER1$/check_apcupsd $ARG1$
#         }
#
# ups1.cfg:
#
# define service {
#         use generic-service
#         host_name ups1
#         service_description CHARGE
#         check_command check_apcupsd!charge!95!50
#         }
# 
# define service {
#         use generic-service
#         host_name ups1
#         service_description TEMP
#         check_command check_apcupsd!temp!35!40
#         }
# 
# define service {
#         use generic-service
#         host_name ups1
#         service_description LOAD
#         check_command check_apcupsd!load!70!85
#         }
# 
# define service {
#         use generic-service
#         host_name ups1
#         service_description TIMELEFT
#         check_command check_apcupsd_no_notify!time
#         }
#
# define service {
#	user generic-service
#	host_name ups1
#	service_description APC STATUS
#	check_command check_apcupsd!status
#

REVISION='1.5'

E_OK=0
E_WARN=1
E_CRIT=2
E_UNKNOWN=3

APCACCESS=/sbin/apcaccess
HOSTNAME=localhost
PORT=3551

usage()
{
    echo "usage: check_apcupsd [-H hostname] [-p port] [-w value] [-c value]"
    echo "                     <charge|temp|load|time|status>"
    echo
    echo "hostname and port default to localhost and 3551, respectively."
    echo
    echo "checks:"
    echo "    charge = battery charge, measured in percent"
    echo "    temp   = internal temperature, measured in degree Celcius"
    echo "    load   = load percent, measured in percent"
    echo "    time   = time remaining, measured in minutes"
    echo "    status = APC UPS STATUS (warn and crit are ignored)" 
    exit $E_OK
}

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

ARG="$@"
while [ $OPTIND -gt 1 ]; do
    ARG=`echo "$ARG" | sed 's/^[^ ][^ ]* *//'`
    OPTIND=$(($OPTIND-1))
done

# for backward compatibility, we use the older arguments
if [ "$ARG" = "charge" ]; then
    ARG=bcharge;
fi
if [ "$ARG" = "load" ]; then
    ARG=loadpct;
fi
if [ "$ARG" = "time" ]; then
    ARG=timeleft; 
fi
if [ "$ARG" = "temp" ]; then
    ARG=itemp; 
fi

if [ "$ARG" != "bcharge" -a "$ARG" != "itemp" -a "$ARG" != "loadpct" \
    -a "$ARG" != "timeleft" -a "$ARG" != "status" ]; then
    usage
fi

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

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

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

if [ "$WARNVAL" != "" -a "$CRITVAL" != "" ]; then
    if [ "$ARG" = "bcharge" -o "$ARG" = "timeleft" ]; then
	if [ $WARNVAL -le $CRITVAL ]; then
	    echo "Error: warning_value must be greater than critical_value!"
	    exit $E_UNKNOWN
	fi
    elif [ "$ARG" = "load" -o "$ARG" = "itemp" ]; then
	if [ $WARNVAL -ge $CRITVAL ]; then
	    echo "Error: warning_value must be less than critical_value!"
	    exit $E_UNKNOWN
	fi
    fi
fi

if [ ! -x "$APCACCESS" ]; then
    echo "Error: $APCACCESS must exist and must be executable!"
    exit $E_UNKNOWN
fi

RESULT=`$APCACCESS status $HOSTNAME:$PORT 2>&1`;
VALUE=`echo $RESULT | grep -i ^Error`
if [ "$VALUE" != "" ]; then
    echo $VALUE
    exit $E_UNKNOWN
fi
if [ "$ARG" = "bcharge" ]; then
    VALUE=`echo $RESULT | sed 's/.*BCHARGE : \([\.0-9][\.0-9]*\) .*/\1/i'`
elif [ "$ARG" = "itemp" ]; then
    CHECK=`echo $RESULT | grep ITEMP`
    if [ "$CHECK" = "" ]; then
        echo "ERROR - $ARG is not available for this UPS model"
        exit $E_UNKNOWN
    fi
    VALUE=`echo $RESULT | sed 's/.*ITEMP : \([\.0-9][\.0-9]*\) .*/\1/i'`
elif [ "$ARG" = "loadpct" ]; then
    VALUE=`echo $RESULT | sed 's/.*LOADPCT : \([\.0-9][\.0-9]*\) .*/\1/i'`
elif [ "$ARG" = "timeleft" ]; then
    VALUE=`echo $RESULT | sed 's/.*TIMELEFT : \([\.0-9][\.0-9]*\) .*/\1/i'`
elif [ "$ARG" = "status" ]; then
    VALUE=`echo $RESULT | sed 's/.* \(STATUS : [^ ][^ ]*\) .*/\1/'`
fi
if [ "$VALUE" = "" ]; then
    echo "ERROR - $ARG cannot be determined"
    exit $E_UNKNOWN
fi
if [ "$VALUE" != "0" ]; then
    VALUE=`echo $VALUE | sed 's/^0*//'`
fi
ROUNDED=`echo $VALUE | sed 's/\..*//'`
CODE=0

case "$ARG" in
bcharge)
    PARAM=charge
    MSG="Battery Charge: ${VALUE}%"
    if [ "$WARNVAL" != "" ]; then
        if [ $ROUNDED -lt $WARNVAL ]; then
            CODE=$E_WARN
        fi
    fi
    if [ "$CRITVAL" != "" ]; then
        if [ $ROUNDED -lt $CRITVAL ]; then
            CODE=$E_CRIT
        fi
    fi
    ;;
itemp)
    PARAM=temperature
    MSG="Internal Temperature: $VALUE C"
    if [ "$WARNVAL" != "" ]; then
        if [ $ROUNDED -ge $WARNVAL ]; then
            CODE=$E_WARN
        fi
    fi
    if [ "$CRITVAL" != "" ]; then
        if [ $ROUNDED -ge $CRITVAL ]; then
            CODE=$E_CRIT
        fi
    fi
    ;;
loadpct)
    PARAM=load
    MSG="Load: ${VALUE}%"
    if [ "$WARNVAL" != "" ]; then
        if [ $ROUNDED -ge $WARNVAL ]; then
            CODE=$E_WARN
        fi
    fi
    if [ "$CRITVAL" != "" ]; then
        if [ $ROUNDED -ge $CRITVAL ]; then
            CODE=$E_CRIT
        fi
    fi
    ;;
timeleft)
    PARAM=timeleft
    MSG="Time Left: $VALUE Minutes"
    if [ "$WARNVAL" != "" ]; then
        if [ $ROUNDED -lt $WARNVAL ]; then
            CODE=$E_WARN
        fi
    fi
    if [ "$CRITVAL" != "" ]; then
        if [ $ROUNDED -lt $CRITVAL ]; then
            CODE=$E_CRIT
        fi
    fi
    ;;
status)
    ONLINE=`echo $VALUE | grep ONLINE| awk '{print $3$4}'`
    if [ "$ONLINE" != "ONLINE" ]; then
        echo "CRITICAL - $VALUE"
        exit $E_CRIT
    fi
    echo "OK - $VALUE"
    exit $E_OK
    ;;
esac

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

echo "$STATUS - $MSG | $PARAM=$VALUE;$WARNVAL;$CRITVAL"

exit $CODE
