Files
scripts_serv/arch-cleanup.sh
T
2026-10-02 22:35:11 +02:00

264 lines
7.5 KiB
Bash

#!/usr/bin/env bash
# Arch LXC Secure Cleanup & Audit Script
# Usage: sudo ./arch-cleanup.sh [--dry-run]
set -euo pipefail
# ---------------------------------------------------------------------------
# Safety check
# ---------------------------------------------------------------------------
if [[ $EUID -ne 0 ]]; then
echo "Error: Run this script with sudo: sudo $0 [--dry-run]"
exit 1
fi
# ---------------------------------------------------------------------------
# Config & User detection
# ---------------------------------------------------------------------------
DRY_RUN=false
if [[ "${1:-}" == "--dry-run" ]]; then
DRY_RUN=true
echo ">>> DRY-RUN MODE: No changes will be made <<<"
echo ""
fi
TARGET_USER="${SUDO_USER:-$(logname 2>/dev/null || echo '')}"
TARGET_UID=""
if [[ "$TARGET_USER" == "root" ]]; then
TARGET_USER=""
fi
if [[ -n "$TARGET_USER" ]]; then
TARGET_UID="$(id -u "$TARGET_USER" 2>/dev/null || echo '')"
fi
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
RED=$'\e[31m'
GREEN=$'\e[32m'
YELLOW=$'\e[33m'
BLUE=$'\e[34m'
CYAN=$'\e[36m'
NC=$'\e[0m'
log() { printf "${GREEN}[INFO]${NC} %s\n" "$*"; }
warn() { printf "${YELLOW}[WARN]${NC} %s\n" "$*"; }
err() { printf "${RED}[ERROR]${NC} %s\n" "$*"; }
section() { printf "\n${BLUE}=== %s ===${NC}\n" "$*"; }
confirm() {
[[ "$DRY_RUN" == true ]] && return 0
local r
read -r -p "$1 [y/N] " r
[[ "$r" =~ ^[Yy]$ ]]
}
run() {
if [[ "$DRY_RUN" == true ]]; then
printf "${CYAN}[DRY-RUN]${NC} %s\n" "$*"
else
"$@"
fi
}
# ---------------------------------------------------------------------------
# Phase 1 — Audit: Where is the 170 GB?
# ---------------------------------------------------------------------------
section "Disk Usage Summary"
df -hT / | grep -E 'Filesystem|/dev/'
section "Suspect Directory Sizes"
suspects=(
/var/cache/pacman/pkg
/var/lib/containers
/var/log
/var/log/journal
/var/lib/systemd/coredump
/var/tmp
/tmp
/root
)
for dir in "${suspects[@]}"; do
[[ -d "$dir" ]] || continue
sz=$(du -sh "$dir" 2>/dev/null | awk '{print $1}')
printf " %-40s %s\n" "$dir" "$sz"
done
if [[ -n "$TARGET_USER" && -d "/home/$TARGET_USER" ]]; then
section "User '$TARGET_USER' Suspect Directories"
user_suspects=(
"/home/$TARGET_USER/.cache"
"/home/$TARGET_USER/.cache/paru"
"/home/$TARGET_USER/.cache/paru/clone"
"/home/$TARGET_USER/.cache/paru/pkg"
"/home/$TARGET_USER/.cache/yay"
"/home/$TARGET_USER/.local/share/containers"
)
for dir in "${user_suspects[@]}"; do
[[ -e "$dir" ]] || continue
sz=$(du -sh "$dir" 2>/dev/null | awk '{print $1}')
printf " %-50s %s\n" "$dir" "$sz"
done
fi
section "Large Individual Files (>1 GB)"
for search_root in /var /home /root /opt; do
[[ -d "$search_root" ]] || continue
find "$search_root" -xdev -maxdepth 5 -type f -size +1G -exec ls -lh {} + 2>/dev/null | head -n 20
done
echo ""
if ! confirm "Continue with cleanup?"; then
log "Aborted by user."
exit 0
fi
# ---------------------------------------------------------------------------
# Phase 2 — Cleanup
# ---------------------------------------------------------------------------
# --- Pacman cache ---
section "Pacman Cache Cleanup"
if command -v paccache &>/dev/null; then
log "Removing cached packages for uninstalled software..."
run paccache -ruv
log "Keeping last 2 versions of installed packages, removing older..."
run paccache -rvk2
else
warn "'paccache' (pacman-contrib) not found."
if confirm "Install pacman-contrib now? (Recommended; needs a little free space)"; then
if [[ "$DRY_RUN" == true ]]; then
log "[DRY-RUN] Would install pacman-contrib and run paccache"
else
pacman -S --noconfirm --needed pacman-contrib
paccache -ruv
paccache -rvk2
fi
else
if confirm "Run fallback 'pacman -Sc'? (Removes ALL uninstalled cached packages)"; then
run pacman -Sc --noconfirm
fi
fi
fi
# --- Orphaned packages ---
section "Orphaned Packages"
orphans="$(pacman -Qdtq 2>/dev/null || true)"
if [[ -z "$orphans" ]]; then
log "No orphaned packages found."
else
warn "Orphaned packages found:"
echo "$orphans"
if confirm "Remove these orphaned packages?"; then
if [[ "$DRY_RUN" == true ]]; then
log "[DRY-RUN] Would remove: $orphans"
else
# shellcheck disable=SC2086
pacman -Rns --noconfirm $orphans
fi
fi
fi
# --- AUR Helpers (paru / yay) ---
section "AUR Helper Cache Cleanup"
clean_aur() {
local helper=$1
local binpath clone_dir pkg_dir sz
binpath="$(command -v "$helper" 2>/dev/null || true)"
if [[ -z "$binpath" ]]; then
log "$helper not installed."
return
fi
if [[ -z "$TARGET_USER" ]]; then
warn "Cannot determine non-root user for $helper cleanup."
return
fi
log "Running safe cache clean for $helper..."
run sudo -u "$TARGET_USER" "$binpath" -Sc --noconfirm || warn "$helper -Sc finished with warnings"
clone_dir="/home/$TARGET_USER/.cache/$helper/clone"
if [[ -d "$clone_dir" ]]; then
sz=$(du -sh "$clone_dir" 2>/dev/null | awk '{print $1}')
warn "$helper clone directory size: $sz"
if confirm "Delete $helper PKGBUILD clones? (They must be re-downloaded later)"; then
run rm -rf "${clone_dir:?}"/*
log "Cleaned $clone_dir"
fi
fi
pkg_dir="/home/$TARGET_USER/.cache/$helper/pkg"
if [[ -d "$pkg_dir" ]] && command -v paccache &>/dev/null; then
log "Running paccache on $helper package dir..."
run paccache -ruv --cachedir "$pkg_dir" || true
fi
}
clean_aur "paru"
clean_aur "yay"
# --- Podman (rootful + rootless) ---
section "Podman Cleanup"
if command -v podman &>/dev/null; then
log "Rootful Podman disk usage:"
run podman system df || true
if confirm "Prune unused rootful Podman resources (containers, networks, images, build cache)?"; then
run podman system prune -a -f
fi
else
log "Podman (rootful) not installed."
fi
if [[ -n "$TARGET_USER" && -n "$TARGET_UID" ]]; then
if sudo -u "$TARGET_USER" podman --version &>/dev/null; then
log "Rootless Podman disk usage for $TARGET_USER:"
run sudo -u "$TARGET_USER" podman system df || true
if confirm "Prune unused rootless Podman resources for $TARGET_USER?"; then
run sudo -u "$TARGET_USER" \
XDG_RUNTIME_DIR="/run/user/$TARGET_UID" \
podman system prune -a -f ||
run sudo -u "$TARGET_USER" podman system prune -a -f
fi
else
log "Rootless Podman not configured for $TARGET_USER."
fi
else
log "Skipping rootless Podman (no target user detected)."
fi
# --- Logs ---
section "System Logs"
if [[ -d /var/log/journal ]] && command -v journalctl &>/dev/null; then
jsz=$(du -sh /var/log/journal 2>/dev/null | awk '{print $1}')
log "Persistent journal size: $jsz"
if confirm "Vacuum journal to max 500 MB?"; then
run journalctl --vacuum-size=500M
fi
else
log "No persistent systemd journal detected."
fi
if find /var/log -maxdepth 2 -type f -size +500M 2>/dev/null | grep -q .; then
warn "Large uncompressed log files remain in /var/log. You may want to truncate them manually."
fi
# ---------------------------------------------------------------------------
# Final Summary
# ---------------------------------------------------------------------------
section "Final Disk Usage"
df -hT /
log "Cleanup complete. Review the output above to see how much was recovered."
if [[ "$DRY_RUN" == true ]]; then
log "This was a DRY RUN. Re-run without --dry-run to actually free space."
fi