#!/usr/bin/perl -w # # lsfd - list open file descriptors. Solaris 10, Perl. # # This program lists processes and their open file descriptors with the # path to each file they have open. This is made easy by a new procfs # structure in Solaris 10. # # NOTE: The path printed isn't 100% accurate! for example, in the case of # hard links, the path printed could be any of the names for that inode. # # 23-Jan-2006, ver 0.85 (check for newer versions) # # USAGE: lsfd [-hl] [-n name] [-p PID] # # -h # help # -l # long output, includes command name # -n name # match on this command name # -p PID # match on this PID # eg, # lsfd # default output: PID, FD, PATH # lsfd -p 386 # examine PID 386 # lsfd -n syslogd # match processes called syslogd # # NOTE: Running this as root will display more output; as a regular # user we can only see processes that we own. PATHs that appear blank # may be sockets - lsfd cannot print their data. # # SEE ALSO: lsof # this works for all versions of Solaris, prints sockets. # pfiles # updated in Solaris 10 # # COPYRIGHT: Copyright (c) 2004 Brendan Gregg. # # 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 2 # 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, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # (http://www.gnu.org/copyleft/gpl.html) # # Author: Brendan Gregg [Sydney, Australia] # # 05-Apr-2005 Brendan Gregg Created this. # 23-Jan-2006 " " Tweaked style. use strict; use Getopt::Std; # # Process Arguments # getopts('hln:p:') or usage(); usage() if defined $main::opt_h; my $LONG = defined $main::opt_l ? $main::opt_l : 0; my $PID = defined $main::opt_p ? $main::opt_p : 0; my $NAME = defined $main::opt_n ? $main::opt_n : ""; $main::opt_h = 0; my $PRFNSZ = 12; # chars of COMM to print my $comm; my @Out; # # Check for Solaris 10 # if (! -e "/proc/$$/path") { print STDERR "ERROR1: Can't find /proc/PID/path,\n"; print STDERR " This needs Solaris 10 or newer.\n"; exit 1; } # # Fetch PIDs # chdir "/proc"; my @PIDs = $PID ? $PID : <*>; # # Fetch Paths # foreach my $pid (@PIDs) { ### Try path dir, chdir "/proc/$pid/path" or next; ### Fetch the numerical FDs, my @FD = grep(/^\d+$/, <*>); ### Fetch the path data, foreach my $fd (@FD) { my $path = readlink $fd; $path = defined $path ? $path : ""; if ($LONG or $NAME ne "") { # determine command name $comm = readlink "a.out"; $comm =~ s:.*/::; $comm = substr $comm, 0, $PRFNSZ; } # check for name next if $NAME ne "" and $NAME ne $comm; # don't print yet - this loop needs to be quick, if ($LONG) { push @Out, sprintf "%5d %-${PRFNSZ}s %4d %s\n", $pid, $comm, $fd, $path; } else { push @Out, sprintf "%5d %4d %s\n", $pid, $fd, $path; } } } # # Print Report # if ($LONG) { printf "%5s %-${PRFNSZ}s %4s %s\n", "PID", "COMM", "FD", "PATH"; } else { printf "%5s %4s %s\n", "PID", "FD", "PATH"; } print @Out; # usage - print usage message and exit # sub usage { print STDERR <