#!/usr/bin/awk -f # $Id: lowdisk,v 3.49 2024/06/16 19:18:22 bscott Exp bscott $ # Reports disks/filesystems/volumes/whatever with low free space. # Looks at percentage free vs total filesystem size (not absolute bytes). # Provides a report with system info and unhealthy filesystems if any, # or no-output if none, so good to stick in crontab for email alerts. # # Optional config file /etc/lowdisk.conf is read if possible. # # This is free and unencumbered software released into the public domain. # It is provided "AS IS", without warranty or liability of any kind. # See the UNLICENSE file or http://unlicense.org/ for full license terms. BEGIN { # -------------------------------------------------------------------------- # constants # config file location conf = "/etc/lowdisk.conf" # separate output by tabs OFS = "\t" # used to print to stderr err = "cat 1>&2" # included at start of output when an alert is issued headline = "The following file systems have low disk space:" # -------------------------------------------------------------------------- # defaults # These can be overridden by the config file # disk free command dfcmd = "df -l -P" # -l local file systems only # -P POSIX-portable format # warn over this percent max = 80 # -------------------------------------------------------------------------- # config file line = 0 # line number in file while(result = getline < conf) { # If we got an error (such as "No such file or directory"), # just forget the config file and use the defaults. if (result < 0) { break } line++ # skip blank or comment lines if ( /^[\t ]*$/ || /^[\t ]*#/ ) { continue } cmd = $1 # global default maximum space used before warning if (cmd == "max") { max = $2 max = max + 0 # force to number if ((max < 1) || (max > 99)) { printf("lowdisk: %s:%d: %s: bad max percent\n", \ conf, line, max) | err exit 1 } } # disk free command, if you don't like the default else if (cmd == "dfcmd") { dfcmd = $0 # strip "dfcmd" at start of line sub(/^[\t ]*dfcmd[\t ]*/, "", dfcmd) # make sure something is left if ( dfcmd ~ /^[\t ]*$/ ) { printf("lowdisk: %s:%d: empty dfcmd\n", \ conf, line) | err exit 1 } } # per-filesystem directives else if (cmd == "fs") { val = $2 # value for max pat = $3 # pattern to match against mount point if (val != "skip") { val = val + 0 } # force num if ( ! length(pat) ) { printf("lowdisk: %s:%d: empty fs pattern\n", \ conf, line) | err exit 1 } fs[pat] = val # no range check if this is a skip directive if (val == "skip") { continue } if ((val < 1) || (val > 99)) { printf("lowdisk: %s:%d: %s: bad fs max percent\n", \ conf, line, val) | err exit 1 } } else { printf("lowdisk: %s:%d: %s: bad command\n", \ conf, line, cmd) | err exit 1 } } # while conf # -------------------------------------------------------------------------- # check free space any = 0 # did we find any valid input? used for sanity check good = 1 # true if no problems reported (yet) while (dfcmd | getline) { # lines where field 5 looks like a percentage if ($5 ~ /^[0-9]+%/) { pct=$5 sub(/%/, "", pct) # strip percent sign pct = pct + 0 # force to number any = 1 # get max for this filesystem, default, or match from fs thismax = max for (pat in fs) { if ($6 ~ pat) { thismax = fs[pat] break } } # for # skip this filesystem if that's what fs says to do if (thismax == "skip") { continue } # the actual disk space check if (pct > thismax) { if (good) { # header upon the first non-good print headline print "" print "USED", "MOUNT" good = 0 } print $5, $6 } # if max } # if looks-like-percent } # while dfcmd # -------------------------------------------------------------------------- # ending reports # if any non-good, include system information with the output if (!good) { "hostname" | getline host "date" | getline now print "" printf "Host: %s\n", host printf "Date: %s\n", now } # if nothing matched, likely the df options are wrong or this program broke if (!any) { printf("lowdisk: WARNING: found no filesystems\n", prog) | err } # -------------------------------------------------------------------------- } # BEGIN