#!/bin/bash
# Copyright (C) 2017-2026 Thomas Wagner <wagner-thomas@gmx.at>
# SPDX-License-Identifier: GPL-2.0-or-later

# string for help text
usage()
{
cat << EOF
usage:
This script reads the status of supplies of a laser printer via snmp, i.e. the toner fill level and the wear level of the image drum.
OPTIONS:
 -h	Show this message
 -w	warning level of supply status as integer number 0-100 (default 3)
 -c 	critical value of supply status as integer number 0-100 (default 0, empty)
 -H	hostname or address of the printer (required)
 -s	supply index (default 1)
 -d	snmp domain (default "public")
 -P	snmp version (default 1)
 -v	verbose
EOF
}

# nagios expects one of these as return values
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
STATE_DEPENDENT=4


# set default values
HOSTNAME=""
DOM="public"
SNMP_VERSION=1
SUPP_IDX=1
CRIT_PERCENT=0 # in percent of max level
WARN_PERCENT=3 # in percent of max level
VERBOSE=0


# override default values with input arguments
while getopts ":hw:c:H:s:d:P:v" OPTION
do
  case $OPTION in
	h) usage
	   exit $STATE_UNKNOWN; # nothing checked, but feasible input
	   ;;
	w) WARN_PERCENT=$OPTARG
	   ;;
	c) CRIT_PERCENT=$OPTARG
	   ;;
	H) HOSTNAME=$OPTARG
	   ;;
	s) SUPP_IDX=$OPTARG
	   ;;
	d) DOM=$OPTARG
	   ;;
	P) SNMP_VERSION=$OPTARG
	   ;;
	v) VERBOSE=1;
	   ;;
	?) echo "unknown parameter" 
	   usage
	   exit $STATE_UNKNOWN;
 	   ;;
  esac
done

if [ -z "$HOSTNAME" ]; then
	echo "UNKNOWN - no printer given, use -H"
	exit $STATE_UNKNOWN
fi

for LEVEL in "$WARN_PERCENT" "$CRIT_PERCENT"; do
	if ! [[ "$LEVEL" =~ ^[0-9]+$ ]] || [ "$LEVEL" -gt 100 ]; then
		echo "UNKNOWN - -w and -c take an integer number 0-100, not '$LEVEL'"
		exit $STATE_UNKNOWN
	fi
done


# reads one value from the printer into VALUE, exits UNKNOWN if it cannot
# snmp_value OID DESCRIPTION [integer]
snmp_value()
{
	local RC
	VALUE=$(snmpwalk -v "$SNMP_VERSION" -Ov -Oq -c "$DOM" "$HOSTNAME" "$1" 2>&1)
	RC=$?
	if [ $RC -ne 0 ]; then
		echo "UNKNOWN - snmpwalk exited with exit code $RC: $(echo "$VALUE" | head -n 1)"
		exit $STATE_UNKNOWN
	fi
	# a missing index gives no output with SNMP v1 and "No Such Instance ..." with v2c
	if [ -z "$VALUE" ] || [[ "$VALUE" == No\ Such* ]]; then
		echo "UNKNOWN - printer $HOSTNAME has no $2"
		exit $STATE_UNKNOWN
	fi
	if [ "$3" = "integer" ] && ! [[ "$VALUE" =~ ^-?[0-9]+$ ]]; then
		echo "UNKNOWN - unexpected value '$VALUE' for $2"
		exit $STATE_UNKNOWN
	fi
}


# get values from printer
snmp_value 1.3.6.1.2.1.43.11.1.1.6.1.$SUPP_IDX "supply $SUPP_IDX"
SUPP_STR=$VALUE
snmp_value 1.3.6.1.2.1.43.11.1.1.9.1.$SUPP_IDX "level of supply $SUPP_IDX" integer
SUPP_LEV=$VALUE
snmp_value 1.3.6.1.2.1.43.11.1.1.8.1.$SUPP_IDX "capacity of supply $SUPP_IDX" integer
SUPP_MAX_LEV=$VALUE
# 3: consumed like toner, the level is what is left; 4: filled like the waste
# toner bottle, the level is the space left
snmp_value 1.3.6.1.2.1.43.11.1.1.4.1.$SUPP_IDX "class of supply $SUPP_IDX" integer
if [ "$VALUE" -eq 4 ]; then
	EMPTY_STR="full"
else
	EMPTY_STR="empty"
fi

if [ $SUPP_MAX_LEV -le 0 ]; then
	# the capacity is unknown, so only an exhausted supply can be told
	WARN_LEV=""
	CRIT_LEV=""
	SUPP_MAX_LEV=""
else
	# calculate values of of percentages
	WARN_LEV=$(($WARN_PERCENT*$SUPP_MAX_LEV/100))
	CRIT_LEV=$(($CRIT_PERCENT*$SUPP_MAX_LEV/100))
fi

if [ $VERBOSE -gt 0 ]; then
	echo "Warn level is $WARN_LEV and crit level is $CRIT_LEV"
fi

PERFDATA="level=$SUPP_LEV;$WARN_LEV;$CRIT_LEV;0${SUPP_MAX_LEV:+;$SUPP_MAX_LEV}"

# compare values to crit- and warn-levels
if [ $SUPP_LEV -eq -3 ]; then
	# printer can say that some is left, but can not determine the amount
	echo "OK - $SUPP_STR is not $EMPTY_STR"
	RET_VAL=$STATE_OK
elif [ $SUPP_LEV -lt 0 ]; then
	# -2: printer can not read the level, -1: other
	echo "UNKNOWN - Printer can not determine the level of $SUPP_STR"
	RET_VAL=$STATE_UNKNOWN
elif [ $SUPP_LEV -eq 0 ]; then
	# an exhausted supply stops the printer, whatever the thresholds are
	echo "CRITICAL - $SUPP_STR is $EMPTY_STR|$PERFDATA"
	RET_VAL=$STATE_CRITICAL
elif [ -z "$SUPP_MAX_LEV" ]; then
	echo "OK - $SUPP_STR is at $SUPP_LEV, capacity unknown|$PERFDATA"
	RET_VAL=$STATE_OK
elif [ $SUPP_LEV -lt $CRIT_LEV ]; then
	echo "CRITICAL - $SUPP_STR is low at $SUPP_LEV/$SUPP_MAX_LEV|$PERFDATA"
	RET_VAL=$STATE_CRITICAL
elif [ $SUPP_LEV -lt $WARN_LEV ]; then
	echo "WARNING - $SUPP_STR is low at $SUPP_LEV/$SUPP_MAX_LEV|$PERFDATA"
	RET_VAL=$STATE_WARNING
else
	echo "OK - $SUPP_STR is at $SUPP_LEV/$SUPP_MAX_LEV|$PERFDATA"
	RET_VAL=$STATE_OK
fi

exit $RET_VAL
