delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
my $LSOF = '/usr/bin/lsof -F0';
-my $VERSION = '0.2012042101';
+my $VERSION = '0.2015012901';
# nagios exit codes
my $OK = 0;
exit $UNKNOWN;
}
+sub convert_time {
+ my $in = shift;
+ my ($ticks, $unit) = ($in =~ /^(\d+)([smhdw]?)$/);
+
+ if ($unit eq 's' || $unit eq '') { }
+ elsif ($unit eq 'm') { $ticks *= 60; }
+ elsif ($unit eq 'h') { $ticks *= 60*60; }
+ elsif ($unit eq 'd') { $ticks *= 60*60*24; }
+ elsif ($unit eq 'w') { $ticks *= 60*60*24*7; }
+ else { die "Invalid unit '$unit' in '$in'\n" }
+ return $ticks;
+}
+
+
if (!GetOptions (
- '--help' => \$params->{'help'},
- '--version' => \$params->{'version'},
- '--quiet' => \$params->{'quiet'},
- '--verbose' => \$params->{'verbose'},
- '--config=s' => \$params->{'config'},
+ '--help' => \$params->{'help'},
+ '--version' => \$params->{'version'},
+ '--quiet' => \$params->{'quiet'},
+ '--ignore-pid-namespaces' => \$params->{'ignore_pid_namespaces'},
+ '--verbose' => \$params->{'verbose'},
+ '--ignore-younger=s' => \$params->{'ignore_younger'},
+ '-v' => \$params->{'verbose'},
+ '--config=s' => \$params->{'config'},
)) {
- dief ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [--help|--version] [--verbose] [--quiet] [--config=<CONFIGFILE>]\n");
+ dief ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [--help|--version] [--ignore-pid-namespaces] [--verbose] [--quiet] [--config=<CONFIGFILE>]\n");
};
if ($params->{'help'}) {
- print "$PROGRAM_NAME: Usage: $PROGRAM_NAME [--help|--version] [--verbose] [--quiet] [--config=<CONFIGFILE>]\n";
+ print "$PROGRAM_NAME: Usage: $PROGRAM_NAME [--help|--version] [--ignore-pid-namespaces] [--verbose] [--quiet] [--config=<CONFIGFILE>]\n";
print "Reports processes that are linked against libraries that no longer exist.\n";
print "The optional config file can specify ignore rules - see the sample config file.\n";
+ print "Can optionally ignore processes from other PID namespaces.\n";
exit (0);
};
if ($params->{'version'}) {
dief("Config->ignorelist is not an array!\n");
}
-
my %processes;
sub getPIDs($$) {
close F;
return 0;
}
+sub getYoungProcesses() {
+ my $ignore_hash = {};
+ if (defined $params->{'ignore_younger'}) {
+ eval "use Proc::ProcessTable; 1" or die "We need Proc::ProcessTable to use --ignore-younger.\n";
+ my $min_age = convert_time($params->{'ignore_younger'});
+ my $cutoff = time() - $min_age;
+
+ my $process_table = new Proc::ProcessTable(enable_ttys => 0);
+ for my $p ( @{$process_table->table} ){
+ $ignore_hash->{$p->pid} = 1 if $p->start > $cutoff;
+ }
+ }
+ return $ignore_hash;
+}
+
+
+my $IGNORE_YOUNG_PROCESSES = getYoungProcesses();
+
+
+
my $INVSERVER = inVserver();
+my $PID_NS_SUPPORT = (-f '/proc/self/ns/pid');
+my $PID_NS;
+if ($PID_NS_SUPPORT and $params->{'ignore_pid_namespaces'}) {
+ $PID_NS = readlink('/proc/self/ns/pid');
+}
+
print STDERR "Running $LSOF -n\n" if $params->{'verbose'};
-open (LSOF, "$LSOF -n|") or dief ("Cannot run $LSOF -n: $!\n");
+open (LSOF, "$LSOF -n 2>/dev/null|") or dief ("Cannot run $LSOF -n: $!\n");
my @lsof=<LSOF>;
close LSOF;
if ($CHILD_ERROR) { # program failed
my %fields = map { m/^(.)(.*)$/ ; $1 => $2 } grep { defined $_ and length $_ >1} split /\0/, $line;
$process = $fields{c};
$pid = $fields{p};
- $user = $fields{L};
+ $user = $fields{L} || '<unknown>';
next;
}
+ if ($PID_NS_SUPPORT and $params->{'ignore_pid_namespaces'}) {
+ my $pidns = readlink('/proc/'.$pid.'/ns/pid');
+ next if (defined $pidns and $PID_NS ne $pidns);
+ }
+
unless ( $line =~ /^f/ ) {
dief("UNKNOWN strange line read from lsof\n");
# don't print it because it contains NULL characters...
my $inode = $fields{i};
my $path = $fields{n};
if ($path =~ m/\.dpkg-/ || $path =~ m/\(deleted\)/ || $path =~ /path inode=/ || $path =~ m#/\.nfs# || $fd eq 'DEL') {
+ my $deleted_in_path = ($path =~ m/\(deleted\)/ || $path =~ m/\.nfs/);
+ next if ($deleted_in_path && $fd =~ /^[0-9]*$/); # Ignore deleted files that are open via normal file handles.
+ next if ($deleted_in_path && $fd eq 'cwd'); # Ignore deleted directories that we happen to be in.
+
$path =~ s/^\(deleted\)//; # in some cases "(deleted)" is at the beginning of the string
for my $i (@{$config->{'ignorelist'}}) {
my $ignore = eval($i);
next LINE if $ignore;
}
next if ($INVSERVER && ($process eq 'init') && ($pid == 1) && ($user eq 'root'));
+ if (exists $IGNORE_YOUNG_PROCESSES->{$pid}) {
+ if ( $params->{'verbose'} ) {
+ print STDERR "ignoring young $process($pid) because of [$path]:\n";
+ print STDERR $line;
+ }
+ next LINE
+ }
if ( $params->{'verbose'} ) {
print STDERR "adding $process($pid) because of [$path]:\n";
print STDERR $line;