294 lines
6.5 KiB
Bash
Executable File
294 lines
6.5 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# === SETTINGS ===
|
|
EXLUDE_USR=(root jhub nginx)
|
|
|
|
RESCAN_S=3
|
|
MAX_CPU_P=50
|
|
MAX_RAM_GB=32
|
|
IMMUNITY_TIME_S=15
|
|
HARDKILL_DELAY_S=10
|
|
|
|
NERDFONT=0
|
|
COLOR=0
|
|
KILL=0
|
|
HARDKILL=0
|
|
# === === ===
|
|
|
|
# ansi
|
|
UNDERLINE="\e[4m"
|
|
BOLD="\e[1m"
|
|
BLINK="\e[5m"
|
|
ORANGE="\e[38;5;208m"
|
|
RED="\033[31m"
|
|
GREEN="\033[32m"
|
|
RESET="\033[0m"
|
|
|
|
# icons
|
|
ICON_RAM=" "
|
|
ICON_CPU=" "
|
|
ICON_MAG=""
|
|
ICON_SKULL=" "
|
|
|
|
SIGTERM=15
|
|
SIGKILL=9
|
|
SCANNED_PIDS=()
|
|
|
|
print_banner() {
|
|
cat <<"EOF"
|
|
_ _ _ _ _ _
|
|
| | (_) | | | | | |
|
|
| | ___| | |_____ _ _ _ ____ ____ _ _ __ | |_ ___ __| |
|
|
| |/ / | | |_____| | | | '_ \ \ /\ / / _` | '_ \| __/ _ \/ _` |
|
|
| <| | | | | |_| | | | \ V V / (_| | | | | || __/ (_| |
|
|
|_|\_\_|_|_| \__,_|_| |_|\_/\_/ \__,_|_| |_|\__\___|\__,_|
|
|
EOF
|
|
}
|
|
|
|
show_help() {
|
|
cat <<EOF
|
|
Usage: $(basename "$0") [OPTIONS]
|
|
|
|
Options:
|
|
-m, --memory [GiB]
|
|
Set maximum allowed RAM usage.
|
|
If no value is given, prints current value.
|
|
Default: ${MAX_RAM_GB} GiB
|
|
|
|
-t, --time [SECONDS]
|
|
Set process immunity time.
|
|
If no value is given, prints current value.
|
|
Default: ${IMMUNITY_TIME_S} s
|
|
|
|
-u, --utilization [PERCENT]
|
|
Set maximum allowed CPU usage.
|
|
If no value is given, prints current value.
|
|
Default: ${MAX_CPU_P} %
|
|
|
|
-r, --refresh [SECONDS]
|
|
Set time between rescans.
|
|
If no value is given, prints current value.
|
|
Default: ${RESCAN_S} s
|
|
|
|
-k, --kill
|
|
Send SIGTERM to detected processes.
|
|
|
|
-h, --hardkill [SECONDS]
|
|
Send SIGTERM and after a delay
|
|
SIGKILL to detected processes.
|
|
Optionally a delay can be specified.
|
|
Default: ${HARDKILL_DELAY_S} s
|
|
|
|
-n, --nerdfonts
|
|
Enable Nerd Font icons.
|
|
|
|
-c, --color
|
|
Enable colored output.
|
|
|
|
-h, --help
|
|
Display this help message and exit.
|
|
|
|
Examples:
|
|
$(basename "$0") --memory 8
|
|
$(basename "$0") -t 60 -u 10 -m 1 -r 2 -c
|
|
$(basename "$0") --utilization -c
|
|
$(basename "$0") -m -u -r 2 -n -c
|
|
EOF
|
|
}
|
|
|
|
kill_ps() {
|
|
VICTIM_PID="${1}"
|
|
if [[ "$KILL" == "0" ]]; then
|
|
return
|
|
fi
|
|
|
|
echo "${ICON_SKULL}killing"
|
|
kill "-$SIGTERM" "${VICTIM_PID}"
|
|
|
|
if [[ "$HARDKILL" == "0" ]]; then
|
|
return
|
|
fi
|
|
|
|
(
|
|
sleep ${HARDKILL_DELAY_S};
|
|
if kill -0 "${VICTIM_PID}" > /dev/zero; then
|
|
# still alive
|
|
echo -e "${ICON_SKULL}Terminating (${VICTIM_PID})"
|
|
kill "-${SIGKILL}" "${VICTIM_PID}"
|
|
else
|
|
echo "{ICON_SKULL}Died successfully ($VICTIM_PID)"
|
|
fi
|
|
) &
|
|
}
|
|
|
|
# === ARG PARSING ===
|
|
print_banner
|
|
echo ""
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
-m|--memory)
|
|
if [[ -n $2 && "$2" != -* ]]; then
|
|
MAX_RAM_GB="${2}"
|
|
echo -e "- Maximum allowed RAM set to ${2}GiB"
|
|
shift
|
|
else
|
|
echo -e "- Maximum allowed RAM usage: ${MAX_RAM_GB}GiB"
|
|
fi
|
|
|
|
;;
|
|
|
|
-t|--time)
|
|
if [[ -n $2 && "$2" != -* ]]; then
|
|
IMMUNITY_TIME_S="${2}"
|
|
echo -e "- Process immunity time set to ${2}s"
|
|
shift
|
|
else
|
|
echo -e "- Process immunity time: ${IMMUNITY_TIME_S}s"
|
|
fi
|
|
;;
|
|
|
|
-u|--utilization)
|
|
if [[ -n $2 && "$2" != -* ]]; then
|
|
MAX_CPU_P="${2}"
|
|
echo -e "- Maximum allowed CPU usage set to ${2}%"
|
|
shift
|
|
else
|
|
echo -e "- Maximum allowed CPU usage: ${MAX_CPU_P}%"
|
|
fi
|
|
;;
|
|
|
|
-r|--refresh)
|
|
if [[ -n $2 && "$2" != -* ]]; then
|
|
RESCAN_S="${2}"
|
|
shift
|
|
else
|
|
echo -e "- Rescan time set to: ${RESCAN_S}s"
|
|
fi
|
|
;;
|
|
|
|
-k|--kill)
|
|
KILL=1
|
|
echo "- Killing enabled"
|
|
;;
|
|
|
|
-h|--hardkill)
|
|
KILL=1
|
|
HARDKILL=1
|
|
if [[ -n $2 && "$2" != -* ]]; then
|
|
HARDKILL_DELAY_S="${2}"
|
|
shift
|
|
fi
|
|
echo -e "- Hardkill enabled with delay: ${HARDKILL_DELAY_S}s"
|
|
;;
|
|
|
|
-n|--nerdfonts)
|
|
# enable nerdfont icons
|
|
NERDFONT=1
|
|
;;
|
|
|
|
-c|--color)
|
|
# enable color
|
|
COLOR=1
|
|
;;
|
|
|
|
--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
|
|
*)
|
|
echo "! ERROR: unknown command: ${1}"
|
|
exit 0
|
|
esac
|
|
shift
|
|
done
|
|
|
|
|
|
# setting icons according to input
|
|
if [[ "$NERDFONT" == "0" ]]; then
|
|
ICON_RAM=""
|
|
ICON_CPU=""
|
|
ICON_MAG=""
|
|
ICON_SKULL=""
|
|
fi
|
|
|
|
# setting ansi according to input
|
|
if [[ "$COLOR" == "0" ]]; then
|
|
UNDERLINE=""
|
|
BOLD=""
|
|
BLINK=""
|
|
ORANGE=""
|
|
RED=""
|
|
GREEN=""
|
|
RESET=""
|
|
fi
|
|
|
|
|
|
sleep 0.4
|
|
echo -e "${GREEN}${UNDERLINE}\n${ICON_MAG} starting scan..${RESET}"
|
|
|
|
# === SCAN ===
|
|
|
|
while true; do
|
|
#echo "SCANNED: ${SCANNED_PIDS[@]}"
|
|
while read -r PID TIME USER MEM CPU; do
|
|
# === Check if process should be excluded ===
|
|
skip=0
|
|
MEM_GB=$(awk "BEGIN {print $MEM/1024/1024}") # KiB -> GiB
|
|
|
|
for user_i in "${EXLUDE_USR[@]}"; do
|
|
if [[ "$user_i" == "$USER" ]]; then
|
|
skip=1
|
|
break
|
|
fi
|
|
done
|
|
|
|
for element in "${SCANNED_PIDS[@]}"; do
|
|
if [[ "$PID" == "$element" ]]; then
|
|
skip=1
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ "$TIME" -lt "$IMMUNITY_TIME_S" ]]; then
|
|
skip=1
|
|
fi
|
|
|
|
if [[ $skip -eq 1 ]]; then
|
|
continue
|
|
fi
|
|
|
|
# === Check if ps should be killed ===
|
|
|
|
NAME="$(ps -p $PID -o args=)"
|
|
KILL_PREFIX="-> \"${RED}${NAME}${RESET}\" (PID: ${PID})"
|
|
should_die=0
|
|
|
|
# check memory usage
|
|
if awk "BEGIN {exit !(${MEM_GB} > ${MAX_RAM_GB})}"; then
|
|
# kill ps
|
|
echo -e "${KILL_PREFIX} - ${ICON_RAM}RAM usage too high (${ORANGE}${MEM_GB}GiB${RESET} > ${MAX_RAM_GB}GiB)"
|
|
should_die=1
|
|
fi
|
|
|
|
# check cpu usage
|
|
if awk "BEGIN {exit !(${CPU} > ${MAX_CPU_P})}"; then
|
|
# kill ps
|
|
echo -e "${KILL_PREFIX} - ${ICON_CPU}CPU usage too high (${ORANGE}${CPU}%${RESET} > ${MAX_CPU_P}%)"
|
|
should_die=1
|
|
fi
|
|
|
|
if [[ "$should_die" == 1 ]]; then
|
|
SCANNED_PIDS+=($PID)
|
|
kill_ps "$PID"
|
|
continue
|
|
fi
|
|
|
|
# next ps
|
|
done < <(ps -eo pid,etimes,user,rss,%cpu --no-headers | tr -s " ")
|
|
|
|
## no process found - repeat
|
|
sleep ${RESCAN_S}
|
|
done
|