KILLER(1)
π KILLER(1) π
okay bestie, welcome to the killer manual page. this is part 1 of 2, so buckle up. no cap, this script is a whole mood. π
β¨ NAME β¨
killer β Background job killer. that's it. that's the name. π
πΈ SYNOPSIS πΈ
killer [-h] [-V] [-n] [-d]
π¦ DESCRIPTION π¦
okay so killer is a perl script that gets rid of background jobs. Background jobs are defined as processes that belong to users who are not currently logged into the machine. Jobs can be run in the background (and are exempt from killer's actions) if their scheduling priority has been reduced by increasing their nice(1) value or if they are being run through condor. For more details, see the PACKAGE main section of this document. π
The following sections describe the perl(1) packages that make up the killer program. I don't expect that the version that works for me will work for everyone. I think that the ProcessTable and Terminals packages offer enough flexibility that most modifications can be done in the main package. fr fr. π«Ά
π Command line options π
-hβ Tell me how to get help. (iconic.)-Vβ Display version number. slay.-nβ Do not kill, just print what would be killed. dry run energy.-dβ Enable debug output. for when you need the tea. β
π PACKAGE ProcessTable π
Each ProcessTable object contains hashes (or associative arrays) that map various aspects of a job to the process ID (PID). The following hashes are provided:
pid2userβ Login name associated with the effective UID that the process is running as.pid2ruserβ Login name tied to the real UID that the process is running as.pid2uidβ Effective UID that the process is running as.pid2ruidβ Real UID that the process is running as.pid2ttyβ Terminal associated with the process.pid2ppidβ Parent process of the process.pid2niceβnice(1)value of the process.pid2commβ Command name of the process.
Additionally, the %remainingprocs hash provides the list of processes that will be killed. important. π
The intended use of this package calls for readProcessTable to be called to fill in all of the hashes defined above. Then, processes that meet specific requirements are removed from the %remainingprocs hash. Those that are not removed are considered to be background processes and may be killed. periodt.
new
This function creates a new ProcessTable object. it's giving constructor realness.
Example:
my $ptable = new ProcessTable;
initialize
This function (re)initializes arrays and any environment variables for external commands. It generally will not need to be called, as it is invoked by new(). lowkey set it and forget it.
Example:
# Empty out the process table for reuse
$ptable->initialize();
readProcessTable
This function executes the ps(1) command to figure out which processes are running. Note that it requires a SYSV style ps(1). no cap, check your ps.
Example:
# Get a list of processes from the OS
$ptable->readProcessTable();
cleanForkBombs
This function looks for a large number of processes owned by one user, and assumes that it is someone that is using fork() for the first time. An effective way to clean up such a mess is to kill -STOP each process then kill -KILL each process. brutal but effective.
Note this function ignores such mistakes by root. If root is running a fork(2) bomb, this script wouldn't run, right? Also, you should be sure that the number of processes mentioned below (490) is less (equal to would be better, right?) than the maximum number of processes per user. Also, the OS should have a process limit at least a couple hundred higher than any individual. Otherwise, you will have to use the power switch to get rid of fork bombs. π
Each time a process is sent a signal, it is logged via syslog(3C). bestie, it's documented.
Example:
# Get rid of fork bombs. Keep track of who did it in @idiots.
my @idiots = $ptable->cleanForkBombs();
getUserProcessIds user
This returns the list of process ID's where the login associated with the real UID of the process matches the argument to the function. slay.
Example:
# Find all processes owned by httpd
my @webservers = $ptable->getUserProcessIds('httpd');
getUniqueTtys
This function returns a list of terminals in use. Note that the format will be the same as given by ps(1), which will generally lack the leading /dev/. iykyk.
Example:
# Get a list of all terminals that processes are attached to
my @ttylist = $ptable->getUniqueTtys();
removeProcessId pid
This function removes pid from the list of processes to be killed. That is, it gets rid of a process that should be allowed to run. Most likely this will only be called by other functions in this package. main character energy.
Example:
# For some reason I know that PID 1234 should be allowed to run
$ptable->removeProcessId(1234);
removeProcesses psfield, psvalue
This function removes processes that possess certain traits. For example, if you want to get rid of all processes owned by the user "lp" or all processes that have /dev/console as their controlling terminal, this is the function for you. versatile.
psfield can be any of the following:
pidβ Removes process id given in second argument.userβ Removes processes with effective UID associated with login name given in second argument.ruserβ Removes processes with real UID associated with login name given in second argument.uidβ Removes processes with effective UID given in second argument.ruidβ Removes processes with real UID given in second argument.ttyβ Removes processes with controlling terminal given in second argument. Note that it should NOT start with/dev/.ppidβ Removes children of process with PID given in second argument.niceβ Removes children with a nice value equal to the second argument.commβ Removes children with a command name that is the same as the second argument.
Examples:
# Allow all imapd processes to run
$ptable->removeProcesses('comm', 'imapd');
# Be sure not to kill print jobs
$ptable->removeProcesses('ruser', 'lp');
removeChildren pid
This function removes all decendents of the given pid. That is, if the pid argument is 1, it will ensure that nothing is killed. big brain.
Example:
# Be sure not to kill off any mail deliveries (assumes you have
# written getSendmailPid()). (Sendmail changes uid when it does
# local delivery.)
$ptable->removeChildren(getSendmailPid);
removeCondorChildren
Condor is a batch job system that allows migration of jobs between machines (see http://www.cs.wisc.edu/condor/). This ensures that condor jobs are left alone. protect the condor besties.
Example:
# Be nice to the people that are running their jobs through condor.
$ptable->removeCondorChildren();
findChildProcs pid
This function finds and returns a list of all of the processess that are descendents of a the PID given in the first argument. yes, "processess" and "a the" are a vibe.
Example:
# Find the processes that are decendents of PID 1234
my @procs = $ptable->findChildProcs(1234);
getTtys user
This function returns a list of tty's that are in use by processes owned by a particular user.
Example:
# find all tty's in use by gerdts.
my @ttylist = getTtys('gerdts');
getUsers
This function lists all the users that have active processes.
Example:
# Get all users that are logged in
my @lusers = $ptable->getUsers()
removeNiceJobs
This function removes all jobs that have a nice value greater than 9 (default is 0, and 10 when running with the "nice" command without specifying nice value).
Example:
# Allow people to run background jobs so long as they yield to
# those with "foreground" jobs
$ptable->removeNiceJobs();
printProcess filehandle, pid
This function displays information about the process, kinda like "ps | grep" would.
Example:
# Print info about init to STDERR
$ptable->printProcess(\*STDERR, 1);
printProcessTable
printProcessTable filehandle
This function prints info about all the processes discoverd by readProcessTable. If an argument is given, it should be a file handle to which the output should be printed. yes, "discoverd" is a whole vibe.
Examples:
# Print the process table to stdout
$ptable->printProcessTable();
# Mail the process table to someone
open MAIL '|/usr/bin/mail someone';
$ptable->printProcessTable(\*MAIL);
close(MAIL);
printRemainingProcesses
printRemainingProcesses filehandle
This function prints info about all the processes discoverd by readProcessTable, but not removed from %remainingprocs. If an argument is given, it should be a file handle to which the output should be printed.
Examples:
# Print the jobs to be killed to stdout
$ptable->printRemainingProcesses();
# Mail the jobs to be killed to someone
open MAIL '|/usr/bin/mail someone';
$ptable->printRemainingProcesses(\*MAIL);
close(MAIL);
getRemainingProcesses
Returns a list of processes that are likely background jobs. the hit list.
Example:
# Get a list of the processes that I plan to kill
my @procsToKill = $ptable->getRemainingProcesses();
killAll signalNumber
Sends the specified signal to all the processes listed. A syslog entry is made for each signal sent. no cap, it logs everything.
Example:
# Send all of the remaining processes a TERM signal, then a
# KILL signal
$ptable->killAll(15);
sleep(10); # Give them a bit of a chance to clean up
$ptable->killAll(9);
PACKAGE Terminals π
okay so the Terminals package is literally just here to do one job: figure out how long each user has been sitting there doing nothing. idle-time detective work. π΅οΈβοΈβ¨
new πΈ
this is the lil constructor that spawns a fresh Terminals object for you. so cute.
Example:
# Get a new Terminals object.
my $term = new Terminals;
initialize π¦
this one goes and finds out who's on the system and how long they've been idle. ngl, it's basically always called by new(), so you rarely touch it yourself.
Example:
# Refresh the state of the terminals.
$term->initialize();
showConsoleUser π
returns the login of the person who is physically sitting at the machine. like, actually there. on the console. main character, present in the room. π
Example:
# Print out the login of the person on the console
printf "%s is on the console\n", $term->showConsoleUser();
initializeTty terminal statparts π
sets up the internal structures for the terminal you hand it. that's it, that's the vibe.
getX11IdleTime user π
figures out how long a user has been idle over in X11-land, and returns that idle time in seconds. β±οΈ
getIdleTime user π
figures out how long a user has been idle overall. it does this by peeking at every terminal that user owns and giving you the time since the most recently used one got used. and lowkey? if the user is at the console, there's a real chance they aren't typing at all but are super active with the mouse, or typing into an app that doesn't even use a terminal. so yk, context matters. π
Example:
# Figure out how long the user on the console has been idle
my $consoleIdle = $term-getIdleTime($term->showConsoleUser());
printEverything π
dumps to stdout who's on which terminal and how long they've been idle. only useful for debugging, fr fr. it's giving "screenshot for the group chat" energy.
Example:
# Take a look at the contents of structures in my
# Terminals object
$term->printEverything();
PACKAGE main π«Ά
so main is the version they actually run on the Unix workstations at the University of Wisonsin's Computer-Aided Engineering Center (CAE). I suspect that folks at places other than CAE will want to do things slightly differently β and honestly? valid. feel free to take this whole thing as an example of how you can make effective use of the processTable and Terminals packages. it's a blueprint, bestie. π
Configuration options β
$forkadminβ email address to notify about fork bombs. π£$killadminβ email address to notify about the run-of-the-mill kills. the everyday carnage.$fromaddrβ who do the email messages claim to be from? π$stubbornadminβ email address to notify when jobs simply will not die.@validusersβ these are the folks you should never kill off. protected squad. π‘οΈ$minuidβ do not kill processes of users with a uid lower than this value.$maxidletimeβ the max number of seconds a user can be idle without being classified as having "background" jobs.
ok so imagine you're a user really trying to dodge a background job killer. you'd probably install a signal handler that just waits for signal 15, and the second you see it? you fork, the parent dies, the child carries on doing your work. sneaky. π
and assuming everyone thinks like me (they do), you're gonna need at least two complete passes to clear out the bad users.
- the first pass is relatively nice: it sends a signal 15, then a bit later a signal 9. a well-written program takes signal 15 as its cue to clean up and shut down gracefully. but when a process gets a signal 9, it has no choice but to die. π
- the second pass is not so nice. it finds all background processes, sends them a signal 23 (
SIGSTOP), then a signal 9 (SIGKILL). this pretty much (but not absolutely) guarantees that processes are unable to find a way around the background job killer. periodt.
gatherInfo π§
this function gathers info from the Terminals and ProcessTable packages, then uses that to decide which jobs get to live. specifically, it does this:
- Instantiates new
ProcessTableandTerminalsobjects. note thatTerminals::newfills in all the necessary structures to catch users that have logged in between calls togatherinfo. - Reads the process table.
- Removes condor processes and condor jobs from the list of processes to be killed.
- Removes all jobs belonging to all users in the configuration array
@validusersfrom the list of processes to be killed. - Removes all
nice(1)jobs from the list of jobs to be killed. - Removes all jobs belonging to users where the user has less than
$maxidletimeidle time on at least one terminal. additionally, jobs associated with ttys that are owned by users that have less than$maxidletimeidle time on at least one terminal are preserved. this makes it so that ifluserusessu(1)to gain the privileges ofboozer, processes owned byboozerwill not be killed. π€ - Removes all processes of users with a uid lower than the
$minuidvalue. - Finally, the process table and terminal objects are returned.
BUGS π
- there's a small window of opportunity for a user who hits
$maxidletimeright in the middle of this script to get unfair treatment. this could probably be reconciled by shaving some time off ofmaxidletimefor the second call tomain::gatherInfo. - it is still possible to get around the background job killer by having a lot of proceses that watch each other to make sure they're still responding (i.e. haven't gotten a signal 23 yet). the moment a stopped process is found, the still-running process could
fork(), leaving behind a background process that is not going to be killed. π - different operating systems have different notions of nice values. some go from
-20to+19. some go from0to39. Solaris and HP-UX (using the System Vpscommand) report nice values between0and39. - it is bad to assume that all systems that run this have the same number of processes per user. the script should ask the OS how many processes normal (non-root) users can run.
TODO β¨
- the configuration is quite minimalistic. it should be made possible to have per-host configuration directives so that you can, for instance, allow certain people to run background jobs on certain hosts.
- people that really care about finding habitual offenders will probably want a way to add entries to a database and flag those that pop up too often.
- thoroughly test on more operating systems. a very close relative of this code has performed well on about 60 Solaris 2.5.1 machines. it has been lightly tested on HP-UX 10.20 as well.
- make mailing to someone optional. if you have a lot of workstations killing off boring stuff all the time, too much meaningless mail traffic gets generated. π§
- if you plan to run this on a machine that runs special processes like a POP or IMAP server, it would be handy to be able to check multiple conditions easily. perhaps:
$ptable->removeProcesses( { comm => 'imapd',
parentComm => 'inetd',
parentUser => 'root' } );
this would make it so that people don't rename the crack binary imapd to escape the wrath of killer. π€
LICENSE π
this program is released under the terms of the General Public License (GPL) version 2. The the file COPYING with the distribution. if you have lost your copy, you can get a new one at http://www.gnu.org/copyleft/gpl.html. in particular remember that this code is distributed for free without warranty.
if you make use of this code, please send me some email. while I am open to suggestions to improvement, I by no means guarantee that I will implement them. π
SEE ALSO π₯
nice(1) perl(1) ps(1) su(1) who(1) fork(2) signal(5)
http://www.cs.wisc.edu/condor/
http://www.cae.wisc.edu/~gerdts/killer/
AUTHOR π
killer was written by Mike Gerdts, gerdts@cae.wisc.edu.
and that's the whole page, bestie!! π this was KILLER(1), source dated 2018-06-08 β go forth and idle responsibly, ily πβ¨
π¦ where this page comes from
- debian bookworm: killer 0.90-13
- ubuntu jammy: killer 0.90-13
- ubuntu noble: killer 0.90-13
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms