File Coverage

blib/lib/Proc/Find.pm
Criterion Covered Total %
statement 98 113 86.7
branch 70 98 71.4
condition 16 26 61.5
subroutine 11 14 78.5
pod 4 4 100.0
total 199 255 78.0


line stmt bran cond sub pod time code
1             package Proc::Find;
2              
3             our $DATE = '2019-11-23'; # DATE
4             our $VERSION = '0.051'; # VERSION
5              
6 1     1   600 use 5.010001;
  1         8  
7 1     1   5 use strict;
  1         2  
  1         30  
8 1     1   6 use warnings;
  1         2  
  1         51  
9              
10 1     1   6 use List::Util qw(first);
  1         2  
  1         1633  
11              
12             require Exporter;
13             our @ISA = qw(Exporter);
14             our @EXPORT_OK = qw(
15             find_proc
16             find_any_proc
17             find_all_proc
18             proc_exists
19             );
20              
21             our $CACHE = 0;
22              
23             my $_table_res;
24             sub _table {
25 0     0   0 state $pt = do {
26 0         0 require Proc::ProcessTable;
27 0         0 Proc::ProcessTable->new;
28             };
29 0 0 0     0 if (!$CACHE || !$_table_res) {
30 0         0 $_table_res = $pt->table;
31             }
32 0         0 $_table_res;
33             }
34              
35             sub _match {
36 114     114   190 my ($target, $cond, $is_numeric) = @_;
37 114 100       248 if (ref $cond eq 'Regexp') {
    100          
38 8 100       36 return 0 unless $target =~ $cond;
39             } elsif (ref $cond eq 'ARRAY') {
40 54 50       80 return 0 unless grep { $is_numeric ? $target == $_ : $target eq $_ } @$cond;
  58 100       211  
41             } else {
42 52 100       168 return 0 unless $is_numeric ? $target == $cond : $target eq $cond;
    100          
43             }
44 32         71 1;
45             }
46              
47             sub find_proc {
48 33     33 1 1343 my %args = @_;
49              
50 33         90 my @unknown_args = grep {!/\A(
  69         307  
51             filter|
52             pid|name|cmndline|exec|
53             user|uid|euser|euid|
54             table|detail|
55             result_max
56             )\z/x} keys %args;
57 33 50       88 die "Unknown arguments to find_proc(): ".join(", ", @unknown_args)
58             if @unknown_args;
59              
60 33   33     82 my $table = $args{table} // _table();
61              
62 33         65 my ($arg_uid, $arg_euid);
63              
64 33         0 my @res;
65 33         53 for my $p (@$table) {
66             # create extra fields
67 130         212 $p->{name} = $p->{cmndline};
68 130         355 $p->{name} =~ s/\s.*//;
69 130         279 $p->{name} =~ s!.+/!!;
70              
71 130         165 my $cond = 0;
72             COND:
73             {
74 130 100       149 if (defined $args{filter}) {
  130         222  
75 8         11 local $_ = $p;
76 8 100       16 last COND unless $args{filter}->($p);
77             }
78 126 100       217 if (defined $args{pid}) { last COND unless _match($p->{pid} , $args{pid} , 1) }
  8 100       17  
79 119 100       186 if (defined $args{name}) { last COND unless _match($p->{name} , $args{name} ) }
  12 100       20  
80 109 100       176 if (defined $args{cmndline}) { last COND unless _match($p->{cmndline}, $args{cmndline}) }
  12 100       23  
81 99 100       158 if (defined $args{exec}) {
82 28   100     65 my $exec = $p->{exec} // '';
83 28 100       57 unless ($args{exec} =~ m!/!) {
84 20         52 $exec =~ s!.+/!!;
85             }
86 28 100       48 last COND unless _match($exec, $args{exec});
87             }
88 76 100 100     216 if (defined($args{user}) || defined($args{uid})) {
89 26   66     58 my $cond = $args{user} // $args{uid};
90 26 50       47 if ($cond eq 'Regexp') {
91 0 0       0 last COND unless _match($p->{uid}, $cond, 1); # XXX allow matching against username?
92             } else {
93 26         37 my @uids;
94 26 100       50 for my $val (ref $cond eq 'ARRAY' ? @$cond : $cond) {
95 30 50       83 if ($val =~ /\A\d+\z/) {
96 30         64 push @uids, $val;
97             } else {
98 0         0 my @pw = getpwnam($val);
99 0 0       0 push @uids, @pw ? $pw[2] : -1;
100             }
101             }
102 26 100       56 last COND unless _match($p->{uid}, \@uids, 1);
103             }
104             }
105 61 100 100     173 if (defined($args{euser}) || defined($args{euid})) {
106 28   100     67 my $cond = $args{euser} // $args{euid};
107 28 50       57 if ($cond eq 'Regexp') {
108 0 0       0 last COND unless _match($p->{euid}, $cond, 1); # XXX allow matching against username?
109             } else {
110 28         31 my @uids;
111 28 50       54 for my $val (ref $cond eq 'ARRAY' ? @$cond : $cond) {
112 28 50       83 if ($val =~ /\A\d+\z/) {
113 28         58 push @uids, $val;
114             } else {
115 0         0 my @pw = getpwnam($val);
116 0 0       0 push @uids, @pw ? $pw[2] : -1;
117             }
118             }
119 28 100       53 last COND unless _match($p->{euid}, \@uids, 1);
120             }
121             }
122              
123 44         63 $cond = 1;
124             }
125              
126 130 50       259 $cond = !$cond if $args{inverse};
127 130 100       228 next unless $cond;
128              
129 44 100       66 if ($args{detail}) {
130 4         54 push @res, { %$p }; # unbless
131             } else {
132 40         68 push @res, $p->{pid};
133             }
134              
135 44 100       100 if (defined $args{result_max}) {
136 1 50       4 last if @res >= $args{result_max};
137             }
138             }
139              
140 33         179 \@res;
141             }
142              
143             sub proc_exists {
144 2 100   2 1 2910 @{ find_proc(@_, result_max=>1) } > 0 ? 1:0;
  2         6  
145             }
146              
147             sub find_any_proc {
148 1 50   1 1 2427 return [] unless @_;
149              
150 1         3 my $detail = $_[0]->{detail};
151 1   33     4 my $table = $_[0]->{table} // _table();
152              
153 1         2 my @allres;
154 1         3 for my $crit (@_) {
155 2         8 my $res = find_proc(%$crit, table=>$table, detail=>$detail);
156             ITEM:
157 2         5 for my $item (@$res) {
158             # skip duplicate process
159 2 50       5 if ($detail) {
160 0 0   0   0 next ITEM if first {$_->{pid} == $res->{pid}} @allres;
  0         0  
161             } else {
162 2 50   1   11 next ITEM if first {$_ == $res} @allres;
  1         3  
163             }
164 2         10 push @allres, @$res;
165             }
166             }
167              
168 1         6 \@allres;
169             }
170              
171             sub find_all_proc {
172 2 50   2 1 2188 return [] unless @_;
173              
174 2         5 my $detail = $_[0]->{detail};
175 2   33     6 my $table = $_[0]->{table} // _table();
176              
177 2         4 my @allres;
178             CRIT:
179 2         5 for my $crit (@_) {
180 4         14 my $res = find_proc(%$crit, table=>$table);
181 4 100       10 if (!@allres) {
182 2         4 push @allres, @$res;
183 2         5 next CRIT;
184             }
185             @allres = grep {
186 2         4 my $p = $_;
  4         7  
187             $detail ?
188 0     0   0 ((first {$p->{pid} == $_->{pid}} @$res) ? 1:0) :
189 4 0   4   22 ((first {$p == $_} @$res) ? 1:0)
  4 100       19  
    50          
190             } @allres;
191             }
192              
193 2         11 \@allres;
194             }
195              
196             1;
197             # ABSTRACT: Find processes by name, PID, or some other attributes
198              
199             __END__