#!/bin/bash
# Check real free memory available, i.e. with substract of cached+buffers from
# used memory
#
# Copyright (C) 2016  Easter-eggs <info@easter-eggs.com>
# 
# 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 3 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, see <http://www.gnu.org/licenses/>.


W=85
C=90

function bytes_to_human () {
    bytes=$1
    if [ $bytes -gt $((1000*1000*1000)) ]
    then
        echo $(($bytes / (1000*1000*1000)))GB
    elif [ $bytes -gt $((1000*1000)) ]
    then
        echo $(($bytes / (1000*1000)))MB
    elif [ $bytes -gt 1000 ]
    then
        echo $(($bytes / 1000))kB
    else
        echo ${bytes}B
    fi
}

function usage () {
        echo "Usage: check_free_mem [OPTIONS]"
        echo "  -w P     maximum percent used to trigger a warning alert (default: ${W}%)"
        echo "  -c P     maximum percent used to trigger a critical alert (default: ${C}%)"
        echo "  -h       display this helpfull message"
        exit 3
}

while getopts ":w:c:h" opt; do
  case $opt in
    w)
        if [[ $OPTARG =~ ^[0-9]+$ && $OPTARG -le 100 ]]
        then
            W=$OPTARG
        else
            echo "Error: wrong warning threshold $OPTARG"
            usage
        fi
      ;;
    c)
        if [[ $OPTARG =~ ^[0-9]+$ && $OPTARG -le 100 ]]
        then
            C=$OPTARG
        else
            echo "Error: wrong critical threshold $OPTARG"
            usage
        fi
      ;;
    h)
        usage
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1
      ;;
  esac
done




STATE="UNKNOWN"
EXIT_CODE=3

while read line
do
    if [[ $line =~ ^MemTotal:.*kB ]]
    then
        total=$(echo $line | awk '{print $2}')
        total=$(($total * 1000))
    elif [[ $line =~ ^MemFree:.*kB ]]
    then
        free=$(echo $line | awk '{print $2}')
        free=$(($free * 1000))
    elif [[ $line =~ ^Buffers:.*kB ]]
    then
        buffers=$(echo $line | awk '{print $2}')
        buffers=$(($buffers * 1000))
    elif [[ $line =~ ^Cached:.*kB ]]
    then
        cache=$(echo $line | awk '{print $2}')
        cache=$(($cache * 1000))
    elif [[ $line =~ ^SwapFree:.*kB ]]
    then
        swap_free=$(echo $line | awk '{print $2}')
        swap_free=$(($swap_free * 1000))
    elif [[ $line =~ ^SwapTotal:.*kB ]]
    then
        swap_total=$(echo $line | awk '{print $2}')
        swap_total=$(($swap_total * 1000))
    fi
done < /proc/meminfo

if [ -z "$total" -o -z "$free" ]
then
    echo "UNKNOWN: unable to get values from /proc/meminfo"
    exit 3
fi

used=$(($total - $free - $buffers - $cache))
free=$(($free + $buffers + $cache))
percent_used=$(( 100 * $used / $total  ))



if [ $percent_used -ge $C ]
then
    STATE="CRITICAL"
    EXIT_CODE=2
elif [ $percent_used -ge $W ]
then
    STATE="WARNING"
    EXIT_CODE=1
else
    STATE="OK"
    EXIT_CODE=0
fi


echo "$STATE: ${percent_used}% used ($(bytes_to_human $used) / $(bytes_to_human $total), buffers: $(bytes_to_human $buffers), cached $(bytes_to_human $cache), free: $(bytes_to_human $free))"

exit $EXIT_CODE

