Cover V06, I01
Article
Figure 1
Figure 2
Listing 1
Listing 2

jan97.tar


Listing 1: KP script

#!/usr/bin/wish -f
#
# -----------------------------------------
# KillProc -- signal a hung/runaway process
# -----------------------------------------
#

lappend auto_path "/usr/local/lib/tkextra"

# ------------------------------
# Application-specific globals
# ------------------------------

# arguments for the 'ps' command (change to suite your 'ps')
# SysV:
set ps_user "-fu"
set ps_all "-ef"

# pre-SysV:
# set ps_user "-au | grep "
# set ps_all "-ax"

# initial values for menu options
set user   $env(LOGNAME)
set signal -INT

# ------------------------------
# Application-specific routines
# ------------------------------

#
# Get the selected line(s) from the list-box,
# extract the pid, signal the process
#
proc kill_proc {} {
global user signal

#
# Get the list of selected line numbers
# If the list is empty, nothing is selected, so return
#
set sellist [.ps.list curselection]
if {[llength $sellist] == 0} {
return
}

#
# For each entry in the selected-lines-list,
# Get the line, extract the pid, append to a list of PID's
# (optional: filter out critical processes that shouldn't be touched)
#
foreach index $sellist {
set line [.ps.list get $index]
scan $line "%s %d" uid pid
if {$pid <= 0} {
continue
}

# Use this to skip over "must-not-kill" processes:
# if {[string match "*xyz*" $line]} {
# err "$line\n\nLooks like a 'xyz' process;\n Should not kill it!"
#  continue
# }

lappend pid_list $pid
}

#
# Construct a "kill" command line,
# Execute it and get the error return
#
set cmd [list exec kill $signal $pid_list]
set ret [catch $cmd err]

#
# If there was a problem signalling a process,
# Let the user know
#
if {$ret == 1} {
msg "Could not kill a process;\nit's already gone?"
return
}

#
# Refresh the process list
#
scan_proc
}

#
# Do a "ps", collect the output, put into a list-box
#
proc scan_proc {} {
global user ps_user ps_all

#
# Generate the "ps" command line
#
if {$user == "Any"} {
set cmd "|ps $ps_all | sort"
} {
set cmd "|ps $ps_user $user | sort"
}

#
# Evaluate the command line
# Get the resulting list of lines
# Fill the list-box with the lines
#
fill_list  .ps.list  [read_list $cmd]  0
}


# ------------------------------
# GUI Specific Routines
# ------------------------------


#
# Make the main control panel -- fill it with some controls
#
proc make_control_panel { } {
global user signal

#
# Setup some window-manager options
#
wm title    . "Process Killer"
wm iconname . "KP"
wm command  . "KillProc"

#
# Make the menu
#
menu_bar .mbar 0 \
{menu File}    \
{cmd  Quit exit}   \
{end left}    \
{menu Signals}    \
{radio " 1 Hangup"     signal "-HUP"}  \
{radio " 2 Interrupt"  signal "-INT"}  \
{radio " 3 Quit"       signal "-QUIT"} \
{radio " 9 Kill"       signal "-KILL"} \
{radio "14 Alarm"      signal "-ALRM"} \
{radio "15 Terminate"  signal "-TERM"} \
{radio "23 Stop"       signal "-STOP"} \
{radio "24 Term. Stop" signal "-TSTP"} \
{radio "25 Continue"   signal "-CONT"} \
{end left}   \
{menu User}   \
{radio Any  user Any}  \
{radio Me  user $user}  \
{sep}      \
{radio moe  user moe}  \
{radio curly  user curly}  \
{radio larry  user larry}  \
{end left}

#
# Make the scrolling list-box
#
mk_list .ps kill_proc

#
# Make the control buttons
#
buttons .cmd  ""  left  0 \
{width 4}   \
{cmd "Scan" scan_proc} \
{cmd "Kill" kill_proc} \
{cmd "Quit" exit }

# pack menu   -> top
# pack btns   -> on the bottom
# pack scroll-box -> in the middle

pack .mbar  -side top     -fill x
pack .ps    -side top     -fill both -expand yes
pack .cmd   -side bottom  -fill x
}


# ------------------------------
# M A I N L I N E
# ------------------------------

make_control_panel
scan_proc

# wait for the User menu item to change, then refresh the list-box
while {1} {
tkwait variable user
scan_proc
}

# ------------------------------
# The End.
# ------------------------------