#! /usr/bin/csh -f # # realnice - # # realnice "watches" a program who's `ps -lj` listing contains a given string (name). # Whenever someone logged onto the console is 1) not idle, and 2) not the owner of realnice, # the "watched" job will be stopped. # # Also, "dominant" program and user names may be specified on the realnice command line # (after "name"). (The presence of these "dominators" is asessed by greping a `ps -elf`) # If any matching programs are running, realnice will stop it's watched program. # # If the system is idle, alone, and no dominant programs are running, realnice will restart # the "watched" job again, and continue monitoring. # The idle timeout can be set in the "timeout" environment variable: # # setenv timeout 0 # # will disable idle monitoring and just look for dominant processes # # debugging variables #set debug #set pretend set noglob set alone if(! $?timeout) set timeout = 10 if(! $?HOST) set HOST = `hostname` set minidle set dominant # there must be a command-line argument if ($1 == "") then echo "usage: realnice [ pid | name ] [ domlist ]" echo "" echo "realnice will stop a process matching name while someone is on the console (and not idle)" echo "will also stop a process matching name if a process in domlist is running" echo "" exit 2 endif # user-specified test run if ($1 == realnice) then echo "realnice - diagnostic mode..." set debug set pretend set argv[1] = sh endif again: # get filtered process listing from ps set process = `ps -lju $user | grep $1 | grep -v $$` # make sure the indicated process is actually running if ($#process == 0) then if($?debug) echo $1 "is not running..." sleep 30 goto again endif #extract PGID set PGID=$process[6] # (redundant) keep updating process status if($process[2] == "T") then set stopped if($?debug) echo $1, PGID = $PGID is stopped else unset stopped if($?debug) echo $1, PGID = $PGID is running endif # lost child processes might escape, send start and stop signals now if($?stopped) then if(! $?pretend) kill -STOP -$PGID else if(! $?pretend) kill -CONT -$PGID endif # querry system for activity (converting idle times to minutes) if ($?debug) echo "Querying system for idle times..." set idle = `w -sh | grep " :0" | grep -v $user | nawk '{if(NF > 4) {idle = substr($4, index($4, ":")+1) +0; idle += substr($4, 0, index($4, ":")-1) * 60; if($4 !~ /[a-z]/) print idle} else {print 0}}'` # see if there are any users logged in if ($#idle == 0) then set alone if ($?debug) echo "realnice is alone on" $HOST else # someone (other than $user) is currently on the console unset alone # see if they have been idle for a while set minidle = 99999 foreach num ( $idle ) if($num < $minidle) set minidle = $num end if($?debug) echo $HOST "has been idle for" $minidle "minutes, timeout is" $timeout "minutes." if(($minidle != 99999)&&($minidle >= $timeout)) then set alone if($?debug) echo "realnice is not alone, but" $HOST "is idle" endif endif # look for indicated "dominant" processes to stop $1 foreach key ( $* ) if ($key != $1) then set dominant = `ps -el | grep -v $user | grep -v $$ | grep "$key"` if($#dominant > 16) then if($dominant[2] != "T") then if($?debug) echo dominant program $dominant[16] found running by $dominant[3] unset alone else if($?debug) echo dominant program $dominant[16] found idle, run by $dominant[3] endif endif endif end # stop the process if we are not alone if( (! $?alone) && (! $?stopped)) then if( $?debug ) echo stopping $1 process group with PGID=$PGID at `date` if(! $?pretend) kill -STOP -$PGID set stopped endif # restart the process if we are alone again if ($?alone && $?stopped) then if( $?debug ) echo restarting $1 process group with PGID=$PGID at `date` if(! $?pretend) kill -CONT -$PGID unset stopped endif # wait a bit if($?alone) then # ever vigilant of new logins sleep 30 else # no need to keep checking until $timeout has expired sleep `expr 60 \* $timeout + 60` endif # continue monitoring goto again