#!/bin/bash
#< Script to forcibly remove messages from sendmail mail queue
AWK="/bin/awk"
BASENAME="/bin/basename"
DATE="/bin/date"
ECHO="/bin/echo"
EGREP="/bin/egrep"
GREP="/bin/grep"
FIND="/usr/bin/find"
HOSTNAME="/bin/hostname"
KILL="/bin/kill"
PS="/bin/ps"
RM="/bin/rm"
SED="/bin/sed"
SENDMAIL="/usr/lib/sendmail"
SERVICE="/sbin/service"
SLEEP="/bin/sleep"
WC="/usr/bin/wc"
XARGS="/usr/bin/xargs"
THISPROG="$( ${BASENAME} $0 )"
MY_HOSTNAME="$( ${HOSTNAME} )"
MQUEUE="/var/spool/mqueue"
LOGFILE="/var/log/mailq_purge.log"
NUM_HOURS="INVALID" # force user to specify -n (see check_args below)
E_SUCCESS=0
E_ERROR=1
function print_usage {
{
${ECHO} "Usage: ${THISPROG} [-h] -n <num_hours>"
${ECHO} " -n Remove messages older than <num_hours>"
${ECHO} " -h Display this usage message"
} >&2
}
function print_log {
TIMESTAMP=$( ${DATE} )
LEVEL="$1"
MESSAGE="$2"
${ECHO} "${TIMESTAMP} ${MY_HOSTNAME} ${LEVEL} ${MESSAGE}" >> ${LOGFILE}
}
function check_args {
${ECHO} "${NUM_HOURS}" | ${EGREP} -q '^[0-9]+$' || {
print_log "ERROR" "Incorrect arguments passed to script"
print_usage
exit ${E_ERROR}
}
}
function check_num_mailq {
NUMQ=$( ${SENDMAIL} -bp -OMaxQueueRunSize=1 | ${SED} -n '1 s/^[^(]*(\([0-9][0-9]*\) r.*$/\1/p' )
${ECHO} "${NUMQ}" | ${EGREP} -q '^[0-9]+$' || {
print_log "ERROR" "Unable to get number of messages in mailq"
exit ${E_ERROR}
}
${ECHO} "${NUMQ}"
}
function check_sendmail {
SENDMAIL_PROCESSES=$( ${PS} -ef | ${GREP} '[s]endmail' | ${WC} -l | ${AWK} '{print $1}' )
if [ "${SENDMAIL_PROCESSES}" -eq "0" ]; then
print_log "INFO" "There are no sendmail processes running"
else
print_log "INFO" "There are ${SENDMAIL_PROCESSES} sendmail processes running"
fi
${ECHO} "${SENDMAIL_PROCESSES}"
}
function stop_sendmail {
COUNTER=0
print_log "INFO" "Attempting to stop sendmail gracefully"
${SERVICE} sendmail stop >/dev/null 2>&1
while [ "${COUNTER}" -lt "6" ]; do
STILL_RUNNING=$( check_sendmail )
if [ "${STILL_RUNNING}" -ne "0" ]; then
print_log "WARNING" "Sendmail still running after $(( ${COUNTER} * 5 )) seconds"
else
print_log "INFO" "Sendmail stopped"
return
fi
${SLEEP} 5
(( COUNTER = COUNTER + 1 ))
done
print_log "WARNING" "About to kill sendmail forcefully - sending SIGTERM"
${PS} -ef | ${GREP} '[s]endmail' | ${AWK} '{print $2}' | ${XARGS} ${KILL} -15
${SLEEP} 5
STILL_RUNNING=$( check_sendmail )
if [ "${STILL_RUNNING}" -ne "0" ]; then
print_log "WARNING" "Sendmail still running after SIGTERM - sending SIGKILL"
else
print_log "INFO" "Sendmail killed"
return
fi
${PS} -ef | ${GREP} '[s]endmail' | ${AWK} '{print $2}' | ${XARGS} ${KILL} -9
${SLEEP} 5
STILL_RUNNING=$( check_sendmail )
if [ "${STILL_RUNNING}" -ne "0" ]; then
print_log "ERROR" "Sendmail still running after SIGKILL - Good luck with that"
exit ${E_ERROR}
else
print_log "INFO" "Sendmail killed"
return
fi
# never reached
return
}
function start_sendmail {
print_log "INFO" "Attempting to start sendmail"
${SERVICE} sendmail start >/dev/null 2>&1
${SLEEP} 5
IS_RUNNING=$( check_sendmail )
if [ "${IS_RUNNING}" -eq "0" ]; then
print_log "ERROR" "Could not start sendmail"
exit ${E_ERROR}
else
print_log "INFO" "Sendmail started"
return
fi
}
function purge_mailq {
print_log "INFO" "About to purge mail queue - removing anything older than ${NUM_HOURS} hours"
${FIND} "${MQUEUE}" -type f -mmin +$(( 60 * ${NUM_HOURS} )) -print0 | ${XARGS} -0 ${RM} -f
print_log "INFO" "Mail queue purged"
}
while getopts ":hn:" OPTION; do
case ${OPTION} in
"h") print_usage && exit 0 ;;
"n") NUM_HOURS=${OPTARG} ;;
* ) print_usage && exit 1 ;;
esac
done
shift $(( ${OPTIND} - 1 ))
if [ "$#" -ne "0" ]; then
print_usage && exit 1
fi
check_args
NUMQ_BEFORE=$( check_num_mailq )
print_log "INFO" "${NUMQ_BEFORE} messages in mailq before processing"
PROCS_BEFORE=$( check_sendmail )
if [ "${PROCS_BEFORE}" -eq "0" ]; then
print_log "ERROR" "Nothing to do - sendmail not running" && exit ${E_ERROR}
fi
stop_sendmail
purge_mailq
start_sendmail
NUMQ_AFTER=$( check_num_mailq )
print_log "INFO" "${NUMQ_AFTER} messages in mailq after processing"
exit ${E_SUCCESS}