#!/usr/bin/perl
#
# Chris Vanhoof <vanhoof AT redhat DOT com>
#
#     This will iterate through all nfs(or any other fs tag) mounts based on hostname regex
#     and run fuser against it.  If we hang for longer than $timeout, then send an alarm, 
#     and print the faulty mount.  This works, and has been tested against a non-responsive
#     NFS server.  It /should/ work against mvfs as well.
#     
# ... and what follows is mostly a shameless rip of code Dan Beimborn sent me for picking up
#     stale NFS mounts. 
#
 
use strict;
use File::Temp;

$|++; 

## change to a higher value if needed (in seconds)
my $timeout = '10';

## change UNLINK to 0 if you would like to see keep the /tmp/*.fuser file(s) around.
my $tmp = new File::Temp( UNLINK => 1, SUFFIX => '.fuser' );
my $temp_filename = $tmp->filename;
	
## change to suit a suitable hostname match
my $hostname_regex = qr/\.rdu\.redhat\.com/;

## change to match target fs to run fuser against
my $filesystem_type = 'nfs';
 
open(FILE, '/proc/mounts') or die("cannot open /proc/mounts $!");
my @lines = <FILE>;
close(FILE);

eval {
	local $SIG{ALRM} = sub { 
		open(TEMP, $temp_filename);
		my @line_array = <TEMP>;
		close(TEMP);

		my $last_line = $line_array[-1];
		die("$last_line");
	}; 
	
	alarm $timeout;
	
	foreach my $line (@lines) { 
		chomp($line);
		my @mounted_fs = split(/\s/, $line);

		next unless ($mounted_fs[2] eq $filesystem_type);

		my $hostname_and_mountpoint_on_hostname = $mounted_fs[0];
		my ($hostname, $mountpoint_on_hostname) = split(/:/, $hostname_and_mountpoint_on_hostname);
			
		next if ($hostname !~ m/$hostname_regex/);

		open(FILE, ">>$temp_filename");
		print FILE $mounted_fs[1]."\n";
		close(FILE);

		`/sbin/fuser $mounted_fs[1]`;
	}
	alarm 0;
};
 
if ($@) {
	print "stuck fuser on $@"."\n";
} else {
	print "fuser completed successfully"."\n";
}
