forked from jnweiger/perl-File-Unpack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
children_fuser.pl
executable file
·116 lines (105 loc) · 2.38 KB
/
children_fuser.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#! /usr/bin/perl -w
#
# children_fuser.pl -- find children of a given process
# that have opened a given file.
#
# 2010-07-31, jw - initial version (not using Proc::ProcessTable)
use Data::Dumper;
use Cwd;
my $file = shift || '/home/testy/.xsession-errors';
my $parent = shift;
my $p = fuser($file, $parent);
fuser_offset($p);
print Dumper $p;
exit 0;
##############################################
sub fuser
{
my ($file, $ppid) = @_;
$ppid ||= 1;
$file = Cwd::abs_path($file);
opendir DIR, "/proc" or die "opendir /proc failed: $!\n";
my %p = map { $_ => {} } grep { /^\d+$/ } readdir DIR;
closedir DIR;
# get all procs, and their parent pids
for my $p (keys %p)
{
if (open IN, "<", "/proc/$p/stat")
{
# don't care if open fails. the process may have exited.
my $text = join '', <IN>;
close IN;
if ($text =~ m{\((.*)\)\s+(\w)\s+(\d+)}s)
{
$p{$p}{cmd} = $1;
$p{$p}{state} = $2;
$p{$p}{ppid} = $3;
}
}
}
# Weed out those who are not in our family
if ($ppid > 1)
{
for my $p (keys %p)
{
my $family = 0;
my $pid = $p;
while ($pid)
{
# Those that have ppid==1 may also belong to our family.
# We never know.
if ($pid == $ppid or $pid == 1)
{
$family = 1;
last;
}
last unless $p{$pid};
$pid = $p{$pid}{ppid};
}
delete $p{$p} unless $family;
}
}
my %o; # matching open files are recorded here
# see what files they have open
for my $p (keys %p)
{
if (opendir DIR, "/proc/$p/fd")
{
my @l = grep { /^\d+$/ } readdir DIR;
closedir DIR;
for my $l (@l)
{
my $r = readlink("/proc/$p/fd/$l");
next unless defined $r;
# warn "$p, $l, $r\n";
if ($r eq $file)
{
$o{$p}{cmd} ||= $p{$p}{cmd};
$o{$p}{fd}{$l} = { file => $file };
}
}
}
}
return \%o;
}
# see if we can read the file offset of a file descriptor, and the size of its file.
sub fuser_offset
{
my ($p) = @_;
for my $pid (keys %$p)
{
for my $fd (keys %{$p->{$pid}{fd}})
{
if (open IN, "/proc/$pid/fdinfo/$fd")
{
while (defined (my $line = <IN>))
{
chomp $line;
$p->{$pid}{fd}{$fd}{$1} = $2 if $line =~ m{^(\w+):\s+(.*)\b};
}
}
close IN;
$p->{$pid}{fd}{$fd}{size} = -s $p->{$pid}{fd}{$fd}{file};
}
}
}