Files

1322 lines
43 KiB
Bash
Executable File

#!/bin/bash
set -eo pipefail
################################################################################
# Disk Space Analyzer (WinDirStat for Linux)
################################################################################
# Purpose: Find space hogs, identify cleanup candidates, visualize disk usage
# Features:
# - Top space consumers by directory
# - Largest files scanner
# - Old/temporary file detection
# - Log/email/backup/database analysis
# - WordPress-specific analysis
# - Safe cleanup with preview
# - Export reports
################################################################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
source "$SCRIPT_DIR/lib/common-functions.sh"
source "$SCRIPT_DIR/lib/system-detect.sh"
source "$SCRIPT_DIR/lib/reference-db.sh"
# Require root
if [ "$EUID" -ne 0 ]; then
print_error "This script must be run as root"
exit 1
fi
# Ensure cache is fresh (only rebuilds if > 1 hour old)
db_ensure_fresh 2>/dev/null || true
# Temp file for results
TEMP_DIR="/tmp/disk-analysis-$$"
mkdir -p "$TEMP_DIR"
# Cache file for faster repeated scans
CACHE_FILE="$TEMP_DIR/scan_cache.txt"
# Cleanup on exit
trap 'rm -rf "$TEMP_DIR"' EXIT
################################################################################
# UTILITY FUNCTIONS
################################################################################
format_size() {
local bytes=$1
# Handle empty or non-numeric input
if ! [[ "$bytes" =~ ^[0-9]+$ ]]; then
echo "0B"
return
fi
if [ "$bytes" -ge 1099511627776 ]; then
awk "BEGIN {printf \"%.2fTB\", $bytes/1099511627776}"
elif [ "$bytes" -ge 1073741824 ]; then
awk "BEGIN {printf \"%.2fGB\", $bytes/1073741824}"
elif [ "$bytes" -ge 1048576 ]; then
awk "BEGIN {printf \"%.2fMB\", $bytes/1048576}"
elif [ "$bytes" -ge 1024 ]; then
awk "BEGIN {printf \"%.2fKB\", $bytes/1024}"
else
echo "${bytes}B"
fi
}
# Convert human-readable size to bytes (no bc dependency)
size_to_bytes() {
local size="$1"
local num=$(echo "$size" | sed 's/[^0-9.]//g')
local unit=$(echo "$size" | sed 's/[0-9.]//g')
# Convert to integer bytes using awk
case "$unit" in
T|TB) awk "BEGIN {printf \"%.0f\", $num * 1099511627776}" ;;
G|GB) awk "BEGIN {printf \"%.0f\", $num * 1073741824}" ;;
M|MB) awk "BEGIN {printf \"%.0f\", $num * 1048576}" ;;
K|KB) awk "BEGIN {printf \"%.0f\", $num * 1024}" ;;
*) echo "${num%%.*}" ;;
esac
}
show_progress() {
local message="$1"
echo -ne "\r${CYAN}${NC} $message... "
}
# Progress bar for long operations
show_progress_bar() {
local current=$1
local total=$2
local width=50
if [ "$total" -eq 0 ]; then
return
fi
local percent=$((current * 100 / total))
local filled=$((current * width / total))
printf "\r${CYAN}["
printf "%${filled}s" | tr ' ' '='
printf "%$((width - filled))s" | tr ' ' '-'
printf "]${NC} %d%%" "$percent"
}
################################################################################
# ANALYSIS FUNCTIONS
################################################################################
analyze_disk_overview() {
clear
print_banner "Disk Space Overview"
echo ""
# Show all mounted filesystems
df -h | grep -E '^/dev/' | while read -r line; do
filesystem=$(echo "$line" | awk '{print $1}')
size=$(echo "$line" | awk '{print $2}')
used=$(echo "$line" | awk '{print $3}')
avail=$(echo "$line" | awk '{print $4}')
use_pct=$(echo "$line" | awk '{print $5}' | tr -d '%')
mount=$(echo "$line" | awk '{print $6}')
# Color code by usage percentage
if [ "$use_pct" -ge 90 ]; then
color="${RED}"
status="CRITICAL"
icon="🔴"
elif [ "$use_pct" -ge 75 ]; then
color="${YELLOW}"
status="WARNING"
icon="🟡"
else
color="${GREEN}"
status="OK"
icon="🟢"
fi
echo -e "${BOLD}$mount${NC} ($filesystem) $icon"
echo -e " Size: $size | Used: ${color}$used ($use_pct%)${NC} | Available: $avail"
echo -e " Status: ${color}${status}${NC}"
echo ""
done
# Inodes check (often overlooked!)
echo -e "${BOLD}Inode Usage:${NC}"
echo ""
df -i | grep -E '^/dev/' | while read -r line; do
filesystem=$(echo "$line" | awk '{print $1}')
iused=$(echo "$line" | awk '{print $3}')
iavail=$(echo "$line" | awk '{print $4}')
iuse_pct=$(echo "$line" | awk '{print $5}' | tr -d '%')
mount=$(echo "$line" | awk '{print $6}')
if [ "$iuse_pct" -ge 90 ]; then
echo -e " ${RED}$mount: ${iuse_pct}% used (CRITICAL - out of inodes!)${NC}"
elif [ "$iuse_pct" -ge 75 ]; then
echo -e " ${YELLOW}$mount: ${iuse_pct}% used${NC}"
fi
done
echo ""
press_enter
}
find_largest_directories() {
local scan_path="${1:-/}"
local depth="${2:-2}"
clear
print_banner "Largest Directories"
echo ""
echo "Scanning: $scan_path (depth: $depth)"
echo "This may take a few minutes..."
echo ""
# Scan directories, excluding system paths that cause errors
show_progress "Analyzing directory sizes"
du -h --max-depth="$depth" \
--exclude="/proc" \
--exclude="/sys" \
--exclude="/dev" \
--exclude="/run" \
"$scan_path" 2>/dev/null | \
sort -rh | \
head -50 > "$TEMP_DIR/largest_dirs.txt"
echo -e "\r${GREEN}${NC} Analysis complete "
echo ""
# Display results in a table
echo -e "${BOLD}Top 30 Largest Directories:${NC}"
echo "───────────────────────────────────────────────────────────────"
printf "%-15s %s\n" "SIZE" "PATH"
echo "───────────────────────────────────────────────────────────────"
head -30 "$TEMP_DIR/largest_dirs.txt" | \
awk '{printf "%-15s %s\n", $1, $2}' | \
while read -r size path; do
# Highlight paths over 10GB
size_bytes=$(size_to_bytes "$size")
if [ "$size_bytes" -ge 10737418240 ]; then
echo -e " ${RED}$size${NC} $path"
elif [ "$size_bytes" -ge 1073741824 ]; then
echo -e " ${YELLOW}$size${NC} $path"
else
echo -e " ${CYAN}$size${NC} $path"
fi
done
echo ""
echo -e "${DIM}Tip: Select a specific directory to drill down deeper${NC}"
echo ""
# Offer drill-down
read -p "Enter path to analyze deeper (or press Enter to skip): " drill_path
if [ -n "$drill_path" ] && [ -d "$drill_path" ]; then
find_largest_directories "$drill_path" 3
else
press_enter
fi
}
find_largest_files() {
local scan_path="${1:-/}"
local min_size="${2:-100M}"
clear
print_banner "Largest Files Scanner"
echo ""
echo "Scanning: $scan_path"
echo "Minimum size: $min_size"
echo "This may take several minutes..."
echo ""
show_progress "Finding large files"
find "$scan_path" -type f -size +"$min_size" \
-not -path "*/proc/*" \
-not -path "*/sys/*" \
-not -path "*/dev/*" \
-exec du -h {} + 2>/dev/null | \
sort -rh | \
head -100 > "$TEMP_DIR/largest_files.txt"
local count=$(wc -l < "$TEMP_DIR/largest_files.txt")
echo -e "\r${GREEN}${NC} Found $count large files "
echo ""
if [ "$count" -eq 0 ]; then
echo -e "${GREEN}No files found larger than $min_size${NC}"
echo ""
press_enter
return
fi
# Display results
echo -e "${BOLD}Top 50 Largest Files:${NC}"
echo "───────────────────────────────────────────────────────────────"
printf "%-15s %-50s %s\n" "SIZE" "FILE" "TYPE"
echo "───────────────────────────────────────────────────────────────"
head -50 "$TEMP_DIR/largest_files.txt" | \
while read -r size path; do
# Determine file type
ext="${path##*.}"
case "$ext" in
log|gz|bz2|xz) filetype="Log" ;;
sql|dump) filetype="Database" ;;
tar|zip|rar|7z) filetype="Archive" ;;
mp4|avi|mkv|mov) filetype="Video" ;;
jpg|jpeg|png|gif) filetype="Image" ;;
pdf) filetype="PDF" ;;
*) filetype="Data" ;;
esac
# Color code by size
size_bytes=$(size_to_bytes "$size")
if [ "$size_bytes" -ge 1073741824 ]; then
color="${RED}"
elif [ "$size_bytes" -ge 524288000 ]; then # 500MB
color="${YELLOW}"
else
color="${CYAN}"
fi
# Truncate path if too long
display_path="$path"
if [ "${#path}" -gt 50 ]; then
display_path="...${path: -47}"
fi
printf " ${color}%-15s${NC} %-50s %s\n" "$size" "$display_path" "$filetype"
done
echo ""
press_enter
}
analyze_old_files() {
local scan_path="${1:-/home}"
local days="${2:-90}"
clear
print_banner "Old Files Detection"
echo ""
echo "Scanning: $scan_path"
echo "Finding files not accessed in $days days..."
echo ""
show_progress "Searching for old files"
find "$scan_path" -type f -atime +$days -size +10M \
-not -path "*/.*" \
-exec du -h {} + 2>/dev/null | \
sort -rh | \
head -100 > "$TEMP_DIR/old_files.txt"
local count=$(wc -l < "$TEMP_DIR/old_files.txt")
echo -e "\r${GREEN}${NC} Found $count old large files "
echo ""
if [ "$count" -eq 0 ]; then
echo -e "${GREEN}No old large files found (>10MB, not accessed in $days days)${NC}"
echo ""
press_enter
return
fi
# Calculate total space
local total_bytes=0
while read -r size path; do
bytes=$(size_to_bytes "$size")
total_bytes=$((total_bytes + bytes))
done < "$TEMP_DIR/old_files.txt"
echo -e "${BOLD}Potential Space Savings: ${GREEN}$(format_size $total_bytes)${NC}"
echo -e "${BOLD}File Count: ${CYAN}$count${NC}"
echo ""
echo -e "${BOLD}Top 30 Old Files:${NC}"
echo "───────────────────────────────────────────────────────────────"
head -30 "$TEMP_DIR/old_files.txt" | \
while read -r size path; do
# Get last access time
access_time=$(stat -c %x "$path" 2>/dev/null | cut -d' ' -f1)
echo -e " ${YELLOW}$size${NC} $path ${DIM}(Last access: $access_time)${NC}"
done
echo ""
press_enter
}
analyze_log_files() {
clear
print_banner "Log Files Analysis"
echo ""
echo "Scanning common log directories..."
echo ""
show_progress "Analyzing log files"
# Find all log files efficiently
{
find /var/log -type f \( -name "*.log" -o -name "*.log.*" -o -name "*.gz" \) -size +1M 2>/dev/null
find /home/*/logs -type f -size +1M 2>/dev/null
find /var/www/vhosts/*/logs -type f -size +1M 2>/dev/null
find /usr/local/apache/domlogs -type f -size +1M 2>/dev/null
} | while read -r file; do
du -h "$file" 2>/dev/null
done | sort -rh > "$TEMP_DIR/log_files.txt"
local count=$(wc -l < "$TEMP_DIR/log_files.txt")
echo -e "\r${GREEN}${NC} Found $count log files "
echo ""
if [ "$count" -eq 0 ]; then
echo -e "${GREEN}No large log files found (>1MB)${NC}"
echo ""
press_enter
return
fi
# Calculate totals by type
local total_bytes=0
local compressed=0
local active=0
while read -r size path; do
bytes=$(size_to_bytes "$size")
total_bytes=$((total_bytes + bytes))
if [[ "$path" =~ \.gz$ ]] || [[ "$path" =~ \.bz2$ ]] || [[ "$path" =~ \.xz$ ]]; then
compressed=$((compressed + 1))
else
active=$((active + 1))
fi
done < "$TEMP_DIR/log_files.txt"
echo -e "${BOLD}Log File Statistics:${NC}"
echo -e " Total Size: ${YELLOW}$(format_size $total_bytes)${NC}"
echo -e " Active Logs: ${CYAN}$active files${NC}"
echo -e " Compressed Logs: ${CYAN}$compressed files${NC}"
echo ""
echo -e "${BOLD}Top 30 Largest Log Files:${NC}"
echo "───────────────────────────────────────────────────────────────"
head -30 "$TEMP_DIR/log_files.txt" | \
while read -r size path; do
# Check if actively being written to
if lsof "$path" &>/dev/null; then
status="${GREEN}[ACTIVE]${NC}"
else
status="${DIM}[IDLE]${NC}"
fi
echo -e " ${YELLOW}$size${NC} $path $status"
done
echo ""
echo -e "${BOLD}Cleanup Suggestions:${NC}"
echo " • Rotate logs: logrotate -f /etc/logrotate.conf"
echo " • Compress old logs: find /var/log -name '*.log' -mtime +7 -exec gzip {} \\;"
echo " • Delete old compressed: find /var/log -name '*.gz' -mtime +30 -delete"
echo ""
press_enter
}
analyze_email_storage() {
clear
print_banner "Email Storage Analysis"
echo ""
# Find mail directories
local mail_dirs=()
[ -d "/var/spool/mail" ] && mail_dirs+=("/var/spool/mail")
[ -d "/home/*/mail" ] && mail_dirs+=(/home/*/mail)
[ -d "/home/*/Maildir" ] && mail_dirs+=(/home/*/Maildir)
[ -d "/var/vmail" ] && mail_dirs+=("/var/vmail")
if [ ${#mail_dirs[@]} -eq 0 ]; then
echo -e "${DIM}No mail directories found${NC}"
echo ""
press_enter
return
fi
echo "Analyzing email storage..."
echo ""
show_progress "Scanning mail directories"
# Scan each mail directory
for dir in "${mail_dirs[@]}"; do
du -sh "$dir" 2>/dev/null
done | sort -rh > "$TEMP_DIR/email_usage.txt"
echo -e "\r${GREEN}${NC} Analysis complete "
echo ""
# Calculate total
local total_bytes=0
while read -r size path; do
bytes=$(size_to_bytes "$size")
total_bytes=$((total_bytes + bytes))
done < "$TEMP_DIR/email_usage.txt"
echo -e "${BOLD}Total Email Storage: ${YELLOW}$(format_size $total_bytes)${NC}"
echo ""
# Show breakdown
echo -e "${BOLD}Mail Directories:${NC}"
echo "───────────────────────────────────────────────────────────────"
while read -r size path; do
echo -e " ${CYAN}$size${NC} $path"
done < "$TEMP_DIR/email_usage.txt"
echo ""
echo -e "${BOLD}Cleanup Suggestions:${NC}"
echo " • Delete old mail: find /home/*/mail -type f -mtime +180 -delete"
echo " • Archive large mailboxes: tar -czf backup.tar.gz /home/user/mail"
echo " • Check quota settings in control panel"
echo ""
press_enter
}
analyze_databases() {
clear
print_banner "Database Storage Analysis"
echo ""
local found=0
# MySQL/MariaDB
if [ -d "/var/lib/mysql" ]; then
echo -e "${BOLD}MySQL/MariaDB Databases:${NC}"
echo ""
show_progress "Analyzing MySQL databases"
du -sh /var/lib/mysql/* 2>/dev/null | sort -rh | head -20 > "$TEMP_DIR/mysql_dbs.txt"
local mysql_total=$(du -sh /var/lib/mysql 2>/dev/null | awk '{print $1}')
echo -e "\r Total Size: ${YELLOW}$mysql_total${NC}"
echo ""
echo " Top 15 Databases:"
echo " ───────────────────────────────────────────────────────────"
head -15 "$TEMP_DIR/mysql_dbs.txt" | while read -r size path; do
dbname=$(basename "$path")
echo -e " ${CYAN}$size${NC} $dbname"
done
echo ""
found=1
fi
# PostgreSQL
if [ -d "/var/lib/pgsql" ] || [ -d "/var/lib/postgresql" ]; then
local pgdir="/var/lib/pgsql"
[ -d "/var/lib/postgresql" ] && pgdir="/var/lib/postgresql"
echo -e "${BOLD}PostgreSQL Databases:${NC}"
echo ""
local pgsql_total=$(du -sh "$pgdir" 2>/dev/null | awk '{print $1}')
echo -e " Total Size: ${YELLOW}$pgsql_total${NC}"
echo ""
found=1
fi
if [ "$found" -eq 0 ]; then
echo -e "${DIM}No database directories found${NC}"
else
echo -e "${BOLD}Cleanup Suggestions:${NC}"
echo " • Drop unused databases"
echo " • Optimize tables: mysqlcheck -o --all-databases"
echo " • Archive old data: mysqldump and compress"
fi
echo ""
press_enter
}
analyze_backups() {
clear
print_banner "Backup Files Analysis"
echo ""
show_progress "Searching for backup files"
# Find common backup files and directories
{
find /backup -type f -size +100M 2>/dev/null
find /backups -type f -size +100M 2>/dev/null
find /home -name "backup*.tar.gz" -o -name "*.sql.gz" -o -name "*.dump" 2>/dev/null | head -100
find /var/backups -type f -size +100M 2>/dev/null
find / -maxdepth 3 -name "*backup*" -type f -size +100M 2>/dev/null
} | while read -r file; do
du -h "$file" 2>/dev/null
done | sort -rh | head -50 > "$TEMP_DIR/backup_files.txt"
local count=$(wc -l < "$TEMP_DIR/backup_files.txt")
echo -e "\r${GREEN}${NC} Found $count backup files "
echo ""
if [ "$count" -eq 0 ]; then
echo -e "${GREEN}No large backup files found (>100MB)${NC}"
echo ""
press_enter
return
fi
# Calculate total
local total_bytes=0
while read -r size path; do
bytes=$(size_to_bytes "$size")
total_bytes=$((total_bytes + bytes))
done < "$TEMP_DIR/backup_files.txt"
echo -e "${BOLD}Total Backup Storage: ${YELLOW}$(format_size $total_bytes)${NC}"
echo -e "${BOLD}File Count: ${CYAN}$count${NC}"
echo ""
echo -e "${BOLD}Top 30 Largest Backups:${NC}"
echo "───────────────────────────────────────────────────────────────"
head -30 "$TEMP_DIR/backup_files.txt" | \
while read -r size path; do
# Get age
age_days=$(( ($(date +%s) - $(stat -c %Y "$path" 2>/dev/null || echo 0)) / 86400 ))
if [ "$age_days" -gt 90 ]; then
age_color="${RED}"
age_text="$age_days days old"
elif [ "$age_days" -gt 30 ]; then
age_color="${YELLOW}"
age_text="$age_days days old"
else
age_color="${GREEN}"
age_text="$age_days days old"
fi
echo -e " ${YELLOW}$size${NC} $path ${age_color}($age_text)${NC}"
done
echo ""
echo -e "${BOLD}Cleanup Suggestions:${NC}"
echo " • Delete backups older than 90 days"
echo " • Move old backups to off-server storage"
echo " • Verify backup rotation is working"
echo ""
press_enter
}
analyze_wordpress() {
clear
print_banner "WordPress Storage Analysis"
echo ""
# Find WordPress installations from cache (instant lookup, no filesystem scan)
show_progress "Finding WordPress installations"
local wp_count=0
local wp_data=""
# Get WordPress data from cache
if command -v db_get_all_wordpress &>/dev/null; then
wp_data=$(db_get_all_wordpress 2>/dev/null || true)
fi
# Count WP installations
if [ -n "$wp_data" ]; then
wp_count=$(echo "$wp_data" | grep -c "^WP|" || echo 0)
fi
if [ "$wp_count" -eq 0 ]; then
echo -e "\r${DIM}No WordPress installations found${NC} "
echo ""
press_enter
return
fi
echo -e "\r${GREEN}${NC} Found ${wp_count} WordPress installations "
echo ""
echo -e "${BOLD}WordPress Space Usage:${NC}"
echo "───────────────────────────────────────────────────────────────"
# Process cached WordPress data
while IFS='|' read -r type domain path db_name db_user version plugins themes; do
if [ "$type" = "WP" ] && [ -d "$path" ]; then
# Calculate sizes
total_size=$(du -sh "$path" 2>/dev/null | awk '{print $1}')
uploads_size=$(du -sh "$path/wp-content/uploads" 2>/dev/null | awk '{print $1}')
plugins_size=$(du -sh "$path/wp-content/plugins" 2>/dev/null | awk '{print $1}')
cache_size=$(du -sh "$path/wp-content/cache" 2>/dev/null | awk '{print $1}')
echo -e "${BOLD}$domain${NC} ($total_size)"
echo -e " Uploads: ${CYAN}${uploads_size:-0}${NC}"
echo -e " Plugins: ${CYAN}${plugins_size:-0}${NC}"
echo -e " Cache: ${CYAN}${cache_size:-0}${NC}"
echo ""
fi
done <<< "$wp_data"
echo -e "${BOLD}Cleanup Suggestions:${NC}"
echo " • Delete old revisions: wp post delete \$(wp post list --post_type=revision --format=ids)"
echo " • Optimize images: Use WP plugins like Imagify or compress manually"
echo " • Clear cache: rm -rf wp-content/cache/*"
echo " • Remove unused plugins/themes"
echo ""
press_enter
}
analyze_temp_files() {
clear
print_banner "Temporary Files Analysis"
echo ""
echo "Scanning /tmp and /var/tmp..."
echo ""
show_progress "Analyzing temporary files"
du -h --max-depth=2 /tmp /var/tmp 2>/dev/null | \
sort -rh | \
head -50 > "$TEMP_DIR/temp_files.txt"
echo -e "\r${GREEN}${NC} Analysis complete "
echo ""
# Calculate total
local tmp_size=$(du -sh /tmp 2>/dev/null | awk '{print $1}')
local var_tmp_size=$(du -sh /var/tmp 2>/dev/null | awk '{print $1}')
echo -e "${BOLD}Temporary Directory Sizes:${NC}"
echo -e " /tmp: ${CYAN}$tmp_size${NC}"
echo -e " /var/tmp: ${CYAN}$var_tmp_size${NC}"
echo ""
# Count old files
local old_count=$(find /tmp -type f -mtime +7 2>/dev/null | wc -l)
if [ "$old_count" -gt 0 ]; then
echo -e " ${YELLOW}Found $old_count files older than 7 days in /tmp${NC}"
echo ""
fi
echo -e "${BOLD}Top 30 Items:${NC}"
echo "───────────────────────────────────────────────────────────────"
head -30 "$TEMP_DIR/temp_files.txt" | \
while read -r size path; do
echo -e " ${CYAN}$size${NC} $path"
done
echo ""
echo -e "${BOLD}Safe Cleanup Commands:${NC}"
echo " • Clear old temp files: find /tmp -type f -mtime +7 -delete"
echo " • Clear package cache: yum clean all (or apt-get clean)"
echo " • Clear user cache: rm -rf /home/*/.cache/*"
echo ""
press_enter
}
analyze_by_user() {
clear
print_banner "Disk Usage by User/Domain"
echo ""
local base_dir="$SYS_USER_HOME_BASE"
echo "Analyzing $base_dir directory..."
echo ""
show_progress "Calculating user disk usage"
du -sh "$base_dir"/* 2>/dev/null | sort -rh > "$TEMP_DIR/user_usage.txt"
local count=$(wc -l < "$TEMP_DIR/user_usage.txt")
echo -e "\r${GREEN}${NC} Analysis complete ($count accounts) "
echo ""
# Calculate total
local total_bytes=0
while read -r size path; do
bytes=$(size_to_bytes "$size")
total_bytes=$((total_bytes + bytes))
done < "$TEMP_DIR/user_usage.txt"
echo -e "${BOLD}Total Usage: ${YELLOW}$(format_size $total_bytes)${NC}"
echo ""
if [ "$SYS_CONTROL_PANEL" = "cPanel" ] || [ "$SYS_CONTROL_PANEL" = "InterWorx" ]; then
echo -e "${BOLD}Top 30 Users by Disk Usage:${NC}"
echo "───────────────────────────────────────────────────────────────"
head -30 "$TEMP_DIR/user_usage.txt" | \
while read -r size path; do
username=$(basename "$path")
# Highlight users over 10GB
size_bytes=$(size_to_bytes "$size")
if [ "$size_bytes" -ge 10737418240 ]; then
echo -e " ${RED}$size${NC} $username"
elif [ "$size_bytes" -ge 5368709120 ]; then
echo -e " ${YELLOW}$size${NC} $username"
else
echo -e " ${CYAN}$size${NC} $username"
fi
done
elif [ "$SYS_CONTROL_PANEL" = "Plesk" ]; then
echo -e "${BOLD}Top 30 Domains by Disk Usage:${NC}"
echo "───────────────────────────────────────────────────────────────"
head -30 "$TEMP_DIR/user_usage.txt" | \
while read -r size path; do
domain=$(basename "$path")
echo -e " ${CYAN}$size${NC} $domain"
done
else
echo -e "${BOLD}Top 30 Directories by Disk Usage:${NC}"
echo "───────────────────────────────────────────────────────────────"
head -30 "$TEMP_DIR/user_usage.txt" | \
while read -r size path; do
echo -e " ${CYAN}$size${NC} $path"
done
fi
echo ""
press_enter
}
analyze_package_cache() {
clear
print_banner "Package Manager Cache"
echo ""
# Detect package manager
if command -v yum &>/dev/null; then
echo "Analyzing YUM/DNF cache..."
echo ""
local cache_dir="/var/cache/yum"
[ -d "/var/cache/dnf" ] && cache_dir="/var/cache/dnf"
if [ -d "$cache_dir" ]; then
local cache_size=$(du -sh "$cache_dir" 2>/dev/null | awk '{print $1}')
local pkg_count=$(find "$cache_dir" -name "*.rpm" 2>/dev/null | wc -l)
echo -e " Cache location: $cache_dir"
echo -e " Cache size: ${YELLOW}$cache_size${NC}"
echo -e " Cached packages: $pkg_count"
echo ""
echo -e "${BOLD}Cleanup command:${NC}"
echo " yum clean all (or dnf clean all)"
fi
elif command -v apt-get &>/dev/null; then
echo "Analyzing APT cache..."
echo ""
local cache_dir="/var/cache/apt/archives"
if [ -d "$cache_dir" ]; then
local cache_size=$(du -sh "$cache_dir" 2>/dev/null | awk '{print $1}')
local count=$(find "$cache_dir" -name "*.deb" 2>/dev/null | wc -l)
echo -e " Cache location: $cache_dir"
echo -e " Cache size: ${YELLOW}$cache_size${NC}"
echo -e " Packages cached: $count"
echo ""
echo -e "${BOLD}Cleanup commands:${NC}"
echo " apt-get clean # Remove all cached packages"
echo " apt-get autoclean # Remove old cached packages"
fi
fi
echo ""
press_enter
}
generate_report() {
clear
print_banner "Generate Disk Usage Report"
echo ""
local report_file="/root/disk-analysis-report-$(date +%Y%m%d-%H%M%S).txt"
echo "Generating comprehensive disk usage report..."
echo ""
{
echo "========================================================================"
echo "DISK SPACE ANALYSIS REPORT"
echo "Generated: $(date)"
echo "Server: $(hostname)"
echo "========================================================================"
echo ""
echo "DISK OVERVIEW:"
echo "------------------------------------------------------------------------"
df -h | grep -E '^/dev/'
echo ""
echo "INODE USAGE:"
echo "------------------------------------------------------------------------"
df -i | grep -E '^/dev/'
echo ""
if [ -f "$TEMP_DIR/largest_dirs.txt" ]; then
echo "LARGEST DIRECTORIES:"
echo "------------------------------------------------------------------------"
head -20 "$TEMP_DIR/largest_dirs.txt"
echo ""
fi
if [ -f "$TEMP_DIR/largest_files.txt" ]; then
echo "LARGEST FILES:"
echo "------------------------------------------------------------------------"
head -20 "$TEMP_DIR/largest_files.txt"
echo ""
fi
if [ -f "$TEMP_DIR/user_usage.txt" ]; then
echo "USER/DOMAIN USAGE:"
echo "------------------------------------------------------------------------"
head -20 "$TEMP_DIR/user_usage.txt"
echo ""
fi
echo "========================================================================"
echo "END OF REPORT"
echo "========================================================================"
} > "$report_file"
echo -e "${GREEN}${NC} Report generated: $report_file"
echo ""
echo "Report contains:"
echo " • Disk and inode usage"
echo " • Largest directories"
echo " • Largest files"
echo " • User/domain breakdown"
echo ""
read -p "View report now? (y/n): " view
if [ "$view" = "y" ]; then
less "$report_file"
fi
press_enter
}
################################################################################
# INTERACTIVE CLEANUP
################################################################################
interactive_cleanup_menu() {
while true; do
clear
print_banner "Interactive Cleanup"
echo ""
echo -e "${BOLD}Safe Cleanup Options:${NC}"
echo ""
echo -e " ${GREEN}1)${NC} Clear old log files (>30 days)"
echo -e " ${GREEN}2)${NC} Clear package manager cache"
echo -e " ${GREEN}3)${NC} Clear old temp files (>7 days)"
echo -e " ${GREEN}4)${NC} Clear old compressed logs (*.gz >30 days)"
echo -e " ${GREEN}5)${NC} Clear WordPress cache files"
echo -e " ${GREEN}6)${NC} Show cleanup summary (dry-run all)"
echo ""
echo -e " ${RED}0)${NC} Back"
echo ""
echo -e "${CYAN}──────────────────────────────────────────────────────────────${NC}"
read -p "Select option: " choice
case "$choice" in
1) cleanup_old_logs ;;
2) cleanup_package_cache ;;
3) cleanup_temp_files ;;
4) cleanup_compressed_logs ;;
5) cleanup_wordpress_cache ;;
6) show_cleanup_summary ;;
0) return ;;
*) echo -e "${RED}Invalid option${NC}"; sleep 1 ;;
esac
done
}
cleanup_old_logs() {
clear
print_banner "Clear Old Log Files"
echo ""
echo "Finding log files older than 30 days..."
echo ""
# Dry run first - show what will be deleted
local files=$(find /var/log -name "*.log" -mtime +30 -type f 2>/dev/null)
local count=$(echo "$files" | grep -v '^$' | wc -l)
if [ "$count" -eq 0 ]; then
echo -e "${GREEN}No old log files found${NC}"
echo ""
press_enter
return
fi
# Calculate size
local total_bytes=0
while IFS= read -r file; do
[ -z "$file" ] && continue
size=$(stat -c%s "$file" 2>/dev/null || echo 0)
total_bytes=$((total_bytes + size))
done <<< "$files"
echo "Found $count log files totaling $(format_size $total_bytes)"
echo ""
echo "Preview (first 10 files):"
echo "$files" | head -10 | while read -r file; do
size=$(stat -c%s "$file" 2>/dev/null || echo 0)
echo -e " ${YELLOW}$(format_size $size)${NC} $file"
done
echo ""
echo -e "${YELLOW}WARNING: This will permanently delete $count log files${NC}"
echo ""
read -p "Continue? (type 'yes' to confirm): " confirm
if [ "$confirm" = "yes" ]; then
find /var/log -name "*.log" -mtime +30 -type f -delete 2>/dev/null
echo ""
echo -e "${GREEN}✓ Deleted $count old log files (freed $(format_size $total_bytes))${NC}"
else
echo ""
echo "Cancelled"
fi
echo ""
press_enter
}
cleanup_package_cache() {
clear
print_banner "Clear Package Cache"
echo ""
if command -v yum &>/dev/null; then
echo "Clearing YUM/DNF cache..."
echo ""
yum clean all
elif command -v apt-get &>/dev/null; then
echo "Clearing APT cache..."
echo ""
apt-get clean
else
echo "No supported package manager found"
fi
echo ""
echo -e "${GREEN}✓ Package cache cleared${NC}"
echo ""
press_enter
}
cleanup_temp_files() {
clear
print_banner "Clear Old Temp Files"
echo ""
echo "Finding temp files older than 7 days..."
echo ""
local files=$(find /tmp -type f -mtime +7 2>/dev/null)
local count=$(echo "$files" | grep -v '^$' | wc -l)
if [ "$count" -eq 0 ]; then
echo -e "${GREEN}No old temp files found${NC}"
echo ""
press_enter
return
fi
# Calculate size
local total_bytes=0
while IFS= read -r file; do
[ -z "$file" ] && continue
size=$(stat -c%s "$file" 2>/dev/null || echo 0)
total_bytes=$((total_bytes + size))
done <<< "$files"
echo "Found $count temp files totaling $(format_size $total_bytes)"
echo ""
echo -e "${YELLOW}WARNING: This will delete temp files older than 7 days${NC}"
echo ""
read -p "Continue? (type 'yes' to confirm): " confirm
if [ "$confirm" = "yes" ]; then
find /tmp -type f -mtime +7 -delete 2>/dev/null
echo ""
echo -e "${GREEN}✓ Deleted $count old temp files (freed $(format_size $total_bytes))${NC}"
else
echo ""
echo "Cancelled"
fi
echo ""
press_enter
}
cleanup_compressed_logs() {
clear
print_banner "Clear Old Compressed Logs"
echo ""
echo "Finding compressed logs older than 30 days..."
echo ""
local files=$(find /var/log -name "*.gz" -mtime +30 -type f 2>/dev/null)
local count=$(echo "$files" | grep -v '^$' | wc -l)
if [ "$count" -eq 0 ]; then
echo -e "${GREEN}No old compressed logs found${NC}"
echo ""
press_enter
return
fi
# Calculate size
local total_bytes=0
while IFS= read -r file; do
[ -z "$file" ] && continue
size=$(stat -c%s "$file" 2>/dev/null || echo 0)
total_bytes=$((total_bytes + size))
done <<< "$files"
echo "Found $count compressed log files totaling $(format_size $total_bytes)"
echo ""
echo -e "${YELLOW}WARNING: This will delete *.gz files older than 30 days${NC}"
echo ""
read -p "Continue? (type 'yes' to confirm): " confirm
if [ "$confirm" = "yes" ]; then
find /var/log -name "*.gz" -mtime +30 -type f -delete 2>/dev/null
echo ""
echo -e "${GREEN}✓ Deleted $count compressed logs (freed $(format_size $total_bytes))${NC}"
else
echo ""
echo "Cancelled"
fi
echo ""
press_enter
}
cleanup_wordpress_cache() {
clear
print_banner "Clear WordPress Cache Files"
echo ""
# Find WordPress cache directories
local wp_caches=()
while IFS= read -r cache_dir; do
wp_caches+=("$cache_dir")
done < <(find /home -path "*/wp-content/cache" -type d 2>/dev/null)
while IFS= read -r cache_dir; do
wp_caches+=("$cache_dir")
done < <(find /var/www -path "*/wp-content/cache" -type d 2>/dev/null)
if [ ${#wp_caches[@]} -eq 0 ]; then
echo -e "${DIM}No WordPress cache directories found${NC}"
echo ""
press_enter
return
fi
# Calculate total size
local total_bytes=0
for cache_dir in "${wp_caches[@]}"; do
size=$(du -sb "$cache_dir" 2>/dev/null | awk '{print $1}')
total_bytes=$((total_bytes + size))
done
echo "Found ${#wp_caches[@]} WordPress cache directories"
echo "Total size: $(format_size $total_bytes)"
echo ""
echo "Cache directories:"
for cache_dir in "${wp_caches[@]}"; do
size=$(du -sh "$cache_dir" 2>/dev/null | awk '{print $1}')
echo -e " ${CYAN}$size${NC} $cache_dir"
done
echo ""
echo -e "${YELLOW}WARNING: This will clear all WordPress cache files${NC}"
echo ""
read -p "Continue? (type 'yes' to confirm): " confirm
if [ "$confirm" = "yes" ]; then
for cache_dir in "${wp_caches[@]}"; do
rm -rf "$cache_dir"/* 2>/dev/null
done
echo ""
echo -e "${GREEN}✓ Cleared WordPress cache (freed $(format_size $total_bytes))${NC}"
else
echo ""
echo "Cancelled"
fi
echo ""
press_enter
}
show_cleanup_summary() {
clear
print_banner "Cleanup Summary (Dry Run)"
echo ""
echo "Calculating potential space savings..."
echo ""
local total_bytes=0
# Old logs
show_progress "Checking old logs"
local old_logs_files=$(find /var/log -name "*.log" -mtime +30 -type f 2>/dev/null)
local old_logs=0
while IFS= read -r file; do
[ -z "$file" ] && continue
size=$(stat -c%s "$file" 2>/dev/null || echo 0)
old_logs=$((old_logs + size))
done <<< "$old_logs_files"
total_bytes=$((total_bytes + old_logs))
local old_logs_count=$(echo "$old_logs_files" | grep -v '^$' | wc -l)
echo -e "\r Old logs (>30 days): ${CYAN}$(format_size $old_logs)${NC} ($old_logs_count files)"
# Compressed logs
show_progress "Checking compressed logs"
local comp_logs_files=$(find /var/log -name "*.gz" -mtime +30 -type f 2>/dev/null)
local comp_logs=0
while IFS= read -r file; do
[ -z "$file" ] && continue
size=$(stat -c%s "$file" 2>/dev/null || echo 0)
comp_logs=$((comp_logs + size))
done <<< "$comp_logs_files"
total_bytes=$((total_bytes + comp_logs))
local comp_logs_count=$(echo "$comp_logs_files" | grep -v '^$' | wc -l)
echo -e "\r Compressed logs (>30 days): ${CYAN}$(format_size $comp_logs)${NC} ($comp_logs_count files)"
# Old temp
show_progress "Checking temp files"
local old_temp_files=$(find /tmp -type f -mtime +7 2>/dev/null)
local old_temp=0
while IFS= read -r file; do
[ -z "$file" ] && continue
size=$(stat -c%s "$file" 2>/dev/null || echo 0)
old_temp=$((old_temp + size))
done <<< "$old_temp_files"
total_bytes=$((total_bytes + old_temp))
local old_temp_count=$(echo "$old_temp_files" | grep -v '^$' | wc -l)
echo -e "\r Old temp files (>7 days): ${CYAN}$(format_size $old_temp)${NC} ($old_temp_count files)"
# Package cache
show_progress "Checking package cache"
local pkg_cache=0
if [ -d "/var/cache/yum" ]; then
pkg_cache=$(du -sb /var/cache/yum 2>/dev/null | awk '{print $1}')
elif [ -d "/var/cache/dnf" ]; then
pkg_cache=$(du -sb /var/cache/dnf 2>/dev/null | awk '{print $1}')
elif [ -d "/var/cache/apt/archives" ]; then
pkg_cache=$(du -sb /var/cache/apt/archives 2>/dev/null | awk '{print $1}')
fi
total_bytes=$((total_bytes + pkg_cache))
echo -e "\r Package cache: ${CYAN}$(format_size $pkg_cache)${NC}"
echo ""
echo "───────────────────────────────────────────────────────────────"
echo -e "${BOLD}Total Potential Savings: ${GREEN}$(format_size $total_bytes)${NC}"
echo ""
press_enter
}
################################################################################
# MAIN MENU
################################################################################
show_main_menu() {
clear
print_banner "Disk Space Analyzer"
echo ""
echo -e "${BOLD}Quick Analysis:${NC}"
echo ""
echo -e " ${GREEN}1)${NC} Disk Overview - Current disk usage summary"
echo -e " ${GREEN}2)${NC} Largest Directories - Find space-consuming directories"
echo -e " ${GREEN}3)${NC} Largest Files - Find individual large files"
echo -e " ${GREEN}4)${NC} Old Files - Files not accessed recently"
echo ""
echo -e "${BOLD}Specific Analysis:${NC}"
echo ""
echo -e " ${CYAN}5)${NC} Log Files - Analyze log file usage"
echo -e " ${CYAN}6)${NC} Email Storage - Mail directory analysis"
echo -e " ${CYAN}7)${NC} Database Storage - MySQL/PostgreSQL data"
echo -e " ${CYAN}8)${NC} Backup Files - Find old backups"
echo -e " ${CYAN}9)${NC} WordPress Sites - WP uploads/cache/plugins"
echo -e " ${CYAN}10)${NC} Temporary Files - /tmp and /var/tmp analysis"
echo -e " ${CYAN}11)${NC} User/Domain Usage - Breakdown by account"
echo -e " ${CYAN}12)${NC} Package Cache - Package manager cache size"
echo ""
echo -e "${BOLD}Actions:${NC}"
echo ""
echo -e " ${YELLOW}13)${NC} Interactive Cleanup - Safe cleanup wizard"
echo -e " ${YELLOW}14)${NC} Generate Report - Export analysis to file"
echo ""
echo -e " ${RED}0)${NC} Exit"
echo ""
echo -e "${CYAN}──────────────────────────────────────────────────────────────${NC}"
read -p "Select option: " choice
}
################################################################################
# MAIN LOOP
################################################################################
main() {
while true; do
show_main_menu
case "$choice" in
1) analyze_disk_overview ;;
2) find_largest_directories "/" 2 ;;
3) find_largest_files "/" "100M" ;;
4) analyze_old_files "/home" 90 ;;
5) analyze_log_files ;;
6) analyze_email_storage ;;
7) analyze_databases ;;
8) analyze_backups ;;
9) analyze_wordpress ;;
10) analyze_temp_files ;;
11) analyze_by_user ;;
12) analyze_package_cache ;;
13) interactive_cleanup_menu ;;
14) generate_report ;;
0)
echo ""
echo -e "${GREEN}Exiting...${NC}"
exit 0
;;
*)
echo -e "${RED}Invalid option${NC}"
sleep 1
;;
esac
done
}
# Run main function
main