#!/bin/bash
#====================================================================
# Reads free diskspace on remote hosts via snmp. 
# 
# Requires Net-SNMP: http://net-snmp.sourceforge.net/
# 
# Jonathan Baxter jbaxter@panscient.com 20080426
# 
#    Copyright (C) 2008, Jonathan Baxter
#
#    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 2 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, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#====================================================================

function usage() {
    echo 
    echo "Usage: $0 [-cp] host [host...]";
    echo "Print fixed disks on the specified host(s) with free space below threshold"
    echo 
    echo "  -c    snmp community string  (default: \"public\")"
    echo "  -p    percent free threshold (default: 10%)"
    echo
    echo "Report bugs to jbaxter@panscient.com"
    echo
}

#===================
# Process options
#===================
while getopts ":c:p:" option; do
    case $option in
	c ) community="$OPTARG"; shift $((OPTIND-1)); OPTIND=1;;
	p ) percent_free_threshold="$OPTARG"; shift $((OPTIND-1)); OPTIND=1;;
	h ) usage; exit 0;;
	\? ) usage; exit 1;;
	* ) usage; exit 1;;
  esac
done
community=${community-public}
percent_free_threshold=${percent_free_threshold-10}
snmp_ver="1"

if [ "$1" = "" ]; then
    echo $usage
    exit 1
fi  

#=============================================================================
# Reads the free space on fixed disks on the specified host
# 
# $1: host 
# return: line for each fixed disk: <name> <size MB> <used MB> <percent free>
#=============================================================================
function read_fixed_diskspace()
{
    local data host type desc au size used
    host=$1
    data="$(snmpwalk -c public -v 1 -OqUes $host hrStorage 2>&1)"
    if [ "$?" != "0" ]; then 
	echo -e "$data"
	return 1;
    fi
    while read nameid value junk; do
	name=${nameid%%.*}
	id=${nameid/$name.}
	lastid=$id
	case "$name" in
	    "hrStorageType" ) type[$id]=$value;;
            "hrStorageDescr" ) desc[$id]=$value;;
	    "hrStorageAllocationUnits" ) au[$id]=$value;;
	    "hrStorageSize" ) size[$id]=$value;;
	    "hrStorageUsed" ) used[$id]=$value;;
	    * ) ;;
        esac
    done < <(echo -e "$data")

    i="0"
    while [[ i -lt ${lastid} ]]; do
	if [[ ("${type[$i]}" = "hrStorageFixedDisk") && 
		    ("${size[$i]-0}" != "0") && 
		    ("${au[$i]-0}" != "0") ]]; then
	    sizeMB=$(( (${au[$i]} * (${size[$i]} / 1024) / 1024) ))
	    usedMB=$(( (${au[$i]} * (${used[$i]} / 1024) / 1024) ))
	    percent_free=$((100 * ( $sizeMB - $usedMB ) / $sizeMB))
	    echo "${desc[$i]} ${sizeMB} ${usedMB} $percent_free\n"
	fi
	let i=i+1;
    done
}

#============================================
# Insert commas as appropriate into integers
# $1: integer, eg: 5555555
# return: commaized integer, eg: 5,555,555
#============================================
function commaize() {
    echo $1 | sed ':a;s/\B[0-9]\{3\}\>/,&/;ta'
}

#======================================
# Process the hosts on the commandline
#======================================
n="0"
num_bad_hosts="0"
for host in "$@"; do
    data="$(read_fixed_diskspace $host)"
    if [ "$?" != "0" ]; then
	bad_hosts[$num_bad_hosts]=$host
	last_bad_host=$host
	let num_bad_hosts+=1
	message[$n]="$host: $data"
	let n+=1
    else
	while read desc size used percent_free junk; do
	    if [[ ("$percent_free" != "") && 
			($percent_free -lt $percent_free_threshold) ]]; then
		if [ "$host" != "$last_bad_host" ]; then
		    bad_hosts[$num_bad_hosts]=$host
		    last_bad_host=$host
		    let num_bad_hosts+=1
		fi
		message[$n]="$host:$desc is $(( 100 - $percent_free ))% full - \
		    $(commaize $used)M used out of $(commaize $size)M total"
		let n+=1
	    fi
	done < <(echo -e "$data")
    fi
done

if [ "$num_bad_hosts" -gt "0" ]; then
    # summary line: all bad hosts
    echo "${bad_hosts[*]}"

    # messages
    lastn=$(( $n-1 ))
    for i in $(seq 0 $lastn); do
	echo ${message[$i]}
    done
    exit 1;
fi

exit 0;
