#!/usr/local/bin/perl
# process-cleaner.pl
# A rude attempt to purge stale processes.
# The script assumes that a process that persists without a change
# in CPU consumption is a candidate and attempts to kill it.
#
# Expected inputs (command line):
# a list of process names to consider
#
# Other data files:
# a list of processes from our last invocation
#
# 05/15/19igorl@ayradyss.org99 Version 1.1
# This script is free, public domain, no strings attached
# Igor S. Livshits <mailto:igorl@ayradyss.org>
# Define some global variables
#
$true= (1==1);
$false= (1==0);
$openToWrite= ">";
$newLine= "\n";
$commentDelimiter= "#";
$comma= ",";
$space= " ";
$tempDirectory= "/var/tmp/";
$candidatesFileName= $tempDirectory . "candidates";
$oldCandidatesFileName= $tempDirectory . "old_candidates";
$ps= "ps -ea -o pid,user,time,stime,comm";
# Read in acceptable processes
#
@processFilters= @ARGV;
# Preserve previous candidates
#
if (-T $candidatesFileName)
{ # previous files exists, rename it
$result= rename($candidatesFileName, $oldCandidatesFileName) or
die "Failed to preserve previous candidates list <$oldCandidatesFileName>";
}
# Check current processes and dump candidates to a file
#
@candidates= (); # clear our list of candidates
open(PROCESSES, "$ps |") or die "Cannot read current processes";
while ($candidate= <PROCESSES>)
{
foreach $filter (@processFilters)
{ # add the process if it matches a filter
if ($candidate=~ /$filter$/)
{
push(@candidates, $candidate);
last; # skip to the next candidate
}
}
}
close(PROCESSES);
@candidates= sort(@candidates);
# Save our list of current candidates
#
open(CANDIDATES, $openToWrite.$candidatesFileName) or die "Cannot save data.";
print(CANDIDATES @candidates);
close(CANDIDATES);
# Find persistent candidates and mark them for murder
#
exit unless (-T $oldCandidatesFileName); # skip if we lack comparison data
exit unless @candidates;
$index= 0; # reset our array index
@victims= (); # clear our victim list
open(OLD, $oldCandidatesFileName) or die "Cannot access previous candidates";
CandidateCheck:
while (<OLD>)
{ # both are sorted; so, check in parallel
next # fast forward past candidates
if ($_ lt @candidates[$index]);
while ($_ gt @candidates[$index])
{ # fast forward current candidates
last CandidateCheck # reached the end of current candidates
if (++$index == @candidates);
}
if ($_ eq @candidates[$index])
{ # found a match
push(@victims, $_);
}
}
close(OLD);
# Extract process IDs from the process report
#
@victimIDs= ();
foreach $victim (@victims)
{
$victimID= $victim; # copy to preserve orignal formatting
while ($victimID =~ s/^\s+//) {}; # kill leading white spaces
($victimID)= split($space, $victimID);
push(@victimIDs, $victimID);
};
# Notify operators while killing victims
#
if (@victims)
{ # make sure we have at least one
print "Victim list:", $newLine, @victims, $newLine;
$result= kill 'TERM', @victimIDs;
if ($result == 1)
{
print "One process was successfully signaled.$newLine";
}
else
{
print "$result processes were successfully signaled.$newLine";
}
}
# Terminate gracefully
#
exit;