#!/usr/bin/perl use Getopt::Std; $CFG_FILE = "/usr/local/nagios/etc/check_disk.cfg"; $CFG_FILE_LOCAL = "/usr/local/nagios/etc/check_disk_local.cfg"; $DFLT_WARN = 90; $DFLT_CRIT = 95; $DFLT_CLASS = "system"; $CURR_WARN = $DFLT_WARN; $CURR_CRIT = $DFLT_CRIT; $CURR_CLASS = $DFLT_CLASS; $sys_type = `uname`; chomp($sys_type); %FSTypes = ( ext2 => 1, ext3 => 1, ext4 => 1, ufs => 1, vxfs => 1, zfs => 1, xfs => 1 ); # -p enable perf stats # -d enable debugging output # -c set default critical threshold # -w set default warning threshold # -f # -C # -t add additional file system types getopts("pdc:w:f:C:t:"); $CURR_WARN = $opt_w if $opt_w ne ''; $CURR_CRIT = $opt_c if $opt_c ne ''; $opt_C = $CURR_CLASS if $opt_C eq ''; # get the types if ($opt_t ne '') { @types = split(/,/, $opt_t); for $t (@types) { print "add type $t\n" if $opt_d; $FSTypes{$t} = 1; } } # get the list of file systems &read_mounts; # read the config file; if it's not there we take the defaults, except # that if we specify a config file on the command line, we return UNKNOWN # if the file isn't there if ($opt_f ne '') { open (CFG_FILE, $opt_f) or unknown("Can't open config file: $opt_f"); &read_config; } else { (open(CFG_FILE, $CFG_FILE_LOCAL) or open(CFG_FILE, $CFG_FILE)) and &read_config; } if ($opt_d) { for $fs (sort keys %Class) { print "fs $fs class $Class{$fs} warn $Warn{$fs} crit $Crit{$fs}\n"; } } # if there are any file systems that are mounted but not mentioned in the config file, # give them default class and thresholds for $fs (keys %Type) { print "testing $fs: ", defined($Interesting{$fs}) ? "" : "not ", "interested\n" if $opt_d; if (! defined($Interesting{$fs})) { $Class{$fs} = $DFLT_CLASS; $Warn{$fs} = $DFLT_WARN; $Crit{$fs} = $DFLT_CRIT; } } if ($sys_type eq "Linux") { $cmd = "/bin/df -kP"; } elsif ($sys_type eq "SunOS") { $cmd = "/usr/bin/df -k"; } else { unknown("I don't grok system type $sys_type"); } $fscount = 0; for $fs (sort keys %Class) { ## unknown("Non-existant FS ($fs) in config file, line $Line{$fs}") if $Type{$fs} eq ''; push(@FSList, $fs); } for $fs (@FSList) { next if $Ignore{$fs}; next if $Class{$fs} ne $opt_C; $cmd = $cmd . " " . $fs; $fscount++; } if ($fscount == 0) { unknown("no file systems in class \'$opt_C\'"); } print "$cmd\n" if $opt_d; $code = 0; open(DF, "$cmd|") or unknown("Unable to exec df command"); $junk = ; # column headers while () { chop; ($dev, $tot, $used, $free, $cap, $fs) = split; $p = int(($tot - $free) * 100 / $tot); print "$fs: $used/$tot $p\n" if $opt_d; $perf .= " $fs=$p\%"; if ($p > $Crit{$fs}) { $crit_result .= " $fs: $p\% (C)"; $code = 2; } elsif ($p > $Warn{$fs}) { $warn_result .= " $fs: $p\% (W)"; $code = 1 if $code != 2; } else { $result .= " $fs: $p\% (OK)"; } } print "perf $perf\n" if $opt_d; @CODE = ("OK", "WARNING", "CRITICAL", "UNKNOWN"); print "DISK $CODE[$code]: class '$opt_C':$crit_result$warn_result$result"; print "|$perf" if $opt_p; print "\n"; exit $code; sub read_mounts { open(MNTTAB, "/etc/mtab") or open(MNTTAB, "/etc/mnttab") or unknown("Can't open file system mount table"); while () { chop; @mnt = split; next if $FSTypes{$mnt[2]} != 1; $fs = $mnt[1]; print "read from mtab: $_\n" if $opt_d; # push(@FSList, $fs); $Type{$fs} = $mnt[2]; # $Class{$fs} = $DFLT_CLASS; # $Warn{$fs} = $DFLT_WARN; # $Crit{$fs} = $DFLT_CRIT; } } sub read_config { my ($tmp_class, $tmp_warn, $tmp_crit); $line_num = 0; while () { $line_num++; chop; s/^[ ]*//; next if /^#/; next if $_ eq ''; if (/^ignore\s/) { ($junk, $fs) = split; $Ignore{$fs} = 1; } elsif (/^crit\s/) { ($junk, $crit) = split; $CURR_CRIT = $crit; } elsif (/^warn\s/) { ($junk, $warn) = split; $CURR_WARN = $warn; } elsif (/^class\s/) { ($junk, $class) = split; $CURR_CLASS = $class; } elsif (/^fs\s/) { ($junk, @a) = split; $fs = $a[0]; @fslist = &match($fs); foreach $fs (@fslist) { $tmp_class = $CURR_CLASS; $tmp_warn = $CURR_WARN; $tmp_crit = $CURR_CRIT; @aa = @a; shift @aa; foreach $arg (@aa) { if ($arg =~ /^class=/) { $tmp_class = substr($arg, 6); } elsif ($arg =~ /^warn=/) { $tmp_warn = substr($arg, 5); } elsif ($arg =~ /^crit=/) { $tmp_crit = substr($arg, 5); } else { unknown("Syntax error in config file, line $line_num"); } } # mark the file system as being of overall interest $Interesting{$fs} = 1; # Only set these values if the class of the file system is the one that # we are looking to check. This allows us to put a file system in # multiple classes (in cases where more than on group wants to know # about a F.S.) and not have one definition overwritten by another one. print "about to test $fs now $Class{$fs} tmp $tmp_class dflt $CURR_CLASS opt $opt_C\n" if $opt_d; next if $tmp_class ne $opt_C; print "setting $fs to class $tmp_class\n" if $opt_d; $Class{$fs} = $tmp_class; $Warn{$fs} = $tmp_warn; $Crit{$fs} = $tmp_crit; $Line{$fs} = $line_num; } } else { # syntax error unknown("Syntax error in config file, line $line_num"); } } close(CFG_FILE); } sub match { my ($fs) = @_; my @glist = glob($fs); my @rlist = (); print "Match glob list is " . join(' ', @glist) . "\n" if $opt_d; foreach $fs (@glist) { push @rlist, $fs if $Type{$fs} ne ''; } print "Match return list is " . join(' ', @rlist) . "\n" if $opt_d; return @rlist; } sub unknown { my ($reason) = @_; print "UNKNOWN: $reason\n"; exit 3; }