#!/usr/bin/perl # vim: ts=2 sts=2 sw=2:et ai: # # Usage: check_nfsmounts [ -t nfs timeout ] [ -w ] # Description: determines whether there are stale NFS mounts on the host. # Author: Clint Byrum # # Copyright 2007 Adicio, Inc. # # 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 . # use utils qw{$TIMEOUT %ERRORS}; use Time::HiRes qw{time alarm}; use Getopt::Long; use strict; my $version="1.0"; my $nfs_timeout=$TIMEOUT; my $nfs_warn=-1; my $writemode=0; my $help=0; sub usage { print STDERR "NFS UNKNOWN: version $version, check_nfs_client [ --nfs-critical|-c seconds ]\n"; print STDERR " [ --nfs-warning seconds ][ --writemode|-w ]\n"; exit $ERRORS{'UNKNOWN'}; } if(!GetOptions('nfs-timeout|nfstimeout|critical|c|t=f' => \$nfs_timeout, 'nfs-warning=f' => \$nfs_warn, 'writemode|write|w' => \$writemode, 'help' => \$help, )) { &usage; } if($help) { &usage; } if($nfs_timeout <= 0) { print STDERR "timeout must be greater than 0\n"; &usage; } our $dir; # Because its a signal handler, we have to sub alarm_handler { print "NFS CRITICAL: Stale NFS mount point - $dir.\n"; exit $ERRORS{'CRITICAL'}; } sub bad_mount { my $mountpoint=shift(); my $emsg=shift(); print "NFS CRITICAL: cannot operate on mount point $mountpoint. [$emsg]\n"; exit $ERRORS{'CRITICAL'}; } #my @dirs = `mount | grep " type nfs " | awk '{print \$3}'`; if(!open MTAB,"< /etc/mtab") { print "NFS UNKNOWN: could not open mtab.\n"; exit $ERRORS{'UNKNOWN'}; } my @dirs=(); my %mountmodes=(); while(my $line=) { if($line =~ /^[^ ]+ [^ ]+ nfs /) { my @fields=split(/\s+/,$line); my $mountpoint=$fields[1]; push(@dirs,$mountpoint); #my %modes=split(/,/,$fields[3]); my $modes = {}; foreach my $mode (split(/,/,$fields[3])) { $modes->{$mode}=1; } $mountmodes{$mountpoint}=$modes; } } close MTAB; if(@dirs < 1) { print "NFS OK: no NFS mounts found.\n"; exit $ERRORS{'OK'}; } my @ages=(); my @warnings=(); foreach $dir (@dirs) { chomp $dir; $SIG{ALRM} = \&alarm_handler; my $start=time; my $pid=fork; if($pid==0) { chdir $dir or &bad_mount($dir,$!); if($writemode and exists($mountmodes{$dir}->{"rw"})) { open X,"> $dir/.nfscheck" or exit $?; print X $ENV{HOSTNAME}."\n".localtime()."\n"; # XXX Full disk may fail.. close X or exit $?; } exit 0; } else { alarm $nfs_timeout; waitpid $pid,0; if($?) { &bad_mount($dir,$?); }; alarm 0; } my $age=time()-$start; if($nfs_warn > 0 and $age > $nfs_warn) { push(@warnings,sprintf("$dir took %7.5f to complete all operations ",$age)); } push(@ages,$age); } my $x=0; my $agetot=0; my $maxage=0; foreach my $age (@ages) { $agetot+=$age; if($age > $maxage) { $maxage=$age; } $x++; } my $avgage=$agetot/$x; my $perfdata=sprintf("maxtime=%9.7f;avgtime=%9.7f;mountpoints=$x",$maxage,$avgage); if(@warnings) { print "NFS WARNING: @warnings|$perfdata\n"; exit $ERRORS{'WARNING'}; } printf "NFS OK: $x mount points avg of %7.5f secs, max %7.5f secs.|$perfdata\n",$avgage,$maxage,$maxage,$avgage; exit $ERRORS{'OK'};