1#!/usr/local/bin/perl 2# 3# watch_a_file.perl -- use lsof -F output to watch a specific file 4# (or file system) 5# 6# usage: watch_a_file.perl file_name 7 8## Interrupt handler 9 10sub interrupt { wait; print "\n"; exit 0; } 11 12 13## Start main program 14 15$Pn = "watch_a_file"; 16# Check file argument. 17 18if ($#ARGV != 0) { print "$#ARGV\n"; die "$Pn usage: file_name\n"; } 19$fnm = $ARGV[0]; 20if (! -r $fnm) { die "$Pn: can't read $fnm\n"; } 21 22# Do setup. 23 24$RPT = 15; # lsof repeat time 25$| = 1; # unbuffer output 26$SIG{'INT'} = 'interrupt'; # catch interrupt 27 28# Set path to lsof. 29 30if (($LSOF = &isexec("../lsof")) eq "") { # Try .. first 31 if (($LSOF = &isexec("lsof")) eq "") { # Then try . and $PATH 32 print "can't execute $LSOF\n"; exit 1 33 } 34} 35 36# Read lsof -nPF output from a pipe and gather the PIDs of the processes 37# and file descriptors to watch. 38 39open(P, "$LSOF -nPFpf $fnm|") || die "$Pn: can't pipe to $LSOF\n"; 40 41$curpid = -1; 42$pids = ""; 43while (<P>) { 44 chop; 45 if (/^p(.*)/) { $curpid = $1; next; } # Identify process. 46 if (/^f/) { 47 if ($curpid > 0) { 48 if ($pids eq "") { $pids = $curpid; } 49 else { $pids = $pids . "," . $curpid; } 50 $curpid = -1; 51 } 52 } 53} 54close(P); 55wait; 56if ($pids eq "") { die "$Pn: no processes using $fnm located.\n"; } 57print "watch_file: $fnm being used by processes:\n\t$pids\n\n"; 58 59# Read repeated lsof output from a pipe and display. 60 61$pipe = "$LSOF -ap $pids -r $RPT $fnm"; 62open(P, "$pipe|") || die "$Pn: can't pipe: $pipe\n"; 63 64while (<P>) { print $_; } 65close(P); 66print "$Pn: unexpected EOF from \"$pipe\"\n"; 67exit 1; 68 69 70## isexec($path) -- is $path executable 71# 72# $path = absolute or relative path to file to test for executabiity. 73# Paths that begin with neither '/' nor '.' that arent't found as 74# simple references are also tested with the path prefixes of the 75# PATH environment variable. 76 77sub 78isexec { 79 my ($path) = @_; 80 my ($i, @P, $PATH); 81 82 $path =~ s/^\s+|\s+$//g; 83 if ($path eq "") { return(""); } 84 if (($path =~ m#^[\/\.]#)) { 85 if (-x $path) { return($path); } 86 return(""); 87 } 88 $PATH = $ENV{PATH}; 89 @P = split(":", $PATH); 90 for ($i = 0; $i <= $#P; $i++) { 91 if (-x "$P[$i]/$path") { return("$P[$i]/$path"); } 92 } 93 return(""); 94} 95