line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Unix::Lsof::Result; |
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
75
|
use 5.008; |
|
3
|
|
|
|
|
9
|
|
|
3
|
|
|
|
|
121
|
|
4
|
3
|
|
|
3
|
|
16
|
use version; our $VERSION = qv('0.1.0'); |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
24
|
|
5
|
|
|
|
|
|
|
|
6
|
3
|
|
|
3
|
|
239
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
122
|
|
7
|
3
|
|
|
3
|
|
19
|
use strict; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
126
|
|
8
|
3
|
|
|
3
|
|
17
|
use Unix::Lsof; |
|
3
|
|
|
|
|
12
|
|
|
3
|
|
|
|
|
296
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
use overload bool => sub { |
11
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
12
|
0
|
0
|
0
|
|
|
|
if ( $self->{error} && (!keys %{$self->{output}}) ) { |
|
0
|
|
|
|
|
|
|
13
|
0
|
|
|
|
|
|
return; |
14
|
|
|
|
|
|
|
} else { |
15
|
0
|
|
|
|
|
|
return 1; |
16
|
|
|
|
|
|
|
} |
17
|
3
|
|
|
3
|
|
18
|
}; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
40
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub _new { |
20
|
0
|
|
|
0
|
|
|
my ( $class, $parsed, $err, $raw,$opt ) = @_; |
21
|
|
|
|
|
|
|
|
22
|
0
|
|
|
|
|
|
my $self = { |
23
|
|
|
|
|
|
|
output => $parsed, |
24
|
|
|
|
|
|
|
error => $err, |
25
|
|
|
|
|
|
|
_raw_output => $raw, |
26
|
|
|
|
|
|
|
options => $opt, |
27
|
|
|
|
|
|
|
}; |
28
|
0
|
|
|
|
|
|
bless $self, $class; |
29
|
|
|
|
|
|
|
|
30
|
0
|
|
|
|
|
|
$self->_get_field_ids(); |
31
|
0
|
|
|
|
|
|
return $self; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub has_errors { |
35
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
36
|
0
|
0
|
|
|
|
|
return $self->{error} ? 1 : 0; |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub errors { |
40
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
41
|
0
|
|
|
|
|
|
return $self->{error}; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub get_pids { |
45
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
46
|
0
|
|
|
|
|
|
my @params = ( "process id"); |
47
|
0
|
0
|
|
|
|
|
unshift @params,$_[0] if ref( $_[0] ); |
48
|
0
|
|
|
|
|
|
my @ret =$self->get_values( @params ); |
49
|
0
|
0
|
|
|
|
|
return wantarray ? @ret : \@ret; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub get_filenames { |
53
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
54
|
0
|
|
|
|
|
|
my @params = ( "file name" ); |
55
|
0
|
0
|
|
|
|
|
unshift @params,$_[0] if ref( $_[0] ); |
56
|
0
|
|
|
|
|
|
my @ret = $self->get_values( @params ); |
57
|
0
|
0
|
|
|
|
|
return wantarray ? @ret : \@ret; |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub get_values { |
61
|
0
|
|
|
0
|
1
|
|
my ( $self, @args ) = @_; |
62
|
0
|
|
|
|
|
|
my @col = $self->get_arrayof_columns(@args); |
63
|
0
|
0
|
|
|
|
|
return if (!defined $col[0]); |
64
|
0
|
0
|
|
|
|
|
return wantarray ? @{$col[0]} : $col[0]; |
|
0
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub get_arrayof_columns { |
68
|
0
|
|
|
0
|
1
|
|
my ( $self, @args ) = @_; |
69
|
0
|
|
|
|
|
|
my @rows = $self->get_arrayof_rows(@args); |
70
|
|
|
|
|
|
|
|
71
|
0
|
|
|
|
|
|
my @cols; |
72
|
0
|
|
|
|
|
|
my $i = 0; |
73
|
0
|
|
|
|
|
|
for my $r (@rows) { |
74
|
0
|
|
|
|
|
|
my $j = 0; |
75
|
0
|
|
|
|
|
|
for my $c (@$r) { |
76
|
0
|
|
|
|
|
|
$cols[ $j++ ][$i] = $c; |
77
|
|
|
|
|
|
|
} |
78
|
0
|
|
|
|
|
|
$i++; |
79
|
|
|
|
|
|
|
} |
80
|
0
|
0
|
|
|
|
|
return wantarray ? @cols : \@cols; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub get_hashof_columns { |
84
|
0
|
|
|
0
|
1
|
|
my ( $self, @args ) = @_; |
85
|
0
|
|
|
|
|
|
my @cols = $self->get_arrayof_columns(@args); |
86
|
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
|
my %return; |
88
|
0
|
|
|
|
|
|
for my $i ( 0 .. $#cols ) { |
89
|
0
|
|
|
|
|
|
$return{ $args[$i] } = $cols[$i]; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
0
|
0
|
|
|
|
|
return wantarray ? %return : \%return; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub get_hashof_rows { |
96
|
0
|
|
|
0
|
1
|
|
my ( $self, @args ) = @_; |
97
|
|
|
|
|
|
|
|
98
|
0
|
|
|
|
|
|
my ( $key, %ret ); |
99
|
0
|
0
|
|
|
|
|
if ( ref( $args[0] ) eq ref( {} ) ) { |
100
|
0
|
|
|
|
|
|
$self->{_query}{filter} = shift @args; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
0
|
|
|
|
|
|
( $key, @{ $self->{_query}{inp_fields} } ) = @args; |
|
0
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
|
105
|
0
|
|
0
|
|
|
|
my $full_key = $Unix::Lsof::op_field{$key} || $key; |
106
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
$full_key =~ s/_/ /g; |
108
|
|
|
|
|
|
|
|
109
|
0
|
|
|
|
|
|
$self->_setup_fields(); |
110
|
0
|
|
|
|
|
|
$self->_setup_filter(); |
111
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
|
my %outp = %{ $self->{output} }; |
|
0
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
|
114
|
0
|
|
|
|
|
|
my %uniqify; |
115
|
0
|
|
|
|
|
|
for my $pid ( keys %outp ) { |
116
|
0
|
|
|
|
|
|
LINELOOP: |
117
|
0
|
|
|
|
|
|
for my $file ( @{ $outp{$pid}{files} } ) { |
118
|
0
|
|
0
|
|
|
|
my $hkey = $self->_get_value( $full_key, $pid, $file ) || next LINELOOP; |
119
|
0
|
|
0
|
|
|
|
my $line = $self->_get_line( $pid, $file ) || next LINELOOP; |
120
|
|
|
|
|
|
|
|
121
|
0
|
|
|
|
|
|
my $i = 0; |
122
|
0
|
|
|
|
|
|
my %rline; |
123
|
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
|
for my $l (@$line) { |
125
|
0
|
0
|
|
|
|
|
if (defined $l) { |
126
|
0
|
|
|
|
|
|
$rline{ $self->{_query}{inp_fields}[ $i ] } = $l; |
127
|
|
|
|
|
|
|
} |
128
|
0
|
|
|
|
|
|
$i++; |
129
|
|
|
|
|
|
|
} |
130
|
0
|
|
|
|
|
|
my $ukey = join $;, sort values %rline; |
131
|
0
|
0
|
|
|
|
|
next LINELOOP if !defined $ukey; |
132
|
|
|
|
|
|
|
|
133
|
0
|
0
|
0
|
|
|
|
if ( !exists $uniqify{$hkey} || !exists $uniqify{$hkey}{$ukey} ) { |
134
|
0
|
|
|
|
|
|
push @{ $ret{$hkey} }, \%rline; |
|
0
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
$uniqify{$hkey}{$ukey}=1; |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
} |
139
|
0
|
|
|
|
|
|
delete $self->{_query}; |
140
|
0
|
0
|
|
|
|
|
return wantarray ? %ret : \%ret; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub get_arrayof_rows { |
144
|
0
|
|
|
0
|
1
|
|
my ( $self, @args ) = @_; |
145
|
|
|
|
|
|
|
|
146
|
0
|
|
|
|
|
|
my @ret; |
147
|
|
|
|
|
|
|
|
148
|
0
|
0
|
|
|
|
|
if ( ref( $args[0] ) eq ref( {} ) ) { |
149
|
0
|
|
|
|
|
|
$self->{_query}{filter} = shift @args; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
$self->{_query}{inp_fields} = \@args; |
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
|
$self->_setup_fields(); |
155
|
0
|
|
|
|
|
|
$self->_setup_filter(); |
156
|
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
|
my %outp = %{ $self->{output} }; |
|
0
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
my %uniqify; |
160
|
0
|
|
|
|
|
|
for my $pid ( keys %outp ) { |
161
|
0
|
|
|
|
|
|
ROWLOOP: |
162
|
0
|
|
|
|
|
|
for my $file ( @{ $outp{$pid}{files} } ) { |
163
|
0
|
|
0
|
|
|
|
my $line = $self->_get_line( $pid, $file ) || next ROWLOOP; |
164
|
|
|
|
|
|
|
|
165
|
0
|
0
|
|
|
|
|
push @ret, $line if ( !$uniqify{ join $;, map { defined $_ ? $_ : "" } @$line }++ ); |
|
0
|
0
|
|
|
|
|
|
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
} |
168
|
0
|
|
|
|
|
|
delete $self->{_query}; |
169
|
0
|
0
|
|
|
|
|
return wantarray ? @ret : \@ret; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub _setup_filter { |
173
|
0
|
|
|
0
|
|
|
my $self = shift; |
174
|
0
|
0
|
|
|
|
|
return if ( !exists $self->{_query}{filter} ); |
175
|
|
|
|
|
|
|
|
176
|
0
|
|
|
|
|
|
%{ $self->{_query}{filter} } = |
|
0
|
|
|
|
|
|
|
177
|
0
|
|
|
|
|
|
map { my $t = $_; $t =~ s/_/ /g; |
|
0
|
|
|
|
|
|
|
178
|
0
|
|
0
|
|
|
|
$Unix::Lsof::op_field{$t} || $t => $self->{_query}{filter}{$_} } |
179
|
0
|
|
|
|
|
|
keys %{ $self->{_query}{filter} }; |
180
|
|
|
|
|
|
|
|
181
|
0
|
|
|
|
|
|
my %check_filter = map { $_ => 1 } @{ $self->{_query}{ret_fields} }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
182
|
0
|
|
|
|
|
|
@{ $self->{_query}{force_validate} } = grep { !exists $check_filter{$_} } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
183
|
0
|
|
|
|
|
|
keys %{ $self->{_query}{filter} }; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub _setup_fields { |
187
|
0
|
|
|
0
|
|
|
my $self = shift; |
188
|
0
|
|
|
|
|
|
my ( @temp_fields, @ret_fields ); |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# Use either field designators or names |
191
|
0
|
|
|
|
|
|
@ret_fields = |
192
|
0
|
0
|
|
|
|
|
map { $_ =~ s/_/ /g; $Unix::Lsof::op_field{$_} || $_ } |
|
0
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
@{ $self->{_query}{inp_fields} }; |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
for my $f (@ret_fields) { |
196
|
0
|
0
|
0
|
|
|
|
if ( exists $self->{_program_field_ids}{$f} || |
197
|
|
|
|
|
|
|
exists $self->{_file_field_ids}{$f} |
198
|
|
|
|
|
|
|
) { |
199
|
0
|
|
|
|
|
|
push @temp_fields, $f; |
200
|
|
|
|
|
|
|
} else { |
201
|
0
|
|
|
|
|
|
$self->_iwarn("$f is not in the list of fields returned by lsof"); |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
0
|
|
|
|
|
|
$self->{_query}{ret_fields} = \@temp_fields; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub _validate { |
209
|
0
|
|
|
0
|
|
|
my ( $self, $filter_key, $value ) = @_; |
210
|
|
|
|
|
|
|
|
211
|
0
|
|
|
|
|
|
my $filter = $self->{_query}{filter}{$filter_key}; |
212
|
|
|
|
|
|
|
|
213
|
0
|
0
|
|
|
|
|
return if !defined $value; |
214
|
|
|
|
|
|
|
|
215
|
0
|
0
|
0
|
0
|
|
|
if ( ref($filter) eq ref( sub { } ) ) { |
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
return $filter->($value); |
217
|
|
|
|
|
|
|
} elsif ( ref($filter) eq ref(qr//) ) { |
218
|
0
|
0
|
|
|
|
|
return $value =~ $filter ? 1 : 0; |
219
|
|
|
|
|
|
|
} elsif ( $filter =~ m/\A\d+\z/ && $value =~ m/\A\d+\z/) { |
220
|
0
|
0
|
|
|
|
|
return $filter == $value ? 1 : 0; |
221
|
|
|
|
|
|
|
} elsif ( !ref($filter) ) { |
222
|
0
|
0
|
|
|
|
|
return $filter eq $value ? 1 : 0; |
223
|
|
|
|
|
|
|
} else { |
224
|
0
|
|
|
|
|
|
$self->_iwarn(qq(Invalid filter specified for "$filter_key")); |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub _get_line { |
230
|
0
|
|
|
0
|
|
|
my ( $self, $pid, $file ) = @_; |
231
|
0
|
|
|
|
|
|
my @line; |
232
|
|
|
|
|
|
|
|
233
|
0
|
|
|
|
|
|
for my $force ( @{ $self->{_query}{force_validate} } ) { |
|
0
|
|
|
|
|
|
|
234
|
0
|
|
|
|
|
|
my $val = $self->_get_value( $force, $pid, $file ); |
235
|
0
|
0
|
|
|
|
|
$self->_validate( $force, $val ) || return; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
0
|
|
|
|
|
|
for my $field ( @{ $self->{_query}{ret_fields} } ) { |
|
0
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
|
240
|
0
|
|
|
|
|
|
my $val = $self->_get_value( $field, $pid, $file ); |
241
|
|
|
|
|
|
|
|
242
|
0
|
0
|
|
|
|
|
if ( exists( $self->{_query}{filter}{$field} ) ) { |
243
|
0
|
0
|
|
|
|
|
$self->_validate( $field, $val ) || return; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
0
|
|
|
|
|
|
push @line, $val; |
247
|
|
|
|
|
|
|
} |
248
|
0
|
|
|
|
|
|
return \@line; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub _get_value { |
252
|
0
|
|
|
0
|
|
|
my ( $self, $name, $pid, $file ) = @_; |
253
|
0
|
0
|
|
|
|
|
my $ret = |
254
|
|
|
|
|
|
|
exists $self->{_program_field_ids}{$name} |
255
|
|
|
|
|
|
|
? $self->{output}{$pid}{$name} |
256
|
|
|
|
|
|
|
: $file->{$name}; |
257
|
0
|
|
|
|
|
|
return $ret; |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub _get_field_ids { |
261
|
0
|
|
|
0
|
|
|
my $self = shift; |
262
|
|
|
|
|
|
|
|
263
|
0
|
|
|
|
|
|
for my $pid ( keys %{ $self->{output} } ) { |
|
0
|
|
|
|
|
|
|
264
|
0
|
|
|
|
|
|
for my $pfield ( keys %{ $self->{output}{$pid} } ) { |
|
0
|
|
|
|
|
|
|
265
|
0
|
0
|
|
|
|
|
if ( $pfield eq "files" ) { |
266
|
0
|
|
|
|
|
|
for my $file ( @{ ${ $self->{output} }{$pid}{files} } ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
for my $id ( keys %$file ) { |
268
|
0
|
|
|
|
|
|
$self->{_file_field_ids}{$id}++; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
} else { |
272
|
0
|
|
|
|
|
|
$self->{_program_field_ids}{$pfield}++; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
sub _iwarn { |
280
|
0
|
|
|
0
|
|
|
my $self = shift; |
281
|
0
|
|
|
|
|
|
my $message = $_[0]; |
282
|
0
|
0
|
|
|
|
|
if ( $self->{options}{suppress_errors} ) { |
283
|
0
|
|
|
|
|
|
$self->{error} .= $message; |
284
|
|
|
|
|
|
|
} else { |
285
|
0
|
|
|
|
|
|
warn @_; |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=head1 NAME |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
Unix::Lsof::Result - Perlish interface to lsof output |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=head1 VERSION |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
This document describes Unix::Lsof::Result version 0.1.0 |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=head1 SYNOPSIS |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
use Unix::Lsof; |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
my $lr = lsof("-p",$$); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
if ($lr->has_errors()) { |
307
|
|
|
|
|
|
|
print qq(Errors encountered: $lr->errors()); |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
my @pids = $lr->get_pids(); |
311
|
|
|
|
|
|
|
my @file_types = $lr->get_values( "file type" ); |
312
|
|
|
|
|
|
|
my $access_modes = $lr->get_values( "access mode" ); |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# Print out file name and type |
315
|
|
|
|
|
|
|
my @filenames = $lr->get_arrayof_rows( "file type", "file name" ); |
316
|
|
|
|
|
|
|
for my $p (@filenames) { |
317
|
|
|
|
|
|
|
print "File type: $p->[0] - File name: $p->[1]\n"; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
# Print a list of open IPv4 connections |
321
|
|
|
|
|
|
|
my %filetype = $lr->get_hashof_rows( "file type", "n", "protocol name" ); |
322
|
|
|
|
|
|
|
for my $conn ( @{ $filetype{"IPv4"} } ) { |
323
|
|
|
|
|
|
|
print qq(IPv4 connection to: $conn->{"n"}, protocol: $conn->{"protocol name"}\n); |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# Print out a list of open files larger than 1kb |
327
|
|
|
|
|
|
|
my @filesize = $lr->get_arrayof_columns( "file name", "file size" ); |
328
|
|
|
|
|
|
|
for my $i ( 0..scalar( @{ $filesize[1] } ) ) { |
329
|
|
|
|
|
|
|
if ( $filesize[1][$i] >= 1024 ) { |
330
|
|
|
|
|
|
|
print "File $filesize[0][$1] is over 1k\n"; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
# Print out the size of text files found |
335
|
|
|
|
|
|
|
my $fs = $lr->get_hashof_columns( "file name", "file size" ); |
336
|
|
|
|
|
|
|
for my $i ( 0..scalar( @{ $fs->{"file name"} } ) ) { |
337
|
|
|
|
|
|
|
if ( $fs->{"file name"}[$i] =~ m/\.txt\z/ ) { |
338
|
|
|
|
|
|
|
print qq(Found $fs->{"file size"}[$i] bytes large text file\n); |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# The same as previous, using filters |
343
|
|
|
|
|
|
|
my @file_list = $lr->get_values( { "file name" => qr/\.txt\z/ }, |
344
|
|
|
|
|
|
|
"file size" ); |
345
|
|
|
|
|
|
|
for my $f (@file_list) { |
346
|
|
|
|
|
|
|
print qq(Found $f bytes large text file); |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
# Looking for text files between 1 and 4k |
350
|
|
|
|
|
|
|
my @file_list = $lr->get_filenames( { "file name" => qr/\.txt\z/, |
351
|
|
|
|
|
|
|
"file size" => sub { $_[0] > 1024 && |
352
|
|
|
|
|
|
|
$_[0] <= 4096 } |
353
|
|
|
|
|
|
|
}, "file name"); |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=head1 DESCRIPTION |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
This module offers multiple ways of organising and retrieving the data returned |
359
|
|
|
|
|
|
|
by lsof. It attempts to make it as easy as possible for the user to obtain the |
360
|
|
|
|
|
|
|
information he wants in the way he wants it. |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
The C object is returned when calling C<lsof()>> |
363
|
|
|
|
|
|
|
in scalar context. When evaluated in boolean context the object will evaluate to |
364
|
|
|
|
|
|
|
true unless no STDOUT output is obtained from running the C binary and |
365
|
|
|
|
|
|
|
STDERR output was obtained from the same run. This allows for the following |
366
|
|
|
|
|
|
|
logic : |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
if ($lf = $lsof(@params)) { |
369
|
|
|
|
|
|
|
# we got output or no errors, some success was had |
370
|
|
|
|
|
|
|
warn "Errors: ".$lf->errors() |
371
|
|
|
|
|
|
|
if $lf->has_errors(); |
372
|
|
|
|
|
|
|
# normal processing continues |
373
|
|
|
|
|
|
|
# ... |
374
|
|
|
|
|
|
|
} else { |
375
|
|
|
|
|
|
|
# no output and we have an error message, something is badly wrong |
376
|
|
|
|
|
|
|
die "Errors: ".$lf->errors(); |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
Note that you will only find out whether B errors were encountered by |
380
|
|
|
|
|
|
|
examining the C return value, examining truth of the object itself |
381
|
|
|
|
|
|
|
only makes sense if you just care about some valid output being returned (e.g. |
382
|
|
|
|
|
|
|
if you're passing in a list of files, some of which may not exist). |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
All of the output accessor methods (i.e. the methods starting with C, for |
385
|
|
|
|
|
|
|
example C, C) have the following properties: |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=over 4 |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=item * |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
Only return unique values |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
All output accessor methods will only return unique result sets, e.g. if |
394
|
|
|
|
|
|
|
a single file is opened by multiple programs |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
$lf->get_arrayof_rows( "file name", "process id"); |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
will return as many rows as there are processes opening the file, whereas |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
$lf->get_arrayof_rows( "file name", "file type"); |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
will only return a single row, since file name and file type are the same for |
403
|
|
|
|
|
|
|
all return sets. |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=item * |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
Returns list or reference depending on calling context |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
The accessor methods are sensitive to their calling context and will return |
410
|
|
|
|
|
|
|
either a list or a reference to an array/hash. |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
# This will return a list |
413
|
|
|
|
|
|
|
@e = $lf->get_pids(); |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# This will return an array reference |
416
|
|
|
|
|
|
|
$e = $lf->get_pids() |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=item * |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
Fields can be specified either with their full name or single character |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
When specifying a list of fields which you want returned from the accessor, you |
423
|
|
|
|
|
|
|
can either use the single character associated with that field (see the lsof man |
424
|
|
|
|
|
|
|
page section "OUTPUT FOR OTHER PROGRAMS" for a list of these) or the full field |
425
|
|
|
|
|
|
|
name as given in ther C perldoc, or the full field name with spaces |
426
|
|
|
|
|
|
|
replaced by underscores (e.g. file_name instead of "file name"). |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=item * |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
Filters |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
The method can optionally be provided with a "filter" which limits the |
433
|
|
|
|
|
|
|
data returned. For this, pass a hash reference as the first argument, of the |
434
|
|
|
|
|
|
|
format |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
{ |
437
|
|
|
|
|
|
|
=> , |
438
|
|
|
|
|
|
|
=> , |
439
|
|
|
|
|
|
|
... |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
where can be either a scalar value, a reference to a regular expression |
443
|
|
|
|
|
|
|
or a reference to a subroutine. Only record sets that match on all fields will |
444
|
|
|
|
|
|
|
be returned. A subroutine must return true to "match", the field value is passed |
445
|
|
|
|
|
|
|
in normally as the first element of the @_ array. |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
Example: |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
{ |
450
|
|
|
|
|
|
|
"process id" => 4242, |
451
|
|
|
|
|
|
|
"n" => qr/\.txt\z/i, |
452
|
|
|
|
|
|
|
"command_name" => sub { $_[0] =~ m/kde/ || $_[0] eq "cupsd" } |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
Limitations: is is very well possible to specify a filter that completely excludes |
456
|
|
|
|
|
|
|
any files, e.g. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
{ "process id" => "-1" } |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
. Also, to specify more than one condition on a given field name (e.g. greater |
461
|
|
|
|
|
|
|
than 100 but not 105) you need to use a sub e.g. |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
{ "process id" => sub { $_[0] > 100 && $_[0] != 105 } } |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
The same goes if you need to C a set of constraints. Note that there is |
466
|
|
|
|
|
|
|
currently no way to C constraints over several fields (e.g. process id equals |
467
|
|
|
|
|
|
|
1000 or user id equals 42). |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=back |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=head1 INTERFACE |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
=head2 Methods |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=over 4 |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=item C |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
$lf->has_errors(); |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
Returns true if the call to the lsof binary returned any STDERR output. |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
=item C |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
$lf->errors(); |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
Returns the STDERR output of the lsof binary in a single string. WARNING: it is |
489
|
|
|
|
|
|
|
possible that this B change in some future version to allow for more |
490
|
|
|
|
|
|
|
sophisticated error handling (though using the result of this subroutine as a |
491
|
|
|
|
|
|
|
simple string will almost certainly continue to be supported). |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=item C |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
$lf->get_values( $field_name ); |
496
|
|
|
|
|
|
|
$lf->get_values( $filter, $field_name ); |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
Returns a list with the values for a single field. |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
=item C |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
$lf->get_values(); |
503
|
|
|
|
|
|
|
$lf->get_values( $filter ); |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
Specialised version of get_values which returns a list of process ids. |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=item C |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
$lf->get_filenames(); |
510
|
|
|
|
|
|
|
$lf->get_filenames( $filter ); |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
Specialised version of get_values which returns a list of file names. |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=item C |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
$lf->get_arrayof_rows( @column_names ); |
517
|
|
|
|
|
|
|
$lf->get_arrayof_rows( $filter, @column_names ); |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
Returns a list of array references, each of which corresponds to a row of lsof |
520
|
|
|
|
|
|
|
output. The order of the values in the referenced arrays corresponds to the |
521
|
|
|
|
|
|
|
order of the parameters passed in; e.g. a call to |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
$lf->get_arrayof_rows( "file name", "file type"); |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
would produce a data structure like this |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
[ |
528
|
|
|
|
|
|
|
[ filename1, filetype1 ], |
529
|
|
|
|
|
|
|
[ filename2, filetype2 ], |
530
|
|
|
|
|
|
|
... |
531
|
|
|
|
|
|
|
] |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=item C |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
$lf->get_arrayof_columns( @column_names ); |
536
|
|
|
|
|
|
|
$lf->get_arrayof_columns( $filter, @column_names ); |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
Returns a list of array references, each of which correspond to a field name |
539
|
|
|
|
|
|
|
column. The order of array references correspond to the order of parameters |
540
|
|
|
|
|
|
|
passed in, e.g. a call to |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
$lf->get_arrayof_columns( "file name", "file type"); |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
would produce a data structure like this |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
[ |
547
|
|
|
|
|
|
|
[ filename1, filename2, ... ], |
548
|
|
|
|
|
|
|
[ filetype1, filetype2, ... ] |
549
|
|
|
|
|
|
|
] |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=item C |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
$lf->get_hashof_columns( @column_names ); |
554
|
|
|
|
|
|
|
$lf->get_arrayof_columns( $filter, @column_names ); |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
Returns a hash references (or list which can be assigned to a hash). The hash |
557
|
|
|
|
|
|
|
keys are the column names specified in the parameters, the hash values are array |
558
|
|
|
|
|
|
|
references with the column values. E.g. a call to |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
$lf->get_hashof_columns( "file name", "file type"); |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
would produce a data structure like this |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
{ |
565
|
|
|
|
|
|
|
"file name" => [ filename1, filename2 ], |
566
|
|
|
|
|
|
|
"file type" => [ filetype1, filetype2 ] |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
The hash keys returned are exactly of the same format as passed in via the |
570
|
|
|
|
|
|
|
parameters, so passing in a single character will B create a full field |
571
|
|
|
|
|
|
|
name key. E.g. |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
$lf->get_hashof_columns( "file_name", "t"); |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
will produce this |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
{ |
578
|
|
|
|
|
|
|
"file_name" => [ filename1, filename2 ], |
579
|
|
|
|
|
|
|
"t" => [ filetype1, filetype2 ] |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
=item C |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
$lf->get_hashof_rows( $key, @column_names ); |
585
|
|
|
|
|
|
|
$lf->get_arrayof_rows( $filter, $key, @column_names ); |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
Returns a hash reference (or a list which can be assigned to a hash). The hash |
588
|
|
|
|
|
|
|
keys are the value of the field which is given as the first parameter. The hash |
589
|
|
|
|
|
|
|
values are references to arrays, each of which contain a row of the requested |
590
|
|
|
|
|
|
|
fields in a hash; e.g. a call to |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
$lf->get_hashof_rows( "process id", "file name", "t" ); |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
would produce a data structure like this |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
{ |
597
|
|
|
|
|
|
|
pid1 => [ |
598
|
|
|
|
|
|
|
{ |
599
|
|
|
|
|
|
|
"file name" => filename1, |
600
|
|
|
|
|
|
|
"t" => filetype1 |
601
|
|
|
|
|
|
|
}, |
602
|
|
|
|
|
|
|
{ |
603
|
|
|
|
|
|
|
"file name" => filename2, |
604
|
|
|
|
|
|
|
"t" => filetype2 |
605
|
|
|
|
|
|
|
}, |
606
|
|
|
|
|
|
|
], |
607
|
|
|
|
|
|
|
pid2 => [ |
608
|
|
|
|
|
|
|
{ |
609
|
|
|
|
|
|
|
"file name" => filename3, |
610
|
|
|
|
|
|
|
"t" => filetype3 |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
] |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
=back |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
=head1 DIAGNOSTICS |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
=over |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
=item C<< %s is not in the list of fields returned by lsof >> |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
You requested a field which was not in the list of fields returned by the lsof |
626
|
|
|
|
|
|
|
binary. Check that you spelt the field name correctly and that it is in the list |
627
|
|
|
|
|
|
|
of field names specified in the C docs. Also check that the field |
628
|
|
|
|
|
|
|
name is supported on the platform you are running lsof on. |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
=item C<< Invalid filter specified for "%s" >> |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
You specified an invalid filter. Valid filters are strings, numbers or |
633
|
|
|
|
|
|
|
references to regular expressions or subroutines. See the documentation on |
634
|
|
|
|
|
|
|
"Filters" above. |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
=back |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=head1 CONFIGURATION AND ENVIRONMENT |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
Unix::Lsof::Result requires no configuration files or environment variables. |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
=head1 DEPENDENCIES |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
Unix::Lsof::Result requires the following modules: |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
=over |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=item * |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
version |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
=back |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
=head1 INCOMPATIBILITIES |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
None reported. |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=head1 BUGS AND LIMITATIONS |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
Please report any bugs or feature requests to |
665
|
|
|
|
|
|
|
C, or through the web interface at |
666
|
|
|
|
|
|
|
L. |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
No bugs have been reported so far. As with C, there are a number of |
669
|
|
|
|
|
|
|
improvements that could be made to this module, particularly with regards to |
670
|
|
|
|
|
|
|
filtering. Further development is almost certainly strictly "develop by |
671
|
|
|
|
|
|
|
bugreport", so if you want a feature added, please open a wishlist item in the |
672
|
|
|
|
|
|
|
RT web interface and let me know. I'm more than happy to do more work on this |
673
|
|
|
|
|
|
|
module, but want to see what concrete improvements people would like to have. |
674
|
|
|
|
|
|
|
As always, patches are more than welcome. |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
A very heartfelt thanks to Vic Abell for writing C, it has been invaluable |
680
|
|
|
|
|
|
|
to me over the years. Many thanks as always to http://www.perlmonks.org, the |
681
|
|
|
|
|
|
|
monks continue to amaze and enlighten me. A very special thanks to Damian |
682
|
|
|
|
|
|
|
Conway, who (amongst other things) recommends writing module documentation |
683
|
|
|
|
|
|
|
at the same time as code (in his excellent book "Perl Best Practices"). I didn't |
684
|
|
|
|
|
|
|
follow that advice and as a result writing these docs was more painful and |
685
|
|
|
|
|
|
|
error-prone than it should have been. Please Mr. Conway, for the next edition |
686
|
|
|
|
|
|
|
could you put more emphasis on that recommendation so that dolts like me get |
687
|
|
|
|
|
|
|
it the first time? |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
=head1 AUTHOR |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
Marc Beyer C<< >> |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
=head1 LICENCE AND COPYRIGHT |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
Copyright (c) 2008-2013,2009, Marc Beyer C<< >>. All rights reserved. |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or |
698
|
|
|
|
|
|
|
modify it under the same terms as Perl itself. See L. |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=head1 DISCLAIMER OF WARRANTY |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY |
704
|
|
|
|
|
|
|
FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN |
705
|
|
|
|
|
|
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES |
706
|
|
|
|
|
|
|
PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
707
|
|
|
|
|
|
|
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
708
|
|
|
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE |
709
|
|
|
|
|
|
|
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH |
710
|
|
|
|
|
|
|
YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL |
711
|
|
|
|
|
|
|
NECESSARY SERVICING, REPAIR, OR CORRECTION. |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
714
|
|
|
|
|
|
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |
715
|
|
|
|
|
|
|
REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE |
716
|
|
|
|
|
|
|
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, |
717
|
|
|
|
|
|
|
OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE |
718
|
|
|
|
|
|
|
THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING |
719
|
|
|
|
|
|
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A |
720
|
|
|
|
|
|
|
FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF |
721
|
|
|
|
|
|
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
722
|
|
|
|
|
|
|
SUCH DAMAGES. |