#!/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