#!/local/gnu/bin/perl -w # process_killer.pl # # Interactive process killer utilizing the Tk GUI toolkit. # Uses the system's "ps" command to get a list of the currently-running processes, # and the system's "kill" command to send them signals. # # My machine's "ps", when run with "ps ux", gives output like the following: # USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND # falkkin 531 0.0 1.4 2316 1380 tty1 S 08:53 0:00 -bash # # On Solaris 2.7 "ps -Af" output looks like: # UID PID PPID C STIME TTY TIME CMD # root 0 0 0 03:02:12 ? 0:00 sched # baw 21539 16592 0 08:53:12 pts/7 0:00 tcsh # baw 16914 1 4 08:07:46 ? 4:16 /local/comm476/netscape # Please note that there is whitespace before the username # # My machine's "kill" is of the form "kill -s $signal $pid". # Supported signals include TERM, STOP, CONT, INT, HUP, and KILL. # # You'll need to modify this script if your "ps" command formats output differently # or your "kill" command has different syntax. # Eventually, I hope to make this script more portable. # # Authored by Colin McMillen (e-mail: colin at jenovaproject.org) and released # into the public domain. You may use, copy, redistribute, and modify this program # without any restrictions. # # use strict; use Tk; my $VERSION = v0.1; # Choose the options to send to "ps". Defaults to "ps ux". # BAW - Solaris 2.7 on SPARC's ps doesn't support ps ux, changed to ps -Af my $PS_OPTIONS = $ARGV[0] || "-Af"; # Index (starting from 0) of the fields for process ID and command name. # BAW - Added support for showing only your processes my $OWNER = 1; my $PID_FIELD = 2; my $COMMAND_FIELD = 8; my $USERNAME = getpwuid $<; # Create the main window and add an informational label. my $top = MainWindow->new(); $top->title("process_killer.pl"); $top->Label(text => "Double-click on the process you would like to kill.")->pack(); # Create a frame to hold the process list and its scrollbar. my $frame1 = $top->Frame()->pack(fill => "both", expand => "y"); # Get the actual process list and discard the first line of output (which # contains informational headers that we want to ignore). my @processes = `ps $PS_OPTIONS`; shift @processes; # Use the process list to create a listbox. Add the listbox to $frame1. my $process_list = $frame1->Listbox(width => 80, height => 15)->pack(side => "left", fill => "both", expand => "y"); # Split each line of output into fields, based on whitespace. Then, get the # process ID and command name out of the fields, and add them to the listbox. # BAW - Changed output format to USER PID COMMAND foreach my $process (@processes) { my (@fields) = split(/\s+/, $process); my $pid = $fields[$PID_FIELD]; my $owner = $fields[$OWNER]; my @command = @fields[ $COMMAND_FIELD .. @fields-1 ]; my $command = join(" ", @command); # BAW - Show only my processes unless($owner eq $USERNAME){ next; } $process_list->insert("end","$owner $pid $command"); } # Bind a double-click on the listbox to the kill() subroutine. $process_list->bind("", \&kill); # Create a scrollbar to scroll the listbox vertically and add it to $frame1. my $scrollbar = $frame1->Scrollbar(orient => "vertical", width => 10, command => ["yview", $process_list], )->pack(side => "left", fill => "y"); $process_list->configure(yscrollcommand => ["set", $scrollbar]); # Create a frame to hold radiobuttons for choosing a signal. my $frame2 = $top->Frame()->pack(); # Create the radiobuttons inside $frame2. $frame2->Label(text => "Choose a signal:")->pack(side => "left"); my $signal = "TERM"; $frame2->Radiobutton(variable => \$signal, text => "Terminate", value => "TERM")->pack(side => "left"); $frame2->Radiobutton(variable => \$signal, text => "Stop", value => "STOP")->pack(side => "left"); $frame2->Radiobutton(variable => \$signal, text => "Continue", value => "CONT")->pack(side => "left"); $frame2->Radiobutton(variable => \$signal, text => "Interrupt", value => "INT")->pack(side => "left"); $frame2->Radiobutton(variable => \$signal, text => "Hangup", value => "HUP")->pack(side => "left"); $frame2->Radiobutton(variable => \$signal, text => "Kill", value => "KILL")->pack(side => "left"); # BAW - Refresh the PS list every 10 seconds $process_list->repeat(10000,\&refresh_list); # Hand control of the program off to the GUI. MainLoop(); # Subroutine called when a field in the listbox is double-clicked. # The process ID of the process is the first field in the listbox's active item. # The signal to send the process is set by the radiobuttons and stored in # the variable $signal. sub kill { my $process = $process_list->get('active'); my $trash; my $pid; ($trash, $pid) = split(/ /, $process); return unless $pid; system("kill -s $signal $pid"); } # BAW - The callback routine for the repeat method # BAW - Redraws the listbox with updated ps info sub refresh_list{ $process_list->delete(0, 'end'); my @processes = `ps $PS_OPTIONS`; shift @processes; foreach my $process (@processes) { my(@fields) = split(/\s+/, $process); my $pid = $fields[$PID_FIELD]; my $owner = $fields[$OWNER]; my @command = @fields[ $COMMAND_FIELD .. @fields-1 ]; my $command = join(" ", @command); unless($owner eq $USERNAME){ next; } $process_list->insert("end","$owner $pid $command"); } }