#!/usr/bin/env bash working_dir="$(dirname $(realpath $0))" # ------------- # - Some Variables # ------------- LOCK_DIR="/tmp/$(basename $0).LOCK" KILL_SIGNAL=HUP #CHECK_USER="$*" # ------------- # - Some functions # ------------- usage() { [[ -n "$1" ]] && error "$1" [[ $terminal ]] && echo -e " \033[1mUsage:\033[m $(basename $0) -u \033[1mDescription\033[m Searches for zombie (defunct) child prozesses owned by a given user. If such processes exists, the script tries to kill them by sending a HUP signal to the parent process. A user must be given using option '-u'. \033[1mOptions\033[m -h Prints this help. -u Searches for zombie (defunct) prozesses owned by this user. \033[1mExample:\033[m Search for (and delete) defunct child prozesses owned by user 'sympa'' $(basename $0) -u sympa " clean_up 1 } clean_up() { # Perform program exit housekeeping rm -rf "$LOCK_DIR" exit $1 } trim() { local var="$*" var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters echo -n "$var" } fatal(){ echo "" if $terminal ; then echo -e " [ \033[31m\033[1mFatal\033[m ]: $*" echo "" echo -e " \033[31m\033[1mScript was interupted\033[m!" else echo "[ Fatal ]: $*" echo "" echo " Script was terminated...." fi echo "" clean_up 1 } error (){ echo "" if $terminal ; then echo -e " [ \033[31m\033[1mError\033[m ]: $*" else echo "[ Error ]: $*" fi echo "" } warn (){ echo "" if $terminal ; then echo -e " [ \033[33m\033[1mWarning\033[m ]: $*" else echo "[ Warning ]: $*" fi echo "" } info (){ echo "" if $terminal ; then echo -e " [ \033[32m\033[1mInfo\033[m ]: $*" else echo "[ Info ]: $*" fi echo "" } info_terminal (){ if $terminal ; then echo "" echo -e " [ \033[32m\033[1mInfo\033[m ]: $*" echo "" fi } ok (){ echo "" if $terminal ; then echo -e " [ \033[32m\033[1mOk\033[m ]: $*" else echo "[ Ok ]: $*" fi echo "" } # ------------- # - Check some prerequisites # ------------- # - Is this script running on terminal ? # - if [[ -t 1 ]] ; then terminal=true else terminal=false fi if [[ -z "$(which basename)" ]]; then fatal 'It seems "basename" is not installed, but needed!' fi if [[ -z "$(which realpath)" ]]; then fatal 'It seems "realpath" is not installed, but needed!' fi # ------------- # - Jobhandling # ------------- # - If job already runs, stop execution.. # - if mkdir "$LOCK_DIR" 2> /dev/null ; then ## - Remove lockdir when the script finishes, or when it receives a signal trap clean_up SIGHUP SIGINT SIGTERM else datum="$(date +"%d.%m.%Y %H:%M")" fatal "A previos instance of that script \"$(basename $0)\" seems already be running." exit 1 fi # ------------- # - Read Commanline Arguments # ------------- while getopts hu: opt ; do case $opt in h) usage ;; u) CHECK_USER=$OPTARG ;; *) usage esac done if [[ -z "$CHECK_USER" ]]; then usage "No user (option -u) given" fi shift $(expr $OPTIND - 1) [[ "$#" -gt 0 ]] && usage "Wrong number of arguments given!" # ------------- # Checking .. # ------------- if $terminal ; then echo "" echo -e " \033[1mCheck for zombie (defunct) child prozesses owned by a given user\033[m" echo " ================================================================" fi if $(ps -Ao"stat,user,command" | grep "${CHECK_USER}" | grep -v grep | grep -e '^[zZ]' > /dev/null 2>&1) then warn "Found Zombie Processes '${CHECK_USER}' on '$(hostname -f)':" # - Print out the concerning lines frp 'ps' output. # - ps -Ao"stat,user,pid,ppid,command" | grep "$(basename ${CHECK_USER})" | grep -v grep | grep -e '^[zZ]' membefore=$(cat /proc/meminfo | grep Committed_AS | awk '{print $2}') info "Trying a graceful kill to the concerning parents with signal '$KILL_SIGNAL' .." # - Process ID(s) of the zombie process(es) # - ZOMBIE_PIDS="$(ps -Ao"stat,user,pid,ppid,command" | grep "${CHECK_USER}" | grep -v grep | grep -e '^[zZ]' \ | awk '{ print $3 }' | sort -u)" # - Sending the kill signal ($KILL_SIGNAL) to the parent process ID(s) # - ps -Ao"stat,user,pid,ppid,command" | grep "${CHECK_USER}" | grep -v grep | grep -e '^[zZ]' \ | awk '{ print $4 }' | sort -u | xargs --no-run-if-empty kill -$KILL_SIGNAL if [[ "$?" -eq 0 ]];then declare -i count=0 for _PID in $ZOMBIE_PIDS ; do if [[ $count -eq 1 ]]; then KILLED_PIDS="$_PID" else KILLED_PIDS="$KILLED_PIDS $_PID" fi ((count++)) done sleep 10 ok "Cleaning up zombie processes owned by user '${CHECK_USER}' seems succsessfully finisched" ok "$count zombie process(es) with PID(s) '${KILLED_PIDS}' removed from process list" memafter=`cat /proc/meminfo | grep Committed_AS | awk '{print $2}'` info "`expr $membefore - $memafter` KB RAM has been freed" else error "Cleaning up zombie processes owned by user '${CHECK_USER}' failed!" fi else info_terminal "No zombie prossses owned by user '${CHECK_USER}' found." fi if $terminal ; then echo "" fi clean_up 0