Files
cschantz 5c4c733e47 Add comprehensive disk space analyzer to toolkit
New Feature: WinDirStat-like disk space analyzer for Linux
Location: modules/maintenance/disk-space-analyzer.sh
Menu: Backup & Recovery → Maintenance (option 4)

Key Features:
- 14 different analysis and cleanup options
- Inode usage monitoring (critical for detecting inode exhaustion)
- No external dependencies (bc removed, using awk for math)
- Multi-panel support (cPanel/Plesk/InterWorx)
- Interactive drill-down capability
- Preview before deletion for all cleanup operations

Analysis Types:
1. Disk usage overview with warnings (>90% critical, >75% warning)
2. Inode usage checking (often overlooked but critical)
3. Largest directories with drill-down capability
4. Largest files with type detection (log/db/archive/video/image)
5. Old log files analysis (>30 days with size totals)
6. Temporary files finder (/tmp, /var/tmp with age detection)
7. Package manager cache (yum/dnf/apt)
8. Email storage analysis (mail spools, Maildir, Maildrop)
9. Database storage (MySQL/MariaDB, PostgreSQL data dirs)
10. Backup files finder (.bak, .tar.gz, .sql with age)
11. WordPress analysis (uploads, plugins, cache by site)
12. Report generation (exports all analysis to timestamped file)

Cleanup Operations (all with preview):
13. Clean old log files (>30 days, shows preview, requires "yes")
14. Clean package cache (yum/dnf/apt, requires "yes")
15. Clean WordPress cache (per-site WP Super Cache cleanup)

Technical Improvements:
- size_to_bytes() function for human-readable to bytes conversion
- Uses awk for all floating point math (no bc dependency)
- Excludes system dirs (/proc, /sys, /dev, /run) for faster scans
- Format functions for consistent output (bytes/KB/MB/GB/TB)
- Age detection for files (shows days old)
- File type detection by extension
- Interactive menus with color coding

Safety Features:
- Dry-run preview before all deletions
- Confirmation prompts ("yes" required, not just "y")
- Size calculations shown before deletion
- First 10 files previewed in cleanup operations

Changes to launcher.sh:
- Added option 4 to Backup & Recovery menu
- Added case handler to run disk-space-analyzer.sh
- Menu text: "💿 Disk Space Analyzer - Find space issues & cleanup files"

Testing: Script is executable and ready to use
2025-12-17 19:25:58 -05:00

1321 lines
43 KiB
Bash
Executable File

#!/bin/bash
################################################################################
# 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"
# Require root
if [ "$EUID" -ne 0 ]; then
print_error "This script must be run as root"
exit 1
fi
# 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
show_progress "Finding WordPress installations"
local wp_paths=()
# Common locations
if [ -d "/home" ]; then
while IFS= read -r wp_config; do
wp_dir=$(dirname "$wp_config")
wp_paths+=("$wp_dir")
done < <(find /home -name "wp-config.php" -type f 2>/dev/null)
fi
if [ -d "/var/www" ]; then
while IFS= read -r wp_config; do
wp_dir=$(dirname "$wp_config")
wp_paths+=("$wp_dir")
done < <(find /var/www -name "wp-config.php" -type f 2>/dev/null)
fi
if [ ${#wp_paths[@]} -eq 0 ]; then
echo -e "\r${DIM}No WordPress installations found${NC} "
echo ""
press_enter
return
fi
echo -e "\r${GREEN}${NC} Found ${#wp_paths[@]} WordPress installations "
echo ""
echo -e "${BOLD}WordPress Space Usage:${NC}"
echo "───────────────────────────────────────────────────────────────"
for wp_dir in "${wp_paths[@]}"; do
# Get domain/user from path
domain=$(echo "$wp_dir" | awk -F'/' '{for(i=1;i<=NF;i++) if($i~/public_html|httpdocs|www/) print $(i-1)}' | tail -1)
# Calculate sizes
total_size=$(du -sh "$wp_dir" 2>/dev/null | awk '{print $1}')
uploads_size=$(du -sh "$wp_dir/wp-content/uploads" 2>/dev/null | awk '{print $1}')
plugins_size=$(du -sh "$wp_dir/wp-content/plugins" 2>/dev/null | awk '{print $1}')
cache_size=$(du -sh "$wp_dir/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 ""
done
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