proc_watch

# 本代码是将ksh的协进程改为bash的协进程管理,
# bash4.0以后支持coprocesses(协进程)
# Auth:qfongv8
# Sites:selinuxplus.com
#
#代码如下:
# REV LIST:
#
# set -x # Uncomment to debug this script
# set -n # Uncomment to check syntax without ANY execution
#
####################################################
########## DEFINE FILES AND VARIABLES HERE #########
####################################################

typeset -u RUN_PRE_EVENT # Force to UPPERCASE
typeset -u RUN_STARTUP_EVENT # Force to UPPERCASE
typeset -u RUN_POST_EVENT # force to UPPERCASE

RUN_PRE_EVENT='Y' # A 'Y' will execute, anything else will not
RUN_STARTUP_EVENT='Y' # A 'Y' will execute, anything else will not
RUN_POST_EVENT='Y' # A 'Y' will execute, anything else will not

LOGFILE="/var/log/svmm.log"
[[ ! -s $LOGFILE ]] && touch $LOGFILE

SCRIPT_NAME=$(basename $0)
#TTY=$(tty)
TTY="/dev/null"
INTERVAL="1" # Seconds between sampling
JOBS=

####################################################
############# DEFINE FUNCTIONS HERE ################
####################################################
usage ()
{
echo -e "\n\n\t***** USAGE ERROR *****"
echo -e "\n\nUSAGE: $SCRIPT_NAME seconds process"
echo -e "\nWill monitor the specified process for the"
echo -e "specified number of seconds."
echo -e "\nUSAGE: $SCRIPT_NAME [-s|-S seconds] [-m|-M minutes]"
echo -e " [-h|-H hours] [-d|-D days] [-p|-P process]\n"
echo -e "\nWill monitor the specified process for number of"
echo -e "seconds specified within -s seconds, -m minutes,"
echo -e "-h hours and -d days. Any combination of command"
echo -e "switches can be used.\n"
echo -e "\nEXAMPLE: $SCRIPT_NAME 300 dsvmm"
echo -e "\n\nEXAMPLE: $SCRIPT_NAME -m 5 -p dsvmm"
echo -e "\nBoth examples will monitor the dtcalc process"
echo -e "for 5 minutes. Can specify days, hours, minutes"
echo -e "and seconds, using -d, -h, -m and -s\n\n"
}
####################################################
trap_exit ()
{
# set -x # Uncommant to debug this function
# Log an ending time for process monitoring
echo "INTERRUPT: Program Received an Interrupt...EXITING..." > $TTY
echo "INTERRUPT: Program Received an Interrupt...EXITING..." >> $LOGFILE
TIMESTAMP=$(date +%D@%T) # Get a new timestamp...
echo -e "MON_STOPPED: Monitoring for $PROCESS ended ==> $TIMESTAMP\n" \
>> $TTY
echo -e "MON_STOPPED: Monitoring for $PROCESS ended ==> $TIMESTAMP\n" \
>> $LOGFILE
echo -e "LOGFILE: All Events are Logged ==> $LOGFILE \n" > $TTY

# Kill all functions
JOBS=$(jobs -p)
if [[ ! -z $JOBS && $JOBS != '' && $JOBS != '0' ]]
then
kill $(jobs -p) 2>/dev/null 1>&2
fi
return 2
}
####################################################
pre_event_script ()
{
# Put anything that you want to execute BEFORE the
# monitored process STARTS in this function

: # No-OP - Needed as a placeholder for an empty function
# Comment Out the Above colon, ':'
svmmd stop && true
svmmd start
PRE_RC=$?
return $PRE_RC
}
####################################################
startup_event_script ()
{
# Put anything that you want to execute WHEN, or AS, the
# monitored process STARTS in this function

: # No-OP - Needed as a placeholder for an empty function
# Comment Out the Above colon, ':'

STARTUP_RC=$?
return $STARTUP_RC
}
####################################################
post_event_script ()
{
# Put anything that you want to execute AFTER the
# monitored process ENDS in this function

: # No-OP - Need as a placeholder for an empty function
# Comment Out the Above colon, ':'

POST_RC=$?
return $POST_RC
}
####################################################
# This function is used to test character strings

test_string ()
{
if (( $# != 1 ))
then
echo 'ERROR'
return
fi

C_STRING=$1

# Test the character string for its composition

case $C_STRING in

[0-9]) echo 'POS_INT' # Integer >= 0
;;
[-0-9]) echo 'NEG_INT' # Integer < 0 ;; [a-z]) echo 'LOW_CASE' # lower case text ;; [A-Z]) echo 'UP_CASE' # UPPER case text ;; [a-z]|[A-Z]) echo 'MIX_CASE' # MIxed CAse text ;; *) echo 'UNKNOWN' # Anything else ;; esac } #################################################### proc_watch () { # set -x # Uncomment to debug this function # This function does all of the process monitoring! while : # Loop Forever!! do case $RUN in 'Y') # This will run the startup_event_script, which is a function if [[ $RUN_STARTUP_EVENT = 'Y' ]] then echo "STARTUP EVENT: Executing Startup Event Script..."\ > $TTY
echo "STARTUP EVENT: Executing Startup Event Script..."\
>> $LOGFILE

startup_event_script # USER DEFINED FUNCTION!!!
RC=$? # Check the Return Code!!
if (( "RC" == 0 ))
then
echo "SUCCESS: Startup Event Script Completed RC - \
${RC}" > $TTY
echo "SUCCESS: Startup Event Script Completed RC - \
${RC}" >> $LOGFILE

else
echo "FAILURE: Startup Event Script FAILED RC - \
${RC}" > $TTY
echo "FAILURE: Startup Event Script FAILED RC - \
${RC}" >> $LOGFILE
fi
fi
declare -i PROC_COUNT='-1' # Reset the Counters
declare -i LAST_COUNT='-1'
# Loop until the process(es) end(s)

until (( "PROC_COUNT" == 0 ))
do

# This function is a Co-Process. $BREAK checks to see if
# "Program Interrupt" has taken place. If so BREAK will
# be 'Y' and we exit both the loop and function.

PROC_COUNT=$(ps aux | grep -v "grep $PROCESS" \
| grep -v $SCRIPT_NAME \
| grep $PROCESS | wc -l) >/dev/null 2>&1
#echo $PROC_COUNT > $TTY
if (( "LAST_COUNT" > 0 && "LAST_COUNT" != "PROC_COUNT" ))
then
# The Process Count has Changed...
TIMESTAMP=$(date +%D@%T)
# Get a list of the PID of all of the processes
PID_LIST=$(ps aux | grep -v "grep $PROCESS" \
| grep -v $SCRIPT_NAME \
| grep $PROCESS | awk '{print $2}')

echo "PROCESS COUNT: $PROC_COUNT $PROCESS\
Processes Running ==> $TIMESTAMP" >> $LOGFILE &
echo "PROCESS COUNT: $PROC_COUNT $PROCESS\
Processes Running ==> $TIMESTAMP" > $TTY
echo ACTIVE PIDS: $PID_LIST >> $LOGFILE &
echo ACTIVE PIDS: $PID_LIST > $TTY
fi
LAST_COUNT=$PROC_COUNT
sleep $INTERVAL # Needed to reduce CPU load!
done

RUN='N' # Turn the RUN Flag Off
TIMESTAMP=$(date +%D@%T)
echo "ENDING PROCESS: $PROCESS END time ==>\
$TIMESTAMP" >> $LOGFILE &
echo "ENDING PROCESS: $PROCESS END time ==>\
$TIMESTAMP" > $TTY

# This will run the post_event_script, which is a function

if [[ $RUN_POST_EVENT = 'Y' ]]
then
echo "POST EVENT: Executing Post Event Script..."\
> $TTY
echo "POST EVENT: Executing Post Event Script..."\
>> $LOGFILE &

post_event_script # USER DEFINED FUNCTION!!!
declare -i RC=$?
if (( "RC" == 0 ))
then
echo "SUCCESS: Post Event Script Completed RC - \
${RC}" > $TTY
echo "SUCCESS: Post Event Script Completed RC - \
${RC}" >> $LOGFILE
else
echo "FAILURE: Post Event Script FAILED RC - ${RC}"\
> $TTY
echo "FAILURE: Post Event Script FAILED RC - ${RC}"\
>> $LOGFILE
fi
fi
;;

'N')

# This will run the pre_event_script, which is a function

if [[ $RUN_PRE_EVENT = 'Y' ]]
then
echo "PRE EVENT: Executing Pre Event Script..." > $TTY
echo "PRE EVENT: Executing Pre Event Script..." >> $LOGFILE

pre_event_script # USER DEFINED FUNCTION!!!
RC=$? # Check the Return Code!!!
if (( "RC" == 0 ))
then
echo "SUCCESS: Pre Event Script Completed RC - ${RC}"\
> $TTY
echo "SUCCESS: Pre Event Script Completed RC - ${RC}"\
>> $LOGFILE
else
echo "FAILURE: Pre Event Script FAILED RC - ${RC}"\
> $TTY
echo "FAILURE: Pre Event Script FAILED RC - ${RC}"\
>> $LOGFILE
fi
fi

echo "WAITING: Waiting for $PROCESS to \
startup...Monitoring..." >$TTY

declare -i PROC_COUNT='-1' # Initialize to a fake value
# echo $PROC_COUNT >$TTY
# Loop until at least one process starts

until (( "PROC_COUNT" > 0 ))
do

# This is a Co-Process. This checks to see if a "Program
# Interrupt" has taken place. If so BREAK will be 'Y' and
# we exit both the loop and function

PROC_COUNT=$(ps aux | grep -v "grep $PROCESS" \
| grep -v $SCRIPT_NAME | grep $PROCESS | wc -l) \
>/dev/null 2>&1

# echo $PROC_COUNT > $TTY
sleep $INTERVAL # Needed to reduce CPU load!
done

RUN='Y' # Turn the RUN Flag On

TIMESTAMP=$(date +%D@%T)

PID_LIST=$(ps aux | grep -v "grep $PROCESS" \
| grep -v $SCRIPT_NAME \
| grep $PROCESS | awk '{print $2}')

if (( "PROC_COUNT" == 1 ))
then
# echo test************************** >$TTY
echo "START PROCESS: $PROCESS START time ==>\
$TIMESTAMP" >> $LOGFILE &
echo ACTIVE PIDS: $PID_LIST >> $LOGFILE &
echo "START PROCESS: $PROCESS START time ==>\
$TIMESTAMP" > $TTY
echo ACTIVE PIDS: $PID_LIST > $TTY
elif (( "PROC_COUNT" > 1 ))
then
echo "START PROCESS: $PROC_COUNT $PROCESS\
Processes Started: START time ==> $TIMESTAMP" >> $LOGFILE &
echo ACTIVE PIDS: $PID_LIST >> $LOGFILE &
echo "START PROCESS: $PROC_COUNT $PROCESS\
Processes Started: START time ==> $TIMESTAMP" > $TTY
echo ACTIVE PIDS: $PID_LIST > $TTY
fi
;;
esac
done
}

####################################################
############## START OF MAIN #######################
####################################################

### SET A TRAP ####

trap 'kill -9 $COPROC_PID 2>/dev/null;trap_exit \
2>/dev/null;exit 0' 1 2 3 15

BREAK='N' # The BREAK variable is used in the co-process proc_watch
PROCESS= # Initialize to null
declare -i TOTAL_SECONDS=0
#print -p $BREAK
# Check commnand line arguments

if (( $# > 10 || $# < 2 )) then usage exit 1 fi # Check to see if only the seconds and a process are # the only arguments if [[ ($# -eq 2) && ($1 != -*) && ($2 != -*) ]] then NUM_TEST=$(test_string $1) # Is this an Integer? if [[ "$NUM_TEST" = 'POS_INT' ]] then TOTAL_SECONDS=$1 # Yep - It.s an Integer PROCESS=$2 # Can be anything else usage exit 1 fi else # Since getopts does not care what arguments it gets, let.s # do a quick sanity check to make sure that we only have # between 2 and 10 arguments and the first one must start # with a -* (hyphen and anything), else usage error case "$#" in [2-10]) if [[ $1 != -* ]]; then usage; exit 1 fi ;; esac HOURS=0 # Initialize all to zero MINUTES=0 SECS=0 DAYS=0 # Use getopts to parse the command line arguments # For each $OPTARG for DAYS, HOURS, MINUTES and DAYS check to see # that each one is an integer by using the check_string function while getopts ":h:H:m:M:s:S:d:D:P:p:" OPT_LIST 2>/dev/null
do
case $OPT_LIST in
h|H) [[ $(test_string $OPTARG) != 'POS_INT' ]] && usage && exit 1
(( HOURS = $OPTARG * 3600 )) # 3600 seconds per hour
;;
m|H) [[ $(test_string $OPTARG) != 'POS_INT' ]] && usage && exit 1
(( MINUTES = $OPTARG * 60 )) # 60 seconds per minute
;;
s|S) [[ $(test_string $OPTARG) != 'POS_INT' ]] && usage && exit 1
SECS="$OPTARG" # seconds are seconds
;;
d|D) [[ $(test_string $OPTARG) != 'POS_INT' ]] && usage && exit 1
(( DAYS = $OPTARG * 86400 )) # 86400 seconds per day
;;
p|P) PROCESS=$OPTARG # process can be anything
;;
\?) usage # USAGE ERROR
exit 1
;;
:) usage
exit 1
;;
*) usage
exit 1
;;
esac
done
fi

# We need to make sure that we have a process that
# is NOT null or empty! - sanity check - The double quotes are required!

if [[ -z "$PROCESS" || "$PROCESS" = '' ]]
then
usage
exit 1
fi

# Check to see that TOTAL_SECONDS was not previously set

if (( TOTAL_SECONDS == 0 ))
then
# Add everything together if anything is > 0
if [[ $SECS -gt 0 || $MINUTES -gt 0 || $HOURS -gt 0 \
|| $DAYS -gt 0 ]]
then
(( TOTAL_SECONDS = SECS + MINUTES + HOURS + DAYS ))
fi
fi

# Last Sanity Check!

if (( TOTAL_SECONDS $TTY
ps aux | grep -v "grep $PROCESS" | grep -v $SCRIPT_NAME \
| grep $PROCESS > $TTY

PROC_RC=$? # Get the initial state of the monitored function
echo $PROC_RC
echo >$TTY # Send a blank line to the screen

(( PROC_RC != 0 )) && echo -e "\nThere are no $PROCESS processes running\n"

if (( PROC_RC == 0 )) # The Target Process(es) is/are running...
then
RUN='Y' # Set the RUN flag to true, or yes.

declare -i PROC_COUNT # Strips out the "padding" for display

PROC_COUNT=$(ps aux | grep -v "grep $PROCESS" | grep -v \
$SCRIPT_NAME | grep $PROCESS | wc -l) >/dev/null 2>&1
if (( PROC_COUNT == 1 ))
then
echo -e "The $PROCESS process is currently\
running...Monitoring... \n"
elif (( PROC_COUNT > 1 ))
then
print "There are $PROC_COUNT $PROCESS processes currently\
running...Monitoring...\n"
fi
else
echo "The $PROCESS process is not currently running...monitoring..."
RUN='N' # Set the RUN flag to false, or no.
fi

TIMESTAMP=$(date +%D@%T) # Time that this script started monitoring

# Get a list of the currently active process IDs

PID_LIST=$(ps aux | grep -v "grep $PROCESS" \
| grep -v $SCRIPT_NAME \
| grep $PROCESS | awk '{print $2}')

echo "MON_STARTED: Monitoring for $PROCESS began ==> $TIMESTAMP" \
| tee -a $LOGFILE
echo ACTIVE PIDS: $PID_LIST | tee -a $LOGFILE
#echo test*****

##### NOTICE ####
# We kick off the "proc_watch" function below as a "Co-Process"
# This sets up a two way communications link between the
# "proc_watch" background function and this "MAIN BODY" of
# the script. This is needed because the function has two
# "infinite loops", with one always executing at any given time.
# Therefore we need a way to break out of the loop in case of
# an interrupt, i.e. CTRL+C, and when the countdown is complete.
# The "pipe appersand", |&, creates the background Co-Process
# and we use "print -p $VARIABLE" to transfer the variable.s
# value back to the background co-process.
###################################

<strong><span style="color: #ff0000;">coproc proc_watch # Create a Background Co-Process!!</span></strong>
<strong><span style="color: #ff0000;"> WATCH_PID=$! # Get the process ID of the last background job!</span></strong>

#echo "test over "
# Start the Count Down!
#echo $BREAK
declare -i SECONDS_LEFT=$TOTAL_SECONDS
echo $SECONDS_LEFT
while (( SECONDS_LEFT &gt; 0 ))
do
# Next send the current value of $BREAK to the Co-Process
# proc_watch, which was piped to the background...

print -p $BREAK 2&gt;/dev/null
(( SECONDS_LEFT = SECONDS_LEFT - 1 ))
sleep 1 # 1 Second Between Counts
done

# Finished - Normal Timeout Exit...
TIMESTAMP=$(date +%D@%T) # Get a new timestamp...
echo -e "MON_STOPPED: Monitoring for $PROCESS ended ==&gt; $TIMESTAMP\n" \
| tee -a $LOGFILE

echo -e "LOGFILE: All Events are Logged ==&gt; $LOGFILE \n"

# Tell the proc_watch function to break out of the loop and die

kill -9 $COPROC_PID&gt;/dev/null
BREAK='Y'
print -p $BREAK 2&gt;/dev/null
exit 0

# End of Script

发表评论

您的电子邮箱地址不会被公开。