- System protection script with custom enhancements and TUI interface - Browser tab limiting and application-specific monitoring - AI behavior learning and predictive analysis - Terminal-based configuration interface - Multi-distro installation support
797 lines
27 KiB
Bash
Executable File
797 lines
27 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# PC Anti-Freeze Monitor - Comprehensive System Protection
|
|
# Author: Claude Code Assistant
|
|
# Description: Prevents system crashes and freezes with detailed notifications
|
|
|
|
set -euo pipefail
|
|
|
|
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
readonly CONFIG_FILE="/etc/pc-monitor.conf"
|
|
readonly LOG_FILE="/var/log/pc-monitor.log"
|
|
readonly PID_FILE="/var/run/pc-monitor.pid"
|
|
|
|
# Default thresholds (can be overridden in config)
|
|
CPU_THRESHOLD=85
|
|
MEMORY_THRESHOLD=90
|
|
TEMP_THRESHOLD=80
|
|
DISK_THRESHOLD=95
|
|
PROCESS_HANG_TIME=30
|
|
SWAP_THRESHOLD=80
|
|
LOAD_AVG_THRESHOLD=10
|
|
|
|
# Advanced monitoring features
|
|
NETWORK_THRESHOLD=50 # MB/s
|
|
IO_THRESHOLD=100 # MB/s
|
|
BROWSER_TAB_LIMIT=20
|
|
AGGRESSIVE_ON_BROWSERS=true
|
|
AGGRESSIVE_CPU_THRESHOLD=75
|
|
AGGRESSIVE_MEMORY_THRESHOLD=80
|
|
|
|
# Application-specific thresholds
|
|
BROWSER_CPU_THRESHOLD=60
|
|
BROWSER_MEMORY_THRESHOLD=70
|
|
GAME_CPU_THRESHOLD=95
|
|
GAME_MEMORY_THRESHOLD=85
|
|
IDE_MEMORY_THRESHOLD=75
|
|
|
|
# Browser monitoring
|
|
FIREFOX_MAX_TABS=15
|
|
CHROME_MAX_TABS=15
|
|
EDGE_MAX_TABS=10
|
|
|
|
# Notification settings
|
|
NOTIFICATION_TIMEOUT=5000
|
|
NOTIFICATION_URGENCY="critical"
|
|
|
|
# Color codes for notifications
|
|
RED='\033[0;31m'
|
|
YELLOW='\033[1;33m'
|
|
GREEN='\033[0;32m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
# Initialize logging
|
|
init_logging() {
|
|
if [[ ! -f "$LOG_FILE" ]]; then
|
|
sudo touch "$LOG_FILE"
|
|
sudo chmod 644 "$LOG_FILE"
|
|
fi
|
|
exec 3>&1 4>&2
|
|
trap 'exec 2>&4 1>&3' 0 1 2 3
|
|
exec 1> >(tee -a "$LOG_FILE")
|
|
exec 2>&1
|
|
}
|
|
|
|
# Log with timestamp
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
|
}
|
|
|
|
# Send desktop notification
|
|
send_notification() {
|
|
local title="$1"
|
|
local message="$2"
|
|
local urgency="${3:-normal}"
|
|
local icon="${4:-dialog-warning}"
|
|
|
|
log "NOTIFICATION: $title - $message"
|
|
|
|
# Try multiple notification methods
|
|
if command -v notify-send >/dev/null 2>&1; then
|
|
notify-send --urgency="$urgency" --expire-time="$NOTIFICATION_TIMEOUT" \
|
|
--icon="$icon" "$title" "$message"
|
|
elif command -v zenity >/dev/null 2>&1; then
|
|
zenity --notification --text="$title: $message" &
|
|
fi
|
|
|
|
# Also try to send to all active X sessions
|
|
for user_session in $(who | awk '{print $1 ":" $2}' | sort -u); do
|
|
local user="${user_session%:*}"
|
|
local display="${user_session#*:}"
|
|
if [[ -n "$display" && "$display" =~ ^:[0-9]+$ ]]; then
|
|
sudo -u "$user" DISPLAY="$display" notify-send --urgency="$urgency" \
|
|
--expire-time="$NOTIFICATION_TIMEOUT" --icon="$icon" "$title" "$message" 2>/dev/null || true
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Get process information with application classification
|
|
get_process_info() {
|
|
local pid="$1"
|
|
local name cmd cpu_percent mem_percent mem_mb app_type
|
|
|
|
if [[ ! -d "/proc/$pid" ]]; then
|
|
echo "Process $pid no longer exists"
|
|
return 1
|
|
fi
|
|
|
|
name=$(ps -p "$pid" -o comm= 2>/dev/null || echo "unknown")
|
|
cmd=$(ps -p "$pid" -o cmd= 2>/dev/null | cut -c1-50 || echo "unknown")
|
|
cpu_percent=$(ps -p "$pid" -o %cpu= 2>/dev/null || echo "0")
|
|
mem_percent=$(ps -p "$pid" -o %mem= 2>/dev/null || echo "0")
|
|
|
|
# Get memory in MB
|
|
if [[ -f "/proc/$pid/status" ]]; then
|
|
mem_mb=$(awk '/VmRSS:/ {print int($2/1024)}' "/proc/$pid/status" 2>/dev/null || echo "0")
|
|
else
|
|
mem_mb="0"
|
|
fi
|
|
|
|
# Classify application type
|
|
app_type=$(classify_application "$name" "$cmd")
|
|
|
|
echo "PID:$pid NAME:$name CMD:$cmd CPU:$cpu_percent MEM:$mem_percent MEM_MB:${mem_mb} TYPE:$app_type"
|
|
}
|
|
|
|
# Classify application type for targeted monitoring
|
|
classify_application() {
|
|
local name="$1"
|
|
local cmd="$2"
|
|
|
|
case "$name" in
|
|
*firefox*|*chrome*|*chromium*|*brave*|*opera*|*edge*|*safari*)
|
|
echo "browser"
|
|
;;
|
|
*steam*|*game*|*csgo*|*dota*|*minecraft*|*wow*|*lol*|*valorant*)
|
|
echo "game"
|
|
;;
|
|
*code*|*idea*|*eclipse*|*netbeans*|*atom*|*sublime*)
|
|
echo "ide"
|
|
;;
|
|
*blender*|*gimp*|*krita*|*inkscape*|*davinci*)
|
|
echo "graphics"
|
|
;;
|
|
*vlc*|*mpv*|*ffmpeg*|*obs*|*audacity*)
|
|
echo "media"
|
|
;;
|
|
*docker*|*podman*|*virtualbox*|*qemu*|*vmware*)
|
|
echo "virtualization"
|
|
;;
|
|
*)
|
|
echo "general"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Kill process with notification
|
|
kill_process_with_notification() {
|
|
local pid="$1"
|
|
local reason="$2"
|
|
local resource_info="$3"
|
|
|
|
local process_info
|
|
process_info=$(get_process_info "$pid")
|
|
|
|
if [[ $? -eq 0 ]]; then
|
|
local name=$(echo "$process_info" | grep -o 'NAME:[^[:space:]]*' | cut -d: -f2)
|
|
local cmd=$(echo "$process_info" | grep -o 'CMD:[^[:space:]]*' | cut -d: -f2)
|
|
local cpu=$(echo "$process_info" | grep -o 'CPU:[^[:space:]]*' | cut -d: -f2)
|
|
local mem=$(echo "$process_info" | grep -o 'MEM:[^[:space:]]*' | cut -d: -f2)
|
|
local mem_mb=$(echo "$process_info" | grep -o 'MEM_MB:[^[:space:]]*' | cut -d: -f2)
|
|
|
|
# Kill the process
|
|
if kill -9 "$pid" 2>/dev/null; then
|
|
local notification_title="⚠️ Process Terminated - System Protected"
|
|
local notification_message="Killed '$name' (PID: $pid)
|
|
Reason: $reason
|
|
Resource Usage: CPU: ${cpu}%, RAM: ${mem}% (${mem_mb}MB)
|
|
$resource_info
|
|
Command: $cmd"
|
|
|
|
send_notification "$notification_title" "$notification_message" "critical" "process-stop"
|
|
log "KILLED PROCESS: PID=$pid NAME=$name REASON=$reason CPU=${cpu}% MEM=${mem}% (${mem_mb}MB)"
|
|
return 0
|
|
else
|
|
log "FAILED TO KILL: PID=$pid NAME=$name"
|
|
return 1
|
|
fi
|
|
else
|
|
log "PROCESS INFO UNAVAILABLE: PID=$pid"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Monitor CPU usage
|
|
monitor_cpu() {
|
|
local cpu_usage
|
|
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | sed 's/%us,//')
|
|
cpu_usage=${cpu_usage%.*} # Remove decimal part
|
|
|
|
if [[ "$cpu_usage" -gt "$CPU_THRESHOLD" ]]; then
|
|
log "HIGH CPU USAGE: ${cpu_usage}%"
|
|
|
|
# Find top CPU consuming processes
|
|
local top_processes
|
|
top_processes=$(ps aux --sort=-%cpu | head -6 | tail -5)
|
|
|
|
while IFS= read -r line; do
|
|
local pid=$(echo "$line" | awk '{print $2}')
|
|
local cpu_percent=$(echo "$line" | awk '{print $3}')
|
|
local name=$(echo "$line" | awk '{print $11}')
|
|
|
|
if (( $(echo "$cpu_percent > 20" | bc -l) )); then
|
|
kill_process_with_notification "$pid" "High CPU Usage" "System CPU: ${cpu_usage}%, Process CPU: ${cpu_percent}%"
|
|
fi
|
|
done <<< "$top_processes"
|
|
fi
|
|
}
|
|
|
|
# Monitor memory usage
|
|
monitor_memory() {
|
|
local mem_info
|
|
mem_info=$(free | grep '^Mem:')
|
|
local total=$(echo "$mem_info" | awk '{print $2}')
|
|
local used=$(echo "$mem_info" | awk '{print $3}')
|
|
local mem_percent=$(( (used * 100) / total ))
|
|
|
|
if [[ "$mem_percent" -gt "$MEMORY_THRESHOLD" ]]; then
|
|
log "HIGH MEMORY USAGE: ${mem_percent}%"
|
|
|
|
# Find top memory consuming processes
|
|
local top_processes
|
|
top_processes=$(ps aux --sort=-%mem | head -6 | tail -5)
|
|
|
|
while IFS= read -r line; do
|
|
local pid=$(echo "$line" | awk '{print $2}')
|
|
local mem_percent_proc=$(echo "$line" | awk '{print $4}')
|
|
local name=$(echo "$line" | awk '{print $11}')
|
|
local mem_mb=$(echo "$line" | awk '{print $6}')
|
|
mem_mb=$((mem_mb / 1024)) # Convert to MB
|
|
|
|
if (( $(echo "$mem_percent_proc > 15" | bc -l) )); then
|
|
kill_process_with_notification "$pid" "High Memory Usage" "System RAM: ${mem_percent}%, Process RAM: ${mem_percent_proc}% (${mem_mb}MB)"
|
|
fi
|
|
done <<< "$top_processes"
|
|
fi
|
|
}
|
|
|
|
# Monitor temperature
|
|
monitor_temperature() {
|
|
if command -v sensors >/dev/null 2>&1; then
|
|
local max_temp=0
|
|
local temp_info=""
|
|
|
|
# Get CPU temperature
|
|
local cpu_temps
|
|
cpu_temps=$(sensors | grep -E "(Core|Package|CPU)" | grep -o '+[0-9]*\.[0-9]*°C' | sed 's/+//;s/°C//')
|
|
|
|
for temp in $cpu_temps; do
|
|
local temp_int=${temp%.*}
|
|
if [[ "$temp_int" -gt "$max_temp" ]]; then
|
|
max_temp="$temp_int"
|
|
temp_info="CPU Temperature: ${temp}°C"
|
|
fi
|
|
done
|
|
|
|
if [[ "$max_temp" -gt "$TEMP_THRESHOLD" ]]; then
|
|
log "HIGH TEMPERATURE: ${max_temp}°C"
|
|
|
|
# Find processes that might be causing high CPU load
|
|
local cpu_processes
|
|
cpu_processes=$(ps aux --sort=-%cpu | head -4 | tail -3)
|
|
|
|
send_notification "🌡️ High Temperature Warning" \
|
|
"Temperature: ${max_temp}°C (Threshold: ${TEMP_THRESHOLD}°C)
|
|
Killing high CPU processes to reduce heat" "critical" "temperature"
|
|
|
|
while IFS= read -r line; do
|
|
local pid=$(echo "$line" | awk '{print $2}')
|
|
local cpu_percent=$(echo "$line" | awk '{print $3}')
|
|
|
|
if (( $(echo "$cpu_percent > 10" | bc -l) )); then
|
|
kill_process_with_notification "$pid" "Temperature Protection" "$temp_info"
|
|
fi
|
|
done <<< "$cpu_processes"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Monitor disk usage
|
|
monitor_disk() {
|
|
local disk_usage
|
|
disk_usage=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')
|
|
|
|
if [[ "$disk_usage" -gt "$DISK_THRESHOLD" ]]; then
|
|
log "HIGH DISK USAGE: ${disk_usage}%"
|
|
|
|
send_notification "💾 Low Disk Space Warning" \
|
|
"Disk usage: ${disk_usage}% (Threshold: ${DISK_THRESHOLD}%)
|
|
Cleaning temporary files..." "critical" "drive-harddisk"
|
|
|
|
# Clean temporary files
|
|
sudo find /tmp -type f -atime +1 -delete 2>/dev/null || true
|
|
sudo find /var/tmp -type f -atime +1 -delete 2>/dev/null || true
|
|
|
|
# Clean package cache
|
|
if command -v paccache >/dev/null 2>&1; then
|
|
sudo paccache -r -k3 2>/dev/null || true
|
|
fi
|
|
|
|
log "DISK CLEANUP COMPLETED"
|
|
fi
|
|
}
|
|
|
|
# Monitor for hanging processes
|
|
monitor_hanging_processes() {
|
|
local hanging_pids
|
|
hanging_pids=$(ps axo pid,etime,state,comm | awk -v hang_time="$PROCESS_HANG_TIME" '
|
|
$3 ~ /D|T/ && $2 ~ /[0-9]+-/ {
|
|
split($2, time_parts, "-")
|
|
if (time_parts[1] >= hang_time/86400 ||
|
|
(time_parts[1] == 0 && time_parts[2] ~ /[0-9]+:[0-9]+/ &&
|
|
time_parts[2] >= hang_time/60)) {
|
|
print $1
|
|
}
|
|
}')
|
|
|
|
for pid in $hanging_pids; do
|
|
if [[ -n "$pid" && "$pid" =~ ^[0-9]+$ ]]; then
|
|
kill_process_with_notification "$pid" "Process Hanging/Uninterruptible Sleep" "Process stuck for >$PROCESS_HANG_TIME seconds"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Monitor swap usage
|
|
monitor_swap() {
|
|
if [[ -f /proc/swaps ]]; then
|
|
local swap_info
|
|
swap_info=$(free | grep '^Swap:')
|
|
local total=$(echo "$swap_info" | awk '{print $2}')
|
|
|
|
if [[ "$total" -gt 0 ]]; then
|
|
local used=$(echo "$swap_info" | awk '{print $3}')
|
|
local swap_percent=$(( (used * 100) / total ))
|
|
|
|
if [[ "$swap_percent" -gt "$SWAP_THRESHOLD" ]]; then
|
|
log "HIGH SWAP USAGE: ${swap_percent}%"
|
|
|
|
send_notification "🔄 High Swap Usage" \
|
|
"Swap usage: ${swap_percent}% - System may be slow
|
|
Killing memory-heavy processes..." "critical" "system-run"
|
|
|
|
# Kill top memory consumers
|
|
local top_mem_processes
|
|
top_mem_processes=$(ps aux --sort=-%mem | head -4 | tail -3)
|
|
|
|
while IFS= read -r line; do
|
|
local pid=$(echo "$line" | awk '{print $2}')
|
|
kill_process_with_notification "$pid" "High Swap Usage" "System Swap: ${swap_percent}%"
|
|
done <<< "$top_mem_processes"
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Monitor system load
|
|
monitor_load() {
|
|
local load_avg
|
|
load_avg=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | sed 's/,//')
|
|
load_avg=${load_avg%.*} # Remove decimal part
|
|
|
|
if [[ "$load_avg" -gt "$LOAD_AVG_THRESHOLD" ]]; then
|
|
log "HIGH SYSTEM LOAD: $load_avg"
|
|
|
|
send_notification "⚡ High System Load" \
|
|
"Load average: $load_avg (Threshold: $LOAD_AVG_THRESHOLD)
|
|
Killing resource-intensive processes..." "critical" "system-monitor"
|
|
|
|
# Kill processes with high CPU and memory usage
|
|
local resource_heavy_processes
|
|
resource_heavy_processes=$(ps aux | awk '$3+$4 > 20 {print $2}' | tail -n +2)
|
|
|
|
for pid in $resource_heavy_processes; do
|
|
if [[ -n "$pid" && "$pid" =~ ^[0-9]+$ ]]; then
|
|
kill_process_with_notification "$pid" "High System Load" "Load Average: $load_avg"
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
# Monitor for memory leaks
|
|
monitor_memory_leaks() {
|
|
local processes_with_leaks
|
|
processes_with_leaks=$(ps aux --sort=-%mem | head -10 | tail -9 | awk '$4 > 25 {print $2}')
|
|
|
|
for pid in $processes_with_leaks; do
|
|
if [[ -n "$pid" && "$pid" =~ ^[0-9]+$ ]]; then
|
|
# Check if process memory is still growing
|
|
local mem_before mem_after
|
|
mem_before=$(ps -p "$pid" -o rss= 2>/dev/null || echo "0")
|
|
sleep 2
|
|
mem_after=$(ps -p "$pid" -o rss= 2>/dev/null || echo "0")
|
|
|
|
if [[ "$mem_after" -gt "$mem_before" ]] && [[ "$mem_after" -gt 1048576 ]]; then # > 1GB
|
|
kill_process_with_notification "$pid" "Potential Memory Leak" "Memory growing rapidly: ${mem_before}KB → ${mem_after}KB"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Monitor browser tabs and limit them
|
|
monitor_browser_tabs() {
|
|
if [[ "$AGGRESSIVE_ON_BROWSERS" == "true" ]]; then
|
|
# Firefox tab monitoring
|
|
if pgrep firefox >/dev/null 2>&1; then
|
|
local firefox_tabs
|
|
firefox_tabs=$(find /tmp -name "*firefox*" -type d 2>/dev/null | wc -l)
|
|
if [[ "$firefox_tabs" -gt "$FIREFOX_MAX_TABS" ]]; then
|
|
log "FIREFOX TAB LIMIT EXCEEDED: $firefox_tabs tabs (limit: $FIREFOX_MAX_TABS)"
|
|
send_notification "🌐 Firefox Tab Limit" \
|
|
"Too many tabs: $firefox_tabs (limit: $FIREFOX_MAX_TABS)
|
|
Closing oldest Firefox processes..." "critical" "web-browser"
|
|
|
|
# Kill oldest Firefox processes
|
|
local old_firefox_pids
|
|
old_firefox_pids=$(ps aux | grep firefox | grep -v grep | head -3 | awk '{print $2}')
|
|
for pid in $old_firefox_pids; do
|
|
kill_process_with_notification "$pid" "Browser Tab Limit Exceeded" "Firefox tabs: $firefox_tabs"
|
|
done
|
|
fi
|
|
fi
|
|
|
|
# Chrome/Chromium tab monitoring
|
|
local chrome_processes
|
|
chrome_processes=$(pgrep -c chrome 2>/dev/null || echo "0")
|
|
if [[ "$chrome_processes" -gt "$CHROME_MAX_TABS" ]]; then
|
|
log "CHROME TAB LIMIT EXCEEDED: $chrome_processes processes (limit: $CHROME_MAX_TABS)"
|
|
send_notification "🌐 Chrome Tab Limit" \
|
|
"Too many processes: $chrome_processes (limit: $CHROME_MAX_TABS)
|
|
Closing excess Chrome processes..." "critical" "web-browser"
|
|
|
|
# Kill oldest Chrome processes
|
|
local old_chrome_pids
|
|
old_chrome_pids=$(ps aux | grep chrome | grep -v grep | head -3 | awk '{print $2}')
|
|
for pid in $old_chrome_pids; do
|
|
kill_process_with_notification "$pid" "Browser Tab Limit Exceeded" "Chrome processes: $chrome_processes"
|
|
done
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Monitor network usage
|
|
monitor_network() {
|
|
if command -v vnstat >/dev/null 2>&1; then
|
|
local network_usage
|
|
network_usage=$(vnstat -i eth0 --json | jq -r '.interfaces[0].traffic.day[0].tx' 2>/dev/null || echo "0")
|
|
network_usage=$((network_usage / 1024 / 1024)) # Convert to MB
|
|
|
|
if [[ "$network_usage" -gt "$NETWORK_THRESHOLD" ]]; then
|
|
log "HIGH NETWORK USAGE: ${network_usage}MB/s"
|
|
send_notification "🌐 High Network Usage" \
|
|
"Network usage: ${network_usage}MB/s
|
|
Monitoring bandwidth-heavy processes..." "normal" "network-wired"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Monitor I/O usage
|
|
monitor_io() {
|
|
if command -v iotop >/dev/null 2>&1; then
|
|
local high_io_processes
|
|
high_io_processes=$(iotop -a -o -d 1 -n 1 | grep -v "TOTAL" | head -3 | awk '{print $2}')
|
|
|
|
for pid in $high_io_processes; do
|
|
if [[ -n "$pid" && "$pid" =~ ^[0-9]+$ ]]; then
|
|
local io_rate
|
|
io_rate=$(iotop -p "$pid" -o -d 1 -n 1 | tail -1 | awk '{print $4}' | sed 's/M.*//')
|
|
if [[ "$io_rate" -gt "$IO_THRESHOLD" ]]; then
|
|
kill_process_with_notification "$pid" "High I/O Usage" "I/O Rate: ${io_rate}MB/s"
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
# Advanced CPU monitoring with app-specific thresholds
|
|
monitor_cpu_advanced() {
|
|
local cpu_usage
|
|
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | sed 's/%us,//')
|
|
cpu_usage=${cpu_usage%.*}
|
|
|
|
# Use aggressive threshold when browsers are running
|
|
local active_threshold="$CPU_THRESHOLD"
|
|
if [[ "$AGGRESSIVE_ON_BROWSERS" == "true" ]] && (pgrep firefox >/dev/null 2>&1 || pgrep chrome >/dev/null 2>&1); then
|
|
active_threshold="$AGGRESSIVE_CPU_THRESHOLD"
|
|
fi
|
|
|
|
if [[ "$cpu_usage" -gt "$active_threshold" ]]; then
|
|
log "HIGH CPU USAGE: ${cpu_usage}% (threshold: ${active_threshold}%)"
|
|
|
|
local top_processes
|
|
top_processes=$(ps aux --sort=-%cpu | head -6 | tail -5)
|
|
|
|
while IFS= read -r line; do
|
|
local pid=$(echo "$line" | awk '{print $2}')
|
|
local cpu_percent=$(echo "$line" | awk '{print $3}')
|
|
local process_info
|
|
process_info=$(get_process_info "$pid")
|
|
local app_type=$(echo "$process_info" | grep -o 'TYPE:[^[:space:]]*' | cut -d: -f2)
|
|
local process_name=$(echo "$process_info" | grep -o 'NAME:[^[:space:]]*' | cut -d: -f2)
|
|
|
|
# Check process behavior history
|
|
local behavior_score
|
|
behavior_score=$(get_process_behavior_score "$process_name" "$app_type")
|
|
|
|
# Apply app-specific thresholds with behavior adjustment
|
|
local kill_threshold=20
|
|
case "$app_type" in
|
|
"browser")
|
|
kill_threshold=15 # More aggressive on browsers
|
|
;;
|
|
"game")
|
|
kill_threshold=50 # Less aggressive on games
|
|
;;
|
|
"graphics"|"media")
|
|
kill_threshold=30
|
|
;;
|
|
esac
|
|
|
|
# Adjust threshold based on behavior score
|
|
kill_threshold=$((kill_threshold + behavior_score))
|
|
|
|
if (( $(echo "$cpu_percent > $kill_threshold" | bc -l) )); then
|
|
record_process_kill "$process_name" "$app_type" "cpu" "$cpu_percent"
|
|
kill_process_with_notification "$pid" "High CPU Usage ($app_type)" "System CPU: ${cpu_usage}%, Process CPU: ${cpu_percent}%"
|
|
fi
|
|
done <<< "$top_processes"
|
|
fi
|
|
}
|
|
|
|
# Process behavior learning system
|
|
get_process_behavior_score() {
|
|
local process_name="$1"
|
|
local app_type="$2"
|
|
local behavior_file="/var/log/pc-monitor-behavior.db"
|
|
|
|
if [[ ! -f "$behavior_file" ]]; then
|
|
echo "0"
|
|
return
|
|
fi
|
|
|
|
# Get kill count for this process in the last 24 hours
|
|
local kill_count
|
|
kill_count=$(grep "$process_name" "$behavior_file" 2>/dev/null | \
|
|
awk -v since="$(date -d '24 hours ago' +%s)" '$1 >= since' | wc -l)
|
|
|
|
# Calculate behavior score (positive = more lenient, negative = more aggressive)
|
|
local score=0
|
|
if [[ "$kill_count" -gt 5 ]]; then
|
|
score=-5 # Very problematic process - be more aggressive
|
|
elif [[ "$kill_count" -gt 2 ]]; then
|
|
score=-2 # Somewhat problematic
|
|
elif [[ "$kill_count" -eq 0 ]]; then
|
|
score=5 # Well-behaved process - be more lenient
|
|
fi
|
|
|
|
echo "$score"
|
|
}
|
|
|
|
# Record process termination for learning
|
|
record_process_kill() {
|
|
local process_name="$1"
|
|
local app_type="$2"
|
|
local reason="$3"
|
|
local usage="$4"
|
|
local behavior_file="/var/log/pc-monitor-behavior.db"
|
|
local timestamp=$(date +%s)
|
|
|
|
# Ensure file exists and is writable
|
|
if [[ ! -f "$behavior_file" ]]; then
|
|
sudo touch "$behavior_file"
|
|
sudo chmod 644 "$behavior_file"
|
|
fi
|
|
|
|
# Record the kill event
|
|
echo "$timestamp $process_name $app_type $reason $usage" | sudo tee -a "$behavior_file" >/dev/null
|
|
|
|
# Clean old entries (older than 7 days)
|
|
local week_ago=$(date -d '7 days ago' +%s)
|
|
sudo awk -v cutoff="$week_ago" '$1 >= cutoff' "$behavior_file" > "/tmp/pc-monitor-behavior.tmp" 2>/dev/null || true
|
|
sudo mv "/tmp/pc-monitor-behavior.tmp" "$behavior_file" 2>/dev/null || true
|
|
}
|
|
|
|
# Smart process prioritization
|
|
smart_process_prioritization() {
|
|
# Identify long-running, well-behaved processes and give them priority
|
|
local well_behaved_processes
|
|
well_behaved_processes=$(ps aux --sort=-etime | head -20 | tail -15 | awk '{print $2}')
|
|
|
|
for pid in $well_behaved_processes; do
|
|
if [[ -n "$pid" && "$pid" =~ ^[0-9]+$ ]]; then
|
|
local process_info
|
|
process_info=$(get_process_info "$pid" 2>/dev/null) || continue
|
|
local process_name=$(echo "$process_info" | grep -o 'NAME:[^[:space:]]*' | cut -d: -f2)
|
|
local app_type=$(echo "$process_info" | grep -o 'TYPE:[^[:space:]]*' | cut -d: -f2)
|
|
|
|
# Check if this is a well-behaved process
|
|
local behavior_score
|
|
behavior_score=$(get_process_behavior_score "$process_name" "$app_type")
|
|
|
|
if [[ "$behavior_score" -gt 0 ]]; then
|
|
# Give better nice value to well-behaved processes
|
|
sudo renice -5 "$pid" 2>/dev/null || true
|
|
log "PRIORITIZED: Process $process_name (PID: $pid) - good behavior score: $behavior_score"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Predictive resource monitoring
|
|
predictive_monitoring() {
|
|
local resource_trend_file="/var/log/pc-monitor-trends.log"
|
|
local current_time=$(date +%s)
|
|
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | sed 's/%us,//' | cut -d. -f1)
|
|
local mem_usage=$(free | grep '^Mem:' | awk '{printf "%.0f", ($3/$2) * 100}')
|
|
|
|
# Record current resource usage
|
|
echo "$current_time $cpu_usage $mem_usage" | sudo tee -a "$resource_trend_file" >/dev/null
|
|
|
|
# Keep only last 100 entries
|
|
sudo tail -100 "$resource_trend_file" > "/tmp/pc-monitor-trends.tmp" 2>/dev/null || true
|
|
sudo mv "/tmp/pc-monitor-trends.tmp" "$resource_trend_file" 2>/dev/null || true
|
|
|
|
# Analyze trend (simple moving average)
|
|
if [[ -f "$resource_trend_file" ]]; then
|
|
local recent_cpu_avg
|
|
local recent_mem_avg
|
|
recent_cpu_avg=$(tail -10 "$resource_trend_file" | awk '{sum+=$2} END {print int(sum/NR)}')
|
|
recent_mem_avg=$(tail -10 "$resource_trend_file" | awk '{sum+=$3} END {print int(sum/NR)}')
|
|
|
|
# Predict if we're trending towards high usage
|
|
if [[ "$recent_cpu_avg" -gt $((CPU_THRESHOLD - 10)) ]] && [[ "$cpu_usage" -lt "$CPU_THRESHOLD" ]]; then
|
|
log "PREDICTIVE WARNING: CPU usage trending high ($recent_cpu_avg% average)"
|
|
send_notification "📈 Resource Trend Warning" \
|
|
"CPU usage trending upward: ${recent_cpu_avg}% average
|
|
System may reach threshold soon" "normal" "dialog-information"
|
|
fi
|
|
|
|
if [[ "$recent_mem_avg" -gt $((MEMORY_THRESHOLD - 10)) ]] && [[ "$mem_usage" -lt "$MEMORY_THRESHOLD" ]]; then
|
|
log "PREDICTIVE WARNING: Memory usage trending high ($recent_mem_avg% average)"
|
|
send_notification "📈 Memory Trend Warning" \
|
|
"Memory usage trending upward: ${recent_mem_avg}% average
|
|
System may reach threshold soon" "normal" "dialog-information"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Load configuration
|
|
load_config() {
|
|
if [[ -f "$CONFIG_FILE" ]]; then
|
|
source "$CONFIG_FILE"
|
|
log "Configuration loaded from $CONFIG_FILE"
|
|
else
|
|
log "Using default configuration"
|
|
fi
|
|
}
|
|
|
|
# Create default configuration file
|
|
create_default_config() {
|
|
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
sudo tee "$CONFIG_FILE" > /dev/null << EOF
|
|
# PC Monitor Enhanced Configuration
|
|
# ===================================
|
|
|
|
# Basic Thresholds
|
|
CPU_THRESHOLD=85
|
|
MEMORY_THRESHOLD=90
|
|
TEMP_THRESHOLD=80
|
|
DISK_THRESHOLD=95
|
|
PROCESS_HANG_TIME=30
|
|
SWAP_THRESHOLD=80
|
|
LOAD_AVG_THRESHOLD=10
|
|
|
|
# Advanced Features
|
|
NETWORK_THRESHOLD=50
|
|
IO_THRESHOLD=100
|
|
BROWSER_TAB_LIMIT=20
|
|
AGGRESSIVE_ON_BROWSERS=true
|
|
AGGRESSIVE_CPU_THRESHOLD=75
|
|
AGGRESSIVE_MEMORY_THRESHOLD=80
|
|
|
|
# Application-Specific Thresholds
|
|
BROWSER_CPU_THRESHOLD=60
|
|
BROWSER_MEMORY_THRESHOLD=70
|
|
GAME_CPU_THRESHOLD=95
|
|
GAME_MEMORY_THRESHOLD=85
|
|
IDE_MEMORY_THRESHOLD=75
|
|
|
|
# Browser Tab Limits
|
|
FIREFOX_MAX_TABS=15
|
|
CHROME_MAX_TABS=15
|
|
EDGE_MAX_TABS=10
|
|
|
|
# Notification Settings
|
|
NOTIFICATION_TIMEOUT=5000
|
|
EOF
|
|
log "Created enhanced default configuration at $CONFIG_FILE"
|
|
fi
|
|
}
|
|
|
|
# Check dependencies
|
|
check_dependencies() {
|
|
local missing_deps=()
|
|
|
|
for cmd in bc ps free df top sensors; do
|
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
missing_deps+=("$cmd")
|
|
fi
|
|
done
|
|
|
|
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
|
log "Missing dependencies: ${missing_deps[*]}"
|
|
send_notification "⚠️ PC Monitor Warning" \
|
|
"Missing dependencies: ${missing_deps[*]}
|
|
Please install missing packages" "critical" "dialog-error"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Main monitoring loop
|
|
main_loop() {
|
|
log "PC Monitor started - Enhanced system protection with AI-powered features"
|
|
send_notification "🛡️ PC Monitor Active - AI Enhanced" \
|
|
"Advanced system protection enabled
|
|
Features: Smart Learning, Predictive Analysis, App-Specific Control
|
|
Monitoring: CPU, Memory, Temperature, Disk, Processes, Browsers, Network, I/O" "normal" "security-high"
|
|
|
|
local cycle_count=0
|
|
while true; do
|
|
# Core monitoring (every cycle)
|
|
monitor_cpu_advanced
|
|
monitor_memory
|
|
monitor_temperature
|
|
monitor_disk
|
|
monitor_hanging_processes
|
|
monitor_swap
|
|
monitor_load
|
|
monitor_browser_tabs
|
|
|
|
# Extended monitoring (every 3rd cycle to reduce overhead)
|
|
if (( cycle_count % 3 == 0 )); then
|
|
monitor_memory_leaks
|
|
monitor_network
|
|
monitor_io
|
|
predictive_monitoring
|
|
fi
|
|
|
|
# AI features (every 5th cycle to minimize impact)
|
|
if (( cycle_count % 5 == 0 )); then
|
|
smart_process_prioritization
|
|
fi
|
|
|
|
cycle_count=$((cycle_count + 1))
|
|
sleep 5
|
|
done
|
|
}
|
|
|
|
# Signal handlers
|
|
cleanup() {
|
|
log "PC Monitor stopping..."
|
|
rm -f "$PID_FILE"
|
|
send_notification "🛡️ PC Monitor Stopped" \
|
|
"System protection disabled" "normal" "security-medium"
|
|
exit 0
|
|
}
|
|
|
|
# Setup signal traps
|
|
trap cleanup SIGTERM SIGINT
|
|
|
|
# Main execution
|
|
main() {
|
|
init_logging
|
|
check_dependencies
|
|
create_default_config
|
|
load_config
|
|
|
|
# Write PID file
|
|
echo $$ > "$PID_FILE"
|
|
|
|
# Start monitoring
|
|
main_loop
|
|
}
|
|
|
|
# Run main function if script is executed directly
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
main "$@"
|
|
fi |